Compare commits

..

235 Commits

Author SHA1 Message Date
Joe Haddad
fb4d4b5953 Publish Stable
- @now/build-utils@2.1.0
 - @now/next@2.4.0
 - @now/routing-utils@1.7.0
2020-02-28 10:19:47 -05:00
Joe Haddad
de3701c045 Publish Canary
- @now/ruby@1.0.3-canary.1
2020-02-28 10:18:46 -05:00
m5o
9f9b7934cb [now-ruby] Fix ruby test indentation (#3854)
* fix ruby indentation example
  * 💅 indent with 2 spaces for consistency
2020-02-28 14:34:47 +00:00
Steven
bcded1dd17 Publish Canary
- @now/build-utils@2.0.1-canary.3
 - @now/next@2.3.19-canary.2
 - @now/python@1.1.5-canary.1
2020-02-28 08:57:36 -05:00
Steven
8503af75ba [now-python] Fix space encoding 2020-02-28 08:35:27 -05:00
Joe Haddad
158a50f1aa [now-next] Allow Immutable Fallback Artifact (#3850)
* [now-next] Allow Immutable Fallback Artifact

* trigger
2020-02-27 22:00:09 -05:00
Steven
61da552dd6 [now-build-utils] Add test for NODE_ENV behavior (#3852)
This PR adds a test for #3847.
2020-02-27 21:47:27 +00:00
Steven
fa838eecac Publish Canary
- @now/go@1.0.5-canary.0
 - @now/next@2.3.19-canary.1
 - @now/node@1.4.2-canary.0
 - @now/python@1.1.5-canary.0
 - @now/ruby@1.0.3-canary.0
 - @now/static-build@0.14.13-canary.1
2020-02-27 15:52:36 -05:00
Steven
71b6a58783 [all] Exclude @now/build-utils in bundled builder to fix tests (#3848)
This fixes a bug in our `@now/build-utils` tests that pair the current build-utils with a stable builder. Since ncc was bundling `@now/build-utils`, we weren't able to configure a different version and these tests were not actually testing the correct version of build-utils.

A nice side-effect is that each builder will be about 50% smaller (compared by measuring `dist`).
2020-02-27 15:48:03 -05:00
Joe Haddad
22dd78e286 Publish Canary
- @now/build-utils@2.0.1-canary.2
 - @now/next@2.3.19-canary.0
2020-02-27 12:35:52 -05:00
Joe Haddad
e63fcf2630 [now-next] Add Support for Prerender v2 (#3845)
* [now-next] Add Support for Prerender v2

* Copy test suite

* Test that fallback doesn't work for fallback: false

* record omitted lambdas

* Improve test case

* improve omitted routes logic

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2020-02-27 12:33:31 -05:00
Steven
98e1553c2e [now-build-utils] Install all deps regardless of NODE_ENV (#3847)
Some build utilities and SSG Frameworks instruct users to set `NODE_ENV=production` which typically means updating `now.json` to the following:

```json
{
  "build": {
    "env": {
      "NODE_ENV": "production"
    }
  }
}
```

The problem is that this environment variable is assigned during `npm install` or `yarn install` which is the equivalent of running install with the `--production` flag. This flag prevents `devDependencies` from installing. This is almost never what the user intends so they have to remove `now.json` and instead updating their build script to `NODE_ENV=production yarn build`.

This PR improves the experience by deleting `NODE_ENV` during the install step.
2020-02-27 12:14:06 -05:00
Steven
4dc506f17a Publish Canary
- @now/build-utils@2.0.1-canary.1
 - now@17.0.5-canary.5
 - @now/routing-utils@1.6.1-canary.1
2020-02-27 08:05:05 -05:00
Steven
3b396f29e9 [now-build-utils][now-routing-utils] Fix appendRoutesToPhase() when input is null (#3843)
This PR fixes `@now/routing-utils` when the input routes are null. It used to return the empty array but now it will still append.

I also added many more tests to `@now/build-utils` when `featureHandleMiss: true` and refactored the code a bit to make dynamic routes and api routes a little more clear.
2020-02-26 23:30:50 +00:00
JJ Kasper
1f128e69e6 Publish Stable
- @now/next@2.3.18
2020-02-26 15:56:41 -06:00
JJ Kasper
f1487c92cb Publish Canary
- now@17.0.5-canary.4
 - @now/next@2.3.18-canary.0
2020-02-26 15:51:27 -06:00
JJ Kasper
45066cdf44 [now-next] Add /_next/data routes for getServerProps pages (#3771)
This adds the `/_next/data` routes for `getServerProps` pages if they exist

x-ref: https://github.com/zeit/next.js/pull/10077
x-ref: https://github.com/zeit/next.js/pull/10622
2020-02-26 21:47:51 +00:00
Ana Trajkovska
7dde9c8207 Publish Canary
- now@17.0.5-canary.3
 - now-client@7.0.1-canary.1
2020-02-26 08:00:09 +01:00
Ana Trajkovska
fd964f825d Handle deployment cancellation (#3823)
Co-authored-by: Max <8418866+rdev@users.noreply.github.com>
2020-02-26 07:21:27 +01:00
Steven
1656c9874e Publish Canary
- @now/build-utils@2.0.1-canary.0
 - now@17.0.5-canary.2
 - @now/routing-utils@1.6.1-canary.0
2020-02-25 17:32:37 -05:00
Steven
d999a3b2ad [now-routing-utils][now-build-utils] Refactor zero-config rewrites (#3832)
This PR refactors the rewrites (the dynamic routes as well as the route that prevents directory listing for zero config deployments) so they are not in the `handle: miss` phase.

This is necessary because the behavior of `handle: miss` will change in an upcoming release.

The solution is to separate these into `rewriteRoutes` that can then be merged properly with the user's routes. They will be appended to the `handle: filesystem` phase (or add the phase if it doesn't exist).
2020-02-25 22:30:36 +00:00
Joe Haddad
cfb7c9e632 Publish Stable
- @now/next@2.3.17
2020-02-25 15:19:05 -05:00
Joe Haddad
06e8472cf7 Publish Canary
- now@17.0.5-canary.1
 - @now/next@2.3.17-canary.0
 - @now/static-build@0.14.13-canary.0
2020-02-25 14:57:42 -05:00
Joe Haddad
92404135d8 [now-next] Always Emit Prerenders (#3837)
This ensures we always emit Prerender objects for bypass tokens.
2020-02-25 19:51:07 +00:00
Nathan Rajlich
8b5cc23d7c [now-cli] Remove v1 "static build" integration tests (#3833)
* [now-cli] Remove v1 "static build" integration tests

These are the last remaining v1 static type deployments being created.

* Remove from `integration.js` as well

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2020-02-24 17:19:22 -08:00
Shu Uesugi
e10b42bfdc Rename zeit.co/new → zeit.co/import (#3834)
* zeit.co/new → zeit.co/import

* Update docs URL
2020-02-25 01:35:12 +01:00
M. Heide
36f7ec4836 [examples] Fix Go build if Windows Git is configured to checkout CRLF line endings (#3821)
Fixes #3820
2020-02-24 19:53:15 +00:00
Joe Haddad
f89d1c463e Remove Backticks from URL Output (#3830)
![image](https://user-images.githubusercontent.com/616428/75176976-44434880-5703-11ea-8ca5-cb49e4a921cf.png)

![image](https://user-images.githubusercontent.com/616428/75176982-473e3900-5703-11ea-90f6-b31844a486ce.png)
2020-02-24 19:22:58 +00:00
Steven
5dc652eba9 Publish Canary
- now@17.0.5-canary.0
 - now-client@7.0.1-canary.0
2020-02-24 12:53:13 -05:00
Steven
821b2bd50b [now-client] Fix root directory with trailing slash (#3827)
There was a bug in `now-client` when deploying a directory that ends with a slash, for example `/Users/styfle/Code/myapp/` instead of the usual `/Users/styfle/Code/myapp`.

This never affected `now-cli` until we added support for defining the `rootDirectory` which allows the user to type whatever they wish in the Project Settings.

The fix is to use `path.relative()` instead of substring.
2020-02-24 17:45:10 +00:00
Steven
8d5f6f1fa3 Publish Stable
- @now/frameworks@0.0.10
 - @now/build-utils@2.0.0
 - now@17.0.4
 - @now/go@1.0.4
 - @now/next@2.3.16
 - @now/python@1.1.4
 - @now/routing-utils@1.6.0
2020-02-21 18:09:20 -05:00
Steven
617f610c07 [tests] Update cancel workflow (#3817)
Update to latest version, [0.2.0](https://github.com/styfle/cancel-workflow-action/releases/tag/0.2.0), which will fix cancelling on push.

Also this action is available in the [marketplace](https://github.com/marketplace/actions/cancel-workflow-action).
2020-02-21 18:00:27 -05:00
Steven
3229ba0106 Publish Canary
- @now/go@1.0.4-canary.3
 - @now/python@1.1.4-canary.1
2020-02-21 17:27:20 -05:00
Steven
d16a6e4716 [now-go] Fix path segments in now dev (#3816)
The combination of file renaming and brackets doesn't work well for go build so we need to add the file extension back before building.

I also simplified the `.now/cache/folder` logic because it should be the same whether `builds` is defined or not (aka zero config).
2020-02-21 22:25:44 +00:00
Steven
4e5156fb0b [now-python] Fix path segments in now dev (#3815)
The combination of file renaming and brackets doesn't work well for python imports so we need too add the file extension back before importing the python module.

I also simplified the `.now/cache/folder` logic because it should be the same whether `builds` is defined or not (aka zero config).
2020-02-21 20:45:41 +00:00
Joe Haddad
3c013cc36b Publish Canary
- @now/build-utils@2.0.0-canary.2
 - @now/next@2.3.16-canary.1
2020-02-21 11:06:44 -05:00
Joe Haddad
1ed83135be Add Bypass Token to Next.js Builder (#3811)
This pull request adds the bypass token to returned `Prerender` output objects.

There's no tests as this doesn't exist in production yet.
2020-02-21 16:05:22 +00:00
Joe Haddad
0e71ff2df1 [now-build-utils] Add bypassToken to Prerender for iSSG (#3810)
This pull request adds a new `bypassToken` field to the `Prerender` output.

The field is required to be at least 128 bits for security reasons!
2020-02-20 01:59:45 +00:00
JJ Kasper
d8e98ee476 Publish Canary
- @now/next@2.3.16-canary.0
 - @now/routing-utils@1.5.4-canary.0
2020-02-19 16:23:25 -06:00
JJ Kasper
1bc1e8a9b1 [now-routing-utils] Update to not pass used segments in redirect query (#3809)
This updates to not pass segments already used in a redirect's destination query since these values are most likely unwanted and can still be manually added if desired. This change does not affect rewrites and we still pass through all segments in the query
2020-02-19 22:13:36 +00:00
JJ Kasper
274fdeb49a Publish Stable
- @now/next@2.3.15
2020-02-19 15:02:21 -06:00
JJ Kasper
d15c90b42f Publish Canary
- now@17.0.4-canary.3
 - @now/next@2.3.15-canary.0
2020-02-19 14:57:20 -06:00
JJ Kasper
5be2917c47 [now-next] Update 404 handling for pages/404 (#3697)
This adds handling for treating `pages/404.js` as the custom error page in Next.js to allow for more flexible auto static optimization on the 404 page. This makes sure we handle `pages/404.js` being a lambda due to `_app` having `getInitialProps` and also makes sure that visiting `/404` doesn't respond with a 200 status code

~We can add tests for this behavior after the below PR has been released in a canary of Next.js~

x-ref: https://github.com/zeit/next.js/pull/10329
x-ref: https://github.com/zeit/next.js/pull/10593
2020-02-19 20:55:26 +00:00
dependabot[bot]
5f08b24546 Bump codecov from 3.1.0 to 3.6.5 (#3807)
Bumps [codecov](https://github.com/codecov/codecov-node) from 3.1.0 to 3.6.5.
<details>
<summary>Release notes</summary>

*Sourced from [codecov's releases](https://github.com/codecov/codecov-node/releases).*

> ## v3.6.4
> Fix for Cirrus CI
> 
> ## v3.6.3
> AWS Codebuild fixes + package updates
> 
> ## v3.6.2
> command line args sanitised
> 
> ## v3.6.1
> Fix for Semaphore
> 
> ## v3.6.0
> AWS CodeBuild
> Semaphore v2
> 
> ## v3.3.0
> Added pipe `--pipe`, `-l`
</details>
<details>
<summary>Commits</summary>

- See full diff in [compare view](https://github.com/codecov/codecov-node/commits)
</details>
<details>
<summary>Maintainer changes</summary>

This version was pushed to npm by [drazisil](https://www.npmjs.com/~drazisil), a new releaser for codecov since your current version.
</details>
<br />

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=codecov&package-manager=npm_and_yarn&previous-version=3.1.0&new-version=3.6.5)](https://help.github.com/articles/configuring-automated-security-fixes)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
- `@dependabot use these labels` will set the current labels as the default for future PRs for this repo and language
- `@dependabot use these reviewers` will set the current reviewers as the default for future PRs for this repo and language
- `@dependabot use these assignees` will set the current assignees as the default for future PRs for this repo and language
- `@dependabot use this milestone` will set the current milestone as the default for future PRs for this repo and language

You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/zeit/now/network/alerts).

</details>
2020-02-19 20:19:49 +00:00
Steven
cc3026ffcb [tests] Fix builder debug flag (#3805)
When testing, you can set `NOW_BUILDER_DEBUG=1` to print verbose logs from builders.

However, this was causing some tests to fail that depended on a build environment variable.

This PR fixes the assignment so that it preserves the environment variables from the tests by adding `NOW_BUILDER_DEBUG` instead of replacing.
2020-02-18 22:57:17 +00:00
JJ Kasper
8cb6e56679 Publish Stable
- @now/next@2.3.14
2020-02-17 14:28:07 -06:00
JJ Kasper
7da5ff4b1d Publish Canary
- now@17.0.4-canary.2
 - @now/next@2.3.14-canary.1
2020-02-17 11:45:53 -06:00
JJ Kasper
5d1069d464 [now-next] Make sure to 404 and clear cache header for invalid _next requests (#3801)
This handles an edge case where deeply nested dynamic routes were handling `_next` 404s that were cached forever since the immutable header we set isn't cleared after not matching on the filesystem.

I updated our cache-header fixture to check for this edge case also to make sure we don't regress on this
2020-02-17 17:42:51 +00:00
Andy
6e1a72f557 [examples] Use Full URL for Logos (#3800)
Use Full URL for Logos

[PRODUCT-1193]

[PRODUCT-1193]: https://zeit.atlassian.net/browse/PRODUCT-1193
2020-02-17 13:44:35 +00:00
dependabot[bot]
6f97a2cc7a Bump yarn from 1.17.3 to 1.22.0 (#3796)
Bumps [yarn](https://github.com/yarnpkg/yarn) from 1.17.3 to 1.22.0.
<details>
<summary>Changelog</summary>

*Sourced from [yarn's changelog](https://github.com/yarnpkg/yarn/blob/master/CHANGELOG.md).*

> # Changelog
> 
> Please add one entry in this file for each change in Yarn's behavior. Use the same format for all entries, including the third-person verb. Make sure you don't add more than one line of text to keep it clean. Thanks!
> 
> ## Master
> 
> - Passes arguments following `--` when running a workspace script (`yarn workspace pkg run command -- arg`)
> 
>   [#7776](https://github-redirect.dependabot.com/yarnpkg/yarn/pull/7776) - [**Jeff Valore**](https://twitter.com/rally25rs)
> 
> - Prints workspace names with `yarn workspaces` (silence with `-s`)
> 
>   [#7722](https://github-redirect.dependabot.com/yarnpkg/yarn/pull/7722) - [**Orta**](https://twitter.com/orta)
> 
> - Implements `yarn init --install <version>`
> 
>   [#7723](https://github-redirect.dependabot.com/yarnpkg/yarn/pull/7723) - [**Maël Nison**](https://twitter.com/arcanis)
>   
> - Implements `yarn init -2`
> 
>   [#7862](https://github-redirect.dependabot.com/yarnpkg/yarn/pull/7862) - [**Maël Nison**](https://twitter.com/arcanis)
> 
> - Implements `yarn set version <version>` as an alias for `policies set-version`
> 
>   [#7862](https://github-redirect.dependabot.com/yarnpkg/yarn/pull/7862) - [**Maël Nison**](https://twitter.com/arcanis)
> 
> - Fixes an issue where the archive paths were incorrectly sanitized
> 
>   [#7831](https://github-redirect.dependabot.com/yarnpkg/yarn/pull/7831) - [**Maël Nison**](https://twitter.com/arcanis)
> 
> - Allows some dots in binary names again
> 
>   [#7811](https://github-redirect.dependabot.com/yarnpkg/yarn/pull/7811) - [**Valery Bugakov**](https://github.com/valerybugakov)
>   
> - Better error handling on `yarn set version`
> 
>   [#7848](https://github-redirect.dependabot.com/yarnpkg/yarn/pull/7848) - [**Nick Olinger**](https://github.com/olingern)
> 
> ## 1.19.2
> 
> - Folders like `.cache` won't be pruned from the `node_modules` after each install.
> 
>   [#7699](https://github-redirect.dependabot.com/yarnpkg/yarn/pull/7699) - [**Maël Nison**](https://twitter.com/arcanis)
> 
> - Correctly installs workspace child dependencies when workspace child not symlinked to root.
> 
>   [#7289](https://github-redirect.dependabot.com/yarnpkg/yarn/pull/7289) - [**Daniel Tschinder**](https://github.com/danez)
> 
> - Makes running scripts with Plug'n Play possible on node 13.
> 
></tr></table> ... (truncated)
</details>
<details>
<summary>Commits</summary>

- [`eee67d0`](eee67d02ed) v1.22.0
- [`6971622`](69716228e9) Update CHANGELOG.md
- [`0e7133c`](0e7133ca28) Fixes arbitrary file write on fetch ([#7831](https://github-redirect.dependabot.com/yarnpkg/yarn/issues/7831))
- [`fa613f3`](fa613f3a71) handle failed policy set-version ([#7848](https://github-redirect.dependabot.com/yarnpkg/yarn/issues/7848))
- [`f381c5f`](f381c5f0ce) Implements set version ([#7862](https://github-redirect.dependabot.com/yarnpkg/yarn/issues/7862))
- [`d2c3a48`](d2c3a485e0) Configure bug report issue template ([#7844](https://github-redirect.dependabot.com/yarnpkg/yarn/issues/7844))
- [`af4c205`](af4c2056a3) Allow dots in bin names ([#7811](https://github-redirect.dependabot.com/yarnpkg/yarn/issues/7811))
- [`1b334e6`](1b334e687b) fix(workspaces): Pass args following "--" when running workspace scripts ([#7786](https://github-redirect.dependabot.com/yarnpkg/yarn/issues/7786))
- [`2c8e97e`](2c8e97eaf3) Fix suggestions for CLI ([#7808](https://github-redirect.dependabot.com/yarnpkg/yarn/issues/7808))
- [`039bafd`](039bafd74b) Fixes bin overwrites ([#7755](https://github-redirect.dependabot.com/yarnpkg/yarn/issues/7755))
- Additional commits viewable in [compare view](https://github.com/yarnpkg/yarn/compare/v1.17.3...v1.22.0)
</details>
<details>
<summary>Maintainer changes</summary>

This version was pushed to npm by [daniel15](https://www.npmjs.com/~daniel15), a new releaser for yarn since your current version.
</details>
<br />

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=yarn&package-manager=npm_and_yarn&previous-version=1.17.3&new-version=1.22.0)](https://help.github.com/articles/configuring-automated-security-fixes)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
- `@dependabot use these labels` will set the current labels as the default for future PRs for this repo and language
- `@dependabot use these reviewers` will set the current reviewers as the default for future PRs for this repo and language
- `@dependabot use these assignees` will set the current assignees as the default for future PRs for this repo and language
- `@dependabot use this milestone` will set the current milestone as the default for future PRs for this repo and language

You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/zeit/now/network/alerts).

</details>
2020-02-15 01:56:34 +00:00
Steven
6e402bffc3 Publish Canary
- now@17.0.4-canary.1
 - @now/go@1.0.4-canary.2
 - @now/next@2.3.14-canary.0
2020-02-14 15:05:00 -05:00
Steven
e41d0f8e68 [now-go] Fix /api/go.sum detection (#3795)
Follow up to #3793 

The `go.mod` and `go.sum` file must both be moved.
2020-02-14 19:58:44 +00:00
Steven
1a046744f2 [now-go] Add support for root go.mod in api directory (#3793)
Some users wish to put all Go related code in the `/api` directory and the root is reserved for a frontend framework.

This PR adds support for `/api/go.mod` which will act the same as `/go.mod` by moving the file to the root.
2020-02-14 17:32:20 +00:00
Andy
a9bf011f2c [api] Add rewrite to frameworks API (#3794)
* [api] Add rewrite to frameworks API

* Adjust now.json

* Change output file
2020-02-14 00:30:58 +01:00
JJ Kasper
60c76b3290 [now-next] Add support for using the fallback file for dynamic SSG pages (#3752)
This adds support for using the fallback file for dynamic (lazy) SSG pages to allow showing a loading state while the cache is populated with data. We can add tests for this behavior once the below referenced PR is shipped on canary

x-ref: https://github.com/zeit/next.js/pull/10424

~Update: added tests now that fallback support has landed in Next.js although it appears `now-proxy` might need to be updated to revalidate the fallback correctly since the initial fallback is always being shown for lazy SSG pages with these changes~

Looks like this is working properly in `now-proxy` and we were overriding the prerender output with the static page output, thanks @juancampa for helping investigate! 🙏
2020-02-13 01:06:55 +00:00
Steven
c7ff1e7044 [now-cli] Update ZEIT Logo (#3790)
This PR updates the logo to match https://zeit.co/home
2020-02-12 10:17:54 -05:00
Andy Bitz
e2deaef54a Publish Canary
- @now/frameworks@0.0.10-canary.0
2020-02-12 14:46:11 +01:00
Andy
b2c7386c83 [frameworks] Adjust Next.js build command placeholder (#3788) 2020-02-12 14:34:09 +01:00
Steven
3dce84c3cf Publish Canary
- @now/go@1.0.4-canary.1
2020-02-11 16:46:21 -05:00
Steven
443b1ac158 [now-go] Fix path segments with square brackets (#3782)
Previously, `@now/go` would fail when using [Path Segments](https://zeit.co/docs/v2/serverless-functions/introduction#path-segments) since `go build` [doesn't support](https://stackoverflow.com/q/60140859/266535) files that begin with square bracket.

This PR changes the build logic so that the entrypoint file is renamed if if begins with a square bracket.

The output file is not renamed because v3 builders can't rename outputs which works great for this feature.
2020-02-11 21:41:57 +00:00
Andy Bitz
be3dca3d94 Publish Canary
- @now/build-utils@2.0.0-canary.1
 - now@17.0.4-canary.0
 - @now/go@1.0.4-canary.0
 - @now/python@1.1.4-canary.0
2020-02-11 16:50:13 +01:00
Andy Bitz
cb135e4329 [now-build-utils] Bump version 2020-02-11 16:50:01 +01:00
Andy
55c73b68bb [now-build-utils][now-cli] Refactor builds and routes detection (#3784)
* [now-build-utils] Refactor detect builds

* Refactor routes detection

* [now-cli] Adjust `now dev`

* Adjust tests

* Adjust integrations test

* Remove unused file

* Replace reducw with for-loop

* Add cache for absolute paths

* Filter while looping

* Add fallback for entrypoint with buildCommand
2020-02-11 16:47:39 +01:00
Steven
eb793ba139 [tests] Add windows to CI unit tests (#3727)
This adds initial support for Windows in GitHub Actions CI tests.

There is still work to be done to prevent certain tests from hanging in CI so those are skipped for now.
2020-02-11 01:16:14 +00:00
Steven
00908e8ebe [now-python] Fix path segments with square brackets (#3781)
Previously, python would fail when using [Path Segments](https://zeit.co/docs/v2/serverless-functions/introduction#path-segments) as seen in #3729.

This PR changes the import logic so that the entrypoint file is [imported as a relative file path](https://stackoverflow.com/a/67692/266535) instead of by module name.
2020-02-10 21:01:31 +00:00
Leo Lamprecht
5ce7ff86a4 Minor tweaks for CONTRIBUTING.md file (#3778)
* Minor tweaks for CONTRIBUTING.md file

* Update CONTRIBUTING.md

* Update CONTRIBUTING.md
2020-02-10 18:34:00 +01:00
Steven
4b34ee2993 [examples] Remove outdated jekyll build section from README (#3780)
We used to require a `package.json` but we have since introduced [Advanced Project Settings](https://zeit.co/blog/advanced-project-settings) which will ask the user for a build command during the first deploy.
2020-02-10 15:31:52 +00:00
Andi
646bd288ba [now-go] Update go to version 1.13.7 (#3750)
Updates go to the latest version 1.13.7 (https://golang.org/doc/devel/release.html#go1.13). This allows users to use the new error functionality that was introduced in go 1.13 (https://blog.golang.org/go1.13-errors) and also includes a couple of security fixes.

Looking at the last PR that updated the version (https://github.com/zeit/now-builders/pull/247/files) this should be as simple as updating the version number.

P.S. I tried to follow the contribution guidelines, but `yarn lint` fails with `exit code 1`/`295 problems (33 errors, 262 warnings)` and `yarn test` returns `error Command "test" not found` on master. But `yarn test-unit` shows no errors.
2020-02-08 01:47:47 +00:00
Steven
8aba6f1ff8 Publish Stable
- now@17.0.3
2020-02-07 20:01:17 -05:00
Steven
35e5e328aa Publish Canary
- now@17.0.3-canary.1
2020-02-07 19:18:47 -05:00
Andy
bdd4953d62 [now-cli] Consider root directory for now.json (#3764)
* [now-cli] Consider root directory for now.json

* Adjust message check in test

* Fallback if config does not exist as well

* Assign localConfig later and add debug

* Prefere now.json from root directory

* Comment

* Adjust test and add warning
2020-02-08 01:04:34 +01:00
Steven
e938b298e2 [now-cli] Fix port assignment for now dev (#3769)
This fixes a regression from #3749 where the PORT env var was removed. This is necessary so frameworks like create-react-app and gatsby can proxy to `now dev`.

Fixes #3761
2020-02-07 19:03:56 -05:00
Andy
b67f324e10 [api] Add hasDetectors property (#3770) 2020-02-08 00:29:11 +01:00
Andy Bitz
1dfa286af5 Publish Canary
- now@17.0.3-canary.0
2020-02-07 21:14:50 +01:00
Andy
d4391bd4cc [now-cli] Fix chalk template for legacy (#3768)
* [now-cli] Fix chalk template for legacy

* Update packages/now-cli/src/commands/deploy/legacy.ts

Co-Authored-By: Nathan Rajlich <n@n8.io>

Co-authored-by: Nathan Rajlich <n@n8.io>
2020-02-07 21:14:11 +01:00
luc
53eb71f26d Publish Stable
- now@17.0.2
 - @now/routing-utils@1.5.3
2020-02-06 19:18:35 +01:00
luc
92ffd654b5 Publish Canary
- now@17.0.2-canary.1
2020-02-06 18:53:36 +01:00
Luc
36b83f1606 [now-cli] Use npx or yarn to execute dev command (#3760)
1. Use bundled yarn to run `yarn bin`
2. Skip `yarn bin` if `npx` is used
2020-02-06 17:47:39 +00:00
Steven
7a79f620c0 [tests] Fix changelog script (#3751)
Previously, the changelog script was looking for the last "Publish Stable" commit, but it should really be looking for the last Stable release of Now CLI.

This PR updates the changelog script so that it fetches the latest GH Release (which should be Now CLI) and then compares that to the HEAD.
2020-02-06 14:35:15 +00:00
Steven
f3b286ecf3 Publish Canary
- now@17.0.2-canary.0
 - @now/routing-utils@1.5.3-canary.0
2020-02-06 09:12:19 -05:00
Steven
adf31c3fcc [now-routing-utils] Change behavior of trailingSlash: true redirects (#3745)
This PR changes the behavior of `trailingSlash: true` after we received feedback that files should not be redirected with a trailing slash. This matches the behavior of `serve` and `serve-handler`.

### Examples 
* `/index.html` => serve
* `/assets/style.css` => serve
* `/assets` => redirect to `/assets/`
* `/assets/style` => redirect to `/assets/style/` 

### Additional

In order to avoid duplicate content, this PR also adds redirects to files without a trailing slash.

* `/about.html/` => redirect to `/about.html`
* `/assets/style.css/` => redirect to `/assets/style.css`


Fixes #3731
2020-02-06 09:07:46 -05:00
luc
deacdfc47c Publish Stable
- now@17.0.1
2020-02-06 01:07:15 +01:00
Luc
ac9badbe9e [now-cli] Always output deployment url in stdout (#3753) 2020-02-06 00:58:24 +01:00
luc
62beb0f78d Publish Stable
- @now/frameworks@0.0.9
 - @now/build-utils@1.3.9
 - @now/cgi@1.0.3
 - now@17.0.0
 - now-client@7.0.0
 - @now/go@1.0.3
 - @now/next@2.3.13
 - @now/node@1.4.1
 - @now/python@1.1.3
 - @now/routing-utils@1.5.2
 - @now/ruby@1.0.2
 - @now/static-build@0.14.12
2020-02-05 23:03:23 +01:00
luc
5f9777f4af Publish Canary
- now@17.0.0-canary.35
2020-02-05 22:38:39 +01:00
Luc
e00db4437a [now-cli] Use npx when available to run dev command (#3749)
* use npx when available

* add --no-install

* replace $PORT and %PORT% in devCommand

* remove PORT from env variables

* replace more than one $PORT or %PORT%

* fix regex
2020-02-05 22:37:06 +01:00
Steven
b0e4f2590d Publish Stable
- @now/cgi@1.0.2
 - @now/go@1.0.2
 - @now/python@1.1.2
2020-02-05 15:09:14 -05:00
Leo Lamprecht
f0d58eac8c Remove now dev suggestion (#3748) 2020-02-05 20:50:21 +01:00
Steven
dae830d2b6 [examples] Fix hugo theme (#3746)
The Hugo theme was lost when transferring from `zeit/now-examples` to `zeit/now`.

This PR fixes the `.gitignore` file to include the `dist` directory and override our root `.gitignore`.
2020-02-05 19:30:08 +00:00
dependabot[bot]
e3071e4e29 Bump mixin-deep from 1.3.1 to 1.3.2 in /packages/now-cgi (#3736)
Bumps [mixin-deep](https://github.com/jonschlinkert/mixin-deep) from 1.3.1 to 1.3.2.
- [Release notes](https://github.com/jonschlinkert/mixin-deep/releases)
- [Commits](https://github.com/jonschlinkert/mixin-deep/compare/1.3.1...1.3.2)

Signed-off-by: dependabot[bot] <support@github.com>
2020-02-05 09:52:08 -05:00
Steven
073d7ece23 Publish Canary
- @now/build-utils@1.3.9-canary.0
 - now@17.0.0-canary.34
2020-02-05 08:29:10 -05:00
Andy Bitz
071258ba33 Publish Stable
- @now/build-utils@1.3.8
2020-02-05 03:27:31 +01:00
Andy
c0e00dc69a [now-build-utils] Fix build script check (#3743) 2020-02-05 03:27:17 +01:00
luc
6e5c136337 Publish Canary
- now@17.0.0-canary.33
2020-02-05 02:26:53 +01:00
Steven
60428cd4cf [now-cli] Bump @zeit/fun to 0.11.2 (#3741)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2020-02-05 02:20:54 +01:00
Luc
c6b9d80eec Fix now cli breaking tests (#3742) 2020-02-05 02:17:43 +01:00
Luc
953bdc10e5 [now-cli] Fix prompts and fetch team on windows (#3740)
* fix fetch on windows

* update inquirer

Co-authored-by: Leo Lamprecht <mindrun@icloud.com>
2020-02-05 01:58:49 +01:00
Andy Bitz
becdbd2136 Publish Stable
- @now/build-utils@1.3.7
2020-02-05 01:52:02 +01:00
Luc
da9bb31259 [now-cli] Handle no framework detected case (#3738)
* handle no framework detected case

* remove related test

* simplify

Co-authored-by: Leo Lamprecht <mindrun@icloud.com>
2020-02-05 01:49:13 +01:00
Luc
8cbf036921 [now-cli] Do not prompt for root directory when project is linked (#3737)
* do not prompt for root directory when linked

* run tests

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Leo Lamprecht <mindrun@icloud.com>
2020-02-05 01:48:52 +01:00
Andy
8f66e4a308 [now-build-utils] Handle empty buildCommand and outputDirectory (#3739)
* [now-build-utils] Handle empty buildCommand and outputDirectory

* Update comment
2020-02-05 01:47:54 +01:00
Luc
9627b612f2 [now-cli] Do not show spinners with --debug (#3732)
* create output.wait and use it

* fix printing "ended" multiple times

* update more `wait` -> `output.spinner`

* timeout -> delay
2020-02-04 23:23:37 +01:00
Luc
8a9ded6d61 [now-cli] Slugify suggested project name (#3733)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2020-02-04 22:29:07 +01:00
Steven
d89c772bd5 [now-build-utils] Exclude _test.go files (#3735)
Typically, Go tests are side-by-side with their source files in a `_test.go`.

The Go documentation says the following:

> To write a new test suite, create a file whose name ends _test.go that contains the TestXxx functions as described here. Put the file in the same package as the one being tested. The file will be excluded from regular package builds but will be included when the “go test” command is run. [View Docs](https://golang.org/pkg/testing/)

This PR excludes the test files from being turned into Serverless Functions.
2020-02-04 21:11:26 +00:00
Steven
32137586b9 Publish Stable
- @now/static-build@0.14.11
2020-02-04 15:10:33 -05:00
Andy Bitz
9a3e435175 Publish Stable
- @now/frameworks@0.0.8
2020-02-04 21:06:30 +01:00
Andy
01d5a10ebd [@now/frameworks] Add Other (#3734)
* [@now/frameworks] Add Other

* Add logo

* Fix typo

* Add description
2020-02-04 21:03:56 +01:00
Steven
040658fbfa Publish Canary
- now@17.0.0-canary.32
 - @now/go@1.0.2-canary.0
2020-02-03 19:43:39 -05:00
Steven
51c00286a4 [now-go] Fix now dev on Windows (#3730) 2020-02-03 19:40:41 -05:00
Steven
c3e274fc2f [now-cli] Fix now dev when api file is added or removed (#3708)
This PR is a follow up to #3703 which fixes file output renaming on initial boot but not when files are added or removed while `now dev` is running. This PR fixes that behavior.
2020-02-03 16:30:37 -05:00
Steven
fe633c528a Publish Canary
- now@17.0.0-canary.31
 - @now/static-build@0.14.11-canary.2
2020-02-03 13:28:43 -05:00
Steven
5e306d49f8 [now-static-build] Fix error when HUGO_VERSION not found (#3724)
This PR improves the error message when the user specifies a version but that version does not exist.

- HUGO_VERSION
- ZOLA_VERSION
- GUTENBERG_VERSION

Typically this means there is no tag for that particular version. It could also mean there is a tag but no binary is attached to the tag/release.

![image](https://user-images.githubusercontent.com/229881/73673953-900f4e80-467d-11ea-90ed-3317cf83c74e.png)

![image](https://user-images.githubusercontent.com/229881/73673985-9d2c3d80-467d-11ea-8ee4-cc6ecabaac20.png)

Related to [zeit/docs#1624](https://github.com/zeit/docs/pull/1624)
2020-02-03 13:21:11 -05:00
Steven
274259b7dd [tests] Update to use github action cancel workflow (#3720)
Removes script and instead uses proper GitHub Action.

This reduces the time to run from 10 seconds to 5 seconds (due to ncc).

https://github.com/styfle/cancel-workflow-action
2020-02-02 02:47:33 +00:00
Steven
230e96c687 [tests] Change warn to error on unsed vars (#3715)
Follow up to #3714 that turns the warning into an error.

![image](https://user-images.githubusercontent.com/229881/73582375-ea7c9500-445a-11ea-9d20-2a17073a068a.png)
2020-02-01 00:41:40 +00:00
Nathan Rajlich
8c0c6e546d [now-cli] Remove unused fs import (#3714)
Fixes GH pull request auto-lint:

> #### Check warning on line 2 in `packages/now-cli/src/util/input/input-root-directory.ts`:
>
> ## GitHub Actions / Unit Tests (ubuntu-latest, 12)
>
> `packages/now-cli/src/util/input/input-root-directory.ts#L2`
>
> ```
> 'fs' is defined but never used
> ```
2020-01-31 18:57:09 -05:00
Steven
5e8541b936 [tests] Don't run tests in forks (#3713)
There is no need to run the tests in a fork because when the forked repo submits a PR to this repo, the tests will run.
2020-01-31 18:49:56 -05:00
Simon Hänisch
300558f24e [now-static-build] Add caching headers for Stencil (#3493)
/cc @adamdbradley @leo
2020-01-31 23:48:46 +00:00
Steven
829f7d8aeb Publish Canary
- @now/build-utils@1.3.7-canary.2
 - @now/python@1.1.2-canary.0
2020-01-31 16:48:34 -05:00
Steven
340f7db68a [now-python] Add excludeFiles config option (#3712)
This PR adds a `config.excludeFiles` pattern for `@now/python` that defaults to `node_modules/**` for users who are using a Node.js SSG frontend with Python APIs backend.

If the user chooses, they can override to any glob pattern such as `{.cache,node_modules}/**`.

Related to #2830
Related to #3416
2020-01-31 21:47:14 +00:00
luc
2fe987b5da Publish Canary
- now@17.0.0-canary.30
2020-01-31 22:13:11 +01:00
Andy
5b3aa48cd6 [now-cli] Adjust error message for Root Directory (#3710)
* [now-cli] Adjust error message for Root Directory

* Update packages/now-cli/src/commands/deploy/latest.js

Co-Authored-By: Luc <luc.leray@gmail.com>

Co-authored-by: Luc <luc.leray@gmail.com>
2020-01-31 21:36:06 +01:00
Steven
080d96bfa1 [api] Silence github comments (#3709)
Most PRs don't touch the examples api so let's silence the comments and cancel in-progress builds if we push again.

This should reduce the noise in this repository.

Documentation: https://zeit.co/docs/configuration#introduction/configuration-reference
2020-01-31 16:57:18 +00:00
Luc
7d9bf682b4 [now-cli] Add [copied to clipboard] (#3707) 2020-01-31 17:16:29 +01:00
Steven
a913a4f59f [tests] Cancel previous CI runs (#3706)
This PR adds an action to cancel previous runs for the current branch using the [github workflow api](https://developer.github.com/v3/actions/workflow_runs/).

This action is ignored for the `master` branch.
2020-01-31 09:30:09 -05:00
Andy Bitz
2042c96d98 Publish Canary
- now@17.0.0-canary.29
2020-01-31 13:30:12 +01:00
Steven
4ca0ff8426 [now-cli] Fix now dev file output renaming (#3703)
There was a bug where python src files were being renamed when it really should be the output files only.

This is a tricky bug because production deployments build all files first and then perform routing. So we simply rename lambda outputs with prod deployments. But `now dev` matches a request URL to a build before performing the build lazily so we have to rename source files.

The solution is to add both the original file name and the renamed file name in the `files` map so that it matches correctly but `zeit/fun` will still copy the original source files in the output correctly.

Routing will match on the extensionless file, the builder will use the file with extension (it doesn't know about file renaming), then the build results in a lambda output which is renamed to extensionless.

I added a test for `@now/python` and updated the `@now/bash` test.

Fixes #3638
2020-01-31 12:20:46 +00:00
Andy
554cc42d83 [now-cli] Add support for the rootDirectory property (#3686)
* [now-cli] Add support for the `rootDirectory` property

* Only check if rootDirectory exists

* Add test

* Support now dev

* Use defaults

* Comment

* Normalize the path input

* Adjust test

* Remove .only

* Adjust more tests

* Adjust test

* Fix test

* Remove unused import

* Update packages/now-cli/src/util/validate-paths.ts

Co-Authored-By: Luc <luc.leray@gmail.com>

* Run check on normalized path

* Add more checks

* Change error message

* Use basename as prefix

* Use correct path when linking

* Update packages/now-cli/src/util/input/input-root-directory.ts

Co-Authored-By: Luc <luc.leray@gmail.com>

Co-authored-by: Luc <luc.leray@gmail.com>
2020-01-31 12:56:09 +01:00
Steven
3f9e30d031 [docs] Update readme with CI status (#3704)
This repo no longer uses Circle CI since #3660 so this PR updates the badge in the readme.
2020-01-30 17:04:33 -05:00
luc
5a9ca8644c Publish Canary
- now@17.0.0-canary.28
2020-01-30 20:07:27 +01:00
Luc
3f362d4b50 [now-cli] Add scope indication to now secrets (#3699)
It looks like this:
![image](https://user-images.githubusercontent.com/6616955/73408935-03bbff00-42fe-11ea-9f1c-70860437c6bc.png)
2020-01-30 19:01:44 +00:00
Steven
7360886c9a [tests] Run unit tests on ubuntu and macos (#3702)
* [tests] Run unit tests on ubuntu and macos

* Add back Node 10 for Now CLI Tests

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2020-01-30 18:21:16 +01:00
Luc
5b8a1b47b0 [now-cli] Adjust name error messages (#3698)
* adjust `name` error messages

* return after outputting error
2020-01-30 18:10:44 +01:00
luc
0506b262d2 Publish Canary
- now@17.0.0-canary.27
2020-01-30 17:38:31 +01:00
Luc
17c4569f41 [now-cli] Send framework to api-deployments (#3701)
* send `framework` to api-deployments

* add error message

* Update packages/now-cli/src/util/input/edit-project-settings.ts

Co-Authored-By: Steven <steven@ceriously.com>

Co-authored-by: Steven <steven@ceriously.com>
2020-01-30 17:37:48 +01:00
Steven
888ff83309 Publish Stable
- @now/node@1.4.0
 - @now/python@1.1.1
2020-01-30 09:39:59 -05:00
Steven
7191421470 [tests] Fix rate limits for integration tests (#3696)
This PR will fix our CI rate limits for the "Now CLI Tests" check in GH Actions.

Thanks to @AndyBitz for most of the work in #3325
2020-01-29 16:24:02 -05:00
luc
e9c9aa5ce1 Publish Canary
- now@17.0.0-canary.26
2020-01-29 21:10:37 +01:00
Luc
d98f3d8140 [now-cli] Deprecate --name and now.json name property (#3690)
* remove `--name` from help

* add deprecation warning

* refactor

* deprecated `name` property in now.json

* add tests

* remove .only
2020-01-29 21:09:28 +01:00
Luc
fbf659e4e1 [now-cli] Add error message when running now dev on an unlinked folder (#3692)
* refactor getLinkedProject

* adjustments

* refactor getLinkedOrg

* refactor linkFolderToProject to skip linking

* fix dev tests

* adjust tests

* print deployment url for files

* fix missing `NOW_PROJECT_ID` check

* `process.status` -> `link.status`
2020-01-29 21:09:08 +01:00
Steven
6f7069aadd Publish Canary
- @now/python@1.1.1-canary.1
2020-01-29 13:26:41 -05:00
Steven
cef2c889f6 [now-python] Fix dependency detection in now dev (#3695)
Fixes a false positive regression from #3352 where `now dev`  assumed that local dependencies were already installed even when they were not.
2020-01-29 13:24:15 -05:00
Steven
e42d6c422a Publish Canary
- now@17.0.0-canary.25
 - @now/routing-utils@1.5.2-canary.4
2020-01-28 18:15:17 -05:00
Steven
2e9241b454 [now-routing-utils] Enabled case sensitive rewrites and set delimiter (#3688)
This enables case sensitive rewrites and redirects. It also changes the delimiter to `/` to match Next.js.

Unlike `routes` which were case insensitive, `rewrites` and `redirects` are case sensitive.

In the future, we may wish to add an option to toggle the sensitivity.
2020-01-28 18:13:57 -05:00
Steven
257a3b07fc [now-cli] Remove several v1 tests from CI (#3689)
These 5 tests are available in `integration-v1.js` already which can be executed manually.
2020-01-28 17:14:04 -05:00
luc
df9322b392 Publish Canary
- now@17.0.0-canary.24
2020-01-28 20:39:44 +01:00
Luc
28b5476bf3 [now-cli] Add link to "deploying files is deprecated" (#3685) 2020-01-28 20:38:50 +01:00
Luc
70a61f045f [now-cli] (Major) Use local .now scope for all commands and add scope to now whoami (#3643)
* use .now scope for commands

* add cache to getUser

* add cache on getTeams

* add cache for link

* refactor

* add error if NOW_ORG_ID is missing

* remove link cache

* refactor

* fix whoami

* add tests

* move fetching scope/org after subcommand condition

* Update packages/now-cli/src/util/projects/link.ts

Co-Authored-By: Andy <AndyBitz@users.noreply.github.com>

* remove userId from global scope

* show team and user in whoami command

* reset whoami

* Revert "move fetching scope/org after subcommand condition"

This reverts commit d145e6164074fe2442178cd8fafbeb225c978b9c.

* remove `client` from main scope

* tests adjustments

* adjust tests

* adjust tests (bis)

Co-authored-by: Andy <AndyBitz@users.noreply.github.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2020-01-28 20:38:27 +01:00
luc
238a8a8593 Publish Canary
- now@17.0.0-canary.23
 - now-client@7.0.0-canary.3
2020-01-28 15:48:36 +01:00
Luc
6f2d5c0045 [now-cli] Add README.txt when linking project (#3681)
* add README.txt when linking project

* replace ` with "

* add test

* Apply suggestions from code review

Co-Authored-By: Nathan Rajlich <n@n8.io>

* extract NOW_DIR_README.txt

* Update packages/now-cli/src/util/projects/NOW_DIR_README.txt

Co-Authored-By: Nathan Rajlich <n@n8.io>

Co-authored-by: Nathan Rajlich <n@n8.io>
2020-01-28 15:47:45 +01:00
Luc
fc798da398 [now-client] Update @types/node-fetch (#3682)
* update @types/node-fetch

* fix type error (another)

* add noEmitOnError

* add build test github action to test

* Revert "fix type error (another)"

This reverts commit 1d0dace70a0bf2dfb2473a48408e560f060e5c50.

* Revert "add noEmitOnError"

This reverts commit 57286016c69723b625293621f7474882f802521d.

* Revert "update @types/node-fetch"

This reverts commit 6979b5f866faaa141e5be1b1bda353f01a41349c.

* Revert "Revert "update @types/node-fetch""

This reverts commit 7459fb768cd9574854ac0f9f3d48eca1e5e63821.

* Revert "Revert "fix type error (another)""

This reverts commit 820db234f82d0a624cddb625529196807b571b5e.

* Revert "Revert "add noEmitOnError""

This reverts commit 896fdb9f33c7f5d62fea409a073de5c614d11024.

* Revert "add build test github action to test"

This reverts commit a2f1c2f914e6c66653dfabad262311ee2a2720b3.

* add noEmitOnError to now-cli

* fix signal-exit in yarn.lock
2020-01-28 11:42:32 +01:00
luc
0804483316 Publish Canary
- now@17.0.0-canary.22
2020-01-28 11:36:50 +01:00
Luc
4a087f842e [now-cli] Use devCommand from project settings locally (#3673)
* pull devCommand from cloud

* filter out front end builders with devCommand

* remove unnecessary import

* fix wrong directory listing with devCommand

* fix server not stopping

* Apply suggestions from code review

Co-Authored-By: Nathan Rajlich <n@n8.io>

* remove comment

* remove redundant "if"

Co-authored-by: Nathan Rajlich <n@n8.io>
2020-01-28 11:35:57 +01:00
luc
01c7bf0059 Publish Canary
- now@17.0.0-canary.21
2020-01-28 11:29:25 +01:00
Luc
6c439516db [now-cli] Add tip to connect git repositories after now login is successful (#3678)
* add tip after now login is successful

* write success message to stdout
2020-01-28 11:27:56 +01:00
Steven
0db4ee69ef [tests] Add timeout to test jobs (#3683)
Circle CI used to have a max timeout of 10 minutes.

This adds a timeout to each job so that hanging tests are noticed earlier.

For example, these have been "in progress" for 4 hours: 

![image](https://user-images.githubusercontent.com/229881/73222438-3a90ea00-4131-11ea-97a7-76651a2cce45.png)
2020-01-27 19:25:39 -05:00
Steven
aec8a7ac9a Publish Canary
- now@17.0.0-canary.20
 - now-client@7.0.0-canary.2
 - @now/routing-utils@1.5.2-canary.3
 - @now/ruby@1.0.2-canary.0
2020-01-27 17:08:32 -05:00
m5o
882bc8cb99 [now-ruby] Add rack examples to ruby integration tests (#3626)
* add rack examples to ruby integration tests
  * https://github.com/rack/rack

Co-authored-by: Steven <steven@ceriously.com>
2020-01-27 16:55:13 -05:00
Steven
9aad701dfd [now-routing-utils] Merge destination query string with path segments (#3679)
This PR changes the behavior so that `:segment` in the `source` is always added to the query string unless the `destination` query string already contains a key with the same name.
2020-01-27 16:24:10 -05:00
Luc
f224f574be [now-cli] Deprecate deploying files with Now CLI (#3650)
* deprecate uploading files instead of erroring

* fix misc bugs

* remove final `.`

* add test

* check .now folder does not exist in test

* clean up after test
2020-01-27 20:41:38 +01:00
Andy
e201eaa315 [frameworks] Extend CONTRIBUTING.md (#3675)
* [frameworks] Extend CONTRIBUTING.md

* Update .github/CONTRIBUTING.md

Co-Authored-By: Steven <steven@ceriously.com>

* Update .github/CONTRIBUTING.md

Co-Authored-By: Steven <steven@ceriously.com>

Co-authored-by: Steven <steven@ceriously.com>
2020-01-27 15:54:29 +01:00
Andy
b0ed1f2be0 [now-cli] Remove unused code (#3674)
* [now-cli] Remove unused code

* [now-cli] Remove more unused code
2020-01-27 15:19:41 +01:00
Steven
4ac33e1c03 [now-cli][now-client] Drop support for Node 8 (#3670)
Deployments no longer support Node 8 since reaching EOL so we can also drop all of the special casing used to support Node 8 in Now CLI and Now Client.

The `tsconfig.json` has been updated to ES2018 per [Node-Target-Mapping](https://github.com/microsoft/TypeScript/wiki/Node-Target-Mapping).
2020-01-27 13:32:07 +00:00
luc
27ca517666 Publish Canary
- @now/static-build@0.14.11-canary.1
2020-01-25 23:51:36 +01:00
Luc
734e9c072d [now-static-build] Add public folder to Gatsby cache (#3669)
* add `public` to gatsby cache

* add test
2020-01-25 23:38:36 +01:00
Forrest Oliphant
8db54f3093 [examples] Fix svelte example github link (#3657)
https://svelte.now-examples.now.sh/ currently points to https://github.com/zeit/now-examples/tree/master/svelte-functions ... this should be the right link.
2020-01-25 14:41:37 +00:00
Andy
886c0718d6 [tests] Fix GitHub Actions on master (#3664)
* Checkout master on master

* Check if checkout works

* Revert "Check if checkout works"

This reverts commit 66f712a43edfb938c551110c214661e4a920b492.

* Revert "Checkout master on master"

This reverts commit 41b6eab926474830629e758a51e7cfdd1947bdf2.

* Use --depth=10

* Add another fetch
2020-01-25 10:58:13 +01:00
Andy
e160a2f21f [tests] Use GitHub Actions for the tests (#3660)
* Initial Build step

* Typo

* Remove circleci config

* Fix command

* Change Node version

* Add unit tests

* Use artifact

* Fix workflow file

* Remove node_modules

* Remove .git

* Do not upload files

* Checkout master branch

* Use git fetch

* Add now-dev tests

* Fix workflow file

* Use node10 for building

* Use node12 for building

* Download Hugo before building

* Fetch master branch

* Do not cancel other jobs when one fails

* Add all tests

* Remove needs

* Add build step

* Move test up

* Use isCanary function and remove tests

* Update Publish workflow

* Update .github/workflows/continuous-integration.yml

Co-Authored-By: Steven <steven@ceriously.com>

* Specify more events

* Add publish.sh script

* Remove Node8

Co-authored-by: Steven <steven@ceriously.com>
2020-01-25 00:42:55 +01:00
JJ Kasper
e09a418423 Publish Stable
- @now/next@2.3.12
2020-01-24 12:33:56 -06:00
JJ Kasper
52d4464368 Publish Canary
- @now/next@2.3.12-canary.0
2020-01-24 12:31:50 -06:00
JJ Kasper
4dc635e5f2 [now-next] Revert handle: miss/hit (#3658)
This reverts `handle: miss/hit` as it still needs some things sorted out before we're ready to use it in `@now/next`
2020-01-24 18:22:25 +00:00
Steven
510fb7ee7e Publish Canary
- @now/build-utils@1.3.7-canary.1
 - now@17.0.0-canary.19
2020-01-24 12:16:13 -05:00
Steven
243451e94b [now-build-utils] Add function detectApiExtensions() (#3653)
* [now-routing-utils] Add function detectApiExtensions

* Add more tests, fix broken test

* Add missing check for extensions

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2020-01-24 12:07:29 -05:00
Andy Bitz
11bbda977d Publish Stable
- @now/frameworks@0.0.7
 - @now/next@2.3.11
2020-01-24 17:20:55 +01:00
Andy Bitz
62c050f394 Publish Canary
- now@17.0.0-canary.18
 - now-client@7.0.0-canary.1
2020-01-24 17:19:27 +01:00
Andy
bd5a013312 [now-client] (Major) Remove builds check from now-client and change events (#3648)
* [now-client][now-cli] Remove builds check from now-client

* [now-client] Adjust README and change version

* Change events and adjust build error

* Use message from error

* Update packages/now-cli/src/util/deploy/process-deployment.ts

Co-Authored-By: Luc <luc.leray@gmail.com>

* [now-cli] Rename event

* Make types more consistent

* Fix type in process-legacy-deployment

* Adjust type in test

* Update type

* Make events type simpler

Co-authored-by: Max <8418866+rdev@users.noreply.github.com>
Co-authored-by: Luc <luc.leray@gmail.com>
2020-01-24 17:18:56 +01:00
Andy Bitz
1823cf452e Publish Canary
- @now/next@2.3.11-canary.4
2020-01-24 16:09:18 +01:00
Andy
c426d72ccf [now-next] Include file mode for pseudo layers (#3655) 2020-01-24 16:08:39 +01:00
Alex Grover
ddf59c052d Remove duplicated line from .gitignore (#3651) 2020-01-24 11:03:51 +01:00
luc
1dcf6e7fb1 Publish Canary
- now@17.0.0-canary.17
2020-01-23 20:06:18 +01:00
Luc
d4f4792988 [now-cli] Add --confirm to help (#3625)
```
$ now --help
[...]
  -c, --confirm                  Confirm default options and skip questions
```
2020-01-23 19:00:55 +00:00
Steven
7e1f2bd10e Publish Canary
- @now/build-utils@1.3.7-canary.0
2020-01-23 12:29:22 -05:00
Steven
a80a1d0c1d [now-build-utils] Fix api directory detection (#3647)
There was an issue where `@now/next` was emitting an api directory with serverless functions but the functions should not be renamed.
2020-01-23 16:54:34 +00:00
Steven
8ff747b4d7 Publish Canary
- @now/next@2.3.11-canary.3
 - @now/routing-utils@1.5.2-canary.2
2020-01-23 09:37:30 -05:00
Steven
aa63b5a581 [github] Update codeowners (#3642)
Added a few more code owners
2020-01-23 00:25:25 +00:00
luc
2094ec3c99 Publish Canary
- now@17.0.0-canary.16
2020-01-23 00:57:56 +01:00
Luc
bf30d10211 [now-cli] Output error if NOW_PROJECT_ID/NOW_ORG_ID is defined without the other (#3630)
* output error if one of both env is missing

* add test

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2020-01-23 00:53:15 +01:00
Luc
ccc03c9c6e [now-cli] Add warning if linked project was deleted or access was removed (#3631)
![image](https://user-images.githubusercontent.com/6616955/72800302-4ff4a880-3c47-11ea-8d74-0ae0c18469da.png)
2020-01-22 23:27:30 +00:00
Steven
4b7367e2dc [now-routing-utils] Fix segments in query string (#3640)
This PR a regression when path segments are used in the query string.

Take a look at the following ASCII Table for why I had to delete certain parts of the parsed url before formatting again.

https://nodejs.org/api/url.html#url_url_strings_and_url_objects

Related to #3539
2020-01-22 22:46:47 +00:00
JJ Kasper
00aa56a095 [now-next] Add headers support for custom-routes (#3494)
This adds support for `headers` in custom-routes which was landed in Next.js. 

This also updates `@now/routing-utils` `convertHeaders` to call `sourceToRegex` to match behavior with Next.js and allow using `segments` to match in the header `source` as not being able to use the same syntax for a header `source` as a `redirect` source could get confusing
2020-01-22 20:45:36 +00:00
Steven
56ae93a2a5 [examples] Fix jekyll readme build command (#3639)
Fixes #3634
2020-01-22 18:19:12 +00:00
JJ Kasper
adb32a09d3 Publish Canary
- @now/next@2.3.11-canary.2
 - @now/routing-utils@1.5.2-canary.1
2020-01-22 11:46:57 -06:00
JJ Kasper
3358d8e44c [now-next] Add handle: miss and handle: hit for custom-routes (#3489)
This is required to match custom-routes behavior in Next.js by checking dynamic routes after each rewrite although is currently blocked on `now dev` also supporting the feature

This reverts commit 0da98a7f5d.
2020-01-22 17:39:27 +00:00
Steven
c3bd2698e8 [now-routing-utils] Disallow "status" in hit phase (#3637)
This will prevent any strange behavior since production already ignores status code in the hit phase.
2020-01-22 17:03:10 +00:00
Steven
a7baa4761d Publish Canary
- now@17.0.0-canary.15
2020-01-21 19:56:55 -05:00
Steven
5dd2daa970 [now dev] Add support for handle: miss and handle: hit (#3537)
- [x] Add tests from now-proxy for `handle: miss`
- [x] Add tests from now-proxy for `handle: hit`
- [x] Add file output renaming when `featHandleMiss` is true (also assign true for now dev)
2020-01-22 00:54:24 +00:00
JJ Kasper
dd36a489ed Publish Canary
- @now/frameworks@0.0.7-canary.0
 - @now/next@2.3.11-canary.1
 - @now/static-build@0.14.11-canary.0
2020-01-20 15:36:58 -06:00
JJ Kasper
2e742209e3 [now-next] Add initial support for static 404 (#3628)
This adds initial support for static 404 pages when enabled for Next.js applications > `9.2.1-canary.3` it also disables tracing/logging related to lambdas when there aren't any lambdas besides the `_error` when a static 404 is being used 

Closes: #3368
2020-01-20 20:55:08 +00:00
Andy
8d13464cba [frameworks][now-static-build] Use hugo -D --gc as build command (#3624)
* [frameworks][now-static-build] Use `hugo --gc` as build command

* Add -D option
2020-01-20 19:46:15 +01:00
Max Rovensky
20fdcfa0af Publish Stable
- @now/static-build@0.14.10
2020-01-18 04:00:08 +08:00
Max
fac004f83c [now-static-build] Remove legacy message from static build (#3618)
* Remove legacy message from static build

* Remove unused config

* Remove unused config
2020-01-17 20:59:10 +01:00
Andy Bitz
5fee4bbad1 Publish Stable
- @now/static-build@0.14.9
2020-01-17 20:21:52 +01:00
Andy
18e4b18839 [now-static-build] Ignore commands for non-zero-config (#3617) 2020-01-17 20:19:53 +01:00
Max Rovensky
b8627fd384 Publish Stable
- @now/static-build@0.14.8
2020-01-18 02:42:30 +08:00
Max
4e2db6f8a5 [now-static-build] Improve static build errors copy (#3616)
* Improve static build errors copy

* Update packages/now-static-build/src/index.ts

Co-Authored-By: Leo Lamprecht <mindrun@icloud.com>

* Update packages/now-static-build/src/index.ts

Co-Authored-By: Leo Lamprecht <mindrun@icloud.com>

Co-authored-by: Leo Lamprecht <mindrun@icloud.com>
2020-01-17 19:36:52 +01:00
Steven
b685a3afdd Publish Canary
- @now/next@2.3.11-canary.0
 - @now/node@1.3.6-canary.0
2020-01-17 13:09:32 -05:00
Steven
aea3f58970 [api] Fix build script (#3615)
I was getting errors when running `yarn build` locally because the public directory already exists.

This will make sure the public directory is deleted before generating it again.
2020-01-17 13:08:41 -05:00
Steven
b0bb90dc11 Bump node-file-trace to 0.5.1 (#3613)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2020-01-17 13:07:59 -05:00
Andy Bitz
2132c2463f Publish Stable
- @now/next@2.3.10
 - @now/static-build@0.14.7
2020-01-17 18:09:16 +01:00
JJ Kasper
60bf6e2420 [now-next] Update custom-routes tests (#3614)
This adds `permanent: boolean` to the redirects in the custom-routes tests for `@now/next` since this field is required for redirects in Next.js in the latest version 

unblocks: https://github.com/zeit/now/pull/3613
2020-01-17 16:42:55 +00:00
Andy Bitz
9badc9048c Publish Canary
- @now/static-build@0.14.7-canary.0
2020-01-17 00:52:38 +01:00
Andy
a74c1921f8 [now-static-build] Fix package.json command for frameworks (#3611)
* [now-static-build] Fix package.json command for frameworks

* Add test

* Rename function
2020-01-17 00:51:55 +01:00
luc
e6044f2e8d Publish Canary
- now@17.0.0-canary.14
2020-01-17 00:35:54 +01:00
Luc
78d1afa25e [now-cli] Add NOW_PROJECT_ID and NOW_ORG_ID env variable (#3588)
This PR adds `NOW_PROJECT_ID` and `NOW_ORG_ID` environment variables as a way to specify a project to deploy to when running `now`.

eg.
```
NOW_ORG_ID=abc NOW_PROJECT_ID=123 now
```

When using these environment variables:
- the folder is not linked to the project (ie. no `.now` is created)
- we interrupt the process and show an error message if the project is not found:
![image](https://user-images.githubusercontent.com/6616955/72369004-7a061200-36ff-11ea-8b37-168f5339a2bb.png)
2020-01-16 23:30:51 +00:00
luc
4792adf524 Publish Canary
- now@17.0.0-canary.13
2020-01-16 23:38:21 +01:00
Luc
4d8a99141b [now-cli] Improve formatting of new deploy command prompts (#3607)
- Adjust error prompt
- Add spinner while loading org and project
- Use lighter gray for infos
- Remove `{` in inspector url (was mistakenly added in https://github.com/zeit/now/pull/3599)
- Show error when entering a project name
- Fix bug with spinner not cleared when error is displayed
- "Finalizing" -> "Completing"

![image](https://user-images.githubusercontent.com/6616955/72535453-da6c8f00-3878-11ea-838d-dcb4367e5120.png)
2020-01-16 22:24:57 +00:00
Luc
7954ddc1d0 [now-cli] Create .gitignore if it doesn't exist (#3606)
When linking a new project, create `.gitignore` with `.now` if it doesn't exist yet. If it exists, adds `.now` to it.

Also adds a test for that.
2020-01-16 22:04:38 +00:00
Max
216a1fd9d2 [now-static-build] Use NowBuildError for static build errors (#3609)
This PR fixes error messages and uses `NowBuildError ` for static build errors
2020-01-16 18:41:28 +00:00
Luc
e5add6750c [now-cli] Remove .only and remove duplicate test (#3605) 2020-01-16 13:40:05 +01:00
Andy Bitz
b7533650e1 Publish Stable
- @now/frameworks@0.0.6
 - @now/build-utils@1.3.6
 - @now/static-build@0.14.6
2020-01-16 13:11:31 +01:00
luc
6272f5ce5c Publish Canary
- now@17.0.0-canary.12
2020-01-16 12:03:36 +01:00
Luc
bde0538efe [now-cli] Fix inspector url with custom domain suffix (#3599)
When the user is using custom domain suffix, the inspector url is a bit different:
```
https://zeit.co/{orgSlug}/{projectName}/{deploymentShortId}/{suffix}
```

This PR adds the necessary logic when constructing the inspector url.

cc @TooTallNate
2020-01-16 00:31:18 +00:00
Nathan Rajlich
5e6775fca0 [now-cli] Display assigned alias for v2 upgraded static legacy deployments (#3601)
Since v2 deployments are auto-assigned aliases, render as such to match more closely to the v2 pipeline when a static deployments was implicitly upgraded to the v2 platform.
2020-01-15 23:59:52 +00:00
Andy Bitz
e05e0dc40e Publish Canary
- @now/frameworks@0.0.6-canary.3
 - @now/build-utils@1.3.6-canary.0
 - @now/static-build@0.14.6-canary.0
2020-01-16 00:13:35 +01:00
Andy
96dbc6d348 [now-static-build][frameworks][examples] Fixes examples and adjust frameworks (#3584)
* [examples] Fix ionic-react example

* [examples] Fix vue example

* [examples] Fix mithril example

* [examples] Fix riot example

* Fix readmes

* [now-static-build] Add Zola

* Add tests

* [now-build-utils][frameworks] Adjust detect framework

* Move zola back

* Undo Hugo detection changes

* [examples] Fix Vue logo path

* [now-static-build] Use package.json script if defined instead of framework command

* [now-static-build] Add buildCommand everywhere

* Remove devCommand from frameworks.ts

* Fix type

* Change output directory

* [now-static-build] Remove minNodeRange

* Remove devCommand
2020-01-16 00:12:55 +01:00
luc
0a63bd47e8 Publish Canary
- now@17.0.0-canary.11
2020-01-15 23:27:08 +01:00
Luc
35dd50eb61 [now-cli] Pre-fill "project name" prompt (#3598)
* pre-fill project name prompt

* add test

* more tests

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2020-01-15 23:26:23 +01:00
Andy
f70ed94c8c [api] Add Sentry (#3597)
* [api] Add Sentry

* Use function name

* Add test error

* Revert "Add test error"

This reverts commit 39cf8a61dad9fcdcb616e418a0deb6ffe9e04ea9.

* Revert "Revert "Add test error""

This reverts commit c718f201da9d80743319ac87e0d4560e718fff53.

* Add logging

* Revert "Add logging"

This reverts commit 39cd46c8bbeef9024e71fe70478068480a51545b.

* Revert "Revert "Revert "Add test error"""

This reverts commit e6f63ee21fabb4ac8fc065b74281dbcdf5811216.

* Ignore .env

* Use init function for Sentry inline
2020-01-15 23:21:03 +01:00
luc
fb0c8600a2 Publish Canary
- now@17.0.0-canary.10
2020-01-15 22:39:11 +01:00
Luc
5023bdd25d [now-cli] Always add two spaces after emojis and update emojis (#3596)
Updates emojis to fix "spacing issues" with previous emojis and always add 2 spaces after emojis.
- ℹ️ -> 📝
- ⚠️ -> 
- ☑️ -> 🔗



Also fixes a typo:
```
Linked to <project> (created .now and added it to .nowignore)
->
Linked to <project> (created .now and added it to .gitignore)
```

It looks like this:

![image](https://user-images.githubusercontent.com/6616955/72445323-d590d800-37b1-11ea-92eb-a3b503a95774.png)

![image](https://user-images.githubusercontent.com/6616955/72445618-47692180-37b2-11ea-9aed-3b3268c82ad3.png)


![image](https://user-images.githubusercontent.com/6616955/72445492-11c43880-37b2-11ea-8091-1e1e8ac8b3a0.png)
2020-01-15 21:37:57 +00:00
Nathan Rajlich
bf4917ccf2 [now-cli] Handle Now v1 to v2 upgrade (#3593)
* Print warnings / notices from the API
* Print `v2` instead of `v1` when upgraded to v2
* Wait for "alias-assigned" event in v1 pipeline when upgraded to v2
2020-01-15 21:13:44 +00:00
Luc
64aff3aef4 [now-cli] Add tests for project linking and framework detection (#3591)
Adds two test cases:
- linking a project and overwriting build settings
- "overwrite settings" prompt should not appear when no framework is detected
2020-01-15 20:54:18 +00:00
Nathan Rajlich
62b87d1ed1 [now-cli] Remove unnecessary console.log() (#3594)
Seems to be a leftover from dd1d9d856.
2020-01-15 14:58:42 +00:00
Andy
5872114c87 Adjust CONTRIBUTING.md for frameworks (#3592) 2020-01-15 04:11:05 +01:00
luc
ce04246051 Publish Canary
- now@17.0.0-canary.9
2020-01-14 22:21:00 +01:00
Luc
02b03d4533 [now-cli] Hide "overwrite project settings?" prompt if no framework is detected (#3589)
This PR updates the framework auto-detection flow in `deploy` command to not show "overwrite project settings?" prompt when the API returns a `framework` property that is `null`.
2020-01-14 21:09:16 +00:00
501 changed files with 23724 additions and 7417 deletions

View File

@@ -1,501 +0,0 @@
version: 2
jobs:
install:
docker:
- image: circleci/node:10
working_directory: ~/repo
environment:
GOPATH: $HOME/go
steps:
- checkout
- restore_cache:
keys:
- v1-dependencies-{{ checksum "yarn.lock" }}
# fallback to using the latest cache if no exact match is found
- v1-dependencies-
- run:
name: Updating apt packages
command: sudo apt-get update
- run:
name: Installing the latest version of Go
command: sudo apt-get install golang-go
- run:
name: Installing Dependencies
command: yarn install --check-files --frozen-lockfile
- save_cache:
paths:
- node_modules
- packages/gatsby-plugin-now/node_modules
- packages/now-build-utils/node_modules
- packages/now-cgi/node_modules
- packages/now-cli/node_modules
- packages/now-client/node_modules
- packages/now-go/node_modules
- packages/now-next/node_modules
- packages/now-node/node_modules
- packages/now-node-bridge/node_modules
- packages/now-python/node_modules
- packages/now-routing-utils/node_modules
- packages/now-ruby/node_modules
- packages/now-static-build/node_modules
key: v1-dependencies-{{ checksum "yarn.lock" }}
- persist_to_workspace:
root: .
paths:
- node_modules
- packages/gatsby-plugin-now/node_modules
- packages/now-build-utils/node_modules
- packages/now-cgi/node_modules
- packages/now-cli/node_modules
- packages/now-client/node_modules
- packages/now-go/node_modules
- packages/now-next/node_modules
- packages/now-node/node_modules
- packages/now-node-bridge/node_modules
- packages/now-python/node_modules
- packages/now-routing-utils/node_modules
- packages/now-ruby/node_modules
- packages/now-static-build/node_modules
build:
docker:
- image: circleci/node:10
working_directory: ~/repo
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Linking dependencies
command: yarn bootstrap
- run:
name: Building
command: yarn build
- store_artifacts:
path: packages/now-cli/dist
- persist_to_workspace:
root: .
paths:
- packages/gatsby-plugin-now/test/fixtures
- packages/now-build-utils/dist
- packages/now-cgi/dist
- packages/now-cli/dist
- packages/now-cli/assets
- packages/now-client/dist
- packages/now-go/dist
- packages/now-next/dist
- packages/now-node/dist
- packages/now-node/test/fixtures/15-helpers/ts/types.d.ts
- packages/now-node/test/fixtures/11-symlinks/symlink
- packages/now-node-bridge/index.js
- packages/now-node-bridge/bridge.js
- packages/now-python/dist
- packages/now-routing-utils/dist
- packages/now-ruby/dist
- packages/now-static-build/dist
- packages/now-static-build/test/fixtures/10a-gatsby-redirects/plugins
test-lint:
docker:
- image: circleci/node:10
working_directory: ~/repo
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Compiling `now dev` HTML error templates
command: node packages/now-cli/scripts/compile-templates.js
- run:
name: Linting Code
command: yarn test-lint
test-integration-macos-node-8:
macos:
xcode: '9.0.1'
working_directory: ~/repo
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Output version
command: node --version
- run:
name: Running Integration Tests
command: yarn test-integration --clean false
test-integration-macos-node-10:
macos:
xcode: '10.0.0'
working_directory: ~/repo
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Output version
command: node --version
- run:
name: Running Integration Tests
command: yarn test-integration --clean false
test-integration-macos-node-12:
macos:
xcode: '10.3.0'
working_directory: ~/repo
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Output version
command: node --version
- run:
name: Running Integration Tests
command: yarn test-integration --clean false
test-integration-linux-node-8:
docker:
- image: circleci/node:8
working_directory: ~/repo
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Output version
command: node --version
- run:
name: Running Integration Tests
command: yarn test-integration --clean false
test-integration-linux-node-10:
docker:
- image: circleci/node:10
working_directory: ~/repo
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Output version
command: node --version
- run:
name: Running Integration Tests
command: yarn test-integration --clean false
test-integration-linux-node-12:
docker:
- image: circleci/node:12
working_directory: ~/repo
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Output version
command: node --version
- run:
name: Running Integration Tests
command: yarn test-integration --clean false
test-integration-macos-now-dev-node-8:
macos:
xcode: '9.0.1'
working_directory: ~/repo
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Output version
command: node --version
- run:
name: Downloading Hugo
command: curl -L -O https://github.com/gohugoio/hugo/releases/download/v0.56.0/hugo_0.56.0_macOS-64bit.tar.gz && tar -xzf hugo_0.56.0_macOS-64bit.tar.gz && mv ./hugo packages/now-cli/test/dev/fixtures/08-hugo/
- run:
name: Running Integration Tests for `now dev`
command: yarn test-integration-now-dev --clean false
test-integration-macos-now-dev-node-10:
macos:
xcode: '10.0.0'
working_directory: ~/repo
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Output version
command: node --version
- run:
name: Downloading Hugo
command: curl -L -O https://github.com/gohugoio/hugo/releases/download/v0.56.0/hugo_0.56.0_macOS-64bit.tar.gz && tar -xzf hugo_0.56.0_macOS-64bit.tar.gz && mv ./hugo packages/now-cli/test/dev/fixtures/08-hugo/
- run:
name: Running Integration Tests for `now dev`
command: yarn test-integration-now-dev --clean false
test-integration-macos-now-dev-node-12:
macos:
xcode: '10.3.0'
working_directory: ~/repo
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Output version
command: node --version
- run:
name: Downloading Hugo
command: curl -L -O https://github.com/gohugoio/hugo/releases/download/v0.56.0/hugo_0.56.0_macOS-64bit.tar.gz && tar -xzf hugo_0.56.0_macOS-64bit.tar.gz && mv ./hugo packages/now-cli/test/dev/fixtures/08-hugo/
- run:
name: Running Integration Tests for `now dev`
command: yarn test-integration-now-dev --clean false
test-integration-linux-now-dev-node-8:
docker:
- image: circleci/node:8
working_directory: ~/repo
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Output version
command: node --version
- run:
name: Downloading Hugo
command: curl -L -O https://github.com/gohugoio/hugo/releases/download/v0.55.6/hugo_0.55.6_Linux-64bit.tar.gz && tar -xzf hugo_0.55.6_Linux-64bit.tar.gz && mv ./hugo packages/now-cli/test/dev/fixtures/08-hugo/
- run:
name: Running Integration Tests for `now dev`
command: yarn test-integration-now-dev --clean false
test-integration-linux-now-dev-node-10:
docker:
- image: circleci/node:10
working_directory: ~/repo
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Output version
command: node --version
- run:
name: Downloading Hugo
command: curl -L -O https://github.com/gohugoio/hugo/releases/download/v0.55.6/hugo_0.55.6_Linux-64bit.tar.gz && tar -xzf hugo_0.55.6_Linux-64bit.tar.gz && mv ./hugo packages/now-cli/test/dev/fixtures/08-hugo/
- run:
name: Running Integration Tests for `now dev`
command: yarn test-integration-now-dev --clean false
test-integration-linux-now-dev-node-12:
docker:
- image: circleci/node:12
working_directory: ~/repo
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Output version
command: node --version
- run:
name: Downloading Hugo
command: curl -L -O https://github.com/gohugoio/hugo/releases/download/v0.55.6/hugo_0.55.6_Linux-64bit.tar.gz && tar -xzf hugo_0.55.6_Linux-64bit.tar.gz && mv ./hugo packages/now-cli/test/dev/fixtures/08-hugo/
- run:
name: Running Integration Tests for `now dev`
command: yarn test-integration-now-dev --clean false
test-integration-once:
docker:
- image: circleci/node:10
working_directory: ~/repo
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Output version
command: node --version
- run:
name: Running Integration Tests Once
command: yarn test-integration-once --clean false
test-unit:
docker:
- image: circleci/node:10
working_directory: ~/repo
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Compiling `now dev` HTML error templates
command: node packages/now-cli/scripts/compile-templates.js
- run:
name: Output version
command: node --version
- run:
name: Running Unit Tests
command: yarn test-unit --clean false
- persist_to_workspace:
root: .
paths:
- packages/now-cli/.nyc_output
coverage:
docker:
- image: circleci/node:10
working_directory: ~/repo
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Run coverage report
command: yarn workspace now run coverage
source-maps:
docker:
- image: circleci/node:10
working_directory: ~/repo
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Installing Sentry CLI
command: npm install -g @sentry/cli
- run:
name: Creating a New Sentry Release
command: sentry-cli releases new now-cli@`git describe --tags`
- run:
name: Upload Sourcemap Files
command: sentry-cli releases files now-cli@`git describe --tags` upload-sourcemaps ./dist
- run:
name: Finalize Sentry Release
command: sentry-cli releases finalize now-cli@`git describe --tags`
workflows:
version: 2
unscheduled:
jobs:
- install:
filters:
tags:
only: /.*/
- build:
requires:
- install
filters:
tags:
only: /.*/
- test-lint:
requires:
- build
filters:
tags:
only: /.*/
- test-integration-macos-node-8:
requires:
- build
filters:
tags:
only: /.*/
- test-integration-macos-node-10:
requires:
- build
filters:
tags:
only: /.*/
- test-integration-macos-node-12:
requires:
- build
filters:
tags:
only: /.*/
- test-integration-linux-node-8:
requires:
- build
filters:
tags:
only: /.*/
- test-integration-linux-node-10:
requires:
- build
filters:
tags:
only: /.*/
- test-integration-linux-node-12:
requires:
- build
filters:
tags:
only: /.*/
- test-integration-macos-now-dev-node-8:
requires:
- build
filters:
tags:
only: /.*/
- test-integration-macos-now-dev-node-10:
requires:
- build
filters:
tags:
only: /.*/
- test-integration-macos-now-dev-node-12:
requires:
- build
filters:
tags:
only: /.*/
- test-integration-linux-now-dev-node-8:
requires:
- build
filters:
tags:
only: /.*/
- test-integration-linux-now-dev-node-10:
requires:
- build
filters:
tags:
only: /.*/
- test-integration-linux-now-dev-node-12:
requires:
- build
filters:
tags:
only: /.*/
- test-integration-once:
requires:
- build
- test-unit:
requires:
- build
filters:
tags:
only: /.*/
- coverage:
requires:
- test-integration-macos-node-8
- test-integration-macos-node-10
- test-integration-macos-node-12
- test-integration-linux-node-8
- test-integration-linux-node-10
- test-integration-linux-node-12
- test-integration-macos-now-dev-node-8
- test-integration-macos-now-dev-node-10
- test-integration-macos-now-dev-node-12
- test-integration-linux-now-dev-node-8
- test-integration-linux-now-dev-node-10
- test-integration-linux-now-dev-node-12
- test-integration-once
- test-unit
- test-lint
filters:
tags:
only: /.*/

4
.gitattributes vendored
View File

@@ -1,3 +1,7 @@
# Ignore test fixtures in GitHub Languages
# See https://github.com/github/linguist#vendored-code
packages/*/test/* linguist-vendored
# Go build fails with Windows line endings.
*.go text eol=lf
go.mod text eol=lf

9
.github/CODEOWNERS vendored
View File

@@ -2,6 +2,8 @@
# https://help.github.com/en/articles/about-code-owners
* @tootallnate @leo
/.github/workflows @AndyBitz @styfle
/packages/frameworks @AndyBitz
/packages/now-cli/src/commands/dev/ @tootallnate @leo @styfle @AndyBitz
/packages/now-cli/src/util/dev/ @tootallnate @leo @styfle @AndyBitz
/packages/now-cli/src/commands/domains/ @javivelasco @mglagola @anatrajkovska
@@ -10,13 +12,16 @@
/packages/now-build-utils @styfle @AndyBitz
/packages/now-node @styfle @tootallnate @lucleray
/packages/now-node-bridge @styfle @tootallnate @lucleray
/packages/now-next @Timer
/packages/now-next @Timer @ijjk
/packages/now-go @styfle @sophearak
/packages/now-python @styfle @sophearak
/packages/now-ruby @styfle @coetry @nathancahill
/packages/now-static-build @styfle @AndyBitz
/packages/now-routing-utils @dav-is
/packages/now-routing-utils @styfle @dav-is @ijjk
/examples @msweeneydev @timothyis
/examples/create-react-app @Timer
/examples/nextjs @timneutkens
/examples/hugo @msweeneydev @timothyis @styfle
/examples/jekyll @msweeneydev @timothyis @sarupbanskota
/examples/zola @msweeneydev @timothyis @styfle

View File

@@ -94,3 +94,12 @@ Sometimes you want to test changes to a Builder against an existing project, may
4. Run `now *.tgz` to upload the tarball file and get a URL
5. Edit any existing `now.json` project and replace `use` with the URL
6. Run `now` or `now dev` to deploy with the experimental Builder
## Add a New Framework
You can add support for a new Framework by creating a Pull Request for this repository and following the steps below:
1. Add the Framework to the `@now/frameworks` package: The file is located in `packages/frameworks/frameworks.json`. You can copy the structure of an existing one and adjust the required fields. Note that the `settings` property either contains a `value` or a `placeholder`. The `value` property is used when something is not configurable, the `placeholder` is used when something is configurable and can be changed with configuration. An example would be the Output Directory for Hugo, it's `public` by default but can be changed through its config file, so we use `placeholder` with an explanation of what can be used.
2. Add an example to the `examples/` directory: The name of the directory should equal the slug of the framework used in `@now/frameworks`. The `.github/EXAMPLE_README_TEMPLATE.md` file can be used to create a `README.md` file for the example.
3. Update the `@now/static-build` package: The file `packages/now-static-build/src/frameworks.ts` has to be extended. You can add default routes that will always be applied to projects that use this Framework or specify some paths that will be cached to speed up the build process.
4. After your Pull Request has been merged and released, other users can select the example on the ZEIT Now dashboard and deploy it.

View File

@@ -6,7 +6,7 @@ This directory is a brief example of a [Name](site-link) site that can be deploy
Deploy your own [Name] project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now-examples/tree/master/example-directory)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now-examples/tree/master/example-directory)
### How We Created This Example

18
.github/workflows/cancel.yml vendored Normal file
View File

@@ -0,0 +1,18 @@
name: Cancel
on:
push:
branches:
- '*'
- '!master'
jobs:
cancel:
name: 'Cancel Previous Runs'
runs-on: ubuntu-latest
timeout-minutes: 3
steps:
- uses: styfle/cancel-workflow-action@0.2.0
with:
workflow_id: 435869
access_token: ${{ secrets.GITHUB_WORKFLOW_TOKEN }}

View File

@@ -0,0 +1,109 @@
name: CI
on:
push:
branches:
- master
tags:
- '!*'
pull_request:
jobs:
test-unit:
name: Unit Tests
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
node: [10, 12]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- run: git fetch origin master --depth=10
- run: git fetch origin ${{ github.ref }} --depth=10
- uses: actions/setup-node@v1
- run: yarn install
- run: yarn run build
- run: yarn run test-lint
- run: yarn run test-unit --clean false
- name: Upload Artifact
if: matrix.os == 'ubuntu-latest' && matrix.node == 12 # only run once
uses: actions/upload-artifact@v1
with:
name: test-unit-output
path: packages/now-cli/.nyc_output
test-integration:
name: Integration Tests
timeout-minutes: 120
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: git fetch origin master --depth=10
- run: git fetch origin ${{ github.ref }} --depth=10
- run: yarn install
- run: yarn run build
- run: yarn test-integration-once --clean false
test-now-cli:
name: Now CLI Tests
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
node: [10, 12]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- run: git fetch origin master --depth=10
- run: git fetch origin ${{ github.ref }} --depth=10
- name: Install Hugo
if: matrix.os == 'macos-latest'
run: curl -L -O https://github.com/gohugoio/hugo/releases/download/v0.56.0/hugo_0.56.0_macOS-64bit.tar.gz && tar -xzf hugo_0.56.0_macOS-64bit.tar.gz && mv ./hugo packages/now-cli/test/dev/fixtures/08-hugo/
- run: yarn install
- run: yarn run build
- uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node }}
- run: yarn test-integration --clean false
test-now-dev:
name: "`now dev` Tests"
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
node: [10, 12]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- run: git fetch origin master --depth=10
- run: git fetch origin ${{ github.ref }} --depth=10
- name: Install Hugo
if: matrix.os == 'macos-latest'
run: curl -L -O https://github.com/gohugoio/hugo/releases/download/v0.56.0/hugo_0.56.0_macOS-64bit.tar.gz && tar -xzf hugo_0.56.0_macOS-64bit.tar.gz && mv ./hugo packages/now-cli/test/dev/fixtures/08-hugo/
- run: yarn install
- run: yarn run build
- uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node }}
- run: yarn test-integration-now-dev --clean false
coverage:
name: Coverage
timeout-minutes: 10
needs: [test-unit, test-now-cli, test-now-dev, test-integration]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: git fetch origin master --depth=10
- run: git fetch origin ${{ github.ref }} --depth=10
- uses: actions/download-artifact@v1
with:
name: test-unit-output
path: packages/now-cli/.nyc_output
- run: yarn install
- run: yarn workspace now run coverage

View File

@@ -4,25 +4,18 @@ on:
push:
branches:
- master
- canary
tags:
- '!*'
jobs:
Publish:
publish:
name: Publish
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [10.x]
steps:
- uses: actions/checkout@v1
- name: Checkout
uses: actions/setup-node@v1
- uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
node-version: 10
- name: Install
run: yarn install --check-files --frozen-lockfile
- name: Build

1
.gitignore vendored
View File

@@ -22,4 +22,5 @@ packages/now-cli/test/fixtures/integration
test/lib/deployment/failed-page.txt
.DS_Store
.next
.env
public

View File

@@ -1,6 +1,6 @@
![now](https://assets.zeit.co/image/upload/v1542240976/repositories/now-cli/now-cli-repo-banner-v3.png)
![now](https://assets.zeit.co/image/upload/v1581518533/repositories/now-cli/v4.png)
[![Build Status](https://badgen.net/circleci/github/zeit/now/master)](https://circleci.com/gh/zeit/workflows/now/tree/master)
[![CI Status](https://badgen.net/github/checks/zeit/now?label=CI)](https://github.com/zeit/now/actions?workflow=CI)
[![Join the community on Spectrum](https://withspectrum.github.io/badge/badge.svg)](https://spectrum.chat/zeit)
## Usage
@@ -16,13 +16,12 @@ To quickly start a new project, run the following commands:
```
now init # Pick an example project to clone
cd <PROJECT> # Change directory to the newly created project
now dev # Run locally during development
now # Deploy to the cloud
```
## Documentation
For details on how to use Now CLI, check out our [documentation](https://zeit.co/docs).
For details on how to use Now CLI, check out our [documentation](https://zeit.co/docs/now-cli).
## Caught a Bug?

View File

@@ -0,0 +1,9 @@
export function assertEnv(name: string) {
const value = process.env[name];
if (!value) {
throw new Error(`Missing env "${name}"`);
}
return value;
}

View File

@@ -0,0 +1,43 @@
import { init, captureException, withScope } from '@sentry/node';
import { assertEnv } from './assert-env';
const serviceName = 'api-frameworks';
let sentryInitDone = false;
function initSentry() {
if (sentryInitDone) {
return;
}
sentryInitDone = true;
init({
dsn: assertEnv('SENTRY_DSN'),
environment: process.env.NODE_ENV || 'production',
release: `${serviceName}`,
});
}
export function errorHandler(error: Error, extras?: { [key: string]: any }) {
if (!process.env.SENTRY_DSN) {
return;
}
initSentry();
try {
withScope(scope => {
scope.setTag('service', serviceName);
scope.setTag('function_name', assertEnv('AWS_LAMBDA_FUNCTION_NAME'));
for (const [k, v] of Object.entries(extras)) {
scope.setExtra(k, v);
}
captureException(error);
});
} catch (e) {
console.error(`Failed to report error to Sentry: ${e}`);
}
}

View File

@@ -1,4 +1,5 @@
import { NowRequest, NowResponse } from '@now/node';
import { errorHandler } from './error-handler';
type Handler = (req: NowRequest, res: NowResponse) => Promise<any>;
@@ -24,6 +25,20 @@ export function withApiHandler(handler: Handler): Handler {
});
}
return handler(req, res);
try {
const result = await handler(req, res);
return result;
} catch (error) {
errorHandler(error, {
url: req.url,
});
return res.status(500).json({
error: {
code: 'unexpected_error',
message: 'An unexpected error occurred.',
},
});
}
};
}

View File

@@ -2,17 +2,19 @@ import { NowRequest, NowResponse } from '@now/node';
import { withApiHandler } from './_lib/util/with-api-handler';
import frameworkList, { Framework } from '../packages/frameworks';
const frameworks: Framework[] = (frameworkList as Framework[]).map(
framework => {
delete framework.detectors;
const frameworks = (frameworkList as Framework[]).map(frameworkItem => {
const framework = {
...frameworkItem,
hasDetectors: Boolean(frameworkItem.detectors),
detectors: undefined,
};
if (framework.logo) {
framework.logo = `https://res.cloudinary.com/zeit-inc/image/fetch/${framework.logo}`;
}
return framework;
if (framework.logo) {
framework.logo = `https://res.cloudinary.com/zeit-inc/image/fetch/${framework.logo}`;
}
);
return framework;
});
export default withApiHandler(async function(
req: NowRequest,

View File

@@ -8,6 +8,7 @@
"build": "yarn --cwd .. && node ../utils/run.js build all"
},
"dependencies": {
"@sentry/node": "5.11.1",
"got": "10.2.1",
"node-fetch": "2.6.0",
"parse-github-url": "1.0.2",

View File

@@ -9,6 +9,85 @@
dependencies:
"@types/node" "*"
"@sentry/apm@5.11.1":
version "5.11.1"
resolved "https://registry.yarnpkg.com/@sentry/apm/-/apm-5.11.1.tgz#cc89fa4150056fbf009f92eca94fccc3980db34e"
integrity sha512-4iZH11p/7w9IMLT9hqNY1+EqLESltiIoF6/YsbpK93sXWGEs8VQ83IuvGuKWxajvHgDmj4ND0TxIliTsYqTqFw==
dependencies:
"@sentry/browser" "5.11.1"
"@sentry/hub" "5.11.1"
"@sentry/minimal" "5.11.1"
"@sentry/types" "5.11.0"
"@sentry/utils" "5.11.1"
tslib "^1.9.3"
"@sentry/browser@5.11.1":
version "5.11.1"
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-5.11.1.tgz#337ffcb52711b23064c847a07629e966f54a5ebb"
integrity sha512-oqOX/otmuP92DEGRyZeBuQokXdeT9HQRxH73oqIURXXNLMP3PWJALSb4HtT4AftEt/2ROGobZLuA4TaID6My/Q==
dependencies:
"@sentry/core" "5.11.1"
"@sentry/types" "5.11.0"
"@sentry/utils" "5.11.1"
tslib "^1.9.3"
"@sentry/core@5.11.1":
version "5.11.1"
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.11.1.tgz#9e2da485e196ae32971545c1c49ee6fe719930e2"
integrity sha512-BpvPosVNT20Xso4gAV54Lu3KqDmD20vO63HYwbNdST5LUi8oYV4JhvOkoBraPEM2cbBwQvwVcFdeEYKk4tin9A==
dependencies:
"@sentry/hub" "5.11.1"
"@sentry/minimal" "5.11.1"
"@sentry/types" "5.11.0"
"@sentry/utils" "5.11.1"
tslib "^1.9.3"
"@sentry/hub@5.11.1":
version "5.11.1"
resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-5.11.1.tgz#ddcb865563fae53852d405885c46b4c6de68a91b"
integrity sha512-ucKprYCbGGLLjVz4hWUqHN9KH0WKUkGf5ZYfD8LUhksuobRkYVyig0ZGbshECZxW5jcDTzip4Q9Qimq/PkkXBg==
dependencies:
"@sentry/types" "5.11.0"
"@sentry/utils" "5.11.1"
tslib "^1.9.3"
"@sentry/minimal@5.11.1":
version "5.11.1"
resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-5.11.1.tgz#0e705d01a567282d8fbbda2aed848b4974cc3cec"
integrity sha512-HK8zs7Pgdq7DsbZQTThrhQPrJsVWzz7MaluAbQA0rTIAJ3TvHKQpsVRu17xDpjZXypqWcKCRsthDrC4LxDM1Bg==
dependencies:
"@sentry/hub" "5.11.1"
"@sentry/types" "5.11.0"
tslib "^1.9.3"
"@sentry/node@5.11.1":
version "5.11.1"
resolved "https://registry.yarnpkg.com/@sentry/node/-/node-5.11.1.tgz#2a9c18cd1209cfdf7a69b9d91303413149d2c910"
integrity sha512-FbJs0blJ36gEzE0rc2yBfA/KE+kXOLl8MUfFTcyJCBdCGF8XMETDCmgINnJ4TyBUJviwKoPw2TCk9TL2pa/A1w==
dependencies:
"@sentry/apm" "5.11.1"
"@sentry/core" "5.11.1"
"@sentry/hub" "5.11.1"
"@sentry/types" "5.11.0"
"@sentry/utils" "5.11.1"
cookie "^0.3.1"
https-proxy-agent "^4.0.0"
lru_map "^0.3.3"
tslib "^1.9.3"
"@sentry/types@5.11.0":
version "5.11.0"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.11.0.tgz#40f0f3174362928e033ddd9725d55e7c5cb7c5b6"
integrity sha512-1Uhycpmeo1ZK2GLvrtwZhTwIodJHcyIS6bn+t4IMkN9MFoo6ktbAfhvexBDW/IDtdLlCGJbfm8nIZerxy0QUpg==
"@sentry/utils@5.11.1":
version "5.11.1"
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-5.11.1.tgz#aa19fcc234cf632257b2281261651d2fac967607"
integrity sha512-O0Zl4R2JJh8cTkQ8ZL2cDqGCmQdpA5VeXpuBbEl1v78LQPkBDISi35wH4mKmLwMsLBtTVpx2UeUHBj0KO5aLlA==
dependencies:
"@sentry/types" "5.11.0"
tslib "^1.9.3"
"@sindresorhus/is@^1.0.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-1.2.0.tgz#63ce3638cb85231f3704164c90a18ef816da3fb7"
@@ -62,6 +141,11 @@
dependencies:
"@types/node" "*"
agent-base@5:
version "5.1.1"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-5.1.1.tgz#e8fb3f242959db44d63be665db7a8e739537a32c"
integrity sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==
binary@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/binary/-/binary-0.3.0.tgz#9f60553bc5ce8c3386f3b553cff47462adecaa79"
@@ -121,6 +205,18 @@ clone-response@^1.0.2:
dependencies:
mimic-response "^1.0.0"
cookie@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=
debug@4:
version "4.1.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
dependencies:
ms "^2.1.1"
decompress-response@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-5.0.0.tgz#7849396e80e3d1eba8cb2f75ef4930f76461cb0f"
@@ -182,6 +278,14 @@ http-cache-semantics@^4.0.0:
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.0.3.tgz#495704773277eeef6e43f9ab2c2c7d259dda25c5"
integrity sha512-TcIMG3qeVLgDr1TEd2XvHaTnMPwYQUQMIBLy+5pLSDKYFc7UIqj39w8EGzZkaxoLv/l2K8HaI0t5AVA+YYgUew==
https-proxy-agent@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz#702b71fb5520a132a66de1f67541d9e62154d82b"
integrity sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==
dependencies:
agent-base "5"
debug "4"
inherits@^2.0.3:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
@@ -204,6 +308,11 @@ lowercase-keys@^2.0.0:
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479"
integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==
lru_map@^0.3.3:
version "0.3.3"
resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd"
integrity sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0=
mimic-response@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
@@ -226,6 +335,11 @@ mkdirp@^0.5.1:
dependencies:
minimist "0.0.8"
ms@^2.1.1:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
node-fetch@2.6.0:
version "2.6.0"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
@@ -320,6 +434,11 @@ to-readable-stream@^2.0.0:
resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.3.9.tgz#717b8f220cc0bb7b44e40514c22b2e8bbc70d8b9"
integrity sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=
tslib@^1.9.3:
version "1.10.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==
type-fest@^0.8.0:
version "0.8.1"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"

View File

@@ -6,7 +6,7 @@ This directory is a brief example of an [AMP](https://amp.dev/) site that can be
Deploy your own AMP project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/amp)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/amp)
_Live Example: https://amp.now-examples.now.sh_

View File

@@ -1,4 +1,4 @@
![Angular Logo](../packages/frameworks/logos/angular.svg)
![Angular Logo](https://github.com/zeit/now/blob/master/packages/frameworks/logos/angular.svg)
# Angular Example
@@ -8,7 +8,7 @@ This directory is a brief example of an [Angular](https://angular.io/) app that
Deploy your own Angular project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/angular)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/angular)
_Live Example: https://angular.now-examples.now.sh_

View File

@@ -6,7 +6,7 @@ This directory is a brief example of a [Assemble](http://assemble.io/) app that
Deploy your own Assemble project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/assemble)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/assemble)
_Live Example: https://assemble.now-examples.now.sh_

View File

@@ -6,7 +6,7 @@ This directory is a brief example of an [Aurelia](https://aurelia.io/) app that
Deploy your own Aurelia project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/aurelia)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/aurelia)
_Live Example: https://aurelia.now-examples.now.sh_

View File

@@ -6,7 +6,7 @@ This directory is a brief example of a [Brunch](https://brunch.io/) site that ca
Deploy your own Brunch project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/brunch)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/brunch)
_Live Example: https://brunch.now-examples.now.sh_

View File

@@ -6,7 +6,7 @@ This directory is a brief example of a [Charge.js](https://charge.js.org/) site
Deploy your own Charge.js project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/charge)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/charge)
_Live Example: https://charge.now-examples.now.sh_

View File

@@ -1,4 +1,4 @@
![React Logo](../packages/frameworks/logos/react.svg)
![React Logo](https://github.com/zeit/now/blob/master/packages/frameworks/logos/react.svg)
# React Example
@@ -8,7 +8,7 @@ This directory is a brief example of a [React](https://reactjs.org/) app with [S
Deploy your own React project, along with Serverless Functions, with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/create-react-app-functions)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/create-react-app-functions)
_Live Example: https://create-react-app.now-examples.now.sh/_

View File

@@ -6,7 +6,7 @@ This directory is a brief example of using a Custom Build script that can be dep
Deploy your own Custom Built project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/custom-build)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/custom-build)
_Live Example: https://custom-build.now-examples.now.sh_

View File

@@ -1,4 +1,4 @@
![Docusaurus Logo](../packages/frameworks/logos/docusaurus.svg)
![Docusaurus Logo](https://github.com/zeit/now/blob/master/packages/frameworks/logos/docusaurus.svg)
# Docusaurus Example
@@ -8,7 +8,7 @@ This directory is a brief example of a [Docusaurus](https://docusaurus.io/) site
Deploy your own Docusaurus project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/docusaurus)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/docusaurus)
_Live Example: https://docusaurus.now-examples.now.sh_

View File

@@ -6,7 +6,7 @@ This directory is a brief example of a [Docz](https://www.docz.site/) site that
Deploy your own Docz project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/docz)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/docz)
_Live Example: https://docz.now-examples.now.sh_

View File

@@ -1,4 +1,4 @@
![Eleventy Logo](../packages/frameworks/logos/eleventy.svg)
![Eleventy Logo](https://github.com/zeit/now/blob/master/packages/frameworks/logos/eleventy.svg)
# Eleventy Example
@@ -8,7 +8,7 @@ This directory is a brief example of a [Eleventy](https://www.11ty.io/) site tha
Deploy your own Eleventy project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/eleventy)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/eleventy)
_Live Example: https://eleventy.now-examples.now.sh_

View File

@@ -1,4 +1,4 @@
![Ember Logo](../packages/frameworks/logos/ember.svg)
![Ember Logo](https://github.com/zeit/now/blob/master/packages/frameworks/logos/ember.svg)
# Ember Example
@@ -8,7 +8,7 @@ This directory is a brief example of an [Ember](https://emberjs.com/) app that c
Deploy your own Ember project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/ember)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/ember)
_Live Example: https://ember.now-examples.now.sh_

View File

@@ -6,7 +6,7 @@ This directory is a brief example of a [Foundation](https://foundation.zurb.com/
Deploy your own Foundation project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/foundation)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/foundation)
_Live Example: https://foundation.now-examples.now.sh_

View File

@@ -1,4 +1,4 @@
![Gatsby Logo](../packages/frameworks/logos/gatsby.svg)
![Gatsby Logo](https://github.com/zeit/now/blob/master/packages/frameworks/logos/gatsby.svg)
# Gatsby Example
@@ -8,7 +8,7 @@ This directory is a brief example of a [Gatsby](https://www.gatsbyjs.org/) app w
Deploy your own Gatsby project, along with Serverless Functions, with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/gatsby)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/gatsby)
_Live Example: https://gatsby.now-examples.now.sh_

View File

@@ -1,4 +1,4 @@
![Gridsome Logo](../packages/frameworks/logos/gridsome.svg)
![Gridsome Logo](https://github.com/zeit/now/blob/master/packages/frameworks/logos/gridsome.svg)
# Gridsome Example
@@ -8,7 +8,7 @@ This directory is a brief example of a [Gridsome](https://gridsome.org/) app tha
Deploy your own Gridsome project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/gridsome)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/gridsome)
_Live Example: https://gridsome.now-examples.now.sh_

View File

@@ -1,4 +1,4 @@
![Hexo Logo](../packages/frameworks/logos/hexo.svg)
![Hexo Logo](https://github.com/zeit/now/blob/master/packages/frameworks/logos/hexo.svg)
# Hexo Example
@@ -8,7 +8,7 @@ This directory is a brief example of a [Hexo](https://hexo.io/) site that can be
Deploy your own Hexo project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/hexo)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/hexo)
_Live Example: https://hexo.now-examples.now.sh_

View File

@@ -6,7 +6,7 @@ This directory is a brief example of a [Hugo](https://gohugo.io/) app that can b
Deploy your own Hugo project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/hugo)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/hugo)
_Live Example: https://hugo.now-examples.now.sh_

View File

@@ -28,3 +28,5 @@ npm-debug.log
/junit.xml
partials/structure/stylesheet.html
!dist

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
!function(n){function t(e){if(r[e])return r[e].exports;var o=r[e]={i:e,l:!1,exports:{}};return n[e].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var r={};t.m=n,t.c=r,t.i=function(n){return n},t.d=function(n,r,e){t.o(n,r)||Object.defineProperty(n,r,{configurable:!1,enumerable:!0,get:e})},t.n=function(n){var r=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(r,"a",r),r},t.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},t.p="",t(t.s=1)}([function(n,t){},function(n,t,r){"use strict";var e=r(0);!function(n){n&&n.__esModule}(e)}]);

View File

@@ -6,7 +6,7 @@ This directory is a brief example of a [HyperApp](https://github.com/jorgebucara
Deploy your own HyperApp project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/hyperapp)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/hyperapp)
_Live Example: https://hyperapp.now-examples.now.sh_

View File

@@ -1,15 +0,0 @@
# http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
insert_final_newline = false
trim_trailing_whitespace = false

View File

@@ -1,67 +1,9 @@
# Logs
.firebase
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Typescript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# See https://help.github.com/ignore-files/ for more about ignoring files.
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
@@ -75,9 +17,8 @@ typings/
.env.development.local
.env.test.local
.env.production.local
.vscode
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.stencil/

View File

@@ -1,8 +0,0 @@
{
"appId": "io.ionic.starter",
"appName": "ionic-react-conference-app",
"bundledWebRuntime": false,
"npmClient": "npm",
"webDir": "build",
"cordova": {}
}

View File

@@ -1,7 +1,5 @@
{
"name": "ionic-react-conference-app",
"integrations": {
"capacitor": {}
},
"name": "ionic-react",
"integrations": {},
"type": "react"
}

View File

@@ -1,26 +1,26 @@
{
"name": "ionic-react-conference-app",
"name": "ionic-react",
"version": "0.0.1",
"private": true,
"dependencies": {
"@capacitor/core": "1.3.0",
"@ionic/react": "^4.11.4",
"@ionic/react-router": "^4.11.4",
"@types/jest": "24.0.18",
"@types/node": "12.7.5",
"@types/react": "^16.9.2",
"@types/react-dom": "^16.9.0",
"@types/react-router": "^5.0.3",
"@types/react-router-dom": "^4.3.1",
"date-fns": "^2.6.0",
"@ionic/react": "^4.11.0",
"@ionic/react-router": "^4.11.0",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.4.0",
"@testing-library/user-event": "^8.0.3",
"@types/jest": "^24.0.25",
"@types/node": "^12.12.24",
"@types/react": "^16.9.17",
"@types/react-dom": "^16.9.4",
"@types/react-router": "^5.1.4",
"@types/react-router-dom": "^5.1.3",
"ionicons": "^4.6.3",
"node-sass": "^4.13.0",
"react": "^16.9.0",
"react-dom": "^16.9.0",
"react-router": "^5.0.1",
"react-router-dom": "^5.0.1",
"react-scripts": "3.2.0",
"reselect": "^4.0.0"
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-router": "^5.1.2",
"react-router-dom": "^5.1.2",
"react-scripts": "3.3.0",
"typescript": "3.7.4"
},
"scripts": {
"start": "react-scripts start",
@@ -28,17 +28,20 @@
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all"
],
"description": "An Ionic project",
"devDependencies": {
"@capacitor/cli": "1.3.0",
"@testing-library/react": "^9.3.1",
"@types/googlemaps": "^3.38.0",
"typescript": "3.6.3"
}
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"description": "An Ionic project"
}

View File

@@ -6,7 +6,7 @@ This directory is a brief example of an [Ionic React](https://ionicframework.com
Deploy your own Ionic React project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/ionic-react)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/ionic-react)
_Live Example: https://ionic-react.now-examples.now.sh_

View File

@@ -1,12 +1,8 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { render } from '@testing-library/react';
import App from './App';
import { render, fireEvent, waitForElement } from '@testing-library/react'
it('renders without crashing', () => {
// const div = document.createElement('div');
// ReactDOM.render(<App />, div);
// ReactDOM.unmountComponentAtNode(div);
const { asFragment, container } = render(<App />);
expect(asFragment()).toMatchSnapshot();
test('renders without crashing', () => {
const { baseElement } = render(<App />);
expect(baseElement).toBeDefined();
});

View File

@@ -1,9 +1,8 @@
import React, { useEffect } from 'react';
import React from 'react';
import { Redirect, Route } from 'react-router-dom';
import { IonApp, IonRouterOutlet, IonSplitPane } from '@ionic/react';
import { IonApp, IonRouterOutlet } from '@ionic/react';
import { IonReactRouter } from '@ionic/react-router';
import Menu from './components/Menu';
import Home from './pages/Home';
/* Core CSS required for Ionic components to work properly */
import '@ionic/react/css/core.css';
@@ -23,85 +22,16 @@ import '@ionic/react/css/display.css';
/* Theme variables */
import './theme/variables.css';
import MainTabs from './pages/MainTabs';
import { connect } from './data/connect';
import { AppContextProvider } from './data/AppContext';
import { loadConfData } from './data/sessions/sessions.actions';
import { setIsLoggedIn, setUsername, loadUserData } from './data/user/user.actions';
import Account from './pages/Account';
import Login from './pages/Login';
import Signup from './pages/Signup';
import Support from './pages/Support';
import Tutorial from './pages/Tutorial';
import HomeOrTutorial from './components/HomeOrTutorial';
import { Session } from "./models/Session";
const App: React.FC = () => {
return (
<AppContextProvider>
<IonicAppConnected />
</AppContextProvider>
);
};
interface StateProps {
darkMode: boolean,
sessions: Session[],
}
interface DispatchProps {
loadConfData: typeof loadConfData;
loadUserData: typeof loadUserData;
setIsLoggedIn: typeof setIsLoggedIn;
setUsername: typeof setUsername;
}
interface IonicAppProps extends StateProps, DispatchProps { }
const IonicApp: React.FC<IonicAppProps> = ({ darkMode, sessions, setIsLoggedIn, setUsername, loadConfData, loadUserData }) => {
useEffect(() => {
loadUserData();
loadConfData();
// eslint-disable-next-line
}, []);
return (
sessions.length === 0 ? (
<div></div>
) : (
<IonApp className={`${darkMode ? 'dark-theme' : ''}`}>
<IonReactRouter>
<IonSplitPane contentId="main">
<Menu />
<IonRouterOutlet id="main">
<Route path="/tabs" component={MainTabs} />
<Route path="/account" component={Account} />
<Route path="/login" component={Login} />
<Route path="/signup" component={Signup} />
<Route path="/support" component={Support} />
<Route path="/tutorial" component={Tutorial} />
<Route path="/logout" render={() => {
setIsLoggedIn(false);
setUsername(undefined);
return <Redirect to="/tabs" />
}} />
<Route path="/" component={HomeOrTutorial} exact />
</IonRouterOutlet>
</IonSplitPane>
</IonReactRouter>
</IonApp>
)
)
}
const App: React.FC = () => (
<IonApp>
<IonReactRouter>
<IonRouterOutlet>
<Route path="/home" component={Home} exact={true} />
<Route exact path="/" render={() => <Redirect to="/home" />} />
</IonRouterOutlet>
</IonReactRouter>
</IonApp>
);
export default App;
const IonicAppConnected = connect<{}, StateProps, DispatchProps>({
mapStateToProps: (state) => ({
darkMode: state.user.darkMode,
sessions: state.data.sessions
}),
mapDispatchToProps: { loadConfData, loadUserData, setIsLoggedIn, setUsername },
component: IonicApp
});

View File

@@ -1,280 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders without crashing 1`] = `
<DocumentFragment>
<ion-app>
<ion-split-pane
content-id="main"
>
<ion-menu
content-id="main"
>
<ion-header>
<ion-toolbar>
<ion-title>
Menu
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content
class="outer-content"
>
<ion-list>
<ion-list-header>
Navigate
</ion-list-header>
<ion-menu-toggle
auto-hide="false"
>
<ion-item>
<ion-icon
slot="start"
/>
<ion-label>
Schedule
</ion-label>
</ion-item>
</ion-menu-toggle>
<ion-menu-toggle
auto-hide="false"
>
<ion-item>
<ion-icon
slot="start"
/>
<ion-label>
Speakers
</ion-label>
</ion-item>
</ion-menu-toggle>
<ion-menu-toggle
auto-hide="false"
>
<ion-item>
<ion-icon
slot="start"
/>
<ion-label>
Map
</ion-label>
</ion-item>
</ion-menu-toggle>
<ion-menu-toggle
auto-hide="false"
>
<ion-item>
<ion-icon
slot="start"
/>
<ion-label>
About
</ion-label>
</ion-item>
</ion-menu-toggle>
</ion-list>
<ion-list>
<ion-list-header>
Account
</ion-list-header>
<ion-menu-toggle
auto-hide="false"
>
<ion-item>
<ion-icon
slot="start"
/>
<ion-label>
Account
</ion-label>
</ion-item>
</ion-menu-toggle>
<ion-menu-toggle
auto-hide="false"
>
<ion-item>
<ion-icon
slot="start"
/>
<ion-label>
Support
</ion-label>
</ion-item>
</ion-menu-toggle>
<ion-menu-toggle
auto-hide="false"
>
<ion-item>
<ion-icon
slot="start"
/>
<ion-label>
Logout
</ion-label>
</ion-item>
</ion-menu-toggle>
</ion-list>
<ion-list>
<ion-list-header>
Tutorial
</ion-list-header>
<ion-item>
<ion-icon
slot="start"
/>
Show Tutorial
</ion-item>
</ion-list>
</ion-content>
</ion-menu>
<ion-router-outlet
id="main"
>
<div
style="display: flex; position: absolute; top: 0px; left: 0px; right: 0px; bottom: 0px; flex-direction: column; width: 100%; height: 100%; contain: layout size style;"
>
<div
class="tabs-inner"
style="position: relative; flex: 1; contain: layout size style;"
>
<ion-router-outlet>
<div
class="ion-page ion-page-invisible"
>
<ion-header>
<ion-toolbar
color="primary"
>
<ion-buttons
slot="start"
>
<ion-menu-button />
</ion-buttons>
<ion-segment>
<ion-segment-button
value="all"
>
All
</ion-segment-button>
<ion-segment-button
value="favorites"
>
Favorites
</ion-segment-button>
</ion-segment>
<ion-buttons
slot="end"
>
<ion-button>
<ion-icon
slot="icon-only"
/>
</ion-button>
</ion-buttons>
</ion-toolbar>
<ion-toolbar
color="primary"
>
<ion-searchbar
placeholder="Search"
/>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-refresher
slot="fixed"
>
<ion-refresher-content />
</ion-refresher>
<ion-list>
<ion-list-header>
No Sessions Found
</ion-list-header>
</ion-list>
<ion-list
style="display: none;"
/>
</ion-content>
<ion-fab
horizontal="end"
slot="fixed"
vertical="bottom"
>
<ion-fab-button>
<ion-icon />
</ion-fab-button>
<ion-fab-list
side="top"
>
<ion-fab-button
color="vimeo"
>
<ion-icon />
</ion-fab-button>
<ion-fab-button
color="google"
>
<ion-icon />
</ion-fab-button>
<ion-fab-button
color="twitter"
>
<ion-icon />
</ion-fab-button>
<ion-fab-button
color="facebook"
>
<ion-icon />
</ion-fab-button>
</ion-fab-list>
</ion-fab>
</div>
</ion-router-outlet>
</div>
<ion-tab-bar
current-path="/tabs/schedule"
selected-tab="schedule"
slot="bottom"
>
<ion-tab-button
href="/tabs/schedule"
tab="schedule"
>
<ion-icon />
<ion-label>
Schedule
</ion-label>
</ion-tab-button>
<ion-tab-button
href="/tabs/speakers"
tab="speakers"
>
<ion-icon />
<ion-label>
Speakers
</ion-label>
</ion-tab-button>
<ion-tab-button
href="/tabs/map"
tab="map"
>
<ion-icon />
<ion-label>
Map
</ion-label>
</ion-tab-button>
<ion-tab-button
href="/tabs/about"
tab="about"
>
<ion-icon />
<ion-label>
About
</ion-label>
</ion-tab-button>
</ion-tab-bar>
</div>
</ion-router-outlet>
</ion-split-pane>
</ion-app>
</DocumentFragment>
`;

View File

@@ -1,36 +0,0 @@
import React from 'react';
import { IonList, IonItem, IonLabel } from '@ionic/react';
interface AboutPopoverProps {
dismiss: () => void;
};
const AboutPopover: React.FC<AboutPopoverProps> = ({dismiss}) => {
const close = (url: string) => {
window.open(url, '_blank');
dismiss();
};
return (
<IonList>
<IonItem button onClick={() => close('https://ionicframework.com/getting-started')}>
<IonLabel>Learn Ionic</IonLabel>
</IonItem>
<IonItem button onClick={() => close('https://ionicframework.com/docs/react')}>
<IonLabel>Documentation</IonLabel>
</IonItem>
<IonItem button onClick={() => close('https://showcase.ionicframework.com')}>
<IonLabel>Showcase</IonLabel>
</IonItem>
<IonItem button onClick={() => close('https://github.com/ionic-team/ionic')}>
<IonLabel>GitHub Repo</IonLabel>
</IonItem>
<IonItem button onClick={dismiss}>
<IonLabel>Support</IonLabel>
</IonItem>
</IonList >
)
}
export default AboutPopover;

View File

@@ -1,18 +0,0 @@
import React from 'react';
import { connect } from '../data/connect';
import { Redirect } from 'react-router';
interface StateProps {
hasSeenTutorial: boolean;
}
const HomeOrTutorial: React.FC<StateProps> = ({ hasSeenTutorial }) => {
return hasSeenTutorial ? <Redirect to="/tabs/schedule" /> : <Redirect to="/tutorial" />
};
export default connect<{}, StateProps, {}>({
mapStateToProps: (state) => ({
hasSeenTutorial: state.user.hasSeenTutorial
}),
component: HomeOrTutorial
});

View File

@@ -1,56 +0,0 @@
import React, { useRef, useEffect } from 'react';
import { Location } from '../models/Location';
interface MapProps {
locations: Location[]
mapCenter: Location
}
const Map: React.FC<MapProps> = ({ mapCenter, locations }) => {
const mapEle = useRef<HTMLDivElement>(null);
const map = useRef<google.maps.Map>();
useEffect(() => {
map.current = new google.maps.Map(mapEle.current, {
center: {
lat: mapCenter.lat,
lng: mapCenter.lng
},
zoom: 16
});
addMarkers();
google.maps.event.addListenerOnce(map.current, 'idle', () => {
if (mapEle.current) {
mapEle.current.classList.add('show-map');
}
});
function addMarkers() {
locations.forEach((markerData) => {
let infoWindow = new google.maps.InfoWindow({
content: `<h5>${markerData.name}</h5>`
});
let marker = new google.maps.Marker({
position: new google.maps.LatLng(markerData.lat, markerData.lng),
map: map.current!,
title: markerData.name
});
marker.addListener('click', () => {
infoWindow.open(map.current!, marker);
});
});
}
}, [mapCenter, locations]);
return (
<div ref={mapEle} className="map-canvas"></div>
);
}
export default Map;

View File

@@ -1,119 +0,0 @@
import {
IonContent,
IonHeader,
IonIcon,
IonItem,
IonLabel,
IonList,
IonListHeader,
IonMenu,
IonMenuToggle,
IonTitle,
IonToolbar,
IonToggle
} from '@ionic/react';
import { calendar, contacts, hammer, help, informationCircle, logIn, logOut, map, person, personAdd } from 'ionicons/icons';
import React, { useState } from 'react';
import { connect } from '../data/connect';
import { RouteComponentProps, withRouter } from 'react-router';
import { setDarkMode } from '../data/user/user.actions';
const routes = {
appPages: [
{ title: 'Schedule', path: '/tabs/schedule', icon: calendar },
{ title: 'Speakers', path: '/tabs/speakers', icon: contacts },
{ title: 'Map', path: '/tabs/map', icon: map },
{ title: 'About', path: '/tabs/about', icon: informationCircle }
],
loggedInPages: [
{ title: 'Account', path: '/account', icon: person },
{ title: 'Support', path: '/support', icon: help },
{ title: 'Logout', path: '/logout', icon: logOut }
],
loggedOutPages: [
{ title: 'Login', path: '/login', icon: logIn },
{ title: 'Support', path: '/support', icon: help },
{ title: 'Signup', path: '/signup', icon: personAdd }
]
};
interface Pages {
title: string,
path: string,
icon: { ios: string, md: string },
routerDirection?: string
}
interface StateProps {
darkMode: boolean;
isAuthenticated: boolean;
}
interface DispatchProps {
setDarkMode: typeof setDarkMode
}
interface MenuProps extends RouteComponentProps, StateProps, DispatchProps { }
const Menu: React.FC<MenuProps> = ({ darkMode, history, isAuthenticated, setDarkMode }) => {
const [disableMenu, setDisableMenu] = useState(false);
function renderlistItems(list: Pages[]) {
return list
.filter(route => !!route.path)
.map(p => (
<IonMenuToggle key={p.title} auto-hide="false">
<IonItem button routerLink={p.path} routerDirection="none">
<IonIcon slot="start" icon={p.icon} />
<IonLabel>{p.title}</IonLabel>
</IonItem>
</IonMenuToggle>
));
}
return (
<IonMenu type="overlay" disabled={disableMenu} contentId="main">
<IonHeader>
<IonToolbar>
<IonTitle>Menu</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent class="outer-content">
<IonList>
<IonListHeader>Navigate</IonListHeader>
{renderlistItems(routes.appPages)}
</IonList>
<IonList>
<IonListHeader>Account</IonListHeader>
{isAuthenticated ? renderlistItems(routes.loggedInPages) : renderlistItems(routes.loggedOutPages)}
</IonList>
<IonList>
<IonListHeader>Tutorial</IonListHeader>
<IonItem onClick={() => {
setDisableMenu(true);
history.push('/tutorial');
}}>
<IonIcon slot="start" icon={hammer} />
Show Tutorial
</IonItem>
</IonList>
<IonList>
<IonItem>
<IonLabel>Dark Theme</IonLabel>
<IonToggle checked={darkMode} onClick={() => setDarkMode(!darkMode)} />
</IonItem>
</IonList>
</IonContent>
</IonMenu>
);
};
export default connect<{}, StateProps, {}>({
mapStateToProps: (state) => ({
darkMode: state.user.darkMode,
isAuthenticated: state.user.isLoggedin
}),
mapDispatchToProps: ({
setDarkMode
}),
component: withRouter(Menu)
})

View File

@@ -1,92 +0,0 @@
import { IonItemDivider, IonItemGroup, IonLabel, IonList, IonListHeader, IonAlert, AlertButton } from '@ionic/react';
import React, { useState, useCallback } from 'react';
import { Session } from '../models/Session';
import SessionListItem from './SessionListItem';
import { SessionGroup } from '../models/SessionGroup';
import { Time } from '../components/Time';
import { connect } from '../data/connect';
import { addFavorite, removeFavorite } from '../data/sessions/sessions.actions';
interface OwnProps {
sessionGroups: SessionGroup[]
listType: 'all' | 'favorites'
hide: boolean;
}
interface StateProps {
favoriteSessions: number[];
}
interface DispatchProps {
addFavorite: typeof addFavorite;
removeFavorite: typeof removeFavorite;
}
interface SessionListProps extends OwnProps, StateProps, DispatchProps { };
const SessionList: React.FC<SessionListProps> = ({ addFavorite, removeFavorite, favoriteSessions, hide, sessionGroups, listType }) => {
const [showAlert, setShowAlert] = useState(false);
const [alertHeader, setAlertHeader] = useState('');
const [alertButtons, setAlertButtons] = useState<(AlertButton | string)[]>([]);
const handleShowAlert = useCallback((header: string, buttons: AlertButton[]) => {
setAlertHeader(header);
setAlertButtons(buttons);
setShowAlert(true);
}, []);
if (sessionGroups.length === 0 && !hide) {
return (
<IonList>
<IonListHeader>
No Sessions Found
</IonListHeader>
</IonList>
);
}
return (
<>
<IonList style={hide ? { display: 'none' } : {}}>
{sessionGroups.map((group, index: number) => (
<IonItemGroup key={`group-${index}`}>
<IonItemDivider sticky>
<IonLabel>
<Time date={group.startTime} />
</IonLabel>
</IonItemDivider>
{group.sessions.map((session: Session, sessionIndex: number) => (
<SessionListItem
onShowAlert={handleShowAlert}
isFavorite={favoriteSessions.indexOf(session.id) > -1}
onAddFavorite={addFavorite}
onRemoveFavorite={removeFavorite}
key={`group-${index}-${sessionIndex}`}
session={session}
listType={listType}
/>
))}
</IonItemGroup>
))}
</IonList>
<IonAlert
isOpen={showAlert}
header={alertHeader}
buttons={alertButtons}
onDidDismiss={() => setShowAlert(false)}
></IonAlert>
</>
);
};
export default connect({
mapStateToProps: (state) => ({
favoriteSessions: state.data.favorites
}),
mapDispatchToProps: ({
addFavorite,
removeFavorite
}),
component: SessionList
});

View File

@@ -1,4 +0,0 @@
.filter-icon {
margin: 7px 16px 7px 0;
}

View File

@@ -1,108 +0,0 @@
import React from 'react';
import { IonHeader, IonToolbar, IonButtons, IonButton, IonTitle, IonContent, IonList, IonListHeader, IonItem, IonLabel, IonToggle, IonFooter, IonIcon } from '@ionic/react';
import { logoAngular, call, document, logoIonic, hammer, restaurant, cog, colorPalette, construct, compass } from 'ionicons/icons';
import './SessionListFilter.css'
import { connect } from '../data/connect';
import { updateFilteredTracks } from '../data/sessions/sessions.actions';
interface OwnProps {
onDismissModal: () => void;
}
interface StateProps {
allTracks: string[],
filteredTracks: string[]
}
interface DispatchProps {
updateFilteredTracks: typeof updateFilteredTracks;
}
type SessionListFilterProps = OwnProps & StateProps & DispatchProps;
const SessionListFilter: React.FC<SessionListFilterProps> = ({ allTracks, filteredTracks, onDismissModal, updateFilteredTracks }) => {
const toggleTrackFilter = (track: string) => {
if (filteredTracks.indexOf(track) > -1) {
updateFilteredTracks(filteredTracks.filter(x => x !== track));
} else {
updateFilteredTracks([...filteredTracks, track]);
}
};
const handleDeselectAll = () => {
updateFilteredTracks([]);
};
const handleSelectAll = () => {
updateFilteredTracks([...allTracks]);
};
const iconMap: { [key: string]: any } = {
'Angular': logoAngular,
'Documentation': document,
'Food': restaurant,
'Ionic': logoIonic,
'Tooling': hammer,
'Design': colorPalette,
'Services': cog,
'Workshop': construct,
'Navigation': compass,
'Communication': call
}
return (
<>
<IonHeader>
<IonToolbar>
<IonTitle>
Filter Sessions
</IonTitle>
<IonButtons slot="end">
<IonButton onClick={onDismissModal} strong>Done</IonButton>
</IonButtons>
</IonToolbar>
</IonHeader>
<IonContent class="outer-content">
<IonList>
<IonListHeader>Tracks</IonListHeader>
{allTracks.map((track, index) => (
<IonItem key={track}>
<IonIcon className="filter-icon" icon={iconMap[track]} color="medium" />
<IonLabel>{track}</IonLabel>
<IonToggle
onClick={() => toggleTrackFilter(track)}
checked={filteredTracks.indexOf(track) !== -1}
color="success"
value={track}
></IonToggle>
</IonItem>
))}
</IonList>
</IonContent>
<IonFooter>
<IonToolbar>
<IonButtons slot="start">
<IonButton onClick={handleDeselectAll}>Deselect All</IonButton>
</IonButtons>
<IonButtons slot="end">
<IonButton onClick={handleSelectAll}>Select All</IonButton>
</IonButtons>
</IonToolbar>
</IonFooter>
</>
);
};
export default connect<OwnProps, StateProps, DispatchProps>({
mapStateToProps: (state) => ({
allTracks: state.data.allTracks,
filteredTracks: state.data.filteredTracks
}),
mapDispatchToProps: {
updateFilteredTracks
},
component: SessionListFilter
})

View File

@@ -1,83 +0,0 @@
import React, { useRef, useState } from 'react';
import { IonItemSliding, IonAlert, IonItem, IonLabel, IonItemOptions, IonItemOption, AlertButton } from '@ionic/react';
import { Time } from './Time';
import { Session } from '../models/Session';
interface SessionListItemProps {
session: Session;
listType: "all" | "favorites";
onAddFavorite: (id: number) => void;
onRemoveFavorite: (id: number) => void;
onShowAlert: (header: string, buttons: AlertButton[]) => void;
isFavorite: boolean;
}
const SessionListItem: React.FC<SessionListItemProps> = ({ isFavorite, onAddFavorite, onRemoveFavorite, onShowAlert, session, listType }) => {
const ionItemSlidingRef = useRef<HTMLIonItemSlidingElement>(null)
const dismissAlert = () => {
ionItemSlidingRef.current && ionItemSlidingRef.current.close();
}
const removeFavoriteSession = () => {
onAddFavorite(session.id);
onShowAlert('Favorite already added', [
{
text: 'Cancel',
handler: dismissAlert
},
{
text: 'Remove',
handler: () => {
onRemoveFavorite(session.id);
dismissAlert();
}
}
]);
}
const addFavoriteSession = () => {
if (isFavorite) {
// woops, they already favorited it! What shall we do!?
// prompt them to remove it
removeFavoriteSession();
} else {
// remember this session as a user favorite
onAddFavorite(session.id);
onShowAlert('Favorite Added', [
{
text: 'OK',
handler: dismissAlert
}
]);
}
};
return (
<IonItemSliding ref={ionItemSlidingRef} class={'track-' + session.tracks[0].toLowerCase()}>
<IonItem routerLink={`/tabs/schedule/${session.id}`}>
<IonLabel>
<h3>{session.name}</h3>
<p>
<Time date={session.dateTimeStart} /> &mdash;&nbsp;
<Time date={session.dateTimeEnd} /> &mdash;&nbsp;
{session.location}
</p>
</IonLabel>
</IonItem>
<IonItemOptions>
{listType === "favorites" ?
<IonItemOption color="danger" onClick={() => removeFavoriteSession()}>
Remove
</IonItemOption>
:
<IonItemOption color="favorite" onClick={addFavoriteSession}>
Favorite
</IonItemOption>
}
</IonItemOptions>
</IonItemSliding>
);
};
export default React.memo(SessionListItem);

View File

@@ -1,46 +0,0 @@
import { IonLoading, IonFab, IonFabButton, IonIcon, IonFabList } from "@ionic/react"
import { share, logoVimeo, logoGoogleplus, logoTwitter, logoFacebook } from "ionicons/icons"
import React, { useState } from "react"
const ShareSocialFab: React.FC = () => {
const [loadingMessage, setLoadingMessage] = useState('')
const [showLoading, setShowLoading] = useState(false);
const openSocial = (network: string) => {
setLoadingMessage(`Posting to ${network}`);
setShowLoading(true);
};
return(
<>
<IonLoading
isOpen={showLoading}
message={loadingMessage}
duration={2000}
spinner="crescent"
onDidDismiss={() => setShowLoading(false)}
/>
<IonFab slot="fixed" vertical="bottom" horizontal="end">
<IonFabButton>
<IonIcon icon={share} />
</IonFabButton>
<IonFabList side="top">
<IonFabButton color="vimeo" onClick={() => openSocial('Vimeo')}>
<IonIcon icon={logoVimeo} />
</IonFabButton>
<IonFabButton color="google" onClick={() => openSocial('Google+')}>
<IonIcon icon={logoGoogleplus} />
</IonFabButton>
<IonFabButton color="twitter" onClick={() => openSocial('Twitter')}>
<IonIcon icon={logoTwitter} />
</IonFabButton>
<IonFabButton color="facebook" onClick={() => openSocial('Facebook')}>
<IonIcon icon={logoFacebook} />
</IonFabButton>
</IonFabList>
</IonFab>
</>
)
};
export default ShareSocialFab;

View File

@@ -1,125 +0,0 @@
import React, { useState } from 'react';
import { Session } from '../models/Session';
import { Speaker } from '../models/Speaker';
import { IonCard, IonCardHeader, IonItem, IonAvatar, IonCardContent, IonList, IonRow, IonCol, IonButton, IonIcon, IonActionSheet } from '@ionic/react';
import { logoTwitter, shareAlt, chatboxes } from 'ionicons/icons';
import { ActionSheetButton } from '@ionic/core';
interface SpeakerItemProps {
speaker: Speaker;
sessions: Session[];
}
const SpeakerItem: React.FC<SpeakerItemProps> = ({ speaker, sessions }) => {
const [showActionSheet, setShowActionSheet] = useState(false);
const [actionSheetButtons, setActionSheetButtons] = useState<ActionSheetButton[]>([]);
const [actionSheetHeader, setActionSheetHeader] = useState('');
function openSpeakerShare(speaker: Speaker) {
setActionSheetButtons([
{
text: 'Copy Link',
handler: () => {
console.log('Copy Link clicked');
}
},
{
text: 'Share via ...',
handler: () => {
console.log('Share via clicked');
}
},
{
text: 'Cancel',
role: 'cancel',
handler: () => {
console.log('Cancel clicked');
}
}
]);
setActionSheetHeader(`Share ${speaker.name}`);
setShowActionSheet(true);
}
function openContact(speaker: Speaker) {
setActionSheetButtons([
{
text: `Email ( ${speaker.email} )`,
handler: () => {
window.open('mailto:' + speaker.email);
}
},
{
text: `Call ( ${speaker.phone} )`,
handler: () => {
window.open('tel:' + speaker.phone);
}
}
]);
setActionSheetHeader(`Share ${speaker.name}`);
setShowActionSheet(true);
}
return (
<>
<IonCard className="speaker-card">
<IonCardHeader>
<IonItem button detail={false} routerLink={`/tabs/speakers/${speaker.id}`} lines="none">
<IonAvatar slot="start">
<img src={process.env.PUBLIC_URL + speaker.profilePic} alt="Speaker profile pic" />
</IonAvatar>
{speaker.name}
</IonItem>
</IonCardHeader>
<IonCardContent class="outer-content">
<IonList>
{sessions.map(session => (
<IonItem routerLink={`/tabs/speakers/sessions/${session.id}`} key={session.name}>
<h3>{session.name}</h3>
</IonItem>
))}
<IonItem button routerLink={`/tabs/speakers/${speaker.id}`}>
<h3>About {speaker.name}</h3>
</IonItem>
</IonList>
</IonCardContent>
<IonRow justify-content-center>
<IonCol text-left size="4">
<IonButton
fill="clear"
size="small"
color="primary"
href={`https://www.twitter.com/${speaker.twitter}`}
target="_blank"
>
<IonIcon slot="start" icon={logoTwitter} />
Tweet
</IonButton>
</IonCol>
<IonCol text-left size="4">
<IonButton fill="clear" size="small" color="primary" onClick={() => openSpeakerShare(speaker)}>
<IonIcon slot="start" icon={shareAlt} />
Share
</IonButton>
</IonCol>
<IonCol text-left size="4">
<IonButton fill="clear" size="small" color="primary" onClick={() => openContact(speaker)}>
<IonIcon slot="start" icon={chatboxes} />
Contact
</IonButton>
</IonCol>
</IonRow>
</IonCard>
<IonActionSheet
isOpen={showActionSheet}
header={actionSheetHeader}
onDidDismiss={() => setShowActionSheet(false)}
buttons={actionSheetButtons}
/>
</>
);
};
export default SpeakerItem;

View File

@@ -1,8 +0,0 @@
import React from 'react';
import { format, parseISO as parseDate } from 'date-fns';
export const Time: React.FC<{ date: string }> = ({ date }) => (
<>
{format(parseDate(date), "h:mm aaaaa")}m
</>
)

View File

@@ -1,26 +0,0 @@
import React, { createContext, useReducer } from 'react';
import { initialState, AppState, reducers } from './state'
export interface AppContextState {
state: AppState;
dispatch: React.Dispatch<any>;
}
export const AppContext = createContext<AppContextState>({
state: initialState,
dispatch: () => undefined
});
export const AppContextProvider: React.FC = (props => {
const [store, dispatch] = useReducer(reducers, initialState);
return (
<AppContext.Provider value={{
state: store,
dispatch
}}>
{props.children}
</AppContext.Provider>
)
});

View File

@@ -1,14 +0,0 @@
export function combineReducers<R extends any>(reducers: R) {
type keys = keyof typeof reducers;
type returnType = { [K in keys]: ReturnType<typeof reducers[K]> };
const combinedReducer = (state: any, action: any) => {
const newState: returnType = {} as any;
const keys = Object.keys(reducers);
keys.forEach(key => {
const result = reducers[key](state[key], action);
newState[key as keys] = result || state[key];
});
return newState;
};
return combinedReducer;
}

View File

@@ -1,49 +0,0 @@
import React, { useContext, useEffect, useState, useMemo } from 'react';
import { AppContext } from './AppContext';
import { DispatchObject } from '../util/types';
import { AppState } from './state';
interface ConnectParams<TOwnProps, TStateProps, TDispatchProps> {
mapStateToProps?: (state: AppState, props: TOwnProps) => TStateProps,
mapDispatchToProps?: TDispatchProps,
component: React.ComponentType<any>
};
export function connect<TOwnProps = any, TStateProps = any, TDispatchProps = any>({ mapStateToProps = () => ({} as TStateProps), mapDispatchToProps = {} as TDispatchProps, component }: ConnectParams<TOwnProps, TStateProps, TDispatchProps>): React.FunctionComponent<TOwnProps> {
const Connect = (ownProps: TOwnProps) => {
const context = useContext(AppContext);
const dispatchFuncs = useMemo(() => {
const dispatchFuncs: { [key: string]: any } = {};
Object.keys(mapDispatchToProps).forEach((key) => {
const oldFunc = (mapDispatchToProps as any)[key];
const newFunc = (...args: any) => {
const dispatchFunc = oldFunc(...args);
if (typeof dispatchFunc === 'object') {
context.dispatch(dispatchFunc);
} else {
const result = dispatchFunc(context.dispatch)
if (typeof result === 'object' && result.then) {
result.then((dispatchObject?: DispatchObject) => {
if (dispatchObject && dispatchObject.type) {
context.dispatch(dispatchObject);
}
})
}
}
}
dispatchFuncs[key] = newFunc
});
return dispatchFuncs;
}, [mapDispatchToProps])
const props = useMemo(() => {
return Object.assign({}, ownProps, mapStateToProps(context.state, ownProps), dispatchFuncs);
}, [ownProps, context.state]);
return React.createElement<TOwnProps>(component, props);
}
return React.memo(Connect as any);
}

View File

@@ -1,73 +0,0 @@
import { Plugins } from '@capacitor/core';
import { Session } from '../models/Session';
import { Speaker } from '../models/Speaker';
import { Location } from '../models/Location';
const { Storage } = Plugins;
const locationsUrl = '/assets/data/locations.json';
const sessionsUrl = '/assets/data/sessions.json';
const speakersUrl = '/assets/data/speakers.json';
const HAS_LOGGED_IN = 'hasLoggedIn';
const HAS_SEEN_TUTORIAL = 'hasSeenTutorial';
const USERNAME = 'username';
export const getConfData = async () => {
const response = await Promise.all([
fetch(sessionsUrl),
fetch(locationsUrl),
fetch(speakersUrl),
]);
const sessions = (await response[0].json()) as Session[];
const locations = (await response[1].json()) as Location[];
const speakers = (await response[2].json()) as Speaker[];
const allTracks = sessions
.reduce((all, session) => all.concat(session.tracks), [] as string[])
.filter((trackName, index, array) => array.indexOf(trackName) === index)
.sort();
const data = {
sessions,
locations,
speakers,
allTracks,
filteredTracks: [...allTracks],
};
return data;
};
export const getUserData = async () => {
const response = await Promise.all([
Storage.get({ key: HAS_LOGGED_IN }),
Storage.get({ key: HAS_SEEN_TUTORIAL }),
Storage.get({ key: USERNAME }),
]);
const isLoggedin = (await response[0].value) === 'true';
const hasSeenTutorial = (await response[1].value) === 'true';
const username = (await response[2].value) || undefined;
const data = {
isLoggedin,
hasSeenTutorial,
username,
};
return data;
};
export const setIsLoggedInData = async (isLoggedIn: boolean) => {
await Storage.set({ key: HAS_LOGGED_IN, value: JSON.stringify(isLoggedIn) });
};
export const setHasSeenTutorialData = async (hasSeenTutorial: boolean) => {
await Storage.set({
key: HAS_SEEN_TUTORIAL,
value: JSON.stringify(hasSeenTutorial),
});
};
export const setUsernameData = async (username?: string) => {
if (!username) {
await Storage.remove({ key: USERNAME });
} else {
await Storage.set({ key: USERNAME, value: username });
}
};

View File

@@ -1,139 +0,0 @@
import { createSelector } from 'reselect';
import { parseISO as parseDate } from 'date-fns';
import { Session } from '../models/Session';
import { SessionGroup } from '../models/SessionGroup';
import { AppState } from './state';
const getSessions = (state: AppState) => state.data.sessions;
export const getSpeakers = (state: AppState) => state.data.speakers;
const getFilteredTracks = (state: AppState) => state.data.filteredTracks;
const getFavoriteIds = (state: AppState) => state.data.favorites;
const getSearchText = (state: AppState) => state.data.searchText;
export const getFilteredSessions = createSelector(
getSessions,
getFilteredTracks,
(sessions, filteredTracks) => {
return sessions.filter(session => {
let include = false;
session.tracks.forEach(track => {
if (filteredTracks.indexOf(track) > -1) {
include = true;
}
});
return include;
});
}
);
export const getSearchedSessions = createSelector(
getFilteredSessions,
getSearchText,
(sessions, searchText) => {
if (!searchText) {
return sessions;
}
return sessions.filter(
session =>
session.name.toLowerCase().indexOf(searchText.toLowerCase()) > -1
);
}
);
export const getGroupedSessions = createSelector(
getSearchedSessions,
sessions => {
return groupSessions(sessions);
}
);
export const getFavorites = createSelector(
getSearchedSessions,
getFavoriteIds,
(sessions, favoriteIds) =>
sessions.filter(x => favoriteIds.indexOf(x.id) > -1)
);
export const getGroupedFavorites = createSelector(
getFavorites,
sessions => {
return groupSessions(sessions);
}
);
const getIdParam = (_state: AppState, props: any) => {
const stringParam = props.match.params['id'];
return parseInt(stringParam, 10);
};
export const getSession = createSelector(
getSessions,
getIdParam,
(sessions, id) => sessions.find(x => x.id === id)
);
function groupSessions(sessions: Session[]) {
return sessions
.sort(
(a, b) =>
parseDate(a.dateTimeStart).valueOf() -
parseDate(b.dateTimeStart).valueOf()
)
.reduce(
(groups, session) => {
let starterHour = parseDate(session.dateTimeStart);
starterHour.setMinutes(0);
starterHour.setSeconds(0);
const starterHourStr = starterHour.toJSON();
const foundGroup = groups.find(
group => group.startTime === starterHourStr
);
if (foundGroup) {
foundGroup.sessions.push(session);
} else {
groups.push({
startTime: starterHourStr,
sessions: [session],
});
}
return groups;
},
[] as SessionGroup[]
);
}
export const getSpeaker = createSelector(
getSpeakers,
getIdParam,
(speakers, id) => speakers.find(x => x.id === id)
);
export const getSpeakerSessions = createSelector(
getSessions,
sessions => {
const speakerSessions: { [key: number]: Session[] } = {};
sessions.forEach(session => {
session.speakerIds.forEach(speakerId => {
if (speakerSessions[speakerId]) {
speakerSessions[speakerId].push(session);
} else {
speakerSessions[speakerId] = [session];
}
});
});
return speakerSessions;
}
);
export const mapCenter = (state: AppState) => {
const item = state.data.locations.find(l => l.id === state.data.mapCenterId);
if (item == null) {
return {
id: 1,
name: 'Map Center',
lat: 43.071584,
lng: -89.38012,
};
}
return item;
};

View File

@@ -1,54 +0,0 @@
import { getConfData } from '../dataApi';
import { ActionType } from '../../util/types';
import { SessionsState } from './sessions.state';
export const loadConfData = () => async (dispatch: React.Dispatch<any>) => {
dispatch(setLoading(true));
const data = await getConfData();
dispatch(setData(data));
dispatch(setLoading(false));
};
export const setLoading = (isLoading: boolean) =>
({
type: 'set-conf-loading',
isLoading,
} as const);
export const setData = (data: Partial<SessionsState>) =>
({
type: 'set-conf-data',
data,
} as const);
export const addFavorite = (sessionId: number) =>
({
type: 'add-favorite',
sessionId,
} as const);
export const removeFavorite = (sessionId: number) =>
({
type: 'remove-favorite',
sessionId,
} as const);
export const updateFilteredTracks = (filteredTracks: string[]) =>
({
type: 'update-filtered-tracks',
filteredTracks,
} as const);
export const setSearchText = (searchText?: string) =>
({
type: 'set-search-text',
searchText,
} as const);
export type SessionsActions =
| ActionType<typeof setLoading>
| ActionType<typeof setData>
| ActionType<typeof addFavorite>
| ActionType<typeof removeFavorite>
| ActionType<typeof updateFilteredTracks>
| ActionType<typeof setSearchText>;

View File

@@ -1,31 +0,0 @@
import { SessionsActions } from './sessions.actions';
import { SessionsState } from './sessions.state';
export const sessionsReducer = (
state: SessionsState,
action: SessionsActions
): SessionsState => {
switch (action.type) {
case 'set-conf-loading': {
return { ...state, loading: action.isLoading };
}
case 'set-conf-data': {
return { ...state, ...action.data };
}
case 'add-favorite': {
return { ...state, favorites: [...state.favorites, action.sessionId] };
}
case 'remove-favorite': {
return {
...state,
favorites: [...state.favorites.filter(x => x !== action.sessionId)],
};
}
case 'update-filtered-tracks': {
return { ...state, filteredTracks: action.filteredTracks };
}
case 'set-search-text': {
return { ...state, searchText: action.searchText };
}
}
};

View File

@@ -1,14 +0,0 @@
import { Location } from '../../models/Location';
import { Speaker } from '../../models/Speaker';
import { Session } from '../../models/Session';
export interface SessionsState {
sessions: Session[];
speakers: Speaker[];
favorites: number[];
locations: Location[];
filteredTracks: string[];
searchText?: string;
mapCenterId?: number;
loading?: boolean;
allTracks: string[];
}

View File

@@ -1,29 +0,0 @@
import { combineReducers } from './combineReducers';
import { sessionsReducer } from './sessions/sessions.reducer';
import { userReducer } from './user/user.reducer';
export const initialState: AppState = {
data: {
sessions: [],
speakers: [],
favorites: [],
locations: [],
allTracks: [],
filteredTracks: [],
mapCenterId: 0,
loading: false,
},
user: {
hasSeenTutorial: false,
darkMode: false,
isLoggedin: false,
loading: false,
},
};
export const reducers = combineReducers({
data: sessionsReducer,
user: userReducer,
});
export type AppState = ReturnType<typeof reducers>;

View File

@@ -1,76 +0,0 @@
import {
getUserData,
setIsLoggedInData,
setUsernameData,
setHasSeenTutorialData,
} from '../dataApi';
import { ActionType } from '../../util/types';
import { UserState } from './user.state';
export const loadUserData = () => async (dispatch: React.Dispatch<any>) => {
dispatch(setLoading(true));
const data = await getUserData();
dispatch(setData(data));
dispatch(setLoading(false));
};
export const setLoading = (isLoading: boolean) =>
({
type: 'set-user-loading',
isLoading,
} as const);
export const setData = (data: Partial<UserState>) =>
({
type: 'set-user-data',
data,
} as const);
export const logoutUser = () => async (dispatch: React.Dispatch<any>) => {
await setIsLoggedInData(false);
dispatch(setUsername());
};
export const setIsLoggedIn = (loggedIn: boolean) => async (
dispatch: React.Dispatch<any>
) => {
await setIsLoggedInData(loggedIn);
return {
type: 'set-is-loggedin',
loggedIn,
} as const;
};
export const setUsername = (username?: string) => async (
dispatch: React.Dispatch<any>
) => {
await setUsernameData(username);
return {
type: 'set-username',
username,
} as const;
};
export const setHasSeenTutorial = (hasSeenTutorial: boolean) => async (
dispatch: React.Dispatch<any>
) => {
await setHasSeenTutorialData(hasSeenTutorial);
return {
type: 'set-has-seen-tutorial',
hasSeenTutorial,
} as const;
};
export const setDarkMode = (darkMode: boolean) =>
({
type: 'set-dark-mode',
darkMode,
} as const);
export type UserActions =
| ActionType<typeof setLoading>
| ActionType<typeof setData>
| ActionType<typeof setIsLoggedIn>
| ActionType<typeof setUsername>
| ActionType<typeof setHasSeenTutorial>
| ActionType<typeof setDarkMode>;

View File

@@ -1,19 +0,0 @@
import { UserActions } from './user.actions';
import { UserState } from './user.state';
export function userReducer(state: UserState, action: UserActions): UserState {
switch (action.type) {
case 'set-user-loading':
return { ...state, loading: action.isLoading };
case 'set-user-data':
return { ...state, ...action.data };
case 'set-username':
return { ...state, username: action.username };
case 'set-has-seen-tutorial':
return { ...state, hasSeenTutorial: action.hasSeenTutorial };
case 'set-dark-mode':
return { ...state, darkMode: action.darkMode };
case 'set-is-loggedin':
return { ...state, isLoggedin: action.loggedIn };
}
}

View File

@@ -1,7 +0,0 @@
export interface UserState {
isLoggedin: boolean;
username?: string;
darkMode: boolean;
hasSeenTutorial: boolean;
loading: boolean;
}

View File

@@ -1,5 +0,0 @@
export interface AppPage {
url: string;
icon: object;
title: string;
}

View File

@@ -1,5 +1,11 @@
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(<App />, document.getElementById('root'));
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

View File

@@ -1,6 +0,0 @@
export interface Location {
id: number;
name?: string;
lat: number;
lng: number;
}

View File

@@ -1,10 +0,0 @@
export interface Session {
id: number;
dateTimeStart: string;
dateTimeEnd: string;
name: string;
location: string;
description: string;
speakerIds: number[];
tracks: string[];
}

View File

@@ -1,5 +0,0 @@
import { Session } from './Session';
export interface SessionGroup {
startTime: string;
sessions: Session[];
}

View File

@@ -1,10 +0,0 @@
export interface Speaker {
id: number;
name: string;
profilePic: string;
twitter: string;
about: string;
location: string;
email: string;
phone: string;
}

View File

@@ -1,26 +0,0 @@
#about-page {
.about-header {
background-color: #222;
padding: 16px;
width: 100%;
height: 30%;
text-align: center;
}
.about-header img {
max-height: 100%;
}
.about-info p {
color: var(--ion-color-dark);
text-align: left;
}
.about-info ion-icon {
margin-inline-end: 32px;
}
.ios .about-info {
text-align: center;
}
}

View File

@@ -1,81 +0,0 @@
import React, { useState } from 'react';
import { IonHeader, IonToolbar, IonTitle, IonContent, IonPage, IonButtons, IonMenuButton, IonButton, IonIcon, IonDatetime, IonSelectOption, IonList, IonItem, IonLabel, IonSelect, IonPopover } from '@ionic/react';
import './About.scss';
import { calendar, pin, more } from 'ionicons/icons';
import AboutPopover from '../components/AboutPopover';
interface AboutProps { }
const About: React.FC<AboutProps> = () => {
const [showPopover, setShowPopover] = useState(false);
const [popoverEvent, setPopoverEvent] = useState();
const presentPopover = (e: React.MouseEvent) => {
setPopoverEvent(e.nativeEvent);
setShowPopover(true);
};
const conferenceDate = '2047-05-17';
return (
<IonPage id="about-page">
<IonHeader>
<IonToolbar>
<IonButtons slot="start">
<IonMenuButton></IonMenuButton>
</IonButtons>
<IonTitle>About</IonTitle>
<IonButtons slot="end">
<IonButton icon-only onClick={presentPopover}>
<IonIcon slot="icon-only" icon={more}></IonIcon>
</IonButton>
</IonButtons>
</IonToolbar>
</IonHeader>
<IonContent>
<div className="about-header">
<img src="assets/img/ionic-logo-white.svg" alt="ionic logo" />
</div>
<div className="about-info">
<h4 className="ion-padding-start">Ionic Conference</h4>
<IonList lines="none">
<IonItem>
<IonIcon icon={calendar} slot="start"></IonIcon>
<IonLabel position="stacked">Date</IonLabel>
<IonDatetime displayFormat="MMM DD, YYYY" max="2056" value={conferenceDate}></IonDatetime>
</IonItem>
<IonItem>
<IonIcon icon={pin} slot="start"></IonIcon>
<IonLabel position="stacked">Location</IonLabel>
<IonSelect>
<IonSelectOption value="madison" selected>Madison, WI</IonSelectOption>
<IonSelectOption value="austin">Austin, TX</IonSelectOption>
<IonSelectOption value="chicago">Chicago, IL</IonSelectOption>
<IonSelectOption value="seattle">Seattle, WA</IonSelectOption>
</IonSelect>
</IonItem>
</IonList>
<p className="ion-padding-start ion-padding-end">
The Ionic Conference is a one-day conference featuring talks from the Ionic team. It is focused on Ionic applications being
built with Ionic 2. This includes migrating apps from Ionic 1 to Ionic 2, Angular concepts, Webpack, Sass, and many
other technologies used in Ionic 2. Tickets are completely sold out, and were expecting more than 1000 developers
making this the largest Ionic conference ever!
</p>
</div>
</IonContent>
<IonPopover
isOpen={showPopover}
event={popoverEvent}
onDidDismiss={() => setShowPopover(false)}
>
<AboutPopover dismiss={() => setShowPopover(false)} />
</IonPopover>
</IonPage>
);
};
export default React.memo(About);

View File

@@ -1,6 +0,0 @@
#account-page {
img {
max-width: 140px;
border-radius: 50%;
}
}

View File

@@ -1,87 +0,0 @@
import React, { useState } from 'react';
import { IonHeader, IonToolbar, IonTitle, IonContent, IonPage, IonButtons, IonMenuButton, IonList, IonItem, IonAlert } from '@ionic/react';
import './Account.scss';
import { setUsername } from '../data/user/user.actions';
import { connect } from '../data/connect';
import { RouteComponentProps } from 'react-router';
interface OwnProps extends RouteComponentProps { }
interface StateProps {
username?: string;
}
interface DispatchProps {
setUsername: typeof setUsername;
}
interface AccountProps extends OwnProps, StateProps, DispatchProps { }
const Account: React.FC<AccountProps> = ({ setUsername, username }) => {
const [showAlert, setShowAlert] = useState(false);
const clicked = (text: string) => {
console.log(`Clicked ${text}`);
}
return (
<IonPage id="account-page">
<IonHeader>
<IonToolbar>
<IonButtons slot="start">
<IonMenuButton></IonMenuButton>
</IonButtons>
<IonTitle>Account</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent>
{username &&
(<div className="ion-padding-top ion-text-center">
<img src="https://www.gravatar.com/avatar?d=mm&s=140" alt="avatar" />
<h2>{ username }</h2>
<IonList inset>
<IonItem onClick={() => clicked('Update Picture')}>Update Picture</IonItem>
<IonItem onClick={() => setShowAlert(true)}>Change Username</IonItem>
<IonItem onClick={() => clicked('Change Password')}>Change Password</IonItem>
<IonItem routerLink="/support" routerDirection="none">Support</IonItem>
<IonItem routerLink="/logout" routerDirection="none">Logout</IonItem>
</IonList>
</div>)
}
</IonContent>
<IonAlert
isOpen={showAlert}
header="Change Username"
buttons={[
'Cancel',
{
text: 'Ok',
handler: (data) => {
setUsername(data.username);
}
}
]}
inputs={[
{
type: 'text',
name: 'username',
value: username,
placeholder: 'username'
}
]}
onDidDismiss={() => setShowAlert(false)}
/>
</IonPage>
);
};
export default connect<OwnProps, StateProps, DispatchProps>({
mapStateToProps: (state) => ({
username: state.user.username
}),
mapDispatchToProps: {
setUsername,
},
component: Account
})

View File

@@ -0,0 +1,26 @@
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar } from '@ionic/react';
import React from 'react';
const Home: React.FC = () => {
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonTitle>Ionic Blank</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent className="ion-padding">
The world is your oyster.
<p>
If you get lost, the{' '}
<a target="_blank" rel="noopener noreferrer" href="https://ionicframework.com/docs/">
docs
</a>{' '}
will be your guide.
</p>
</IonContent>
</IonPage>
);
};
export default Home;

View File

@@ -1,16 +0,0 @@
#login-page, #signup-page, #support-page {
.login-logo {
padding: 20px 0;
min-height: 200px;
text-align: center;
}
.login-logo img {
max-width: 150px;
}
.list {
margin-bottom: 0;
}
}

View File

@@ -1,108 +0,0 @@
import React, { useState } from 'react';
import { IonHeader, IonToolbar, IonTitle, IonContent, IonPage, IonButtons, IonMenuButton, IonRow, IonCol, IonButton, IonList, IonItem, IonLabel, IonInput, IonText } from '@ionic/react';
import './Login.scss';
import { setIsLoggedIn, setUsername } from '../data/user/user.actions';
import { connect } from '../data/connect';
import { RouteComponentProps } from 'react-router';
interface OwnProps extends RouteComponentProps {}
interface DispatchProps {
setIsLoggedIn: typeof setIsLoggedIn;
setUsername: typeof setUsername;
}
interface LoginProps extends OwnProps, DispatchProps { }
const Login: React.FC<LoginProps> = ({setIsLoggedIn, history, setUsername: setUsernameAction}) => {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [formSubmitted, setFormSubmitted] = useState(false);
const [usernameError, setUsernameError] = useState(false);
const [passwordError, setPasswordError] = useState(false);
const login = async (e: React.FormEvent) => {
e.preventDefault();
setFormSubmitted(true);
if(!username) {
setUsernameError(true);
}
if(!password) {
setPasswordError(true);
}
if(username && password) {
await setIsLoggedIn(true);
await setUsernameAction(username);
history.push('/tabs/schedule', {direction: 'none'});
}
};
return (
<IonPage id="login-page">
<IonHeader>
<IonToolbar>
<IonButtons slot="start">
<IonMenuButton></IonMenuButton>
</IonButtons>
<IonTitle>Login</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent>
<div className="login-logo">
<img src="assets/img/appicon.svg" alt="Ionic logo" />
</div>
<form noValidate onSubmit={login}>
<IonList>
<IonItem>
<IonLabel position="stacked" color="primary">Username</IonLabel>
<IonInput name="username" type="text" value={username} spellCheck={false} autocapitalize="off" onIonChange={e => setUsername(e.detail.value!)}
required>
</IonInput>
</IonItem>
{formSubmitted && usernameError && <IonText color="danger">
<p className="ion-padding-start">
Username is required
</p>
</IonText>}
<IonItem>
<IonLabel position="stacked" color="primary">Password</IonLabel>
<IonInput name="password" type="password" value={password} onIonChange={e => setPassword(e.detail.value!)}>
</IonInput>
</IonItem>
{formSubmitted && passwordError && <IonText color="danger">
<p className="ion-padding-start">
Password is required
</p>
</IonText>}
</IonList>
<IonRow>
<IonCol>
<IonButton type="submit" expand="block">Login</IonButton>
</IonCol>
<IonCol>
<IonButton routerLink="/signup" color="light" expand="block">Signup</IonButton>
</IonCol>
</IonRow>
</form>
</IonContent>
</IonPage>
);
};
export default connect<OwnProps, {}, DispatchProps>({
mapDispatchToProps: {
setIsLoggedIn,
setUsername
},
component: Login
})

View File

@@ -1,54 +0,0 @@
import React from 'react';
import { IonTabs, IonRouterOutlet, IonTabBar, IonTabButton, IonIcon, IonLabel } from '@ionic/react';
import { Route, Redirect } from 'react-router';
import { calendar, contacts, map, informationCircle } from 'ionicons/icons';
import SchedulePage from './SchedulePage';
import SpeakerList from './SpeakerList';
import SpeakerDetail from './SpeakerDetail';
import SessionDetail from './SessionDetail';
import MapView from './MapView';
import About from './About';
interface MainTabsProps { }
const MainTabs: React.FC<MainTabsProps> = () => {
return (
<IonTabs>
<IonRouterOutlet>
<Redirect exact path="/tabs" to="/tabs/schedule" />
{/*
Using the render method prop cuts down the number of renders your components will have due to route changes.
Use the component prop when your component depends on the RouterComponentProps passed in automatically.
*/}
<Route path="/tabs/schedule" render={() => <SchedulePage />} exact={true} />
<Route path="/tabs/speakers" render={() => <SpeakerList />} exact={true} />
<Route path="/tabs/speakers/:id" component={SpeakerDetail} exact={true} />
<Route path="/tabs/schedule/:id" component={SessionDetail} />
<Route path="/tabs/speakers/sessions/:id" component={SessionDetail} />
<Route path="/tabs/map" render={() => <MapView />} exact={true} />
<Route path="/tabs/about" render={() => <About />} exact={true} />
</IonRouterOutlet>
<IonTabBar slot="bottom">
<IonTabButton tab="schedule" href="/tabs/schedule">
<IonIcon icon={calendar} />
<IonLabel>Schedule</IonLabel>
</IonTabButton>
<IonTabButton tab="speakers" href="/tabs/speakers">
<IonIcon icon={contacts} />
<IonLabel>Speakers</IonLabel>
</IonTabButton>
<IonTabButton tab="map" href="/tabs/map">
<IonIcon icon={map} />
<IonLabel>Map</IonLabel>
</IonTabButton>
<IonTabButton tab="about" href="/tabs/about">
<IonIcon icon={informationCircle} />
<IonLabel>About</IonLabel>
</IonTabButton>
</IonTabBar>
</IonTabs>
);
};
export default MainTabs;

View File

@@ -1,18 +0,0 @@
#map-view {
.map-canvas {
position: absolute;
height: 100%;
width: 100%;
background-color: transparent;
opacity: 0;
transition: opacity 250ms ease-in;
}
.show-map {
opacity: 1;
}
}

View File

@@ -1,44 +0,0 @@
import React from 'react';
import Map from '../components/Map';
import { IonHeader, IonToolbar, IonButtons, IonMenuButton, IonTitle, IonContent, IonPage } from '@ionic/react';
import { Location } from '../models/Location';
import { connect } from '../data/connect';
import * as selectors from '../data/selectors';
import './MapView.scss';
interface OwnProps { }
interface StateProps {
locations: Location[];
mapCenter: Location;
}
interface DispatchProps { }
interface MapViewProps extends OwnProps, StateProps, DispatchProps { };
const MapView: React.FC<MapViewProps> = ({ locations, mapCenter }) => {
return (
<IonPage id="map-view">
<IonHeader>
<IonToolbar>
<IonButtons slot="start">
<IonMenuButton></IonMenuButton>
</IonButtons>
<IonTitle>Map</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent class="map-page">
<Map locations={locations} mapCenter={mapCenter} />
</IonContent>
</IonPage>
)};
export default connect<OwnProps, StateProps, DispatchProps>({
mapStateToProps: (state) => ({
locations: state.data.locations,
mapCenter: selectors.mapCenter(state)
}),
component: MapView
});

View File

@@ -1,42 +0,0 @@
#schedule-page {
ion-item-sliding.track-ionic ion-label {
border-left: 2px solid var(--ion-color-primary);
padding-left: 10px;
}
ion-item-sliding.track-angular ion-label {
border-left: 2px solid var(--ion-color-angular);
padding-left: 10px;
}
ion-item-sliding.track-communication ion-label {
border-left: 2px solid var(--ion-color-communication);
padding-left: 10px;
}
ion-item-sliding.track-tooling ion-label {
border-left: 2px solid var(--ion-color-tooling);
padding-left: 10px;
}
ion-item-sliding.track-services ion-label {
border-left: 2px solid var(--ion-color-services);
padding-left: 10px;
}
ion-item-sliding.track-design ion-label {
border-left: 2px solid var(--ion-color-design);
padding-left: 10px;
}
ion-item-sliding.track-workshop ion-label {
border-left: 2px solid var(--ion-color-workshop);
padding-left: 10px;
}
ion-item-sliding.track-food ion-label {
border-left: 2px solid var(--ion-color-food);
padding-left: 10px;
}
ion-item-sliding.track-documentation ion-label {
border-left: 2px solid var(--ion-color-documentation);
padding-left: 10px;
}
ion-item-sliding.track-navigation ion-label {
border-left: 2px solid var(--ion-color-navigation);
padding-left: 10px;
}
}

View File

@@ -1,120 +0,0 @@
import React, { useState, useRef } from 'react';
import { IonToolbar, IonContent, IonPage, IonButtons, IonMenuButton, IonSegment, IonSegmentButton, IonButton, IonIcon, IonSearchbar, IonRefresher, IonRefresherContent, IonToast, IonModal, IonHeader, getConfig } from '@ionic/react';
import { connect } from '../data/connect';
import { options } from 'ionicons/icons';
import SessionList from '../components/SessionList';
import SessionListFilter from '../components/SessionListFilter';
import './SchedulePage.scss'
import * as selectors from '../data/selectors';
import { setSearchText, addFavorite, removeFavorite } from '../data/sessions/sessions.actions';
import ShareSocialFab from '../components/ShareSocialFab';
import { SessionGroup } from '../models/SessionGroup';
interface OwnProps { }
interface StateProps {
sessionGroups: SessionGroup[];
favoriteGroups: SessionGroup[];
mode: 'ios' | 'md'
}
interface DispatchProps {
setSearchText: typeof setSearchText;
}
type SchedulePageProps = OwnProps & StateProps & DispatchProps;
const SchedulePage: React.FC<SchedulePageProps> = ({ favoriteGroups, sessionGroups, setSearchText, mode }) => {
const [segment, setSegment] = useState<'all' | 'favorites'>('all');
const [showFilterModal, setShowFilterModal] = useState(false);
const ionRefresherRef = useRef<HTMLIonRefresherElement>(null);
const [showCompleteToast, setShowCompleteToast] = useState(false);
const doRefresh = () => {
setTimeout(() => {
ionRefresherRef.current!.complete();
setShowCompleteToast(true);
}, 2500)
};
return (
<IonPage id="schedule-page">
<IonHeader>
<IonToolbar>
<IonButtons slot="start">
<IonMenuButton />
</IonButtons>
<IonSegment onIonChange={(e) => setSegment(e.detail.value as any)}>
<IonSegmentButton value="all" checked={segment === 'all'}>
All
</IonSegmentButton>
<IonSegmentButton value="favorites" checked={segment === 'favorites'}>
Favorites
</IonSegmentButton>
</IonSegment>
<IonButtons slot="end">
<IonButton onClick={() => setShowFilterModal(true)}>
{mode === 'ios' ? 'Filter' : <IonIcon icon={options} slot="icon-only" />}
</IonButton>
</IonButtons>
</IonToolbar>
<IonToolbar>
<IonSearchbar
placeholder="Search"
onIonChange={(e: CustomEvent) => setSearchText(e.detail.value)}
/>
</IonToolbar>
</IonHeader>
<IonContent>
<IonRefresher slot="fixed" ref={ionRefresherRef} onIonRefresh={doRefresh}>
<IonRefresherContent />
</IonRefresher>
<IonToast
isOpen={showCompleteToast}
message="Refresh complete"
duration={2000}
onDidDismiss={() => setShowCompleteToast(false)}
/>
<SessionList
sessionGroups={sessionGroups}
listType={segment}
hide={segment === 'favorites'}
/>
<SessionList
sessionGroups={favoriteGroups}
listType={segment}
hide={segment === 'all'}
/>
</IonContent>
<IonModal
isOpen={showFilterModal}
onDidDismiss={() => setShowFilterModal(false)}
>
<SessionListFilter
onDismissModal={() => setShowFilterModal(false)}
/>
</IonModal>
<ShareSocialFab />
</IonPage>
);
};
export default connect<OwnProps, StateProps, DispatchProps>({
mapStateToProps: (state) => ({
sessionGroups: selectors.getGroupedSessions(state),
favoriteGroups: selectors.getGroupedFavorites(state),
mode: getConfig()!.get('mode')
}),
mapDispatchToProps: {
setSearchText
},
component: React.memo(SchedulePage)
});

View File

@@ -1,73 +0,0 @@
#session-detail-page {
.session-track-ionic {
color: var(--ion-color-primary);
}
.session-track-angular {
color: var(--ion-color-angular);
}
.session-track-communication {
color: var(--ion-color-communication);
}
.session-track-tooling {
color: var(--ion-color-tooling);
}
.session-track-services {
color: var(--ion-color-services);
}
.session-track-design {
color: var(--ion-color-design);
}
.session-track-workshop {
color: var(--ion-color-workshop);
}
.session-track-food {
color: var(--ion-color-food);
}
.session-track-documentation {
color: var(--ion-color-documentation);
}
.session-track-navigation {
color: var(--ion-color-navigation);
}
.show-favorite {
position: relative;
}
.icon-heart-empty {
position: absolute;
top: 5px;
right: 5px;
transform: scale(1);
transition: transform 0.3s ease;
}
.icon-heart {
position: absolute;
top: 5px;
right: 5px;
transform: scale(0);
transition: transform 0.3s ease;
}
.show-favorite .icon-heart {
transform: scale(1);
}
.show-favorite .icon-heart-empty {
transform: scale(0);
}
h1 {
margin: 0;
}
}

View File

@@ -1,108 +0,0 @@
import React from 'react';
import { IonHeader, IonToolbar, IonContent, IonPage, IonButtons, IonBackButton, IonButton, IonIcon, IonText, IonList, IonItem, IonLabel } from '@ionic/react';
import { connect } from '../data/connect';
import { withRouter, RouteComponentProps } from 'react-router';
import * as selectors from '../data/selectors';
import { starOutline, star, share, cloudDownload } from 'ionicons/icons';
import './SessionDetail.scss';
import { Time } from '../components/Time';
import { addFavorite, removeFavorite } from '../data/sessions/sessions.actions';
import { Session } from '../models/Session';
interface OwnProps extends RouteComponentProps { };
interface StateProps {
session?: Session;
favoriteSessions: number[],
};
interface DispatchProps {
addFavorite: typeof addFavorite;
removeFavorite: typeof removeFavorite;
}
type SessionDetailProps = OwnProps & StateProps & DispatchProps;
const SessionDetail: React.FC<SessionDetailProps> = ({ session, addFavorite, removeFavorite, favoriteSessions }) => {
if (!session) {
return <div>Session not found</div>
}
const isFavorite = favoriteSessions.indexOf(session.id) > -1;
const toggleFavorite = () => {
isFavorite ? removeFavorite(session.id) : addFavorite(session.id);
};
const shareSession = () => { };
const sessionClick = (text: string) => {
console.log(`Clicked ${text}`);
};
return (
<IonPage id="session-detail-page">
<IonHeader>
<IonToolbar>
<IonButtons slot="start">
<IonBackButton defaultHref="/tabs/schedule"></IonBackButton>
</IonButtons>
<IonButtons slot="end">
<IonButton onClick={() => toggleFavorite()}>
{isFavorite ?
<IonIcon slot="icon-only" icon={star}></IonIcon> :
<IonIcon slot="icon-only" icon={starOutline}></IonIcon>
}
</IonButton>
<IonButton onClick={() => shareSession}>
<IonIcon slot="icon-only" icon={share}></IonIcon>
</IonButton>
</IonButtons>
</IonToolbar>
</IonHeader>
<IonContent>
<div className="ion-padding">
<h1>{session.name}</h1>
{session.tracks.map(track => (
<span key={track} className={`session-track-${track.toLowerCase()}`}>{track}</span>
))}
<p>{session.description}</p>
<IonText color="medium">
<Time date={session.dateTimeStart} /> &ndash; <Time date={session.dateTimeEnd} />
<br />
{session.location}
</IonText>
</div>
<IonList>
<IonItem onClick={() => sessionClick('watch')} button>
<IonLabel color="primary">Watch</IonLabel>
</IonItem>
<IonItem onClick={() => sessionClick('add to calendar')} button>
<IonLabel color="primary">Add to Calendar</IonLabel>
</IonItem>
<IonItem onClick={() => sessionClick('mark as unwatched')} button>
<IonLabel color="primary">Mark as Unwatched</IonLabel>
</IonItem>
<IonItem onClick={() => sessionClick('download video')} button>
<IonLabel color="primary">Download Video</IonLabel>
<IonIcon slot="end" color="primary" size="small" icon={cloudDownload}></IonIcon>
</IonItem>
<IonItem onClick={() => sessionClick('leave feedback')} button>
<IonLabel color="primary">Leave Feedback</IonLabel>
</IonItem>
</IonList>
</IonContent>
</IonPage>
);
};
export default connect<OwnProps, StateProps, DispatchProps>({
mapStateToProps: (state, OwnProps) => ({
session: selectors.getSession(state, OwnProps),
favoriteSessions: state.data.favorites
}),
mapDispatchToProps: {
addFavorite,
removeFavorite
},
component: withRouter(SessionDetail)
})

View File

@@ -1,111 +0,0 @@
import React, { useState } from 'react';
import { IonHeader, IonToolbar, IonTitle, IonContent, IonPage, IonButtons, IonMenuButton, IonRow, IonCol, IonButton, IonList, IonItem, IonLabel, IonInput, IonText } from '@ionic/react';
import './Login.scss';
import { setIsLoggedIn, setUsername } from '../data/user/user.actions';
import { connect } from '../data/connect';
import { RouteComponentProps } from 'react-router';
interface OwnProps extends RouteComponentProps {}
interface DispatchProps {
setIsLoggedIn: typeof setIsLoggedIn;
setUsername: typeof setUsername;
}
interface LoginProps extends OwnProps, DispatchProps { }
const Login: React.FC<LoginProps> = ({setIsLoggedIn, history, setUsername: setUsernameAction}) => {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [formSubmitted, setFormSubmitted] = useState(false);
const [usernameError, setUsernameError] = useState(false);
const [passwordError, setPasswordError] = useState(false);
const login = async (e: React.FormEvent) => {
e.preventDefault();
setFormSubmitted(true);
if(!username) {
setUsernameError(true);
}
if(!password) {
setPasswordError(true);
}
if(username && password) {
await setIsLoggedIn(true);
await setUsernameAction(username);
history.push('/tabs/schedule', {direction: 'none'});
}
};
return (
<IonPage id="signup-page">
<IonHeader>
<IonToolbar>
<IonButtons slot="start">
<IonMenuButton></IonMenuButton>
</IonButtons>
<IonTitle>Signup</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent>
<div className="login-logo">
<img src="assets/img/appicon.svg" alt="Ionic logo" />
</div>
<form noValidate onSubmit={login}>
<IonList>
<IonItem>
<IonLabel position="stacked" color="primary">Username</IonLabel>
<IonInput name="username" type="text" value={username} spellCheck={false} autocapitalize="off" onIonChange={e => {
setUsername(e.detail.value!);
setUsernameError(false);
}}
required>
</IonInput>
</IonItem>
{formSubmitted && usernameError && <IonText color="danger">
<p className="ion-padding-start">
Username is required
</p>
</IonText>}
<IonItem>
<IonLabel position="stacked" color="primary">Password</IonLabel>
<IonInput name="password" type="password" value={password} onIonChange={e => {
setPassword(e.detail.value!);
setPasswordError(false);
}}>
</IonInput>
</IonItem>
{formSubmitted && passwordError && <IonText color="danger">
<p className="ion-padding-start">
Password is required
</p>
</IonText>}
</IonList>
<IonRow>
<IonCol>
<IonButton type="submit" expand="block">Create</IonButton>
</IonCol>
</IonRow>
</form>
</IonContent>
</IonPage>
);
};
export default connect<OwnProps, {}, DispatchProps>({
mapDispatchToProps: {
setIsLoggedIn,
setUsername
},
component: Login
})

View File

@@ -1,11 +0,0 @@
#speaker-detail {
img {
max-width: 140px;
border-radius: 50%;
}
p {
color: #60646B;
}
}

View File

@@ -1,64 +0,0 @@
import React from 'react';
import { RouteComponentProps } from 'react-router';
import { IonIcon, IonHeader, IonToolbar, IonButtons, IonTitle, IonContent, IonButton, IonBackButton, IonPage } from '@ionic/react'
import './SpeakerDetail.scss';
import { logoTwitter, logoGithub, logoInstagram } from 'ionicons/icons';
import { connect } from '../data/connect';
import * as selectors from '../data/selectors';
import { Speaker } from '../models/Speaker';
interface OwnProps extends RouteComponentProps {
speaker?: Speaker;
};
interface StateProps {};
interface DispatchProps {};
interface SpeakerDetailProps extends OwnProps, StateProps, DispatchProps {};
const SpeakerDetail: React.FC<SpeakerDetailProps> = ({ speaker }) => {
if (!speaker) {
return <div>Speaker not found</div>
}
return (
<IonPage id="speaker-detail">
<IonHeader>
<IonToolbar>
<IonButtons slot="start">
<IonBackButton defaultHref="/tabs/speakers" />
</IonButtons>
<IonTitle>{speaker.name}</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent className="ion-padding speaker-detail speaker-page-list">
<div className="ion-text-center">
<img src={speaker.profilePic} alt={speaker.name} />
<br />
<IonButton fill="clear" size="small" color="twitter">
<IonIcon icon={logoTwitter} slot="icon-only"></IonIcon>
</IonButton>
<IonButton fill="clear" size="small" color="github">
<IonIcon icon={logoGithub} slot="icon-only"></IonIcon>
</IonButton>
<IonButton fill="clear" size="small" color="instagram">
<IonIcon icon={logoInstagram} slot="icon-only"></IonIcon>
</IonButton>
</div>
<p>{speaker.about}</p>
</IonContent>
</IonPage>
);
};
export default connect({
mapStateToProps: (state, ownProps) => ({
speaker: selectors.getSpeaker(state, ownProps)
}),
component: SpeakerDetail
});

View File

@@ -1,24 +0,0 @@
#speaker-list {
.scroll {
background: #ededed;
}
.speaker-card {
height: 100%;
display: flex;
flex-direction: column;
}
.speaker-card ion-card-header {
padding: 0;
}
.speaker-card ion-card-header .item {
padding: 4px 16px;
}
.speaker-card ion-card-content {
flex: 1 1 auto;
padding: 0;
}
}

View File

@@ -1,61 +0,0 @@
import React from 'react';
import { IonHeader, IonToolbar, IonTitle, IonContent, IonPage, IonButtons, IonMenuButton, IonList, IonGrid, IonRow, IonCol } from '@ionic/react';
import SpeakerItem from '../components/SpeakerItem';
import { Speaker } from '../models/Speaker';
import { Session } from '../models/Session';
import { connect } from '../data/connect';
import * as selectors from '../data/selectors';
import './SpeakerList.scss';
interface OwnProps { };
interface StateProps {
speakers: Speaker[];
speakerSessions: { [key: number]: Session[] };
};
interface DispatchProps { };
interface SpeakerListProps extends OwnProps, StateProps, DispatchProps { };
const SpeakerList: React.FC<SpeakerListProps> = ({ speakers, speakerSessions }) => {
return (
<IonPage id="speaker-list">
<IonHeader>
<IonToolbar>
<IonButtons slot="start">
<IonMenuButton />
</IonButtons>
<IonTitle>Speakers</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent className={`outer-content`}>
<IonList>
<IonGrid fixed>
<IonRow align-items-stretch>
{speakers.map(speaker => (
<IonCol size="12" size-md="6" key={speaker.id}>
<SpeakerItem
key={speaker.id}
speaker={speaker}
sessions={speakerSessions[speaker.id]}
/>
</IonCol>
))}
</IonRow>
</IonGrid>
</IonList>
</IonContent>
</IonPage>
);
};
export default connect<OwnProps, StateProps, DispatchProps>({
mapStateToProps: (state) => ({
speakers: selectors.getSpeakers(state),
speakerSessions: selectors.getSpeakerSessions(state)
}),
component: React.memo(SpeakerList)
});

View File

@@ -1,83 +0,0 @@
import React, { useState } from 'react';
import { IonHeader, IonToolbar, IonTitle, IonContent, IonPage, IonButtons, IonMenuButton, IonRow, IonCol, IonButton, IonList, IonItem, IonLabel, IonText, IonTextarea, IonToast } from '@ionic/react';
import './Login.scss';
import { connect } from '../data/connect';
interface OwnProps { }
interface DispatchProps { }
interface SupportProps extends OwnProps, DispatchProps { }
const Support: React.FC<SupportProps> = () => {
const [message, setMessage] = useState('');
const [formSubmitted, setFormSubmitted] = useState(false);
const [messageError, setMessageError] = useState(false);
const [showToast, setShowToast] = useState(false);
const send = (e: React.FormEvent) => {
e.preventDefault();
setFormSubmitted(true);
if (!message) {
setMessageError(true);
}
if (message) {
setMessage('');
setShowToast(true);
}
};
return (
<IonPage id="support-page">
<IonHeader>
<IonToolbar>
<IonButtons slot="start">
<IonMenuButton></IonMenuButton>
</IonButtons>
<IonTitle>Support</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent>
<div className="login-logo">
<img src="assets/img/appicon.svg" alt="Ionic logo" />
</div>
<form noValidate onSubmit={send}>
<IonList>
<IonItem>
<IonLabel position="stacked" color="primary">Enter your support message below</IonLabel>
<IonTextarea name="message" value={message} spellCheck={false} autocapitalize="off" rows={6} onIonChange={e => setMessage(e.detail.value!)}
required>
</IonTextarea>
</IonItem>
{formSubmitted && messageError && <IonText color="danger">
<p className="ion-padding-start">
Support message is required
</p>
</IonText>}
</IonList>
<IonRow>
<IonCol>
<IonButton type="submit" expand="block">Submit</IonButton>
</IonCol>
</IonRow>
</form>
</IonContent>
<IonToast
isOpen={showToast}
duration={3000}
message="Your support request has been sent"
onDidDismiss={() => setShowToast(false)} />
</IonPage>
);
};
export default connect<OwnProps, {}, DispatchProps>({
component: Support
})

View File

@@ -1,38 +0,0 @@
#tutorial-page {
ion-toolbar {
// TODO test transparent and fullscreen
--background: transparent;
--border-color: transparent;
}
.swiper-slide {
display: block;
}
.slide-title {
margin-top: 2.8rem;
}
.slide-image {
max-height: 50%;
max-width: 60%;
margin: 36px 0;
pointer-events: none;
}
b {
font-weight: 500;
}
p {
padding: 0 40px;
font-size: 14px;
line-height: 1.5;
color: var(--ion-color-step-600, #60646b);
b {
color: var(--ion-text-color, #000000);
}
}
}

View File

@@ -1,87 +0,0 @@
import React, { useState, useRef } from 'react';
import { IonContent, IonPage, IonHeader, IonToolbar, IonButtons, IonButton, IonSlides, IonSlide, IonIcon } from '@ionic/react';
import { arrowForward } from 'ionicons/icons';
import { setHasSeenTutorial } from '../data/user/user.actions';
import './Tutorial.scss';
import { connect } from '../data/connect';
import { RouteComponentProps } from 'react-router';
interface OwnProps extends RouteComponentProps {};
interface DispatchProps {
setHasSeenTutorial: typeof setHasSeenTutorial
}
interface TutorialProps extends OwnProps, DispatchProps { };
const Tutorial: React.FC<TutorialProps> = ({ history, setHasSeenTutorial }) => {
const [showSkip, setShowSkip] = useState(true);
const slideRef = useRef<HTMLIonSlidesElement>(null);
const startApp = async () => {
await setHasSeenTutorial(true);
history.push('/tabs/schedule', { direction: 'none' });
};
const handleSlideChangeStart = () => {
slideRef.current!.isEnd().then(isEnd => setShowSkip(!isEnd));
};
return (
<IonPage id="tutorial-page">
<IonHeader no-border>
<IonToolbar>
<IonButtons slot="end">
{showSkip && <IonButton color='primary' onClick={startApp}>Skip</IonButton>}
</IonButtons>
</IonToolbar>
</IonHeader>
<IonContent fullscreen>
<IonSlides ref={slideRef} onIonSlideWillChange={handleSlideChangeStart} pager={false}>
<IonSlide>
<img src="assets/img/ica-slidebox-img-1.png" alt="" className="slide-image" />
<h2 className="slide-title">
Welcome to <b>ICA</b>
</h2>
<p>
The <b>ionic conference app</b> is a practical preview of the ionic framework in action, and a demonstration of proper code use.
</p>
</IonSlide>
<IonSlide>
<img src="assets/img/ica-slidebox-img-2.png" alt="" className="slide-image" />
<h2 className="slide-title">What is Ionic?</h2>
<p>
<b>Ionic Framework</b> is an open source SDK that enables developers to build high quality mobile apps with web technologies like HTML, CSS, and JavaScript.
</p>
</IonSlide>
<IonSlide>
<img src="assets/img/ica-slidebox-img-3.png" alt="" className="slide-image" />
<h2 className="slide-title">What is Ionic Appflow?</h2>
<p>
<b>Ionic Appflow</b> is a powerful set of services and features built on top of Ionic Framework that brings a totally new level of app development agility to mobile dev teams.
</p>
</IonSlide>
<IonSlide>
<img src="assets/img/ica-slidebox-img-4.png" alt="" className="slide-image" />
<h2 className="slide-title">Ready to Play?</h2>
<IonButton fill="clear" onClick={startApp}>
Continue
<IonIcon slot="end" icon={arrowForward} />
</IonButton>
</IonSlide>
</IonSlides>
</IonContent>
</IonPage>
);
};
export default connect<OwnProps, {}, DispatchProps>({
mapDispatchToProps: ({
setHasSeenTutorial
}),
component: Tutorial
});

View File

@@ -0,0 +1,145 @@
// This optional code is used to register a service worker.
// register() is not called by default.
// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on subsequent visits to a page, after all the
// existing tabs open on the page have been closed, since previously cached
// resources are updated in the background.
// To learn more about the benefits of this model and instructions on how to
// opt-in, read https://bit.ly/CRA-PWA
const isLocalhost = Boolean(
window.location.hostname === 'localhost' ||
// [::1] is the IPv6 localhost address.
window.location.hostname === '[::1]' ||
// 127.0.0.0/8 are considered localhost for IPv4.
window.location.hostname.match(
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
)
);
type Config = {
onSuccess?: (registration: ServiceWorkerRegistration) => void;
onUpdate?: (registration: ServiceWorkerRegistration) => void;
};
export function register(config?: Config) {
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
// The URL constructor is available in all browsers that support SW.
const publicUrl = new URL(
process.env.PUBLIC_URL,
window.location.href
);
if (publicUrl.origin !== window.location.origin) {
// Our service worker won't work if PUBLIC_URL is on a different origin
// from what our page is served on. This might happen if a CDN is used to
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
return;
}
window.addEventListener('load', () => {
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
if (isLocalhost) {
// This is running on localhost. Let's check if a service worker still exists or not.
checkValidServiceWorker(swUrl, config);
// Add some additional logging to localhost, pointing developers to the
// service worker/PWA documentation.
navigator.serviceWorker.ready.then(() => {
console.log(
'This web app is being served cache-first by a service ' +
'worker. To learn more, visit https://bit.ly/CRA-PWA'
);
});
} else {
// Is not localhost. Just register service worker
registerValidSW(swUrl, config);
}
});
}
}
function registerValidSW(swUrl: string, config?: Config) {
navigator.serviceWorker
.register(swUrl)
.then(registration => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
if (installingWorker == null) {
return;
}
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// At this point, the updated precached content has been fetched,
// but the previous service worker will still serve the older
// content until all client tabs are closed.
console.log(
'New content is available and will be used when all ' +
'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
);
// Execute callback
if (config && config.onUpdate) {
config.onUpdate(registration);
}
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
console.log('Content is cached for offline use.');
// Execute callback
if (config && config.onSuccess) {
config.onSuccess(registration);
}
}
}
};
};
})
.catch(error => {
console.error('Error during service worker registration:', error);
});
}
function checkValidServiceWorker(swUrl: string, config?: Config) {
// Check if the service worker can be found. If it can't reload the page.
fetch(swUrl, {
headers: { 'Service-Worker': 'script' }
})
.then(response => {
// Ensure service worker exists, and that we really are getting a JS file.
const contentType = response.headers.get('content-type');
if (
response.status === 404 ||
(contentType != null && contentType.indexOf('javascript') === -1)
) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then(registration => {
registration.unregister().then(() => {
window.location.reload();
});
});
} else {
// Service worker found. Proceed as normal.
registerValidSW(swUrl, config);
}
})
.catch(() => {
console.log(
'No internet connection found. App is running in offline mode.'
);
});
}
export function unregister() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then(registration => {
registration.unregister();
});
}
}

View File

@@ -0,0 +1,5 @@
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom/extend-expect';

View File

@@ -1,179 +0,0 @@
/* Ionic Variables and Theming. For more information, please see
// https://beta.ionicframework.com/docs/theming/
// The app direction is used to include
// rtl styles in your app. For more information, please see
// https://beta.ionicframework.com/docs/layout/rtl
// $app-direction: ltr;
// Ionic Colors
// --------------------------------------------------
// Named colors makes it easy to reuse colors on various components.
// It's highly recommended to change the default colors
// to match your app's branding. Ionic provides eight layered colors
// that can be changed to theme an app. Additional colors can be
// added as well (see below). For more information, please see
// https://beta.ionicframework.com/docs/theming/advanced
// To easily create custom color palettes for your apps UI,
// check out our color generator:
// https://beta.ionicframework.com/docs/theming/color-generator
*/
:root {
--ion-color-angular: #ac282b;
--ion-color-communication: #8e8d93;
--ion-color-tooling: #fe4c52;
--ion-color-services: #fd8b2d;
--ion-color-design: #fed035;
--ion-color-workshop: #69bb7b;
--ion-color-food: #3bc7c4;
--ion-color-documentation: #b16be3;
--ion-color-navigation: #6600cc;
--ion-color-primary: #3880ff;
--ion-color-primary-rgb: 56, 128, 255;
--ion-color-primary-contrast: #ffffff;
--ion-color-primary-contrast-rgb: 255, 255, 255;
--ion-color-primary-shade: #3171e0;
--ion-color-primary-tint: #4c8dff;
--ion-color-secondary: #0cd1e8;
--ion-color-secondary-rgb: 12, 209, 232;
--ion-color-secondary-contrast: #ffffff;
--ion-color-secondary-contrast-rgb: 255, 255, 255;
--ion-color-secondary-shade: #0bb8cc;
--ion-color-secondary-tint: #24d6ea;
--ion-color-tertiary: #7044ff;
--ion-color-tertiary-rgb: 112, 68, 255;
--ion-color-tertiary-contrast: #ffffff;
--ion-color-tertiary-contrast-rgb: 255, 255, 255;
--ion-color-tertiary-shade: #633ce0;
--ion-color-tertiary-tint: #7e57ff;
--ion-color-success: #10dc60;
--ion-color-success-rgb: 16, 220, 96;
--ion-color-success-contrast: #ffffff;
--ion-color-success-contrast-rgb: 255, 255, 255;
--ion-color-success-shade: #0ec254;
--ion-color-success-tint: #28e070;
--ion-color-warning: #ffce00;
--ion-color-warning-rgb: 255, 206, 0;
--ion-color-warning-contrast: #ffffff;
--ion-color-warning-contrast-rgb: 255, 255, 255;
--ion-color-warning-shade: #e0b500;
--ion-color-warning-tint: #ffd31a;
--ion-color-danger: #f04141;
--ion-color-danger-rgb: 245, 61, 61;
--ion-color-danger-contrast: #ffffff;
--ion-color-danger-contrast-rgb: 255, 255, 255;
--ion-color-danger-shade: #d33939;
--ion-color-danger-tint: #f25454;
--ion-color-dark: #222428;
--ion-color-dark-rgb: 34, 34, 34;
--ion-color-dark-contrast: #ffffff;
--ion-color-dark-contrast-rgb: 255, 255, 255;
--ion-color-dark-shade: #1e2023;
--ion-color-dark-tint: #383a3e;
--ion-color-medium: #989aa2;
--ion-color-medium-rgb: 152, 154, 162;
--ion-color-medium-contrast: #ffffff;
--ion-color-medium-contrast-rgb: 255, 255, 255;
--ion-color-medium-shade: #86888f;
--ion-color-medium-tint: #a2a4ab;
--ion-color-light: #f4f5f8;
--ion-color-light-rgb: 244, 244, 244;
--ion-color-light-contrast: #000000;
--ion-color-light-contrast-rgb: 0, 0, 0;
--ion-color-light-shade: #d7d8da;
--ion-color-light-tint: #f5f6f9;
}
/* Additional Ionic Colors
// --------------------------------------------------
// In order to add colors to be used with Ionic components,
// the color should be added as a class with the convention `.ion-color-{COLOR}`
// where `{COLOR}` is the color to be used on the Ionic component
// and each variant is defined for the color. For more information, please see
// https://beta.ionicframework.com/docs/theming/advanced
*/
.ion-color-favorite {
--ion-color-base: #69bb7b;
--ion-color-base-rgb: 105, 187, 123;
--ion-color-contrast: #ffffff;
--ion-color-contrast-rgb: 255, 255, 255;
--ion-color-shade: #5ca56c;
--ion-color-tint: #78c288;
}
.ion-color-twitter {
--ion-color-base: #1da1f4;
--ion-color-base-rgb: 29, 161, 244;
--ion-color-contrast: #ffffff;
--ion-color-contrast-rgb: 255, 255, 255;
--ion-color-shade: #1a8ed7;
--ion-color-tint: #34aaf5;
}
.ion-color-google {
--ion-color-base: #dc4a38;
--ion-color-base-rgb: 220, 74, 56;
--ion-color-contrast: #ffffff;
--ion-color-contrast-rgb: 255, 255, 255;
--ion-color-shade: #c24131;
--ion-color-tint: #e05c4c;
}
.ion-color-vimeo {
--ion-color-base: #23b6ea;
--ion-color-base-rgb: 35, 182, 234;
--ion-color-contrast: #ffffff;
--ion-color-contrast-rgb: 255, 255, 255;
--ion-color-shade: #1fa0ce;
--ion-color-tint: #39bdec;
}
.ion-color-facebook {
--ion-color-base: #3b5998;
--ion-color-base-rgb: 59, 89, 152;
--ion-color-contrast: #ffffff;
--ion-color-contrast-rgb: 255, 255, 255;
--ion-color-shade: #344e86;
--ion-color-tint: #4f6aa2;
}
/* Shared Variables
// --------------------------------------------------
// To customize the look and feel of this app, you can override
// the CSS variables found in Ionic's source files.
// To view all the possible Ionic variables, see:
// https://beta.ionicframework.com/docs/theming/css-variables#ionic-variables
*/
:root {
--ion-headings-font-weight: 300;
--ion-color-angular: #ac282b;
--ion-color-communication: #8e8d93;
--ion-color-tooling: #fe4c52;
--ion-color-services: #fd8b2d;
--ion-color-design: #fed035;
--ion-color-workshop: #69bb7b;
--ion-color-food: #3bc7c4;
--ion-color-documentation: #b16be3;
--ion-color-navigation: #6600cc;
}
.md {
--ion-toolbar-background: var(--ion-color-primary);
--ion-toolbar-color: #fff;
--ion-toolbar-color-activated: #fff;
}

Some files were not shown because too many files have changed in this diff Show More