Compare commits

...

655 Commits

Author SHA1 Message Date
Szilárd Dóró
11b4d12f12 Merge pull request #1794 from nhost/changeset-release/main
chore: update versions
2023-03-30 19:56:33 +02:00
Szilárd Dóró
12301e6551 fix: use correct @nhost/apollo version 2023-03-30 15:57:43 +02:00
github-actions[bot]
74e52cac2d chore: update versions 2023-03-30 09:07:41 +00:00
Szilárd Dóró
f17823760a Merge pull request #1795 from nhost/fix/presigned-urls
fix: don't alter URLs when no transformation parameters are available
2023-03-30 11:06:32 +02:00
Szilárd Dóró
bb8803a1e3 fix: don't alter URLs 2023-03-30 10:41:57 +02:00
Szilárd Dóró
b846291331 Merge pull request #1793 from nhost/fix/export-issue
fix: don't use conflicting names
2023-03-30 10:07:24 +02:00
Szilárd Dóró
2b2fb94f00 chore: add type checking step 2023-03-30 09:42:23 +02:00
Szilárd Dóró
551760c4f0 fix: don't break builds 2023-03-30 09:37:39 +02:00
Szilárd Dóró
5ae5a8e77d fix: don't break builds 2023-03-30 09:31:54 +02:00
Szilárd Dóró
56aae0c964 fix: don't break builds 2023-03-30 09:28:34 +02:00
Szilárd Dóró
a0e093d77b fix: don't use conflicting names 2023-03-30 09:16:30 +02:00
Szilárd Dóró
5e82e1b3da Merge pull request #1784 from nhost/changeset-release/main
chore: update versions
2023-03-29 09:20:48 +02:00
github-actions[bot]
e618b705e7 chore: update versions 2023-03-28 15:52:47 +00:00
Szilárd Dóró
a232c9f0f6 Merge pull request #1789 from nhost/fix/azuread-description
fix(dashboard): use correct description for Azure AD
2023-03-28 17:50:51 +02:00
Szilárd Dóró
bf4644ea10 fix: use correct description for Azure AD 2023-03-28 16:52:54 +02:00
Szilárd Dóró
0aca907ea4 Merge pull request #1788 from nhost/fix/azuread-provider-name
fix: correct typos in Azure AD
2023-03-28 16:25:59 +02:00
Szilárd Dóró
394f4c4174 fix: correct typos in Azure AD 2023-03-28 16:25:26 +02:00
Szilárd Dóró
8fef08a150 Merge pull request #1786 from nhost/renovate/turbo-1.x
chore(deps): update dependency turbo to v1.8.6
2023-03-28 16:16:57 +02:00
Szilárd Dóró
1bd2c37301 chore: bump turbo in the Dockerfile 2023-03-28 15:54:37 +02:00
renovate[bot]
5cdb70bd81 chore(deps): update dependency turbo to v1.8.6 2023-03-28 12:01:36 +00:00
Szilárd Dóró
1a5f80e1b6 Merge pull request #1785 from nhost/renovate/react-monorepo
chore(deps): update dependency @types/react to v18.0.30
2023-03-28 13:59:29 +02:00
Szilárd Dóró
59e0cb00c5 Merge pull request #1787 from nhost/feat/azuread-provider 2023-03-28 12:25:42 +02:00
Szilárd Dóró
406b0f2cb7 Merge pull request #1163 from dipakparmar/feat/dashboard-azuread-settings
feat(dashboard): add azure ad provider settings
2023-03-28 10:52:17 +02:00
Szilárd Dóró
d329b6218f chore: add changeset 2023-03-28 10:46:50 +02:00
Szilárd Dóró
335b58670e Merge branch 'renovate/react-monorepo' of https://github.com/nhost/nhost into renovate/react-monorepo 2023-03-28 10:43:08 +02:00
renovate[bot]
efa2d89067 chore(deps): update dependency @types/react to v18.0.30 2023-03-28 08:35:55 +00:00
Szilárd Dóró
77ce4bd738 Merge pull request #1783 from nhost/fix/random-words
fix(tests): avoid name collision in database tests
2023-03-28 10:33:33 +02:00
Szilárd Dóró
017adea700 chore: update comment 2023-03-28 10:04:38 +02:00
Dipak Parmar
378284faa8 chore(dashboard): remove docs and title for now from azuread component
Signed-off-by: Dipak Parmar <hi@dipak.tech>
2023-03-27 23:44:40 -07:00
renovate[bot]
e5e2d114b1 chore(deps): update dependency @types/react to v18.0.30 2023-03-27 19:03:37 +00:00
Szilárd Dóró
5e3dbdeb7d Merge pull request #1781 from nhost/renovate/react-monorepo
chore(deps): update dependency @types/react to v18.0.29
2023-03-27 20:55:47 +02:00
Szilárd Dóró
98b777491a fix: improve flaky tests 2023-03-27 18:13:10 +02:00
Szilárd Dóró
71de870cb0 fix: use admin secret as env var 2023-03-27 17:29:09 +02:00
Szilárd Dóró
74d4deba28 feat: cleanup public schema after tests 2023-03-27 17:00:07 +02:00
Szilárd Dóró
cb248f0d30 chore: add changeset 2023-03-27 15:44:08 +02:00
Szilárd Dóró
09e4f1eb34 fix: avoid duplicate table names in tests 2023-03-27 15:16:40 +02:00
Szilárd Dóró
19818e2b59 Merge pull request #1777 from nhost/changeset-release/main
chore: update versions
2023-03-27 12:03:16 +02:00
Szilárd Dóró
6e1f03eaee chore: accomodate changes to API 2023-03-27 11:57:24 +02:00
github-actions[bot]
b3eeec82ef chore: update versions 2023-03-27 09:38:55 +00:00
Szilárd Dóró
34ff254696 Merge pull request #1782 from nhost/renovate/sharp-0.x
fix(deps): update dependency sharp to ^0.32.0
2023-03-27 11:37:33 +02:00
Szilárd Dóró
867c807699 chore: add changeset 2023-03-27 11:21:42 +02:00
Szilárd Dóró
1c4806bf51 chore: add changeset 2023-03-27 11:17:41 +02:00
renovate[bot]
2fb82ec97d fix(deps): update dependency sharp to ^0.32.0 2023-03-27 07:50:45 +00:00
renovate[bot]
d0673d7825 chore(deps): update dependency @types/react to v18.0.29 2023-03-27 07:50:19 +00:00
Dipak Parmar
106f23dcfa fixdashboard-settings): remove extra whitespace azuread provider import in settings
Signed-off-by: Dipak Parmar <hi@dipak.tech>
2023-03-27 00:48:56 -07:00
Szilárd Dóró
0c994a9651 Merge pull request #1779 from nhost/renovate/pnpm-find-workspace-dir-6.x
fix(deps): update dependency @pnpm/find-workspace-dir to v6
2023-03-27 09:48:14 +02:00
Dipak Parmar
83ef755822 feat(dashboard-settings): update azuread provider settings component
Signed-off-by: Dipak Parmar <hi@dipak.tech>
2023-03-27 00:47:09 -07:00
Dipak Parmar
b7703ffd70 feat(graphql): add azuread to signinmethods query
Signed-off-by: Dipak Parmar <hi@dipak.tech>
2023-03-27 00:46:30 -07:00
Szilárd Dóró
4713cecfc2 chore: add changeset 2023-03-27 09:26:44 +02:00
Dipak Parmar
340ea5b115 chore: merge branch 'main' into feat/dashboard-azuread-settings
* main: (1322 commits)
  chore(ci): adjust preview fetcher
  chore: add changeset
  fix: fetch valid previews only
  fix: use correct Vercel token
  fix: use staging project ID
  chore: use dynamic test URL
  fix(deps): update docusaurus monorepo to v2.4.0
  chore(hasura-storage-js): improve presignedUrl test
  fix: remove test.only call
  chore: add tests for table deletion
  chore: update versions
  fix: potential subscription fix
  Fix import in docs
  fix: remove `test.only` call
  chore: add remaining table creation tests
  chore: add foreign key constraint test
  chore: add extra database UI tests
  chore: restructure tests, add basic table creation test
  chore: update versions
  chore: add changeset
  ...

Signed-off-by: Dipak Parmar <hi@dipak.tech>
2023-03-26 19:16:40 -07:00
renovate[bot]
f79eebadbf fix(deps): update dependency @pnpm/find-workspace-dir to v6 2023-03-24 21:30:22 +00:00
Szilárd Dóró
ac174b5e51 Merge pull request #1780 from nhost/chore/vercel-preview-fetcher 2023-03-24 17:07:43 +01:00
Szilárd Dóró
dc9ddfc9ae chore(ci): adjust preview fetcher 2023-03-24 16:30:29 +01:00
Szilárd Dóró
3bdd9f570c Merge pull request #1773 from nhost/chore/dashboard-delete-table-tests
chore(dashboard): tests for table deletion
2023-03-24 15:52:25 +01:00
Szilárd Dóró
94477be998 Merge pull request #1778 from nhost/chore/fetch-preview-url
chore: use dynamic test URL
2023-03-24 15:51:47 +01:00
Szilárd Dóró
568577e8ca Merge pull request #1774 from nhost/renovate/docusaurus-monorepo
fix(deps): update docusaurus monorepo to v2.4.0
2023-03-24 15:38:23 +01:00
Szilárd Dóró
e93b06ab8f chore: add changeset 2023-03-24 15:37:08 +01:00
Szilárd Dóró
c75bf46ba1 fix: fetch valid previews only 2023-03-24 15:24:36 +01:00
Szilárd Dóró
63a1fd09b5 fix: use correct Vercel token 2023-03-24 15:09:42 +01:00
Szilárd Dóró
630d44ad6e fix: use staging project ID 2023-03-24 14:55:26 +01:00
Szilárd Dóró
d7db521974 chore: use dynamic test URL 2023-03-24 14:16:05 +01:00
renovate[bot]
90e4053f0a fix(deps): update docusaurus monorepo to v2.4.0 2023-03-24 09:57:19 +00:00
Szilárd Dóró
8e9d5d1b38 Merge pull request #1775 from nhost/fix/storage-sdk-tests
chore(hasura-storage-js): improve presignedUrl test
2023-03-24 10:54:51 +01:00
Szilárd Dóró
43c86fef14 chore(hasura-storage-js): improve presignedUrl test 2023-03-24 10:25:18 +01:00
Szilárd Dóró
6b97340cf4 fix: remove test.only call 2023-03-23 16:14:49 +01:00
Szilárd Dóró
1605756362 chore: add tests for table deletion 2023-03-23 16:05:21 +01:00
Szilárd Dóró
6437544384 Merge pull request #1771 from nhost/changeset-release/main
chore: update versions
2023-03-23 14:20:16 +01:00
github-actions[bot]
b4dcd1996d chore: update versions 2023-03-23 13:01:48 +00:00
Szilárd Dóró
7fb73dbb1b Merge pull request #1770 from nhost/fix/subscription-errors
fix(apollo): retry subscriptions on error
2023-03-23 14:00:11 +01:00
Szilárd Dóró
a66b11d245 Merge pull request #1769 from st3phan/patch-1
Fix import in docs for SignedIn component
2023-03-23 13:23:35 +01:00
Szilárd Dóró
912ed76c64 fix: potential subscription fix 2023-03-23 12:30:14 +01:00
Szilárd Dóró
b47c0d1af7 Merge pull request #1765 from nhost/chore/dashboard-db-tests
chore(dashboard): tests for table creation
2023-03-23 09:36:27 +01:00
Stephan van Opstal
b97ab2be2f Fix import in docs 2023-03-22 21:46:58 +01:00
Szilárd Dóró
f12cb666ff fix: remove test.only call 2023-03-22 15:42:05 +01:00
Szilárd Dóró
c3b2b1cd02 chore: add remaining table creation tests 2023-03-22 15:40:39 +01:00
Szilárd Dóró
c0b71102d4 chore: add foreign key constraint test 2023-03-22 15:32:18 +01:00
Szilárd Dóró
5f68ae95c4 chore: add extra database UI tests 2023-03-22 15:22:49 +01:00
Szilárd Dóró
2d1b7bb292 chore: restructure tests, add basic table creation test 2023-03-22 14:57:33 +01:00
Szilárd Dóró
ee154d4eca Merge pull request #1764 from nhost/changeset-release/main
chore: update versions
2023-03-22 14:21:18 +01:00
github-actions[bot]
58ef9bbe02 chore: update versions 2023-03-22 12:49:02 +00:00
Szilárd Dóró
f3f35beefd Merge pull request #1758 from nhost/renovate/turbo-1.x
chore(deps): update dependency turbo to v1.8.5
2023-03-22 13:47:44 +01:00
Szilárd Dóró
d31330e6c0 Merge pull request #1762 from nhost/renovate/react-error-boundary-4.x
fix(deps): update dependency react-error-boundary to v4
2023-03-22 13:47:30 +01:00
Szilárd Dóró
c3dda79d95 Merge branch 'renovate/react-error-boundary-4.x' of https://github.com/nhost/nhost into renovate/react-error-boundary-4.x 2023-03-22 13:11:13 +01:00
Szilárd Dóró
7c1273725d chore: add changeset 2023-03-22 13:11:01 +01:00
renovate[bot]
70be0e1ab4 fix(deps): update dependency react-error-boundary to v4 2023-03-22 12:08:14 +00:00
renovate[bot]
4f5870cfd7 chore(deps): update dependency turbo to v1.8.5 2023-03-22 12:07:47 +00:00
Szilárd Dóró
623607476e Merge branch 'main' into renovate/react-error-boundary-4.x 2023-03-22 13:07:31 +01:00
Szilárd Dóró
1e232713d9 Merge pull request #1763 from nhost/chore/improve-e2e
chore(tests): improve E2E tests
2023-03-22 13:05:43 +01:00
Szilárd Dóró
1ed647c4e9 fix: fix lint and test jobs 2023-03-22 12:50:12 +01:00
Szilárd Dóró
b666a173b1 fix: use correct name for the build script 2023-03-22 12:15:48 +01:00
Szilárd Dóró
caba147b32 chore: add changeset 2023-03-22 12:07:44 +01:00
Szilárd Dóró
ca365fc8e7 cleanup cypress 2023-03-22 12:06:46 +01:00
Szilárd Dóró
d88cdedb26 migrated file upload e2e tests 2023-03-22 11:39:17 +01:00
Szilárd Dóró
1de08cecaf migrate password change e2e tests 2023-03-22 11:21:38 +01:00
Szilárd Dóró
47bb997036 migrate email change e2e tests 2023-03-22 11:15:20 +01:00
Szilárd Dóró
4e4d962f30 migrate apollo e2e tests 2023-03-22 11:05:46 +01:00
Szilárd Dóró
883fb82c77 migrate sign-in tests 2023-03-22 10:46:11 +01:00
Szilárd Dóró
c9f5634ac2 chore: migrate sign in e2e tests 2023-03-21 18:25:19 +01:00
renovate[bot]
6ee9a589fb fix(deps): update dependency react-error-boundary to v4 2023-03-21 17:21:51 +00:00
Szilárd Dóró
e2d733cf34 chore: migrate passwordless e2e tests 2023-03-21 16:45:19 +01:00
Szilárd Dóró
a0d7327c8d chore: migrate sign up tests 2023-03-21 16:33:56 +01:00
Szilárd Dóró
c7c8a20334 chore: port some tests to playwright 2023-03-21 16:10:37 +01:00
Szilárd Dóró
cca8de5805 Merge pull request #1760 from nhost/fix/dashboard-e2e-workflow
fix dashboard e2e workflow
2023-03-21 13:42:10 +01:00
Szilárd Dóró
8c065c42d6 fix: remove dashboard-e2e job 2023-03-21 13:19:31 +01:00
Szilárd Dóró
210af3a3e8 merge ci and e2e workflows 2023-03-21 12:52:01 +01:00
Szilárd Dóró
fbb12a8079 update workflow triggers 2023-03-21 12:44:37 +01:00
Szilárd Dóró
77692ac40e remove unnecessary job from e2e workflow 2023-03-21 11:57:49 +01:00
Szilárd Dóró
2c2a42a8e8 fix test script 2023-03-21 11:51:22 +01:00
Szilárd Dóró
a8466798a3 Merge pull request #1761 from nhost/changeset-release/main
chore: update versions
2023-03-21 11:47:58 +01:00
Szilárd Dóró
a45c0970bb pin playwright version 2023-03-21 11:46:30 +01:00
Szilárd Dóró
9bf30a1ccc fix e2e script 2023-03-21 11:35:12 +01:00
github-actions[bot]
99d3d82c72 chore: update versions 2023-03-21 10:23:53 +00:00
Szilárd Dóró
43acb3fb50 Merge pull request #1757 from nhost/renovate/hookform-resolvers-3.x
fix(deps): update dependency @hookform/resolvers to v3
2023-03-21 11:22:15 +01:00
Szilárd Dóró
ba9ef13ba3 update workflow 2023-03-21 11:21:28 +01:00
Szilárd Dóró
cea507a271 fix: install browsers before e2e tests 2023-03-21 11:07:24 +01:00
Szilárd Dóró
9130ab1230 chore(deps): bump yup and @hookform/resolvers 2023-03-21 10:58:44 +01:00
Szilárd Dóró
27acdd6f56 fix: add missing env vars 2023-03-21 10:43:55 +01:00
Szilárd Dóró
dcdacd73ec fix: fix dashboard e2e workflow 2023-03-21 10:24:10 +01:00
Szilárd Dóró
9c9966a30f Merge pull request #1759 from diecknet/patch-1
fix DevDependencies parameter for @types/express
2023-03-21 10:22:50 +01:00
Andreas Dieckmann
5a23e7a0a8 fix DevDependencies parameter for @types/express
it's `-D` not `-d`
2023-03-20 22:18:40 +01:00
renovate[bot]
47500fac39 fix(deps): update dependency @hookform/resolvers to v3 2023-03-20 18:24:31 +00:00
Szilárd Dóró
cbbf53c05b Merge pull request #1756 from nhost/feat/playwright
chore(dashboard): prepare E2E testing framework
2023-03-20 16:02:27 +01:00
Szilárd Dóró
11bd011860 fix: correct CI workflows 2023-03-20 15:02:36 +01:00
Szilárd Dóró
e3c0c47777 fix: correct tests 2023-03-20 14:03:27 +01:00
Szilárd Dóró
d825404b54 Merge branch 'main' into feat/playwright 2023-03-20 13:45:17 +01:00
Szilárd Dóró
d46d77ee71 Merge pull request #1751 from Glenas7/docs/google-oauth-guide
Added Javascript origins step to docs
2023-03-20 12:20:35 +01:00
Szilárd Dóró
a292482705 Update docs/docs/authentication/sign-in-methods/4-google.mdx 2023-03-20 12:20:27 +01:00
Szilárd Dóró
8a4ca41172 Merge pull request #1754 from nhost/changeset-release/main
chore: update versions
2023-03-20 11:33:21 +01:00
github-actions[bot]
fd3ce98600 chore: update versions 2023-03-20 10:08:17 +00:00
Szilárd Dóró
04f36a0491 Merge pull request #1669 from nhost/new-create-app-mutation
feat(dashboard): Limit Free Projects
2023-03-20 11:05:30 +01:00
Szilárd Dóró
5e2ecb4d1e Merge pull request #1749 from nhost/changeset-release/main
chore: update versions
2023-03-20 10:00:29 +01:00
Glenas7
eca9e551e8 Added Javascript origins step 2023-03-18 21:30:46 +01:00
github-actions[bot]
52ebbef762 chore: update versions 2023-03-17 15:01:14 +00:00
Szilárd Dóró
82faa4ca0a Merge pull request #1748 from nhost/fix/presigned-url-params
fix(hasura-storage-js): allow image transformation parameters in `getPresignedUrl`
2023-03-17 15:58:38 +01:00
Szilárd Dóró
d06a21764a fix unit tests 2023-03-17 15:10:15 +01:00
Szilárd Dóró
8b54d290a5 Merge pull request #1747 from nhost/changeset-release/main
chore: update versions
2023-03-17 14:51:41 +01:00
Szilárd Dóró
4cfa6bbe1e chore: update changeset 2023-03-17 14:12:48 +01:00
Szilárd Dóró
614f213e26 feat: allow image transformation parameters in getPresignedUrl 2023-03-17 14:11:17 +01:00
github-actions[bot]
4eebf51821 chore: update versions 2023-03-17 11:29:52 +00:00
Szilárd Dóró
9a52298aa7 Merge pull request #1746 from nhost/fix/data-grid-date-cell
fix(dashboard): show correct date in data grid
2023-03-17 12:28:34 +01:00
Szilárd Dóró
099eebe602 Merge pull request #1745 from nhost/fix/disable-new-users
fix(dashboard): disable new users
2023-03-17 12:20:38 +01:00
Szilárd Dóró
7cce8652e7 chore: update response message for pausing 2023-03-17 12:20:16 +01:00
Szilárd Dóró
f2e2323801 fix: refresh list when deleting app 2023-03-17 12:09:41 +01:00
Szilárd Dóró
4e16de6db2 chore: cleanup, improve error messages 2023-03-17 12:01:11 +01:00
Szilárd Dóró
798e591b1d fix: show correct date in data grid 2023-03-17 10:19:39 +01:00
Szilárd Dóró
b48bc034ca chore: add changeset 2023-03-17 10:01:26 +01:00
Szilárd Dóró
f57819230b fix: disable new users 2023-03-17 10:00:25 +01:00
Szilárd Dóró
3d8067ff7b fix: show pausing only for free projects
- improve project list
2023-03-17 09:44:02 +01:00
Szilárd Dóró
0fa4b428a9 chore: change function to string 2023-03-16 15:04:13 +01:00
Szilárd Dóró
8c5864340e fix: fix build error 2023-03-16 14:57:25 +01:00
Szilárd Dóró
c131100af9 chore: fetch free and live apps separately 2023-03-16 14:52:35 +01:00
Szilárd Dóró
e363fef8cf fix: refetch projects after delete/pause 2023-03-16 13:11:28 +01:00
Szilárd Dóró
d8072101c8 feat: added pause section to settings 2023-03-16 13:03:11 +01:00
Szilárd Dóró
afbba531a1 Merge branch 'main' into new-create-app-mutation 2023-03-16 10:28:02 +01:00
Szilárd Dóró
4b6df8b9d6 Merge pull request #1731 from nhost/changeset-release/main
chore: update versions
2023-03-16 10:23:45 +01:00
Szilárd Dóró
a2af5a674d fix(deps): fix @nhost/apollo version 2023-03-16 09:55:43 +01:00
github-actions[bot]
c33c1fd6b9 chore: update versions 2023-03-16 08:37:32 +00:00
Szilárd Dóró
041d9b98e3 Merge pull request #1741 from nhost/renovate/stripe-react-stripe-js-2.x
fix(deps): update dependency @stripe/react-stripe-js to v2
2023-03-16 09:37:26 +01:00
Szilárd Dóró
e4b4940397 Merge pull request #1730 from nhost/chore/remove-axios-deprecation
fix: remove `useAxios`, restore autogenerated docs
2023-03-16 09:36:09 +01:00
renovate[bot]
be91f4ed2a fix(deps): update dependency @stripe/react-stripe-js to v2 2023-03-13 22:14:47 +00:00
Siarhei Lipchyk
ec6ba846cf Merge pull request #1732 from nhost/chore/dashboard-hasura-admin-secret
Allow to override hasura admin secret in docker
2023-03-13 10:01:47 +01:00
Szilárd Dóró
a9e9fc4305 chore: extend tests 2023-03-10 16:57:21 +01:00
Siarhei Lipchyk
d8d8394b3b Allow to override hasura admin secret in docker 2023-03-10 13:11:02 +01:00
Szilárd Dóró
f051a121b2 Merge pull request #1729 from nhost/fix/sdk-backend-url 2023-03-10 12:37:48 +01:00
Szilárd Dóró
c547b490e5 chore: improved overview tests 2023-03-10 11:46:12 +01:00
Szilárd Dóró
4f4449b855 Merge remote-tracking branch 'origin/main' into feat/playwright 2023-03-10 11:28:13 +01:00
Szilárd Dóró
6ed46ce2d4 fix(docs): fix broken link 2023-03-10 11:15:22 +01:00
Szilárd Dóró
bfb4c1a6cc fix docs and remove useAxios 2023-03-10 11:04:51 +01:00
Szilárd Dóró
776c8f9237 Merge pull request #1721 from nhost/changeset-release/main
chore: update versions
2023-03-10 11:03:55 +01:00
github-actions[bot]
c0773d82e9 chore: update versions 2023-03-10 09:38:58 +00:00
Siarhei Lipchyk
c46b1383f2 Merge pull request #1724 from nhost/fix/dashboard-docker-entrypoint
Fix default values for placeholders
2023-03-10 10:37:46 +01:00
Siarhei Lipchyk
beed2eba21 Fix default values for placeholders 2023-03-10 10:36:01 +01:00
Szilárd Dóró
70f9610041 Merge pull request #1723 from nhost/fix/provisioning-status-indicator
fix(dashboard): miscellaneous fixes
2023-03-10 10:23:22 +01:00
Szilárd Dóró
e91de1088d chore: remove unused helper 2023-03-10 10:22:56 +01:00
Szilárd Dóró
ce1ee40dab fix: deprecate backendUrl, allow other params 2023-03-10 10:22:11 +01:00
Szilárd Dóró
bd7929f5ed revert provisioning status changes 2023-03-10 09:35:36 +01:00
Szilárd Dóró
2c8559a319 fix(dashboard): misc fixes 2023-03-09 15:54:17 +01:00
Szilárd Dóró
bd5ea5ee3a Merge pull request #1722 from nhost/chore/renovate-ci
chore(ci): remove renovate changeset automation
2023-03-09 13:09:59 +01:00
Szilárd Dóró
3538dbac39 chore(ci): remove renovate changeset automation 2023-03-09 11:12:06 +01:00
Szilárd Dóró
03b5cda69a Merge pull request #1700 from nhost/renovate/graphiql-react-0.x
fix(deps): update dependency @graphiql/react to ^0.17.0
2023-03-09 11:08:04 +01:00
Szilárd Dóró
4329d04854 chore: bump graphiql dependencies 2023-03-09 10:41:46 +01:00
Szilárd Dóró
ca50c5ce0c Merge remote-tracking branch 'origin/main' into renovate/graphiql-react-0.x 2023-03-09 10:25:37 +01:00
Szilárd Dóró
a3271ed014 Merge pull request #1719 from nhost/changeset-release/main
chore: update versions
2023-03-09 10:14:06 +01:00
github-actions[bot]
d4fc99a77c chore: update versions 2023-03-09 08:20:32 +00:00
Szilárd Dóró
d90fcf3c24 Merge pull request #1713 from nhost/chore/mimir-cleanup
chore(dashboard): mimir migration cleanup
2023-03-09 09:19:06 +01:00
Szilárd Dóró
ee70b226fc Merge pull request #1716 from nhost/changeset-release/main
chore: update versions
2023-03-09 09:18:45 +01:00
github-actions[bot]
227ef968e6 chore: update versions 2023-03-08 09:26:55 +00:00
Szilárd Dóró
430b37b2e1 Merge pull request #1711 from nhost/fix/responsive-fixes
fix(dashboard): improve mobile responsive layout
2023-03-08 10:25:18 +01:00
Szilárd Dóró
124620c33e Merge pull request #1467 from nhost/fix/local-urls
feat: add support for custom local subdomains
2023-03-08 09:49:32 +01:00
Szilárd Dóró
ce3ece1ad7 Merge pull request #1714 from nhost/changeset-release/main
chore: update versions
2023-03-08 09:21:29 +01:00
github-actions[bot]
c81002622c chore: update versions 2023-03-07 16:27:40 +00:00
Szilárd Dóró
35fa6bb043 Merge pull request #1712 from nhost/fix/functions
fix(nhost-js): correct return type in functions
2023-03-07 17:24:07 +01:00
Siarhei Lipchyk
a4469a5942 Add default values for NEXT_PUBLIC_NHOST_* envs to make it work with current stable CLI version 2023-03-07 15:23:12 +01:00
Szilárd Dóró
b8f11a13d7 fix: add missing type 2023-03-07 15:09:35 +01:00
Szilárd Dóró
1d1555593f fix: correct return type in functions 2023-03-07 15:03:28 +01:00
Szilárd Dóró
001b3dccec chore: update codegen 2023-03-07 14:50:26 +01:00
Szilárd Dóró
6755dfb17b fix: improve line heights 2023-03-07 13:24:28 +01:00
Szilárd Dóró
2ac90dfdec chore: add changeset 2023-03-07 13:22:08 +01:00
Szilárd Dóró
093f3906a4 fix: additional responsive fixes 2023-03-07 13:21:26 +01:00
Szilárd Dóró
6fb81a27ba fix: additional responsive fixes 2023-03-07 13:07:51 +01:00
Szilárd Dóró
9be41bf594 fix: fixes for responsive issues 2023-03-07 12:58:51 +01:00
Szilárd Dóró
cbb1fc5bc8 chore: cleanup GraphQL operations 2023-03-07 11:23:55 +01:00
Szilárd Dóró
99fcc36250 Merge pull request #1695 from nhost/changeset-release/main
chore: update versions
2023-03-07 10:22:13 +01:00
github-actions[bot]
7e4a756cfe chore: update versions 2023-03-06 07:49:58 +00:00
Szilárd Dóró
5bf61583e0 Merge pull request #1699 from nhost/renovate/xstate-inspect-0.x
chore(deps): update dependency @xstate/inspect to ^0.8.0
2023-03-06 08:48:24 +01:00
Szilárd Dóró
7eac17a1cb chore: add changeset 2023-03-06 08:48:02 +01:00
Szilárd Dóró
a41aeeb9ef Merge pull request #1697 from nhost/fix/deployment-glitch
fix(dashboard): show correct deployment status on the main page
2023-03-03 15:37:22 +01:00
Johan Eliasson
e33df513ff Merge pull request #1698 from nhost/chatgpt-b9asdasd
tests: hasura-storage-js
2023-03-03 15:20:27 +01:00
Johan Eliasson
323fd5cbe3 Update packages/hasura-storage-js/src/utils/index.ts
Co-authored-by: Szilárd Dóró <doroszilard@icloud.com>
2023-03-03 13:30:36 +01:00
renovate[bot]
0ec3abf47c fix(deps): update dependency @graphiql/react to ^0.17.0 2023-03-03 00:19:25 +00:00
renovate[bot]
ffb3c426d3 chore(deps): update dependency @xstate/inspect to ^0.8.0 2023-03-03 00:17:57 +00:00
Johan Eliasson
889ee6589e added tests 2023-03-02 23:13:03 +01:00
Johan Eliasson
ae19105302 cleanup 2023-03-02 21:32:34 +01:00
Johan Eliasson
730a482598 optimization 2023-03-02 21:25:43 +01:00
Szilárd Dóró
b00d261916 fix: update error message 2023-03-02 14:39:08 +01:00
Szilárd Dóró
6e05ab4628 Merge remote-tracking branch 'origin/main' into fix/local-urls 2023-03-02 14:18:10 +01:00
Szilárd Dóró
5223ee9353 fix(dashboard): don't show weird deployment dates 2023-03-02 14:08:59 +01:00
Szilárd Dóró
c8c5ace7cc Merge pull request #1500 from nhost/renovate/turbo-1.x
chore(deps): update dependency turbo to v1.8.3
2023-03-02 13:05:29 +01:00
Johan Eliasson
c6a4c28579 Merge pull request #1694 from nhost/renovate-changesets
chore: create changesest from Renovate bumps
2023-03-02 12:36:10 +01:00
szilarddoro
850a049ca2 chore(deps): update docker/build-push-action action to v4 2023-03-02 11:36:03 +00:00
Szilárd Dóró
eff3f0aefd Merge pull request #1641 from nhost/renovate/docker-build-push-action-4.x
chore(deps): update docker/build-push-action action to v4
2023-03-02 12:34:35 +01:00
Szilárd Dóró
2b1338f716 chore(deps): bump turbo for the dashboard 2023-03-02 11:50:48 +01:00
Szilárd Dóró
2b58c60747 Merge remote-tracking branch 'origin/main' into renovate/turbo-1.x 2023-03-02 11:44:21 +01:00
Szilárd Dóró
1b2e3fbd1d Merge pull request #1689 from nhost/changeset-release/main
chore: update versions
2023-03-02 11:39:55 +01:00
github-actions[bot]
6f4fdcf73f chore: update versions 2023-03-02 09:58:26 +00:00
Szilárd Dóró
cb529dc60c Merge pull request #1557 from nhost/renovate/vitest-monorepo
chore(deps): update vitest monorepo to ^0.29.0
2023-03-02 10:56:23 +01:00
Szilárd Dóró
68a449dbfc Merge remote-tracking branch 'origin/main' into renovate/vitest-monorepo 2023-03-02 10:33:42 +01:00
Szilárd Dóró
7d0c6d083a Merge pull request #1680 from nhost/renovate/glob-9.x
fix(deps): update dependency glob to v9
2023-03-02 10:28:58 +01:00
Szilárd Dóró
1353477da1 fix: lint error 2023-03-02 10:22:49 +01:00
Szilárd Dóró
549c7cb7eb chore(deps): bump glob to v9 2023-03-02 10:17:39 +01:00
Szilárd Dóró
e131c12d5d Merge branch 'renovate/vitest-monorepo' of https://github.com/nhost/nhost into renovate/vitest-monorepo 2023-03-02 10:03:45 +01:00
Szilárd Dóró
8bb097c9a7 chore(deps): bump vitest 2023-03-02 10:01:27 +01:00
renovate[bot]
ea31e64a71 chore(deps): update vitest monorepo to ^0.29.0 2023-03-02 08:58:06 +00:00
renovate[bot]
369b931689 chore(deps): update dependency turbo to v1.8.3 2023-03-02 08:56:38 +00:00
Szilárd Dóró
e1ec5c1be2 Merge remote-tracking branch 'origin/main' into renovate/vitest-monorepo 2023-03-02 09:51:23 +01:00
Szilárd Dóró
9822a160d4 Merge remote-tracking branch 'origin/main' into renovate/glob-9.x 2023-03-02 09:50:28 +01:00
Szilárd Dóró
7c67a2c437 chore(sync-versions): bump glob to v9 2023-03-02 09:50:11 +01:00
Szilárd Dóró
8e8884f4e1 Merge pull request #1629 from nhost/renovate/typescript-4.x
chore(deps): update dependency typescript to v4.9.5
2023-03-02 09:49:23 +01:00
Szilárd Dóró
9923be41ce Merge pull request #1675 from nhost/fix/isomorphic-unfetch
chore(deps): replace `cross-fetch` with `isomorphic-unfetch`
2023-03-02 09:29:49 +01:00
Szilárd Dóró
3141ce5b68 Merge branch 'main' into fix/local-urls 2023-03-01 16:10:07 +01:00
Szilárd Dóró
9c22a616a7 Merge pull request #1687 from nhost/changeset-release/main
chore: update versions
2023-03-01 14:56:43 +01:00
github-actions[bot]
6bc67e95a5 chore: update versions 2023-03-01 13:56:24 +00:00
Szilárd Dóró
0f6074c16f Merge pull request #1686 from nhost/fix/docker-build
fix(dashboard): fix docker build
2023-03-01 14:55:05 +01:00
Szilárd Dóró
c96d7ccdf2 fix(dashboard): fix docker build 2023-03-01 14:40:39 +01:00
Szilárd Dóró
fde7ac7c1c Merge pull request #1684 from nhost/changeset-release/main
chore: update versions
2023-03-01 13:40:28 +01:00
github-actions[bot]
24ef6071cc chore: update versions 2023-03-01 12:31:54 +00:00
Szilárd Dóró
bb993b6b03 Merge pull request #1595 from nhost/feat/settings-from-mimir
feat(dashboard): Settings from Mimir
2023-03-01 13:30:21 +01:00
Szilárd Dóró
89ca34be9a fix(dashboard): add tests, improve readability 2023-03-01 13:18:25 +01:00
Szilárd Dóró
b66d095c95 fix(dashboard): fix review comments 2023-03-01 13:07:41 +01:00
Szilárd Dóró
0bad9ff4fa feat(dashboard): add option to bypass maintenance 2023-03-01 11:15:24 +01:00
Szilárd Dóró
9a761f4fec feat(dashboard): add maintenance alert 2023-03-01 11:03:26 +01:00
Johan Eliasson
253dd235ca added changeset 2023-03-01 09:43:00 +01:00
Johan Eliasson
991e8f2d15 removed unused code 2023-02-28 19:57:51 +01:00
Johan Eliasson
e500e87022 review fixes 2023-02-28 19:15:25 +01:00
Szilárd Dóró
bd6b55868a Merge remote-tracking branch 'origin/main' into renovate/typescript-4.x 2023-02-28 17:04:20 +01:00
Szilárd Dóró
afb3fe490e Merge pull request #1646 from nhost/renovate/major-graphqlcodegenerator-monorepo
chore(deps): update graphqlcodegenerator monorepo to v3 (major)
2023-02-28 17:02:07 +01:00
Johan Eliasson
c684d0307b Update dashboard/src/utils/CONSTANTS.ts
Co-authored-by: Szilárd Dóró <doroszilard@icloud.com>
2023-02-28 16:59:35 +01:00
Szilárd Dóró
eaebd2b028 fix(dashboard): fix build errors 2023-02-28 16:31:19 +01:00
Szilárd Dóró
f03ecd91a9 fix(dashboard): disable settings through env vars 2023-02-28 16:20:54 +01:00
Szilárd Dóró
96f17c39b1 fix(dashboard): improve error handling 2023-02-28 15:25:08 +01:00
Johan Eliasson
2d657b9c29 styled 2023-02-28 13:42:22 +01:00
renovate[bot]
cb7c8c6398 fix(deps): update dependency glob to v9 2023-02-28 11:06:48 +00:00
Szilárd Dóró
4bf40995b5 chore(deps): add changeset 2023-02-28 12:02:28 +01:00
Szilárd Dóró
ab5f704280 chore(deps): remove direct typescript dependency 2023-02-28 11:59:38 +01:00
Szilárd Dóró
f65e4de955 chore(dashboard): add changeset 2023-02-28 11:54:23 +01:00
Szilárd Dóró
7e0e4d05aa Merge remote-tracking branch 'origin/main' into renovate/typescript-4.x 2023-02-28 11:45:49 +01:00
Szilárd Dóró
decb0b057c Merge pull request #1677 from nhost/changeset-release/main
chore: update versions
2023-02-28 11:39:26 +01:00
Szilárd Dóró
0954a44f84 Merge remote-tracking branch 'origin/main' into fix/isomorphic-unfetch 2023-02-28 11:38:25 +01:00
Szilárd Dóró
700cbd9e47 fix(dashboard): fix secrets' dialog management 2023-02-28 11:14:38 +01:00
Szilárd Dóró
3238543b08 Merge remote-tracking branch 'origin/main' into feat/settings-from-mimir 2023-02-28 11:11:09 +01:00
github-actions[bot]
fc79b890df chore: update versions 2023-02-28 10:06:25 +00:00
Szilárd Dóró
211eb42af5 Merge pull request #1622 from nhost/chore/improved-dialogs
chore(dashboard): improve Dialog and Drawer API
2023-02-28 11:05:03 +01:00
Szilárd Dóró
a7398451e3 fix(dashboard): add dirty state checking to user form 2023-02-28 10:47:42 +01:00
Szilárd Dóró
4b4f0d0150 chore(dashboard): add changeset 2023-02-28 10:31:47 +01:00
Szilárd Dóró
f37e2a23e2 Merge remote-tracking branch 'origin/main' into chore/improved-dialogs 2023-02-28 10:31:10 +01:00
Szilárd Dóró
3f8d68ffab fix(dashboard): fix build 2023-02-28 09:57:46 +01:00
Szilárd Dóró
f7e706724c chore(dashboard): update generated code 2023-02-28 09:52:51 +01:00
Johan Eliasson
f46d96bafc query fix 2023-02-27 17:33:26 +01:00
Szilárd Dóró
6b8acd35bd fix(nhost-js): fix tests 2023-02-27 14:23:37 +01:00
Szilárd Dóró
2832d7299f fix(dashboard): add adminSecret to local app 2023-02-27 14:03:39 +01:00
Szilárd Dóró
44c5b386c3 Merge branch 'main' into feat/settings-from-mimir 2023-02-27 13:52:26 +01:00
Szilárd Dóró
44ff6a059f Merge remote-tracking branch 'origin/main' into fix/local-urls 2023-02-27 13:50:34 +01:00
Johan Eliasson
1a4a061284 Merge pull request #1674 from nhost/changeset-release/main
chore: update versions
2023-02-27 11:55:28 +01:00
Szilárd Dóró
5a91c477f0 fix(dashboard): fix tests 2023-02-27 11:45:22 +01:00
Szilárd Dóró
66f73d06a8 fix(hasura-storage-js): fix build error 2023-02-27 11:17:53 +01:00
Szilárd Dóró
35d52aab87 chore(deps): replace cross-fetch with isomorphic-unfetch 2023-02-27 10:57:37 +01:00
Johan Eliasson
8261743bd3 show warning if max free projects has been created by the user already 2023-02-27 10:44:52 +01:00
Szilárd Dóró
ddd41aae99 chore(dashboard): migrate DB settings to Mimir 2023-02-27 10:32:05 +01:00
github-actions[bot]
78555c7e85 chore: update versions 2023-02-27 08:22:19 +00:00
Johan Eliasson
01ded8ffff Merge pull request #1670 from nhost/functions-tests
Functions fix + tests
2023-02-27 09:21:05 +01:00
Johan Eliasson
3c7cf92edf Create .changeset/eighty-mugs-flash.md 2023-02-27 09:20:49 +01:00
Johan Eliasson
bb4301fd34 more tests 2023-02-26 17:49:19 +01:00
Johan Eliasson
34cf1d79a0 readability 2023-02-26 15:01:07 +01:00
Johan Eliasson
9d4542b3db revert back 2023-02-26 14:51:14 +01:00
Johan Eliasson
bb5dbdf5a3 small cleanup 2023-02-26 14:49:44 +01:00
Johan Eliasson
2801b03bf4 removed unused code 2023-02-26 09:57:46 +01:00
Johan Eliasson
8298d458d5 cleanup 2023-02-26 09:56:58 +01:00
Johan Eliasson
6e9b941b89 handle slug server side 2023-02-26 09:54:00 +01:00
Johan Eliasson
5dd25941e5 update 2023-02-26 09:25:40 +01:00
renovate[bot]
832210d8ad chore(deps): update vitest monorepo to ^0.29.0 2023-02-25 11:09:59 +00:00
Szilárd Dóró
a09dad060c fix(dashboard): migrate to new admin secret location 2023-02-24 17:48:46 +01:00
Szilárd Dóró
76b63debf0 Merge branch 'main' into feat/settings-from-mimir 2023-02-24 17:13:56 +01:00
Szilárd Dóró
e88684ff2a Merge branch 'main' into fix/local-urls 2023-02-24 15:41:03 +01:00
Szilárd Dóró
c8c8948755 Merge pull request #1667 from nhost/changeset-release/main
chore: update versions
2023-02-24 12:45:06 +01:00
github-actions[bot]
17e9e5899e chore: update versions 2023-02-24 11:44:31 +00:00
Szilárd Dóró
bd22c48131 Merge pull request #1666 from nhost/fix/workspace-invitation
fix(nhost-js): use correct URL for functions requests
2023-02-24 12:43:02 +01:00
Szilárd Dóró
095d6e918c Merge branch 'main' into feat/settings-from-mimir 2023-02-24 12:41:56 +01:00
Szilárd Dóró
89a239ff3a fix(nhost-js): improve code readability 2023-02-24 12:22:54 +01:00
Szilárd Dóró
0131886011 fix(nhost-js): use correct URL for functions requests 2023-02-24 12:06:30 +01:00
Szilárd Dóró
340c014fe8 Merge pull request #1664 from nhost/update-codeowners
chore: update codeowners
2023-02-24 11:06:07 +01:00
Szilárd Dóró
bc9c8b9456 chore: update codeowners 2023-02-24 11:05:35 +01:00
Nuno Pato
c22b2621ba Merge pull request #1661 from nhost/changeset-release/main
chore: update versions
2023-02-23 20:33:34 -01:00
github-actions[bot]
726746c4d3 chore: update versions 2023-02-23 19:19:03 +00:00
Nuno Pato
c431570783 Merge pull request #1662 from nhost/fix/file-upload
fix(hasura-storage-js): fix forbidden error
2023-02-23 18:17:47 -01:00
Szilárd Dóró
445d8ef449 fix(hasura-storage-js): fix forbidden error 2023-02-23 18:16:22 +01:00
Szilárd Dóró
0f4ea18e42 Merge pull request #1655 from nhost/feat/auth-storage-permissions
fix(dashboard): allow permission editing for auth and storage schemas
2023-02-23 15:22:05 +01:00
Szilárd Dóró
dae7c5d517 Merge pull request #1660 from nhost/fix/user-creation-content-type
fix(dashboard): set correct Content-Type for user creation
2023-02-23 14:38:16 +01:00
Szilárd Dóró
f673adea00 fix(dashboard): set correct Content-Type for user creation 2023-02-23 12:50:00 +01:00
Szilárd Dóró
1c6f1e3b33 Merge pull request #1656 from nhost/changeset-release/main
chore: update versions
2023-02-23 11:56:07 +01:00
renovate[bot]
6593e8d3eb chore(deps): update graphqlcodegenerator monorepo to v3 2023-02-23 10:28:10 +00:00
github-actions[bot]
d1365ea516 chore: update versions 2023-02-23 10:20:53 +00:00
Szilárd Dóró
72dbba7881 Merge pull request #1659 from nhost/chore/revert-graphql-client
chore(graphql-js): revert GraphQL Client
2023-02-23 11:19:26 +01:00
Szilárd Dóró
a3f3991d5a Merge pull request #1658 from nhost/fix/user-creation
fix(dashboard): false positive message on user creation
2023-02-23 11:01:44 +01:00
Szilárd Dóró
c71fe2cf72 Revert "chore(graphql-js): revert GraphQL client for now"
This reverts commit 9a0ab5b887.
2023-02-23 10:15:02 +01:00
Szilárd Dóró
24c5ed3ea4 chore(graphql-js): cleanup 2023-02-23 10:14:43 +01:00
Szilárd Dóró
2d9145f918 chore(graphql-js): revert GraphQL client for now 2023-02-23 10:10:14 +01:00
Szilárd Dóró
9a0ab5b887 chore(graphql-js): revert GraphQL client for now 2023-02-23 10:06:58 +01:00
Szilárd Dóró
1ddf704c5b fix(dashboard): false positive message on user creation 2023-02-23 09:39:32 +01:00
Szilárd Dóró
6f4ee845c6 Merge pull request #1643 from nhost/fix/auth-last-seen
fix(dashboard): use correct date for last seen
2023-02-22 20:01:18 +01:00
Szilárd Dóró
0368663dea fix(dashboard): allow permission editing for auth and storage schemas
fixes #1555
2023-02-22 19:59:20 +01:00
Pilou
76ce7d7b6e Merge pull request #1653 from nhost/changeset-release/main
chore: update versions
2023-02-22 15:43:41 +01:00
github-actions[bot]
538bfbcb3e chore: update versions 2023-02-22 14:23:55 +00:00
Pilou
07b35d1e5f Merge pull request #1650 from nhost/docs/graphql-client-readme
GraphQL client: fix snake_case bug and improve readme
2023-02-22 15:22:34 +01:00
Pierre-Louis Mercereau
2200a0ed07 fix: correct types on snake case operations 2023-02-22 15:13:43 +01:00
Szilárd Dóró
9219838127 Merge remote-tracking branch 'origin/main' into feat/settings-from-mimir 2023-02-22 15:13:21 +01:00
Szilárd Dóró
df23d97126 Merge pull request #1652 from nhost/changeset-release/main
chore: update versions
2023-02-22 14:44:46 +01:00
Szilárd Dóró
43b68a79eb fix(dashboard): improve error handling 2023-02-22 14:43:21 +01:00
github-actions[bot]
104f149369 chore: update versions 2023-02-22 13:26:08 +00:00
Szilárd Dóró
01228583a0 Merge pull request #1651 from nhost/fix/permission-editor-dropdown
fix(dashboard): prevent permission editor dropdown from being always open
2023-02-22 14:24:51 +01:00
Pierre-Louis Mercereau
93309dd851 docs: strictNullChecks 2023-02-22 14:06:10 +01:00
Szilárd Dóró
2cc18dcb51 fix(dashboard): prevent permission editor dropdown from being always open 2023-02-22 13:54:31 +01:00
Pierre-Louis Mercereau
3b48a62790 docs: ✏️ improve readme instructions 2023-02-22 13:44:15 +01:00
Pierre-Louis Mercereau
8897dec056 docs: add package.json script instructions 2023-02-22 12:23:54 +01:00
Pierre-Louis Mercereau
324dda8309 docs: streamline readme instructions 2023-02-22 11:58:51 +01:00
Szilárd Dóró
ac845c6d92 Merge remote-tracking branch 'origin/main' into feat/settings-from-mimir 2023-02-22 11:06:08 +01:00
Szilárd Dóró
cfcb97b8ee chore(actions): update workflow 2023-02-22 11:04:59 +01:00
Pilou
95f62bed07 Merge pull request #1644 from nhost/changeset-release/main
chore: update versions
2023-02-22 08:50:38 +01:00
Szilárd Dóró
892ad66ba1 Merge remote-tracking branch 'origin/main' into fix/local-urls 2023-02-21 19:08:20 +01:00
Szilárd Dóró
f4af81020b Merge branch 'main' into feat/settings-from-mimir 2023-02-21 18:51:11 +01:00
Pierre-Louis Mercereau
0e4d8ff118 chore: manually bump @nhost/react-apollo 2023-02-21 18:20:41 +01:00
renovate[bot]
6999562b59 chore(deps): update dependency typescript to v4.9.5 2023-02-21 17:03:56 +00:00
github-actions[bot]
baec5bada7 chore: update versions 2023-02-21 17:03:03 +00:00
Pilou
4e56cfc628 Merge pull request #1348 from nhost/sdk-next-major
Sdk next major version
2023-02-21 18:01:13 +01:00
Szilárd Dóró
d167121093 chore(dashboard): add changeset
hide the "Secrets" menu item on the Settings page
2023-02-21 17:02:08 +01:00
Szilárd Dóró
822e251b11 cleanup part 2 2023-02-21 15:37:12 +01:00
Szilárd Dóró
328c6bb486 chore(packages): cleanup 2023-02-21 15:36:04 +01:00
Szilárd Dóró
bef8198cbf fix(dashboard): provider validation and scope 2023-02-21 14:59:06 +01:00
Szilárd Dóró
179313d8a2 fix(dashboard): run codegen, fix validation 2023-02-21 13:56:26 +01:00
Pierre-Louis Mercereau
54bc91923f docs: update changeset 2023-02-21 12:40:52 +01:00
Szilárd Dóró
c3ce004f46 Merge remote-tracking branch 'origin/main' into feat/settings-from-mimir 2023-02-21 10:48:29 +01:00
Szilárd Dóró
a1ffad77eb chore(dashboard): move sign in to global setup
- add test skeletons for the Overview
2023-02-20 17:19:46 +01:00
Szilárd Dóró
77b12feb95 Merge pull request #1639 from nhost/renovate/testing-library-react-14.x
chore(deps): update dependency @testing-library/react to v14
2023-02-20 16:30:11 +01:00
Pierre-Louis Mercereau
32d4670bbb Merge branch 'main' into sdk-next-major 2023-02-20 16:05:23 +01:00
Pilou
1dc09942d2 Merge pull request #1587 from nhost/next-client
Next GraphQL client
2023-02-20 16:01:49 +01:00
Szilárd Dóró
3343a36358 chore(deps): bump @testing-library 2023-02-20 15:52:18 +01:00
Szilárd Dóró
de4d59da99 feat(dashboard): add Playwright to the dashboard 2023-02-20 15:44:45 +01:00
Szilárd Dóró
b755e9086c fix(dashboard): use correct date for last seen 2023-02-20 14:19:56 +01:00
Pierre-Louis Mercereau
48866d0ee1 chore: fail on runtime when passing an invalid field 2023-02-20 12:45:52 +01:00
renovate[bot]
7d577a68b7 chore(deps): update docker/build-push-action action to v4 2023-02-20 10:08:41 +00:00
renovate[bot]
5b3b76bd41 chore(deps): update dependency @testing-library/react to v14 2023-02-20 10:08:36 +00:00
Szilárd Dóró
7f7e7ea7d4 Merge pull request #1638 from nhost/changeset-release/main
chore: update versions
2023-02-20 11:05:47 +01:00
github-actions[bot]
aaaf2dc9c5 chore: update versions 2023-02-20 10:02:33 +00:00
Szilárd Dóró
fa9c1ea28c Merge pull request #1626 from nhost/renovate/react-18.x
chore(deps): update dependency @types/react to v18.0.28
2023-02-20 11:01:06 +01:00
Szilárd Dóró
87eda76e2b chore(dashboard): bump @types/react-dom to v18.0.11 2023-02-20 10:17:41 +01:00
Szilárd Dóró
982059e18e fix(dashboard): fix build error 2023-02-20 09:53:53 +01:00
Szilárd Dóró
02c0586467 Merge remote-tracking branch 'origin/main' into fix/local-urls 2023-02-20 09:37:51 +01:00
Szilárd Dóró
8a596f2a9e Merge pull request #1621 from nhost/feat/show-version
feat(dashboard): show dashboard version
2023-02-20 09:13:40 +01:00
Szilárd Dóró
89b70eb93c Merge pull request #1627 from nhost/changeset-release/main
chore: update versions
2023-02-17 13:09:56 +01:00
renovate[bot]
d6d2381598 chore(deps): update dependency @types/react to v18.0.28 2023-02-17 11:24:40 +00:00
github-actions[bot]
860d872d07 chore: update versions 2023-02-17 11:18:24 +00:00
Szilárd Dóró
b9917c0c69 Merge pull request #1628 from nhost/chore/react-monorepo-18
chore(deps): bump `react` to v18
2023-02-17 12:16:58 +01:00
Szilárd Dóró
bf1e4071db chore(deps): bump react to v18 2023-02-17 10:36:25 +01:00
Szilárd Dóró
e5601581f5 Merge pull request #1624 from nhost/renovate-changesets
chore: create changesest from Renovate bumps
2023-02-17 10:03:53 +01:00
Szilárd Dóró
5013213bc3 fix changesets 2023-02-17 10:03:22 +01:00
szilarddoro
8be094be54 fix(deps): update docusaurus monorepo to v2.3.1 2023-02-17 08:56:50 +00:00
Szilárd Dóró
43e5221119 Merge pull request #1559 from nhost/renovate/docusaurus-monorepo
fix(deps): update docusaurus monorepo to v2.3.1
2023-02-17 09:55:40 +01:00
Szilárd Dóró
6f8feaffc5 Merge pull request #1518 from nhost/renovate/commander-10.x
fix(deps): update dependency commander to v10
2023-02-17 09:30:45 +01:00
Pierre-Louis Mercereau
284ef7e7f2 test: multiple where 2023-02-17 08:57:02 +01:00
Pierre-Louis Mercereau
6d5c202da9 changes 2023-02-17 08:44:48 +01:00
Szilárd Dóró
962563d6a0 chore(dashboard): cleanup 2023-02-16 16:51:40 +01:00
Szilárd Dóró
8bf58ba26b chore(dashboard): migrate remaining dialogs 2023-02-16 16:37:44 +01:00
Szilárd Dóró
0c175e7a11 chore(dashboard): migrate additional dialogs to the new API 2023-02-16 16:13:47 +01:00
Szilárd Dóró
70f2fbcfc2 chore(dashboard): partially migrate dialogs to new API 2023-02-16 15:59:35 +01:00
Szilárd Dóró
d2c4ad3260 chore(dashboard): cleanup dialog provider 2023-02-16 13:32:21 +01:00
Szilárd Dóró
a9ca2c2946 chore(dashboard): migrate drawers to use new API 2023-02-16 13:25:23 +01:00
Szilárd Dóró
d854dd74b1 chore(dashboard): improve dialog management 2023-02-16 12:54:21 +01:00
Szilárd Dóró
cf347341d4 Merge pull request #1620 from nhost/changeset-release/main
chore: update versions
2023-02-16 09:54:38 +01:00
renovate[bot]
5262fac6d5 fix(deps): update docusaurus monorepo to v2.3.1 2023-02-16 08:39:58 +00:00
github-actions[bot]
d6c670a78b chore: update versions 2023-02-16 08:32:50 +00:00
Szilárd Dóró
197e406209 Merge pull request #1614 from nhost/fix/deployments-are-undefined
fix(dashboard): don't break the UI when deployments are unavailable
2023-02-16 09:30:53 +01:00
Szilárd Dóró
6f0ac5706c feat(dashboard): show dashboard version 2023-02-15 19:19:15 +01:00
Szilárd Dóró
5fc78964dc fix(dashboard): fix deployments on the deployments page 2023-02-15 18:32:55 +01:00
Szilárd Dóró
1bb71df7a1 Merge pull request #1616 from nhost/changeset-release/main
chore: update versions
2023-02-15 15:30:21 +01:00
Szilárd Dóró
5880f0cd17 chore(hasura-auth-js): bump msw version 2023-02-15 15:14:15 +01:00
github-actions[bot]
d7404e2247 chore: update versions 2023-02-15 14:04:47 +00:00
Szilárd Dóró
2aa91cf266 Merge pull request #1613 from nhost/fix/header-navlinks
fix(dashboard): fix header link color
2023-02-15 15:03:27 +01:00
Szilárd Dóró
b2b17d71aa fix(dashboard): fix build error 2023-02-15 14:16:54 +01:00
Szilárd Dóró
0785a41070 fix lockfile 2023-02-15 13:52:52 +01:00
Szilárd Dóró
c6c8569088 chore(dashboard): extended deployment tests 2023-02-15 13:51:56 +01:00
Szilárd Dóró
c38f60740e chore(dashboard): added deployment list tests 2023-02-15 13:45:32 +01:00
Pierre-Louis Mercereau
9342937440 readme 2023-02-15 13:39:24 +01:00
Pierre-Louis Mercereau
e89cd4e262 simple mutation example 2023-02-15 13:30:16 +01:00
Pierre-Louis Mercereau
a05438352b inline documentation 2023-02-15 13:28:04 +01:00
Pierre-Louis Mercereau
78437959bb dew 2023-02-15 13:08:20 +01:00
Pierre-Louis Mercereau
e1a7433adb docs: static doc for nhost.functions 2023-02-15 12:41:54 +01:00
Szilárd Dóró
a37a430b9f fix(dashboard): don't break UI when deployments are unavailable 2023-02-15 11:42:28 +01:00
Szilárd Dóró
7b970e6858 fix(dashboard): fix header link color 2023-02-15 09:58:53 +01:00
Szilárd Dóró
5bdb2c605d Merge pull request #1612 from nhost/changeset-release/main 2023-02-15 09:08:22 +01:00
Johan Eliasson
a08cfc696d Merge pull request #1611 from nhost/docs-ytg89ji
CLI docs updates.
2023-02-15 08:09:41 +01:00
Johan Eliasson
9c4223c547 Update docs/docs/reference/cli/up.mdx
Co-authored-by: Szilárd Dóró <doroszilard@icloud.com>
2023-02-15 08:09:12 +01:00
github-actions[bot]
7de3ed5323 chore: update versions 2023-02-14 15:52:32 +00:00
Szilárd Dóró
83f4e32972 Merge pull request #1610 from nhost/feat/new-sign-in-page 2023-02-14 16:50:48 +01:00
Szilárd Dóró
7b86f38ba3 fix(dashboard): add autofocus to reset input 2023-02-14 16:37:23 +01:00
Szilárd Dóró
0753e6529c fix(nhost-js): update service URLs 2023-02-14 15:17:07 +01:00
Szilárd Dóró
a689b0dbe0 fix(dashboard): fix auth pages button feedback 2023-02-14 12:04:21 +01:00
Szilárd Dóró
14235d08bc chore(dashboard): add autofocus to sign in and sign up input fields 2023-02-14 11:55:56 +01:00
Szilárd Dóró
e0a987248f fix(dashboard): fix mobile responsive layout 2023-02-14 11:29:53 +01:00
Szilárd Dóró
1303fc60ac feat(dashboard): update sign in and sign up pages 2023-02-14 11:24:12 +01:00
Siarhei Lipchyk
e87a14a3fe Don't append "/console" to value from NEXT_PUBLIC_NHOST_HASURA_CONSOLE_URL 2023-02-14 11:20:33 +01:00
Johan Eliasson
172cab87c7 updates 2023-02-14 09:38:26 +01:00
Johan Eliasson
a463d5c3bf updates 2023-02-14 08:47:47 +01:00
Szilárd Dóró
041385f19a chore(dashboard): cleanup
- reset original page route structure
2023-02-13 14:08:43 +01:00
Szilárd Dóró
b45aa420d9 fix(dashboard): use scope defined by the schema 2023-02-13 13:53:49 +01:00
Szilárd Dóró
1d76de3f60 Merge branch 'main' into feat/settings-from-mimir 2023-02-13 11:59:40 +01:00
Szilárd Dóró
47949ed4af Update logo.svg 2023-02-13 11:57:10 +01:00
Szilárd Dóró
6a52a267ff Update logo.svg 2023-02-13 11:56:27 +01:00
Szilárd Dóró
f33242f2c4 chore(dashboard): add changeset 2023-02-13 11:51:03 +01:00
Szilárd Dóró
b9013e2f6e feat(dashboard): add reset password page 2023-02-13 11:50:22 +01:00
Szilárd Dóró
bbe6fb39c8 feat(dashboard): update sign in page 2023-02-13 11:35:31 +01:00
Szilárd Dóró
955e3e1316 feat(dashboard): finalize sign up pages 2023-02-13 11:07:11 +01:00
Szilárd Dóró
2dba783ad3 feat(dashboard): updated sign up pages 2023-02-13 10:59:40 +01:00
Pierre-Louis Mercereau
e23cf74975 fix tests 2023-02-10 22:11:53 +01:00
Pierre-Louis Mercereau
a3d01c4fad fix lint config 2023-02-10 21:33:26 +01:00
Pierre-Louis Mercereau
4cdcef9ef5 fix broken links 2023-02-10 19:12:29 +01:00
Pierre-Louis Mercereau
df894ef7e2 upgrade typescript version 2023-02-10 15:51:59 +01:00
Szilárd Dóró
dbc2fadd87 Merge pull request #1606 from nhost/changeset-release/main
chore: update versions
2023-02-10 14:57:35 +01:00
Pierre-Louis Mercereau
f7dd6a9fc6 deactivate functions doc 2023-02-10 14:42:56 +01:00
Pierre-Louis Mercereau
2949ff0f62 fix docgen 2023-02-10 14:33:56 +01:00
github-actions[bot]
4578065807 chore: update versions 2023-02-10 12:30:32 +00:00
Szilárd Dóró
feb0c20eb3 Merge pull request #1574 from nhost/fix/dashboard-dark-mode
fix(dashboard): use correct theme color in dark mode
2023-02-10 13:29:17 +01:00
Szilárd Dóró
9e37ca4cbc fix(dashboard): duplicate input IDs 2023-02-10 10:37:04 +01:00
Szilárd Dóró
af57ccce0f fix lint error and a UI warning 2023-02-10 10:26:06 +01:00
Szilárd Dóró
5f44aefcc6 Merge branch 'main' into feat/settings-from-mimir 2023-02-10 09:58:56 +01:00
Szilárd Dóró
e3efed65a4 Merge pull request #1605 from nhost/changeset-release/main
chore: update versions
2023-02-09 14:54:24 +01:00
github-actions[bot]
194dec1f00 chore: update versions 2023-02-09 13:22:00 +00:00
Szilárd Dóró
0a1b36e600 Merge pull request #1604 from nhost/fix/logs-allow-hasura
fix(dashboard): re-enable Hasura on logs page
2023-02-09 14:20:41 +01:00
Szilárd Dóró
902f486bbe fix(dashboard): re-enable Hasura on logs page 2023-02-09 14:18:52 +01:00
Szilárd Dóró
fa544cc696 Merge pull request #1601 from nhost/changeset-release/main
chore: update versions
2023-02-09 11:45:11 +01:00
Johan Eliasson
7f959b3544 Merge pull request #1545 from nhost/docs-general-9ashd9asd
docs(graphql): updates
2023-02-09 08:18:43 +01:00
github-actions[bot]
bf5056f14b chore: update versions 2023-02-08 17:10:41 +00:00
Szilárd Dóró
b3e674ced0 Merge pull request #1600 from nhost/fix/permissions
fix(dashboard): apply select permissions properly
2023-02-08 18:09:25 +01:00
Szilárd Dóró
1f9720fa25 fix(dashboard): apply select permissions properly 2023-02-08 15:42:15 +01:00
Szilárd Dóró
747bc1104a Merge pull request #1599 from nhost/changeset-release/main
chore: update versions
2023-02-08 10:38:40 +01:00
github-actions[bot]
887c168b1b chore: update versions 2023-02-08 09:37:42 +00:00
Szilárd Dóró
038d903555 Merge pull request #1598 from nhost/country-code-fix
Use country code instead of name
2023-02-08 10:36:31 +01:00
Szilárd Dóró
deb14b510b chore(dashboard): add changeset 2023-02-08 10:35:52 +01:00
Johan Eliasson
8ee23c9303 use code 2023-02-08 10:22:56 +01:00
Szilárd Dóró
168616df38 Merge branch 'main' into fix/local-urls 2023-02-06 17:50:37 +01:00
Pilou
bca1835ecd Merge pull request #1586 from nhost/docs/typo
Correct useMultipleFilesUpload inline documentation
2023-02-06 14:28:28 +01:00
Pierre-Louis Mercereau
1527b0a455 remove type-fest dependency 2023-02-06 14:18:13 +01:00
Pierre-Louis Mercereau
375e53a3f0 update ts 2023-02-06 13:35:33 +01:00
Pierre-Louis Mercereau
96e3ca5a32 basic readme 2023-02-06 12:53:11 +01:00
Pierre-Louis Mercereau
0e570df9c5 missing dependency 2023-02-06 12:11:02 +01:00
Pierre-Louis Mercereau
1f4c67283e lockfile 2023-02-06 10:49:47 +01:00
Pierre-Louis Mercereau
fc1c4861a3 cleanup 2023-02-06 10:49:02 +01:00
Pierre-Louis Mercereau
eb55408f85 typo 2023-02-06 10:36:46 +01:00
Pierre-Louis Mercereau
74feaf6add unions 2023-02-02 11:47:29 +01:00
Szilárd Dóró
e9c8909c6b fix(dashboard): use correct theme color in dark mode 2023-02-01 18:31:04 +01:00
Johan Eliasson
d539a103d9 Update docs/docs/graphql/permissions.mdx
Co-authored-by: Szilárd Dóró <doroszilard@icloud.com>
2023-02-01 09:38:31 +01:00
Pierre-Louis Mercereau
8cd97206cc Merge branch 'next-client' of https://github.com/nhost/nhost into next-client 2023-01-31 21:06:17 +01:00
Pierre-Louis Mercereau
02197639f2 dew 2023-01-31 20:59:14 +01:00
Pilou
38b594aef9 Update README.md 2023-01-31 19:40:31 +01:00
Pierre-Louis Mercereau
f3a8886cd0 dew 2023-01-31 19:08:19 +01:00
Szilárd Dóró
96f9278c8f chore(dashboard): ID workaround for config 2023-01-31 18:52:39 +01:00
Pierre-Louis Mercereau
8d76cf8d40 simplify 2023-01-31 17:37:44 +01:00
Pierre-Louis Mercereau
3e1fb974e4 dew 2023-01-31 16:37:40 +01:00
Szilárd Dóró
9fe2ecd317 Merge branch 'main' into feat/settings-from-mimir 2023-01-31 16:31:45 +01:00
Szilárd Dóró
ada5309b49 fix(dashboard): catch errors thrown by mutations 2023-01-31 15:59:49 +01:00
Szilárd Dóró
08698f8246 feat(dashboard): migrate system variables to mimir 2023-01-31 15:46:36 +01:00
Pierre-Louis Mercereau
f74871d872 dew 2023-01-31 15:01:54 +01:00
Szilárd Dóró
0b56e31408 Merge branch 'feat/dark-mode' into feat/settings-from-mimir 2023-01-31 13:32:37 +01:00
Szilárd Dóró
d8c45b452d Merge remote-tracking branch 'origin/main' into fix/local-urls 2023-01-31 09:22:40 +01:00
Szilárd Dóró
c4e3e3f91f Merge branch 'feat/dark-mode' into feat/settings-from-mimir 2023-01-31 09:21:18 +01:00
Szilárd Dóró
483fd6c7f4 feat(dashboard): environment variables to use mimir 2023-01-30 17:19:52 +01:00
Szilárd Dóró
ac37d7bcae chore(dashboard): improve config caching in Apollo 2023-01-30 16:54:48 +01:00
Szilárd Dóró
9adf91ba87 fix(dashboard): infinite query loop 2023-01-30 16:43:26 +01:00
Szilárd Dóró
d11f6eebb0 feat(dashboard): migrate permission variables to mimir 2023-01-30 16:18:32 +01:00
Szilárd Dóró
8a678fbc87 Merge branch 'feat/dark-mode' into feat/settings-from-mimir 2023-01-30 15:42:59 +01:00
Szilárd Dóró
6411ec3ec3 chore(dashboard): all sign-in methods to use mimir 2023-01-30 15:38:23 +01:00
Szilárd Dóró
5187fe76aa feat(dashboard): allowed roles to use mimir 2023-01-30 15:06:28 +01:00
Szilárd Dóró
859f457e4a Merge remote-tracking branch 'origin/main' into feat/settings-from-mimir 2023-01-30 14:50:02 +01:00
Szilárd Dóró
dc2b5b4429 chore(dashboard): migrate rest of the auth forms to mimir 2023-01-30 12:04:10 +01:00
Szilárd Dóró
b7645e7892 chore(dashboard): migrate auth forms to mimir 2023-01-30 11:37:54 +01:00
Pierre-Louis Mercereau
3f26056688 Merge branch 'main' into sdk-next-major 2023-01-30 11:11:51 +01:00
Szilárd Dóró
b1338246aa Merge branch 'feat/dark-mode' into feat/settings-from-mimir 2023-01-30 11:07:54 +01:00
Szilárd Dóró
d04ccd600e feat(dashboard): add Mimir support for all providers 2023-01-28 12:18:27 +01:00
Szilárd Dóró
d483ad5602 feat(dashboard): Apple, Discord and Facebook to use Mimir 2023-01-28 11:37:23 +01:00
Johan Eliasson
1bc3c30f85 formatting 2023-01-27 22:26:29 +01:00
Johan Eliasson
4be6406a1e updates 2023-01-27 22:18:44 +01:00
Szilárd Dóró
bcf3e6bc2c feat(dashboard): SMTP page to update Mimir 2023-01-27 17:00:13 +01:00
Szilárd Dóró
575ff4e9b5 Merge branch 'feat/dark-mode' into feat/settings-from-mimir 2023-01-27 16:43:10 +01:00
Szilárd Dóró
2010638540 feat(dashboard): migrate settings / authentication to Mimir 2023-01-27 16:10:43 +01:00
Szilárd Dóró
0346495a79 feat(dashboard): migrate SMTP settings to Mimir 2023-01-27 14:31:54 +01:00
Szilárd Dóró
2babb0b6f3 feat(dashboard): migrate the rest of the providers 2023-01-27 14:24:25 +01:00
Szilárd Dóró
1f293d0f0c feat(dashboard): migrate Sign In Methods to Mimir 2023-01-27 14:01:57 +01:00
Szilárd Dóró
af4c886437 Merge branch 'feat/dark-mode' into feat/settings-from-mimir 2023-01-27 11:21:25 +01:00
Szilárd Dóró
c182b3ca4b feat(dashboard): finalize secrets functionality 2023-01-27 10:57:40 +01:00
Szilárd Dóró
d5344ed31f feat(dashboard): initial secrets page code 2023-01-26 12:15:07 +01:00
Siarhei Lipchyk
adeb2a6d90 Adjust docker-entrypoint.sh for dashboard 2023-01-25 12:47:23 +01:00
Szilárd Dóró
921243e4d9 fix(dashboard): intercept metadata query in tests 2023-01-25 12:37:40 +01:00
Szilárd Dóró
1c5178f5fb chore(dashboard): _SCHEMA_API -> _API 2023-01-25 12:31:14 +01:00
Szilárd Dóró
72ad9aa8ee Merge branch 'main' into fix/local-urls 2023-01-23 10:39:56 +01:00
Szilárd Dóró
1b45db8caf chore(dashboard): revert users page changes
These will be fixed in a separate PR
2023-01-23 09:35:57 +01:00
Szilárd Dóró
9ffb4d0295 fix(dashboard): use fallbacks for services 2023-01-19 08:51:05 +01:00
Szilárd Dóró
e56340b792 fix(dashboard): env vars in Dockerfile
`localhost` -> `local`
2023-01-19 08:33:23 +01:00
Szilárd Dóró
814c6d997a Merge branch 'main' into fix/local-urls 2023-01-19 08:20:04 +01:00
Szilárd Dóró
7d7a352c33 chore(dashboard): update README 2023-01-16 19:23:22 +01:00
Szilárd Dóró
53a704fc7d chore(nhost-js): add TODO comments 2023-01-16 19:20:37 +01:00
Szilárd Dóró
c23eddf33d chore(dashboard): update README, improve SDK 2023-01-16 19:15:46 +01:00
Szilárd Dóró
d4147f4713 chore(dashboard): cleanup tests, cleanup env vars 2023-01-16 18:22:20 +01:00
Szilárd Dóró
f375eaccf5 feat(dashboard): introduce service based env vars
fix `@nhost/nextjs` and `@nhost/react` constructors
2023-01-16 17:49:03 +01:00
renovate[bot]
88a992ba36 fix(deps): update dependency commander to v10 2023-01-14 04:54:59 +00:00
Siarhei Lipchyk
47f79ba9f3 upd 2023-01-10 12:33:26 +01:00
Siarhei Lipchyk
2e010455cf Update docker-entrypoint.sh 2023-01-10 11:09:00 +01:00
Szilárd Dóró
7e63c822ec Update dashboard/README.md
Co-authored-by: Nuno Pato <nunopato@gmail.com>
2023-01-10 09:27:24 +01:00
Pierre-Louis Mercereau
6a7801be93 chore: update changeset 2023-01-10 09:10:33 +01:00
Pierre-Louis Mercereau
7bc5bb857c chore: add the deprecated useAxios option 2023-01-10 09:02:45 +01:00
Pierre-Louis Mercereau
c957039d75 chore: update lock file 2023-01-09 20:17:12 +01:00
Pierre-Louis Mercereau
96c4032424 Merge branch 'main' into sdk-next-major 2023-01-09 20:13:13 +01:00
Pierre-Louis Mercereau
ec70126b56 fix: iso 8859-1 2023-01-09 19:25:02 +01:00
Szilárd Dóró
276b7d48c3 fix(dashboard): fix typo 2023-01-09 17:44:05 +01:00
Szilárd Dóró
6925b0d510 Merge remote-tracking branch 'origin/main' into fix/local-urls 2023-01-09 17:33:47 +01:00
Szilárd Dóró
6ff306c4e4 fix(dashboard): correct changeset
changed patch bump to minor bump as this version introduces deprecations
2023-01-09 17:33:01 +01:00
Szilárd Dóró
aa440fefe6 fix(dashboard): fix Dockerfile variables 2023-01-09 17:32:07 +01:00
Szilárd Dóró
9fbafc6654 feat(dashboard): introduce new port for services 2023-01-09 17:29:51 +01:00
Pierre-Louis Mercereau
86b9f9040c Merge branch 'main' into sdk-next-major 2023-01-09 16:31:04 +01:00
Szilárd Dóró
b086175045 fix(dashboard): prevent build error 2023-01-09 16:25:06 +01:00
Szilárd Dóró
36db12297b fix(dashboard): resolve linter error 2023-01-09 15:43:49 +01:00
Szilárd Dóró
e5885d9bad fix(dashboard): don't break Auth page in local mode 2023-01-09 15:43:12 +01:00
Szilárd Dóró
15c13f3bbe Merge remote-tracking branch 'origin/main' into fix/local-urls 2023-01-09 15:10:40 +01:00
Szilárd Dóró
8d47cafd86 fix(dashboard): use correct subdomain 2023-01-09 14:59:25 +01:00
Pierre-Louis Mercereau
222f03725b fix(dashboard): use fetch instead of axios 2023-01-06 16:42:40 +01:00
Pierre-Louis Mercereau
10b786e5c6 chore: fix lockfile 2023-01-06 16:30:22 +01:00
Pierre-Louis Mercereau
aa8ae88d12 Merge branch 'main' into sdk-next-major 2023-01-06 16:25:12 +01:00
Pilou
0f2c86b41a Merge pull request #1351 from nhost/refactor/cross-fetch
refactor: replace axios by cross-fetch
2023-01-06 16:17:03 +01:00
Szilárd Dóró
408cb6d10c chore(dashboard): update README 2023-01-06 13:31:01 +01:00
Szilárd Dóró
4d882703f2 fix(dashboard): use localhost for Hasura services 2023-01-06 13:27:57 +01:00
Szilárd Dóró
437dacaa9e chore(nhost-js): refactor port default value 2023-01-04 19:00:58 +01:00
Szilárd Dóró
088584e79d feat: add support for custom local subdomains 2023-01-04 15:34:48 +01:00
Pilou
a4c76892dd Update packages/hasura-storage-js/src/hasura-storage-api.ts
Co-authored-by: Szilárd Dóró <doroszilard@icloud.com>
2023-01-03 10:36:33 +01:00
Pierre-Louis Mercereau
00d278b2cc refactor: adjustments from review 2023-01-02 17:32:34 +01:00
Pilou
cb6b5faeb9 Update packages/hasura-storage-js/src/hasura-storage-client.ts
Co-authored-by: Szilárd Dóró <doroszilard@icloud.com>
2023-01-02 17:29:21 +01:00
Pierre-Louis Mercereau
7c4c847b91 Merge branch 'sdk-next-major' into refactor/cross-fetch 2022-12-26 12:54:40 +01:00
Pierre-Louis Mercereau
908887d8c5 Merge branch 'main' into sdk-next-major 2022-12-26 12:54:19 +01:00
Pierre-Louis Mercereau
a2d67bc2db fix(dashboard): js error from error payload 2022-12-26 12:45:33 +01:00
Pierre-Louis Mercereau
1a6cd78254 Merge branch 'sdk-next-major' into refactor/cross-fetch 2022-12-21 16:42:58 +01:00
Pierre-Louis Mercereau
6500629c4b Merge branch 'main' into sdk-next-major 2022-12-21 16:22:28 +01:00
Pierre-Louis Mercereau
add3c2c10e Merge branch 'sdk-next-major' into refactor/cross-fetch 2022-12-21 14:29:00 +01:00
Pierre-Louis Mercereau
dd29b06260 Merge branch 'main' into sdk-next-major 2022-12-21 14:27:48 +01:00
Pierre-Louis Mercereau
490cb25a0f Merge branch 'sdk-next-major' into refactor/cross-fetch 2022-12-20 10:13:18 +01:00
Pierre-Louis Mercereau
0df0dd741e Merge branch 'main' into sdk-next-major 2022-12-20 10:12:56 +01:00
Pierre-Louis Mercereau
2172946879 Merge branch 'sdk-next-major' into refactor/cross-fetch 2022-12-20 09:17:50 +01:00
Pierre-Louis Mercereau
40e50f0e75 Merge branch 'main' into sdk-next-major 2022-12-20 09:15:30 +01:00
Pierre-Louis Mercereau
65cf0888b5 chore: extract patch changes 2022-12-16 12:14:38 +01:00
Pierre-Louis Mercereau
21833019ca chore: correct error from several mergers 2022-12-14 21:14:48 +01:00
Pierre-Louis Mercereau
b3171ba3e9 chore: remove lockfile 2022-12-14 20:40:16 +01:00
Pierre-Louis Mercereau
6f01f19d02 refactor: remove docgen 2022-12-14 20:33:03 +01:00
Pierre-Louis Mercereau
ce92b01eac Merge branch 'main' into sdk-next-major 2022-12-14 19:25:15 +01:00
Pierre-Louis Mercereau
e24a177434 Merge branch 'main' into sdk-next-major 2022-12-14 19:06:50 +01:00
Pierre-Louis Mercereau
56a52b6d48 chore: remove duplicate changesets 2022-12-12 16:45:42 +01:00
Pierre-Louis Mercereau
92bfa8c723 chore: phrasing 2022-12-12 16:03:07 +01:00
Pierre-Louis Mercereau
2a52aaa4a6 Merge branch 'sdk-next-major' into refactor/cross-fetch 2022-12-12 14:46:39 +01:00
Pierre-Louis Mercereau
8280a3e9d8 chore: use explicit changeset links 2022-12-12 14:30:38 +01:00
Pierre-Louis Mercereau
523f60bf68 Merge branch 'sdk-next-major' into refactor/cross-fetch 2022-12-12 14:20:28 +01:00
Pierre-Louis Mercereau
19b11d4084 chore: details on removed deprecations 2022-12-12 14:15:08 +01:00
Pierre-Louis Mercereau
805bae1507 chore: bump nextjs as major as React removed deprecated methods are reexported 2022-12-12 13:36:25 +01:00
Pierre-Louis Mercereau
f6c014c06f chore: correct changeset 2022-12-12 13:34:19 +01:00
Pierre-Louis Mercereau
c5794f4596 chore: improve changesets 2022-12-12 13:32:09 +01:00
Pierre-Louis Mercereau
fc28817380 chore: explain xhr in changeset 2022-12-12 10:06:56 +01:00
Pierre-Louis Mercereau
80bbd3a165 chore: changesets 2022-12-12 10:02:21 +01:00
Pierre-Louis Mercereau
7a10617a72 test: simplify email verification test 2022-12-12 09:26:02 +01:00
Pierre-Louis Mercereau
f0b6dca1a5 Merge branch 'sdk-next-major' into refactor/cross-fetch 2022-12-08 14:28:03 +01:00
Szilárd Dóró
5db20adc34 fix(react): eliminate error when testing the project 2022-12-08 12:01:05 +01:00
Pierre-Louis Mercereau
12dc41a517 test: TypedDocumentNode 2022-12-08 09:07:46 +01:00
Pierre-Louis Mercereau
768fd56891 feat: graphql-typed-document-node 2022-12-07 21:53:21 +01:00
Pierre-Louis Mercereau
8a508cb1cc chore: run CI on evey pull request, not only the ones to main 2022-12-07 20:47:26 +01:00
Pierre-Louis Mercereau
34f6a8eef4 refactor: upload progress with XHR 2022-12-07 19:48:34 +01:00
Pierre-Louis Mercereau
c9d2d31a9b feat: nhost.graphql.httpUrl and nhost.graphql.wsUrl 2022-12-07 18:53:58 +01:00
Pierre-Louis Mercereau
68fb23a361 refactor: remove last pieces of axios 2022-12-07 17:16:42 +01:00
Pierre-Louis Mercereau
476139e528 refactor: remove axios from hasura-storage-js, with breaking change 2022-12-07 13:27:34 +01:00
Pierre-Louis Mercereau
6a850818a0 Merge branch 'sdk-next-major' into refactor/cross-fetch 2022-12-07 11:41:55 +01:00
Pilou
3970dbba0d Merge pull request #1342 from nhost/chore/improve-internal-dependencies
chore: improve internal dependencies
2022-12-07 11:40:02 +01:00
Pierre-Louis Mercereau
8ee2166f0d fix: correct nhost clients 2022-12-07 11:08:54 +01:00
Szilárd Dóró
e13500a185 fix(docgen): correct class references when used as interface members 2022-12-07 10:47:04 +01:00
Pierre-Louis Mercereau
411f574a51 refactor: re-export @nhost/react in @nhost/nextjs 2022-12-07 09:47:45 +01:00
Szilárd Dóró
7fc91b992e chore: cleanup dependencies, fix references 2022-12-07 08:59:06 +01:00
Pierre-Louis Mercereau
b840012be0 fix: correct fetch errors 2022-12-07 08:56:11 +01:00
Pierre-Louis Mercereau
645c51a9dc refactor: 💡 replace axios by cross-fetch, step 1
Changes not done yet in `nhost.auth.graphql` (will soon use
graphql-request instead) and the upload machines (depends on prrogress)
2022-12-06 22:08:46 +01:00
Pierre-Louis Mercereau
0ce6f05539 Merge branch 'sdk-next-major' into chore/improve-internal-dependencies 2022-12-06 14:10:19 +01:00
Pierre-Louis Mercereau
8b1188af53 Merge branch 'main' into sdk-next-major 2022-12-06 14:08:55 +01:00
Pilou
12b01f8dee Merge pull request #1298 from nhost/fix/react-strict-mode
fix: react strict mode
2022-12-06 14:06:07 +01:00
Pierre-Louis Mercereau
60f4faf409 chore: remove @nhost/core from changeset 2022-12-06 13:05:45 +01:00
Pierre-Louis Mercereau
528dff3f1b Merge branch 'sdk-next-major' into fix/react-strict-mode 2022-12-06 12:52:33 +01:00
Pierre-Louis Mercereau
d429fb4a3e Merge branch 'sdk-next-major' into chore/improve-internal-dependencies 2022-12-06 12:41:25 +01:00
Pilou
816c916709 Merge pull request #1233 from nhost/docs/hide-old-deprecations
chore: remove deprecated methods
2022-12-06 12:40:42 +01:00
Pierre-Louis Mercereau
b7a2b8b537 docs: update installation instructions 2022-12-06 10:50:40 +01:00
Pierre-Louis Mercereau
261d8cf434 merge 2022-12-06 10:10:13 +01:00
Pierre-Louis Mercereau
41f49bde76 Merge branch 'sdk-next-major' into chore/improve-internal-dependencies 2022-12-06 10:06:25 +01:00
Pilou
65f685bdb2 Update packages/core/src/client.ts
Co-authored-by: Szilárd Dóró <doroszilard@icloud.com>
2022-12-06 09:57:29 +01:00
Pilou
f52a7f4aac Update packages/core/src/machines/index.ts
Co-authored-by: Szilárd Dóró <doroszilard@icloud.com>
2022-12-06 09:57:01 +01:00
Pierre-Louis Mercereau
e71b9903d9 Merge branch 'sdk-next-major' into docs/hide-old-deprecations 2022-12-06 09:50:40 +01:00
Pilou
325fd08aef Merge pull request #1246 from nhost/refactor/merge-core
refactor: decommission `@nhost/core`
2022-12-06 09:46:50 +01:00
Pierre-Louis Mercereau
3888704464 chore: remove comment 2022-12-06 09:23:31 +01:00
Pierre-Louis Mercereau
38e8a10a29 chore: 🤖 remove lockfile 2022-12-06 09:19:02 +01:00
Pierre-Louis Mercereau
d8545eae12 chore: 🤖 add changeset 2022-12-06 09:18:16 +01:00
Pierre-Louis Mercereau
3d5bfd87d2 refactor: simplify 2022-12-06 08:59:11 +01:00
Pierre-Louis Mercereau
e66c5626bd fix: don't fetch session when present in initial state 2022-12-05 23:14:17 +01:00
Pierre-Louis Mercereau
a227c6561e refactor: work with nextjs 2022-12-05 23:09:26 +01:00
Pierre-Louis Mercereau
e885c159df refactor: simplify onStart 2022-12-05 14:53:10 +01:00
Pierre-Louis Mercereau
09fcb74bef refactor: use Johan's function name 2022-12-05 14:31:03 +01:00
Pierre-Louis Mercereau
a089197197 Merge branch 'main' into fix/react-strict-mode 2022-12-05 14:29:27 +01:00
Pierre-Louis Mercereau
34f843875b Merge branch 'main' into fix/react-strict-mode 2022-12-05 12:15:01 +01:00
Pierre-Louis Mercereau
ca278a8c39 Merge branch 'main' into fix/react-strict-mode 2022-12-05 11:54:01 +01:00
Pierre-Louis Mercereau
75603786e0 refactor: 💡 Remove unused immer dependency 2022-12-05 11:43:47 +01:00
Pierre-Louis Mercereau
4e4e699b94 refactor: adapt to nextjs 2022-12-05 11:39:36 +01:00
Pierre-Louis Mercereau
da31fa9fba ci: explicit pnpm run 2022-12-02 20:46:25 +01:00
Pierre-Louis Mercereau
95e2afaf47 Merge branch 'main' into fix/react-strict-mode 2022-12-02 15:46:13 +01:00
Pierre-Louis Mercereau
958a56dde9 fix: adapt to nextjs 2022-12-02 15:11:08 +01:00
Pierre-Louis Mercereau
74cb15930e Merge branch 'main' into fix/react-strict-mode 2022-12-02 13:35:53 +01:00
Pierre-Louis Mercereau
aa37a98424 Merge branch 'main' into fix/react-strict-mode 2022-12-02 13:27:37 +01:00
Pierre-Louis Mercereau
11cbdda3a5 Merge branch 'main' into fix/react-strict-mode 2022-12-02 13:20:55 +01:00
Pierre-Louis Mercereau
6d1f4adf10 chore: update changeset 2022-12-02 13:16:31 +01:00
Pierre-Louis Mercereau
ddbc50c15e refactor: avoid ambiguous interpreter getter/setter 2022-12-02 13:15:04 +01:00
Pierre-Louis Mercereau
b2cbf570a3 fix: 🐛 don't throw error when re-setting the interpreter 2022-12-02 12:08:52 +01:00
Pierre-Louis Mercereau
22b8e65031 fix: 🐛 onstart only when interpreter is initialised 2022-12-02 11:26:14 +01:00
Pierre-Louis Mercereau
63c94d2036 chore: fine-tune (peer) dependencies 2022-11-30 12:56:46 +01:00
Pierre-Louis Mercereau
010df48c1e chore: remove deprecations 2022-11-28 20:44:24 +01:00
Pierre-Louis Mercereau
fdc11db93d Merge branch 'main' into docs/hide-old-deprecations 2022-11-28 20:18:26 +01:00
Pierre-Louis Mercereau
cb4749f168 chore: fix lint 2022-11-28 15:53:54 +01:00
Pierre-Louis Mercereau
46a8fcf471 docs: hide > 6m.o. deprecations in the generated documentation 2022-11-28 15:34:09 +01:00
Dipak Parmar
ce4b655c55 fix: correct typos 2022-11-22 19:47:21 -08:00
Dipak Parmar
dc57d31ec9 fix: correct extra space in azureadprovidersettings dir 2022-11-22 19:45:38 -08:00
Dipak Parmar
ea29fd6b73 feat(dashboard-settings): add azuread provider to settings 2022-11-21 20:30:53 -08:00
Dipak Parmar
d8e4073957 feat(dashboard-settings): add azuread provider settings component 2022-11-21 20:29:34 -08:00
Dipak Parmar
3f399a54a3 feat(graphql): add azuread to signinmethods query 2022-11-21 20:28:50 -08:00
603 changed files with 18834 additions and 14056 deletions

18
.github/CODEOWNERS vendored
View File

@@ -1,14 +1,14 @@
# Documentation
# https://help.github.com/en/articles/about-code-owners
/packages @plmercereau @szilarddoro
/packages @szilarddoro
/packages/docgen @szilarddoro
/integrations/stripe-graphql-js @elitan
/.github @plmercereau
/dashboard/ @szilarddoro @guicurcio
/docs/ @guicurcio @elitan
/config/ @plmercereau @szilarddoro
/examples/ @plmercereau
/examples/codegen-react-apollo @elitan @plmercereau
/examples/codegen-react-query @elitan @plmercereau
/examples/react-apollo-crm @elitan @plmercereau
/.github @szilarddoro
/dashboard/ @szilarddoro
/docs/ @elitan
/config/ @szilarddoro
/examples/ @szilarddoro
/examples/codegen-react-apollo @elitan @szilarddoro
/examples/codegen-react-query @elitan @szilarddoro
/examples/react-apollo-crm @elitan @szilarddoro

View File

@@ -23,9 +23,7 @@ runs:
- uses: actions/cache@v3
id: pnpm-cache
with:
path: |
${{ steps.pnpm-cache-dir.outputs.dir }}
~/.cache/Cypress
path: ${{ steps.pnpm-cache-dir.outputs.dir }}
key: ${{ runner.os }}-node-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: ${{ runner.os }}-node-
- name: Use Node.js 16
@@ -40,14 +38,14 @@ runs:
- shell: bash
name: Build packages
if: ${{ inputs.BUILD == 'all' }}
run: pnpm build:all
run: pnpm run build:all
env:
TURBO_TOKEN: ${{ inputs.TURBO_TOKEN }}
TURBO_TEAM: ${{ inputs.TURBO_TEAM }}
- shell: bash
name: Build everything in the monorepo
if: ${{ inputs.BUILD == 'default' }}
run: pnpm build
run: pnpm run build
env:
TURBO_TOKEN: ${{ inputs.TURBO_TOKEN }}
TURBO_TEAM: ${{ inputs.TURBO_TEAM }}

View File

@@ -98,7 +98,7 @@ jobs:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push to Docker Hub
uses: docker/build-push-action@v3
uses: docker/build-push-action@v4
timeout-minutes: 60
with:
context: .

View File

@@ -8,7 +8,6 @@ on:
- '**.md'
- 'LICENSE'
pull_request:
branches: [main]
types: [opened, synchronize]
paths-ignore:
- 'assets/**'
@@ -20,6 +19,12 @@ env:
NEXT_PUBLIC_ENV: dev
NEXT_TELEMETRY_DISABLED: 1
NEXT_PUBLIC_NHOST_BACKEND_URL: http://localhost:1337
NHOST_TEST_DASHBOARD_URL: ${{ vars.NHOST_TEST_DASHBOARD_URL }}
NHOST_TEST_WORKSPACE_NAME: ${{ vars.NHOST_TEST_WORKSPACE_NAME }}
NHOST_TEST_PROJECT_NAME: ${{ vars.NHOST_TEST_PROJECT_NAME }}
NHOST_TEST_USER_EMAIL: ${{ secrets.NHOST_TEST_USER_EMAIL }}
NHOST_TEST_USER_PASSWORD: ${{ secrets.NHOST_TEST_USER_PASSWORD }}
NHOST_TEST_PROJECT_ADMIN_SECRET: ${{ secrets.NHOST_TEST_PROJECT_ADMIN_SECRET }}
jobs:
build:
@@ -56,52 +61,11 @@ jobs:
| xargs -I@ realpath --relative-to=$PWD @ \
| xargs -I@ jq "if (.scripts.e2e | length) != 0 then {name: .name, path: \"@\"} else null end" @/package.json \
| awk "!/null/" \
| jq -c --slurp)
| jq -c --slurp 'map(select(length > 0))')
echo "matrix=$PACKAGES" >> $GITHUB_OUTPUT
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
e2e:
name: 'e2e (${{ matrix.package.path }})'
needs: build
if: ${{ needs.build.outputs.matrix != '[]' && needs.build.outputs.matrix != '' }}
strategy:
# * Don't cancel other matrices when one fails
fail-fast: false
matrix:
package: ${{ fromJson(needs.build.outputs.matrix) }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
# * Install Node and dependencies. Package dependencies won't be downloaded again as they have been cached by the `build` job.
- name: Install Node and dependencies
uses: ./.github/actions/install-dependencies
with:
TURBO_TOKEN: ${{ env.TURBO_TOKEN }}
TURBO_TEAM: ${{ env.TURBO_TEAM }}
# * Install Nhost CLI if a `nhost/config.yaml` file is found
- name: Install Nhost CLI
if: hashFiles(format('{0}/nhost/config.yaml', matrix.package.path)) != ''
uses: ./.github/actions/nhost-cli
# * Run the `ci` script of the current package of the matrix. Dependencies build is cached by Turborepo
- name: Run e2e test
run: pnpm --filter="${{ matrix.package.name }}" run e2e
- id: file-name
if: ${{ failure() }}
name: Tranform package name into a valid file name
run: |
PACKAGE_FILE_NAME=$(echo "${{ matrix.package.name }}" | sed 's/@//g; s/\//-/g')
echo "fileName=$PACKAGE_FILE_NAME" >> $GITHUB_OUTPUT
# * Run this step only if the previous step failed, and some Cypress screenshots/videos exist
- name: Upload Cypress videos and screenshots
if: ${{ failure() && hashFiles(format('{0}/cypress/screenshots/**', matrix.package.path), format('{0}/cypress/videos/**', matrix.package.path)) != ''}}
uses: actions/upload-artifact@v3
with:
name: cypress-${{ steps.file-name.outputs.fileName }}
path: |
${{format('{0}/cypress/screenshots/**', matrix.package.path)}}
${{format('{0}/cypress/videos/**', matrix.package.path)}}
unit:
name: Unit tests
needs: build
@@ -142,3 +106,57 @@ jobs:
# * Run every `lint` script in the workspace . Dependencies build is cached by Turborepo
- name: Lint
run: pnpm run lint:all
e2e:
name: 'E2E (Package: ${{ matrix.package.path }})'
needs: build
if: ${{ needs.build.outputs.matrix != '[]' && needs.build.outputs.matrix != '' }}
strategy:
# * Don't cancel other matrices when one fails
fail-fast: false
matrix:
package: ${{ fromJson(needs.build.outputs.matrix) }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
# * Install Node and dependencies. Package dependencies won't be downloaded again as they have been cached by the `build` job.
- name: Install Node and dependencies
uses: ./.github/actions/install-dependencies
with:
TURBO_TOKEN: ${{ env.TURBO_TOKEN }}
TURBO_TEAM: ${{ env.TURBO_TEAM }}
# * Install Nhost CLI if a `nhost/config.yaml` file is found
- name: Install Nhost CLI
if: hashFiles(format('{0}/nhost/config.yaml', matrix.package.path)) != ''
uses: ./.github/actions/nhost-cli
- name: Fetch Dashboard Preview URL
id: fetch-dashboard-preview-url
uses: zentered/vercel-preview-url@v1.1.9
if: github.ref_name != 'main'
env:
VERCEL_TOKEN: ${{ secrets.DASHBOARD_VERCEL_DEPLOY_TOKEN }}
GITHUB_REF: ${{ github.ref_name }}
GITHUB_REPOSITORY: ${{ github.repository }}
with:
vercel_team_id: ${{ secrets.DASHBOARD_VERCEL_TEAM_ID }}
vercel_project_id: ${{ secrets.DASHBOARD_STAGING_VERCEL_PROJECT_ID }}
vercel_state: BUILDING,READY,INITIALIZING
- name: Set Dashboard Preview URL
if: steps.fetch-dashboard-preview-url.outputs.preview_url != ''
run: echo "NHOST_TEST_DASHBOARD_URL=https://${{ steps.fetch-dashboard-preview-url.outputs.preview_url }}" >> $GITHUB_ENV
# * Run the `ci` script of the current package of the matrix. Dependencies build is cached by Turborepo
- name: Run e2e tests
run: pnpm --filter="${{ matrix.package.name }}" run e2e
- id: file-name
if: ${{ failure() }}
name: Transform package name into a valid file name
run: |
PACKAGE_FILE_NAME=$(echo "${{ matrix.package.name }}" | sed 's/@//g; s/\//-/g')
echo "fileName=$PACKAGE_FILE_NAME" >> $GITHUB_OUTPUT
# * Run this step only if the previous step failed, and Playwright generated a report
- name: Upload Playwright Report
if: ${{ failure() && hashFiles(format('{0}/playwright-report/**', matrix.package.path)) != ''}}
uses: actions/upload-artifact@v3
with:
name: playwright-${{ steps.file-name.outputs.fileName }}
path: ${{format('{0}/playwright-report/**', matrix.package.path)}}

View File

@@ -9,6 +9,7 @@ env:
NEXT_PUBLIC_ENV: dev
NEXT_TELEMETRY_DISABLED: 1
NEXT_PUBLIC_NHOST_BACKEND_URL: http://localhost:1337
jobs:
build:
name: Build

View File

@@ -1,89 +0,0 @@
name: Renovate
on:
pull_request:
branches: [main]
types: [closed]
paths-ignore:
- 'assets/**'
- '**.md'
- 'LICENSE'
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: nhost
jobs:
renovate-changeset:
name: Add changeset
if: github.event.pull_request.merged == true && startsWith(github.head_ref, 'renovate/')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
token: ${{ secrets.GH_PAT }}
# * Install Node and dependencies. Package downloads will be cached for the next jobs.
- name: Install Node and dependencies
uses: ./.github/actions/install-dependencies
with:
TURBO_TOKEN: ${{ env.TURBO_TOKEN }}
TURBO_TEAM: ${{ env.TURBO_TEAM }}
BUILD: 'none'
- name: Determine bumps
id: bumps
run: |
LAST_NON_PR_SHA=$(git log --no-merges main origin/${{ github.head_ref }} --format=format:%h -- | head -2 | tail -1)
echo "result<<EOF" >> $GITHUB_OUTPUT
pnpm recursive list --depth -1 --parseable \
--filter='!nhost-root' \
--filter=[$LAST_NON_PR_SHA] \
| xargs -I@ jq ".name" @/package.json \
| sort \
| uniq -u \
| awk '$0=$0": patch"' \
>> $GITHUB_OUTPUT
echo 'EOF' >> $GITHUB_OUTPUT
- name: Install dictionary
if: steps.bumps.outputs.result != ''
run: sudo apt-get install wbritish
- name: Generate changeset file name
id: file_name
if: steps.bumps.outputs.result != ''
run: |
FILE_NAME=$(shuf -n 3 /usr/share/dict/words | tr '\n' '-' | sed 's/-$//' | sed 's/'"'"'s//g' | tr '[:upper:]' '[:lower:]')
echo "result=./.changeset/${FILE_NAME}.md" >> $GITHUB_OUTPUT
- name: Create changeset file
if: steps.bumps.outputs.result != ''
run: |
cat <<EOF > ${{ steps.file_name.outputs.result }}
---
${{ steps.bumps.outputs.result }}
---
${{ github.event.pull_request.title }}
EOF
- name: Create Pull Request
id: cpr
uses: peter-evans/create-pull-request@v4
with:
token: ${{ secrets.GH_PAT }}
commit-message: ${{ github.event.pull_request.title }}
branch: renovate-changesets
delete-branch: true
title: 'chore: create changesest from Renovate bumps'
labels: |
dependencies
body: |
This PR creates the changesets from the Renovate dependencies that have been merged to main.
- name: Enable Pull Request Automerge
if: steps.cpr.outputs.pull-request-operation == 'created'
uses: peter-evans/enable-pull-request-automerge@v2
with:
token: ${{ secrets.GH_PAT }}
pull-request-number: ${{ steps.cpr.outputs.pull-request-number }}
- name: Auto approve
if: steps.cpr.outputs.pull-request-operation == 'created'
uses: juliangruber/approve-pull-request-action@v2
with:
github-token: ${{ secrets.GH_PAT }}
number: ${{ steps.cpr.outputs.pull-request-number }}

View File

@@ -23,8 +23,8 @@ module.exports = {
'e2e/**/*.ts',
'e2e/**/*.d.ts'
],
plugins: ['@typescript-eslint', 'cypress'],
extends: ['plugin:cypress/recommended'],
plugins: ['@typescript-eslint'],
extends: [],
parserOptions: {
ecmaVersion: 2020,
sourceType: 'module'

View File

@@ -45,6 +45,9 @@
"@nhost/docgen": [
"../packages/docgen/src/index.ts"
],
"@nhost/graphql-js": [
"../packages/graphql-js/src/index.ts"
],
"@nhost/hasura-auth-js": [
"../packages/hasura-auth-js/src/index.ts"
],

View File

@@ -1,7 +1,6 @@
import replace from '@rollup/plugin-replace'
import fs from 'fs'
import path from 'path'
import { defineConfig } from 'vite'
import dts from 'vite-plugin-dts'
import tsconfigPaths from 'vite-tsconfig-paths'
@@ -21,7 +20,9 @@ export default defineConfig({
exclude: ['**/*.spec.ts', '**/*.test.ts', '**/tests/**'],
entryRoot: 'src',
// Was defaulting to true until version 1.7
skipDiagnostics: true
skipDiagnostics: true,
// Was defaulting to true until version 2.0
copyDtsFiles: true
})
],
test: {
@@ -61,7 +62,6 @@ export default defineConfig({
'@apollo/client/utilities': '@apollo/client/utilities',
'graphql-ws': 'graphql-ws',
xstate: 'xstate',
axios: 'axios',
'js-cookie': 'Cookies',
react: 'React',
'react-dom': 'ReactDOM',

View File

@@ -1,8 +1,17 @@
# General Environment Variables
NEXT_PUBLIC_ENV=dev
NEXT_PUBLIC_NHOST_HASURA_URL=http://localhost:9695
NEXT_PUBLIC_NHOST_MIGRATIONS_URL=http://localhost:9693
NEXT_PUBLIC_NHOST_BACKEND_URL=http://localhost:1337
NEXT_PUBLIC_NHOST_PLATFORM=false
# Environment Variables for Self Hosting and Local Development
NEXT_PUBLIC_NHOST_AUTH_URL=https://local.auth.nhost.run/v1
NEXT_PUBLIC_NHOST_FUNCTIONS_URL=https://local.functions.nhost.run/v1
NEXT_PUBLIC_NHOST_GRAPHQL_URL=https://local.graphql.nhost.run/v1
NEXT_PUBLIC_NHOST_STORAGE_URL=https://local.storage.nhost.run/v1
NEXT_PUBLIC_NHOST_HASURA_CONSOLE_URL=https://local.hasura.nhost.run
NEXT_PUBLIC_NHOST_HASURA_MIGRATIONS_API_URL=https://local.hasura.nhost.run/v1/migrations
NEXT_PUBLIC_NHOST_HASURA_API_URL=https://local.hasura.nhost.run
# Environment Variables when running the Nhost Dashboard against the Nhost Backend
NEXT_PUBLIC_STRIPE_PK=<nhost_stripe_public_key>
NEXT_PUBLIC_GITHUB_APP_INSTALL_URL=<github_app_install_url>
NEXT_PUBLIC_ANALYTICS_WRITE_KEY=<analytics_write_key>

View File

@@ -30,6 +30,7 @@ module.exports = {
'error',
{ ignoreTypeReferences: true },
],
'no-console': ['warn', { allow: ['error'] }],
'no-shadow': 'off',
'@typescript-eslint/no-shadow': 'error',
'no-unused-vars': 'off',

View File

@@ -49,4 +49,8 @@ tailwind.json
.idea
# Do not ignore Logs page
!src/**/logs*
!src/**/logs*
/test-results/
/playwright-report/
/playwright/.cache/
storageState.json

View File

@@ -51,7 +51,7 @@ export const decorators = [
(Story) => (
<NhostApolloProvider
fetchPolicy="cache-first"
graphqlUrl="http://localhost:1337/v1/graphql"
graphqlUrl="https://local.graphql.nhost.run/v1"
>
<Story />
</NhostApolloProvider>

View File

@@ -1,5 +1,285 @@
# @nhost/dashboard
## 0.14.1
### Patch Changes
- @nhost/react-apollo@5.0.15
- @nhost/nextjs@1.13.19
## 0.14.0
### Minor Changes
- 6e1f03ea: feat(dashboard): add support for the Azure AD provider
### Patch Changes
- 1bd2c373: chore(deps): bump `turbo` to 1.8.6
- d329b621: chore(deps): bump `@types/react` to 18.0.30
- cb248f0d: fix(tests): avoid name collision in database tests
- 867c8076: chore(deps): bump `@types/react` to 18.0.29
## 0.13.10
### Patch Changes
- e93b06ab: fix(dashboard): remove left margin from workspace list on mobile
- 1c4806bf: chore(deps): bump `sharp` to 0.32.0
- @nhost/react-apollo@5.0.14
- @nhost/nextjs@1.13.18
## 0.13.9
### Patch Changes
- 912ed76c: chore(dashboard): bump `@apollo/client` to 3.7.10
- Updated dependencies [912ed76c]
- @nhost/react-apollo@5.0.13
## 0.13.8
### Patch Changes
- 7c127372: chore(dashboard): bump `react-error-boundary` to v4
## 0.13.7
### Patch Changes
- 9130ab12: chore(dashboard): bump `yup` to v1 and `@hookform/resolvers` to v3
## 0.13.6
### Patch Changes
- 253dd235: using new mutation to create projects + refactor Create Project page.
## 0.13.5
### Patch Changes
- @nhost/react-apollo@5.0.12
- @nhost/nextjs@1.13.17
## 0.13.4
### Patch Changes
- b48bc034: fix(dashboard): disable new users
- 798e591b: fix(dashboard): show correct date in data grid
## 0.13.3
### Patch Changes
- bfb4c1a6: chore(dashboard): remove `useAxios` property
- d8d8394b: Dashboard: allow to override hasura admin secret in docker
- Updated dependencies [ce1ee40d]
- @nhost/nextjs@1.13.16
- @nhost/react-apollo@5.0.11
## 0.13.2
### Patch Changes
- beed2eba: Fix docker entrypoint for dashboard
- 2c8559a3: fix(dashboard): refresh project list after deleting a project
- 4329d048: chore(dashboard): bump `graphiql` dependencies
## 0.13.1
### Patch Changes
- cbb1fc5b: chore(dashboard): cleanup GraphQL operations
## 0.13.0
### Minor Changes
- 088584e7: feat(dashboard): add support for custom local subdomains
### Patch Changes
- 2ac90dfd: fix(dashboard): improve mobile responsive layout
- Updated dependencies [f375eacc]
- @nhost/nextjs@1.13.15
- @nhost/react-apollo@5.0.10
## 0.12.4
### Patch Changes
- @nhost/react-apollo@5.0.9
- @nhost/nextjs@1.13.14
## 0.12.3
### Patch Changes
- 2b1338f7: chore(dashboard): bump `turbo` to 1.8.3
- 5223ee93: fix(dashboard): show correct deployment status on the main page
- 850a049c: chore(deps): update docker/build-push-action action to v4
- Updated dependencies [850a049c]
- @nhost/nextjs@1.13.13
- @nhost/react-apollo@5.0.8
## 0.12.2
### Patch Changes
- 4bf40995: chore(deps): bump `typescript` to `4.9.5`
- 8bb097c9: chore(deps): bump `vitest`
- 35d52aab: chore(deps): replace `cross-fetch` with `isomorphic-unfetch`
- Updated dependencies [4bf40995]
- Updated dependencies [8bb097c9]
- Updated dependencies [35d52aab]
- @nhost/react-apollo@5.0.7
- @nhost/nextjs@1.13.12
## 0.12.1
### Patch Changes
- c96d7ccd: fix(dashboard): fix docker builds
## 0.12.0
### Minor Changes
- d1671210: feat(dashboard): use mimir to manage project configuration
### Patch Changes
- f65e4de9: chore(deps): bump @graphql-codegen monorepo to v3
## 0.11.20
### Patch Changes
- 4b4f0d01: chore(dashboard): improve dialog management
## 0.11.19
### Patch Changes
- @nhost/react-apollo@5.0.6
- @nhost/nextjs@1.13.11
## 0.11.18
### Patch Changes
- 01318860: fix(nhost-js): use correct URL for functions requests
- Updated dependencies [01318860]
- @nhost/react-apollo@5.0.5
- @nhost/nextjs@1.13.10
## 0.11.17
### Patch Changes
- f673adea: fix(dashboard): set correct Content-Type for user creation
- 445d8ef4: chore(deps): bump `@nhost/react-apollo` to 5.0.4
- 445d8ef4: chore(deps): bump `@nhost/nextjs` to 1.13.9
- 0368663d: fix(dashboard): allow permission editing for auth and storage schemas
- Updated dependencies [445d8ef4]
- Updated dependencies [445d8ef4]
- @nhost/react-apollo@5.0.4
- @nhost/nextjs@1.13.9
## 0.11.16
### Patch Changes
- b755e908: fix(dashboard): use correct date for last seen
- 2d9145f9: chore(deps): revert GraphQL client
- 1ddf704c: fix(dashboard): don't show false positive message for failed user creation
- @nhost/react-apollo@5.0.3
- @nhost/nextjs@1.13.8
## 0.11.15
### Patch Changes
- @nhost/react-apollo@5.0.2
- @nhost/nextjs@1.13.7
## 0.11.14
### Patch Changes
- 2cc18dcb: fix(dashboard): prevent permission editor dropdown from being always open
## 0.11.13
### Patch Changes
- 3343a363: chore(dashboard): bump `@testing-library/react` to v14 and `@testing-library/dom` to v9
- @nhost/react-apollo@5.0.1
- @nhost/nextjs@1.13.6
## 0.11.12
### Patch Changes
- 87eda76e: chore(dashboard): bump `@types/react` to v18.0.28 and `@types/react-dom` to v18.0.11
- 6f0ac570: feat(dashboard): show dashboard version in account menu
## 0.11.11
### Patch Changes
- bf1e4071: chore(dashboard): bump `react-is` version to `18.2.0`
- Updated dependencies [bf1e4071]
- Updated dependencies [5013213b]
- @nhost/nextjs@1.13.5
- @nhost/react-apollo@4.13.5
## 0.11.10
### Patch Changes
- a37a430b: fix(dashboard): don't break UI when deployments are unavailable
- @nhost/react-apollo@4.13.4
- @nhost/nextjs@1.13.4
## 0.11.9
### Patch Changes
- 7b970e68: fix(dashboard): fix header link color
## 0.11.8
### Patch Changes
- f33242f2: feat(dashboard): add new sign up, sign in and reset password pages
## 0.11.7
### Patch Changes
- e9c8909c: fix(dashboard): use correct theme color in dark mode
## 0.11.6
### Patch Changes
- 902f486b: fix(dashboard): re-enable Hasura on logs page
## 0.11.5
### Patch Changes
- 1f9720fa: fix(dashboard): apply select permissions properly
## 0.11.4
### Patch Changes
- deb14b51: fix(dashboard): don't break billing form
## 0.11.3
### Patch Changes

View File

@@ -3,7 +3,7 @@ RUN apk add --no-cache libc6-compat
RUN apk update
WORKDIR /app
RUN yarn global add turbo@1.6.3
RUN yarn global add turbo@1.8.6
COPY . .
RUN turbo prune --scope="@nhost/dashboard" --docker
@@ -11,7 +11,7 @@ FROM node:16-alpine AS builder
ARG TURBO_TOKEN
ARG TURBO_TEAM
RUN apk add --no-cache libc6-compat
RUN apk add --no-cache libc6-compat python3 make g++
RUN apk update
WORKDIR /app
@@ -19,10 +19,15 @@ ENV NEXT_TELEMETRY_DISABLED 1
ENV NEXT_PUBLIC_ENV dev
ENV NEXT_PUBLIC_NHOST_PLATFORM false
# placeholders for ports, will be replaced on runtime by entrypoint script
ENV NEXT_PUBLIC_NHOST_MIGRATIONS_PORT __NEXT_PUBLIC_NHOST_MIGRATIONS_PORT__
ENV NEXT_PUBLIC_NHOST_HASURA_PORT __NEXT_PUBLIC_NHOST_HASURA_PORT__
ENV NEXT_PUBLIC_NHOST_LOCAL_BACKEND_PORT __NEXT_PUBLIC_NHOST_LOCAL_BACKEND_PORT__
# placeholders for URLs, will be replaced on runtime by entrypoint script
ENV NEXT_PUBLIC_NHOST_ADMIN_SECRET __NEXT_PUBLIC_NHOST_ADMIN_SECRET__
ENV NEXT_PUBLIC_NHOST_AUTH_URL __NEXT_PUBLIC_NHOST_AUTH_URL__
ENV NEXT_PUBLIC_NHOST_FUNCTIONS_URL __NEXT_PUBLIC_NHOST_FUNCTIONS_URL__
ENV NEXT_PUBLIC_NHOST_GRAPHQL_URL __NEXT_PUBLIC_NHOST_GRAPHQL_URL__
ENV NEXT_PUBLIC_NHOST_STORAGE_URL __NEXT_PUBLIC_NHOST_STORAGE_URL__
ENV NEXT_PUBLIC_NHOST_HASURA_CONSOLE_URL __NEXT_PUBLIC_NHOST_HASURA_CONSOLE_URL__
ENV NEXT_PUBLIC_NHOST_HASURA_MIGRATIONS_API_URL __NEXT_PUBLIC_NHOST_HASURA_MIGRATIONS_API_URL__
ENV NEXT_PUBLIC_NHOST_HASURA_API_URL __NEXT_PUBLIC_NHOST_HASURA_API_URL__
RUN yarn global add pnpm@7.17.0
COPY .gitignore .gitignore

View File

@@ -35,8 +35,17 @@ You can connect the Nhost Dashboard to your locally running backend by setting t
```bash
NEXT_PUBLIC_ENV=dev
NEXT_PUBLIC_NHOST_PLATFORM=false
NEXT_PUBLIC_NHOST_AUTH_URL=https://local.auth.nhost.run/v1
NEXT_PUBLIC_NHOST_FUNCTIONS_URL=https://local.functions.nhost.run/v1
NEXT_PUBLIC_NHOST_GRAPHQL_URL=https://local.graphql.nhost.run/v1
NEXT_PUBLIC_NHOST_STORAGE_URL=https://local.storage.nhost.run/v1
NEXT_PUBLIC_NHOST_HASURA_CONSOLE_URL=https://local.hasura.nhost.run
NEXT_PUBLIC_NHOST_HASURA_MIGRATIONS_API_URL=https://local.hasura.nhost.run/v1/migrations
NEXT_PUBLIC_NHOST_HASURA_API_URL=https://local.hasura.nhost.run
```
This will connect the Nhost Dashboard to your locally running Nhost backend.
### Storybook
Components are documented using [Storybook](https://storybook.js.org/). To run Storybook, run the following command:
@@ -45,20 +54,39 @@ Components are documented using [Storybook](https://storybook.js.org/). To run S
pnpm storybook
```
### Full list of environment variables
### General Environment Variables
| Name | Description |
| ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| `NEXT_PUBLIC_ENV` | `dev`, `staging` or `prod`. Should be set to `dev` in most cases. |
| `NEXT_PUBLIC_NHOST_PLATFORM` | This should be set to `false` to connect the Nhost Dashboard to a locally running Nhost backend. Setting this to `true` turns off local development. |
| `NEXT_PUBLIC_NHOST_LOCAL_MIGRATIONS_PORT` | Custom port that was passed to the CLI. Used only if local development is enabled. Default: `9693` |
| `NEXT_PUBLIC_NHOST_LOCAL_HASURA_PORT` | Custom port that was passed to the CLI. Used only if local development is enabled and `NEXT_PUBLIC_ENV` is `dev`. Default: `9695` |
| `NEXT_PUBLIC_NHOST_LOCAL_BACKEND_PORT` | Custom port that was passed to the CLI. Used only if local development is enabled. Default: `1337` |
| `NEXT_PUBLIC_NHOST_BACKEND_URL` | Backend URL. Not necessary for local development. |
| `NEXT_PUBLIC_STRIPE_PK` | Stripe public key. Not necessary for local development. |
| `NEXT_PUBLIC_GITHUB_APP_INSTALL_URL` | URL of the GitHub application. Not necessary for local development. |
| `NEXT_PUBLIC_ANALYTICS_WRITE_KEY` | Analytics key. Not necessary for local development. |
| `NEXT_PUBLIC_NHOST_BRAGI_WEBSOCKET` | URL of the Bragi websocket. Not necessary for local development. |
| Name | Description |
| -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `NEXT_PUBLIC_ENV` | `dev`, `staging` or `prod`. This should be set to `dev` in most cases. |
| `NEXT_PUBLIC_NHOST_ADMIN_SECRET` | Admin secret for Hasura. Default: `nhost-admin-secret` |
| `NEXT_PUBLIC_NHOST_PLATFORM` | This should be set to `false` to connect the Nhost Dashboard to a locally running or a self-hosted Nhost backend. Setting this to `true` will connect the Nhost Dashboard to the cloud environment. Default: `false` |
### Environment Variables for Local Development and Self-Hosting
| Name | Description |
| ---- | ----------- |
| `NEXT_PUBLIC_NHOST_AUTH_URL` | The URL of the Auth service. When working locally, point it to the Auth service started by the CLI. When self-hosting, point it to the self-hosted Auth service. |
| `NEXT_PUBLIC_NHOST_FUNCTIONS_URL` | The URL of the Functions service. When working locally, point it to the Functions service started by the CLI. When self-hosting, point it to the self-hosted Functions service. |
| `NEXT_PUBLIC_NHOST_GRAPHQL_URL` | The URL of the GraphQL service. When working locally, point it to the GraphQL service started by the CLI. When self-hosting, point it to the self-hosted GraphQL service. |
| `NEXT_PUBLIC_NHOST_STORAGE_URL` | The URL of the Storage service. When working locally, point it to the Storage service started by the CLI. When self-hosting, point it to the self-hosted Storage service. |
| `NEXT_PUBLIC_NHOST_HASURA_CONSOLE_URL` | The URL of the Hasura Console. When working locally, point it to the Hasura Console started by the CLI. When self-hosting, point it to the self-hosted Hasura Console. |
| `NEXT_PUBLIC_NHOST_HASURA_MIGRATIONS_API_URL` | The URL of Hasura's Migrations service. When working locally, point it to the Migrations service started by the CLI. |
| `NEXT_PUBLIC_NHOST_HASURA_API_URL` | The URL of Hasura's Schema and Metadata API. When working locally, point it to the Schema and Metadata API started by the CLI. When self-hosting, point it to the self-hosted Schema and Metadata API. |
### Other Environment Variables
| Name | Description |
| --------------------------------------- | ------------------------------------------------------------------------------------------- |
| `NEXT_PUBLIC_NHOST_BACKEND_URL` | Backend URL. This is only used if `NEXT_PUBLIC_NHOST_PLATFORM` is `true`. |
| `NEXT_PUBLIC_STRIPE_PK` | Stripe public key. This is only used if `NEXT_PUBLIC_NHOST_PLATFORM` is `true`. |
| `NEXT_PUBLIC_GITHUB_APP_INSTALL_URL` | URL of the GitHub application. This is only used if `NEXT_PUBLIC_NHOST_PLATFORM` is `true`. |
| `NEXT_PUBLIC_ANALYTICS_WRITE_KEY` | Analytics key. This is only used if `NEXT_PUBLIC_NHOST_PLATFORM` is `true`. |
| `NEXT_PUBLIC_NHOST_BRAGI_WEBSOCKET` | URL of the Bragi websocket. This is only used if `NEXT_PUBLIC_NHOST_PLATFORM` is `true`. |
| `NEXT_PUBLIC_MAINTENANCE_ACTIVE` | Determines whether or not maintenance mode is active. |
| `NEXT_PUBLIC_MAINTENANCE_END_DATE` | Date when maintenance mode will end. |
| `NEXT_PUBLIC_MAINTENANCE_UNLOCK_SECRET` | Secret that can be used to bypass maintenance mode. |
## ESLint Rules
@@ -83,3 +111,22 @@ pnpm storybook
| `@typescript-eslint/consistent-type-imports` | Enforces `import type { Type } from 'module'` syntax. It prevents false positive circular dependency errors. |
| `@typescript-eslint/naming-convention` | Enforces a consistent naming convention. |
| `no-restricted-imports` | Enforces absolute imports and consistent import paths for components from `src/components/ui` folder. |
### End-to-End Tests
End-to-end tests are written using [Playwright](https://playwright.dev/). To run the tests, run the following command:
```bash
pnpm e2e
```
Most of the tests require access to the Nhost test user. To run these tests, you need to set the following environment variables in `.env.test`:
```
NHOST_TEST_DASHBOARD_URL=<test_dashboard_url>
NHOST_TEST_USER_EMAIL=<test_user_email>
NHOST_TEST_USER_PASSWORD=<test_user_password>
NHOST_TEST_WORKSPACE_NAME=<test_workspace_name>
NHOST_TEST_PROJECT_NAME=<test_project_name>
NHOST_TEST_PROJECT_ADMIN_SECRET=<test_project_admin_secret>
```

View File

@@ -1,15 +1,25 @@
#!/bin/sh
set -e
set -euo pipefail
# read ports from env variables or use defaults
NEXT_PUBLIC_NHOST_MIGRATIONS_PORT="${NEXT_PUBLIC_NHOST_MIGRATIONS_PORT:=9693}"
NEXT_PUBLIC_NHOST_HASURA_PORT="${NEXT_PUBLIC_NHOST_HASURA_PORT:=9695}"
NEXT_PUBLIC_NHOST_LOCAL_BACKEND_PORT="${NEXT_PUBLIC_NHOST_LOCAL_BACKEND_PORT:=1337}"
# read URLs from env variables (with defaults)
NEXT_PUBLIC_NHOST_ADMIN_SECRET="${NEXT_PUBLIC_NHOST_ADMIN_SECRET:-nhost-admin-secret}"
NEXT_PUBLIC_NHOST_AUTH_URL="${NEXT_PUBLIC_NHOST_AUTH_URL:-http://localhost:1337/v1/auth}"
NEXT_PUBLIC_NHOST_FUNCTIONS_URL="${NEXT_PUBLIC_NHOST_FUNCTIONS_URL:-http://localhost:1337/v1/functions}"
NEXT_PUBLIC_NHOST_GRAPHQL_URL="${NEXT_PUBLIC_NHOST_GRAPHQL_URL:-http://localhost:1337/v1/graphql}"
NEXT_PUBLIC_NHOST_STORAGE_URL="${NEXT_PUBLIC_NHOST_STORAGE_URL:-http://localhost:1337/v1/storage}"
NEXT_PUBLIC_NHOST_HASURA_CONSOLE_URL="${NEXT_PUBLIC_NHOST_HASURA_CONSOLE_URL:-http://localhost:9695}"
NEXT_PUBLIC_NHOST_HASURA_MIGRATIONS_API_URL="${NEXT_PUBLIC_NHOST_HASURA_MIGRATIONS_API_URL:-http://localhost:9693}"
NEXT_PUBLIC_NHOST_HASURA_API_URL="${NEXT_PUBLIC_NHOST_HASURA_API_URL:-http://localhost:8080}"
# replace placeholders
find dashboard -type f -exec sed -i "s/__NEXT_PUBLIC_NHOST_MIGRATIONS_PORT__/${NEXT_PUBLIC_NHOST_MIGRATIONS_PORT}/g" {} +
find dashboard -type f -exec sed -i "s/__NEXT_PUBLIC_NHOST_HASURA_PORT__/${NEXT_PUBLIC_NHOST_HASURA_PORT}/g" {} +
find dashboard -type f -exec sed -i "s/__NEXT_PUBLIC_NHOST_LOCAL_BACKEND_PORT__/${NEXT_PUBLIC_NHOST_LOCAL_BACKEND_PORT}/g" {} +
find dashboard -type f -exec sed -i "s~__NEXT_PUBLIC_NHOST_ADMIN_SECRET__~${NEXT_PUBLIC_NHOST_ADMIN_SECRET}~g" {} +
find dashboard -type f -exec sed -i "s~__NEXT_PUBLIC_NHOST_AUTH_URL__~${NEXT_PUBLIC_NHOST_AUTH_URL}~g" {} +
find dashboard -type f -exec sed -i "s~__NEXT_PUBLIC_NHOST_FUNCTIONS_URL__~${NEXT_PUBLIC_NHOST_FUNCTIONS_URL}~g" {} +
find dashboard -type f -exec sed -i "s~__NEXT_PUBLIC_NHOST_GRAPHQL_URL__~${NEXT_PUBLIC_NHOST_GRAPHQL_URL}~g" {} +
find dashboard -type f -exec sed -i "s~__NEXT_PUBLIC_NHOST_STORAGE_URL__~${NEXT_PUBLIC_NHOST_STORAGE_URL}~g" {} +
find dashboard -type f -exec sed -i "s~__NEXT_PUBLIC_NHOST_HASURA_CONSOLE_URL__~${NEXT_PUBLIC_NHOST_HASURA_CONSOLE_URL}~g" {} +
find dashboard -type f -exec sed -i "s~__NEXT_PUBLIC_NHOST_HASURA_MIGRATIONS_API_URL__~${NEXT_PUBLIC_NHOST_HASURA_MIGRATIONS_API_URL}~g" {} +
find dashboard -type f -exec sed -i "s~__NEXT_PUBLIC_NHOST_HASURA_API_URL__~${NEXT_PUBLIC_NHOST_HASURA_API_URL}~g" {} +
exec "$@"

View File

@@ -0,0 +1,93 @@
import {
TEST_PROJECT_NAME,
TEST_PROJECT_SLUG,
TEST_WORKSPACE_SLUG,
} from '@/e2e/env';
import { openProject } from '@/e2e/utils';
import type { Page } from '@playwright/test';
import { expect, test } from '@playwright/test';
let page: Page;
test.describe.configure({ mode: 'serial' });
test.beforeAll(async ({ browser }) => {
page = await browser.newPage();
await page.goto('/');
await openProject({
page,
projectName: TEST_PROJECT_NAME,
workspaceSlug: TEST_WORKSPACE_SLUG,
projectSlug: TEST_PROJECT_SLUG,
});
await page
.getByRole('navigation', { name: /main navigation/i })
.getByRole('link', { name: /auth/i })
.click();
await page.waitForURL(`/${TEST_WORKSPACE_SLUG}/${TEST_PROJECT_SLUG}/users`);
});
test.afterAll(async () => {
await page.close();
});
test('should create a user', async () => {
await expect(
page.getByRole('heading', { name: /there are no users yet/i }),
).toBeVisible();
await page
.getByRole('button', { name: /create user/i })
.first()
.click();
await expect(page.getByRole('dialog')).toBeVisible();
await expect(
page.getByRole('heading', { name: /create user/i }),
).toBeVisible();
await page
.getByRole('textbox', { name: /email/i })
.fill('testuser@example.com');
await page.getByRole('textbox', { name: /password/i }).fill('test.password');
await page.getByRole('button', { name: /create/i, exact: true }).click();
await expect(page.getByRole('dialog')).not.toBeVisible();
await expect(
page.getByRole('button', { name: /view testuser@example.com/i }),
).toBeVisible();
});
test('should delete a user', async () => {
await expect(
page.getByRole('button', { name: /view testuser@example.com/i }),
).toBeVisible();
await page
.getByRole('button', { name: /more options for testuser@example.com/i })
.click();
await page.getByRole('menuitem', { name: /delete user/i }).click();
await expect(page.getByRole('dialog')).toBeVisible();
await expect(
page.getByRole('heading', { name: /delete user/i }),
).toBeVisible();
await expect(
page.getByText(
/are you sure you want to delete the "testuser@example.com" user?/i,
),
).toBeVisible();
await page.getByRole('button', { name: /delete/i, exact: true }).click();
await expect(page.getByRole('dialog')).not.toBeVisible();
await expect(
page.getByRole('heading', { name: /there are no users yet/i }),
).toBeVisible();
});

View File

@@ -0,0 +1,280 @@
import {
TEST_PROJECT_NAME,
TEST_PROJECT_SLUG,
TEST_WORKSPACE_SLUG,
} from '@/e2e/env';
import { openProject, prepareTable } from '@/e2e/utils';
import { faker } from '@faker-js/faker';
import type { Page } from '@playwright/test';
import { expect, test } from '@playwright/test';
import { snakeCase } from 'snake-case';
let page: Page;
test.beforeAll(async ({ browser }) => {
page = await browser.newPage();
});
test.beforeEach(async () => {
await page.goto('/');
await openProject({
page,
projectName: TEST_PROJECT_NAME,
workspaceSlug: TEST_WORKSPACE_SLUG,
projectSlug: TEST_PROJECT_SLUG,
});
await page
.getByRole('navigation', { name: /main navigation/i })
.getByRole('link', { name: /database/i })
.click();
});
test.afterAll(async () => {
await page.close();
});
test('should create a simple table', async () => {
await page.getByRole('button', { name: /new table/i }).click();
await expect(page.getByText(/create a new table/i)).toBeVisible();
const tableName = snakeCase(faker.lorem.words(3));
await prepareTable({
page,
name: tableName,
primaryKey: 'id',
columns: [
{ name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'title', type: 'text' },
],
});
// create table
await page.getByRole('button', { name: /create/i }).click();
await page.waitForURL(
`/${TEST_WORKSPACE_SLUG}/${TEST_PROJECT_SLUG}/database/browser/default/public/${tableName}`,
);
await expect(
page.getByRole('link', { name: tableName, exact: true }),
).toBeVisible();
});
test('should create a table with unique constraints', async () => {
await page.getByRole('button', { name: /new table/i }).click();
await expect(page.getByText(/create a new table/i)).toBeVisible();
const tableName = snakeCase(faker.lorem.words(3));
await prepareTable({
page,
name: tableName,
primaryKey: 'id',
columns: [
{ name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'title', type: 'text', unique: true },
{ name: 'isbn', type: 'text', unique: true },
],
});
// create table
await page.getByRole('button', { name: /create/i }).click();
await page.waitForURL(
`/${TEST_WORKSPACE_SLUG}/${TEST_PROJECT_SLUG}/database/browser/default/public/${tableName}`,
);
await expect(
page.getByRole('link', { name: tableName, exact: true }),
).toBeVisible();
});
test('should create a table with nullable columns', async () => {
await page.getByRole('button', { name: /new table/i }).click();
await expect(page.getByText(/create a new table/i)).toBeVisible();
const tableName = snakeCase(faker.lorem.words(3));
await prepareTable({
page,
name: tableName,
primaryKey: 'id',
columns: [
{ name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'title', type: 'text', nullable: true },
{ name: 'description', type: 'text', nullable: true },
],
});
// create table
await page.getByRole('button', { name: /create/i }).click();
await page.waitForURL(
`/${TEST_WORKSPACE_SLUG}/${TEST_PROJECT_SLUG}/database/browser/default/public/${tableName}`,
);
await expect(
page.getByRole('link', { name: tableName, exact: true }),
).toBeVisible();
});
test('should create a table with an identity column', async () => {
await page.getByRole('button', { name: /new table/i }).click();
await expect(page.getByText(/create a new table/i)).toBeVisible();
const tableName = snakeCase(faker.lorem.words(3));
await prepareTable({
page,
name: tableName,
primaryKey: 'id',
columns: [
{ name: 'id', type: 'int4' },
{ name: 'title', type: 'text', nullable: true },
{ name: 'description', type: 'text', nullable: true },
],
});
await page.getByRole('button', { name: /identity/i }).click();
await page.getByRole('option', { name: /id/i }).click();
// create table
await page.getByRole('button', { name: /create/i }).click();
await page.waitForURL(
`/${TEST_WORKSPACE_SLUG}/${TEST_PROJECT_SLUG}/database/browser/default/public/${tableName}`,
);
await expect(
page.getByRole('link', { name: tableName, exact: true }),
).toBeVisible();
});
test('should create table with foreign key constraint', async () => {
await page.getByRole('button', { name: /new table/i }).click();
await expect(page.getByText(/create a new table/i)).toBeVisible();
const firstTableName = snakeCase(faker.lorem.words(3));
await prepareTable({
page,
name: firstTableName,
primaryKey: 'id',
columns: [
{ name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'name', type: 'text' },
],
});
// create table
await page.getByRole('button', { name: /create/i }).click();
await page.waitForURL(
`/${TEST_WORKSPACE_SLUG}/${TEST_PROJECT_SLUG}/database/browser/default/public/${firstTableName}`,
);
await page.getByRole('button', { name: /new table/i }).click();
await expect(page.getByText(/create a new table/i)).toBeVisible();
const secondTableName = snakeCase(faker.lorem.words(3));
await prepareTable({
page,
name: secondTableName,
primaryKey: 'id',
columns: [
{ name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'title', type: 'text' },
{ name: 'author_id', type: 'uuid' },
],
});
await page.getByRole('button', { name: /add foreign key/i }).click();
// select column in current table
await page
.getByRole('button', { name: /column/i })
.first()
.click();
await page.getByRole('option', { name: /author_id/i }).click();
// select reference schema
await page.getByRole('button', { name: /schema/i }).click();
await page.getByRole('option', { name: /public/i }).click();
// select reference table
await page.getByRole('button', { name: /table/i }).click();
await page.getByRole('option', { name: firstTableName, exact: true }).click();
// select reference column
await page
.getByRole('button', { name: /column/i })
.nth(1)
.click();
await page.getByRole('option', { name: /id/i }).click();
await page.getByRole('button', { name: /add/i }).click();
await expect(
page.getByText(`public.${firstTableName}.id`, { exact: true }),
).toBeVisible();
// create table
await page.getByRole('button', { name: /create/i }).click();
await page.waitForURL(
`/${TEST_WORKSPACE_SLUG}/${TEST_PROJECT_SLUG}/database/browser/default/public/${secondTableName}`,
);
await expect(
page.getByRole('link', { name: secondTableName, exact: true }),
).toBeVisible();
});
test('should not be able to create a table with a name that already exists', async () => {
await page.getByRole('button', { name: /new table/i }).click();
await expect(page.getByText(/create a new table/i)).toBeVisible();
const tableName = snakeCase(faker.lorem.words(3));
await prepareTable({
page,
name: tableName,
primaryKey: 'id',
columns: [
{ name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'name', type: 'text' },
],
});
// create table
await page.getByRole('button', { name: /create/i }).click();
await page.waitForURL(
`/${TEST_WORKSPACE_SLUG}/${TEST_PROJECT_SLUG}/database/browser/default/public/${tableName}`,
);
await page.getByRole('button', { name: /new table/i }).click();
await expect(page.getByText(/create a new table/i)).toBeVisible();
await prepareTable({
page,
name: tableName,
primaryKey: 'id',
columns: [
{ name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'title', type: 'text' },
{ name: 'author_id', type: 'uuid' },
],
});
// create table
await page.getByRole('button', { name: /create/i }).click();
await expect(
page.getByText(/error: a table with this name already exists/i),
).toBeVisible();
});

View File

@@ -0,0 +1,165 @@
import {
TEST_PROJECT_NAME,
TEST_PROJECT_SLUG,
TEST_WORKSPACE_SLUG,
} from '@/e2e/env';
import { deleteTable, openProject, prepareTable } from '@/e2e/utils';
import { faker } from '@faker-js/faker';
import type { Page } from '@playwright/test';
import { expect, test } from '@playwright/test';
import { snakeCase } from 'snake-case';
let page: Page;
test.beforeAll(async ({ browser }) => {
page = await browser.newPage();
});
test.beforeEach(async () => {
await page.goto('/');
await openProject({
page,
projectName: TEST_PROJECT_NAME,
workspaceSlug: TEST_WORKSPACE_SLUG,
projectSlug: TEST_PROJECT_SLUG,
});
await page
.getByRole('navigation', { name: /main navigation/i })
.getByRole('link', { name: /database/i })
.click();
});
test.afterAll(async () => {
await page.close();
});
test('should delete a table', async () => {
const tableName = snakeCase(faker.lorem.words(3));
await page.getByRole('button', { name: /new table/i }).click();
await prepareTable({
page,
name: tableName,
primaryKey: 'id',
columns: [
{ name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'title', type: 'text' },
],
});
await page.getByRole('button', { name: /create/i }).click();
await page.waitForURL(
`/${TEST_WORKSPACE_SLUG}/${TEST_PROJECT_SLUG}/database/browser/default/public/${tableName}`,
);
await deleteTable({
page,
name: tableName,
});
// navigate to next URL
await page.waitForURL(
`/${TEST_WORKSPACE_SLUG}/${TEST_PROJECT_SLUG}/database/browser/default/public/**`,
);
await expect(
page.getByRole('link', { name: tableName, exact: true }),
).not.toBeVisible();
});
test('should not be able to delete a table if other tables have foreign keys referencing it', async () => {
await page.getByRole('button', { name: /new table/i }).click();
await expect(page.getByText(/create a new table/i)).toBeVisible();
const firstTableName = snakeCase(faker.lorem.words(3));
await prepareTable({
page,
name: firstTableName,
primaryKey: 'id',
columns: [
{ name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'name', type: 'text' },
],
});
// create table
await page.getByRole('button', { name: /create/i }).click();
await page.waitForURL(
`/${TEST_WORKSPACE_SLUG}/${TEST_PROJECT_SLUG}/database/browser/default/public/${firstTableName}`,
);
await page.getByRole('button', { name: /new table/i }).click();
await expect(page.getByText(/create a new table/i)).toBeVisible();
const secondTableName = snakeCase(faker.lorem.words(3));
await prepareTable({
page,
name: secondTableName,
primaryKey: 'id',
columns: [
{ name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'title', type: 'text' },
{ name: 'author_id', type: 'uuid' },
],
});
await page.getByRole('button', { name: /add foreign key/i }).click();
// select column in current table
await page
.getByRole('button', { name: /column/i })
.first()
.click();
await page.getByRole('option', { name: /author_id/i }).click();
// select reference schema
await page.getByRole('button', { name: /schema/i }).click();
await page.getByRole('option', { name: /public/i }).click();
// select reference table
await page.getByRole('button', { name: /table/i }).click();
await page.getByRole('option', { name: firstTableName, exact: true }).click();
// select reference column
await page
.getByRole('button', { name: /column/i })
.nth(1)
.click();
await page.getByRole('option', { name: /id/i }).click();
await page.getByRole('button', { name: /add/i }).click();
await expect(
page.getByText(`public.${firstTableName}.id`, { exact: true }),
).toBeVisible();
// create table
await page.getByRole('button', { name: /create/i }).click();
await page.waitForURL(
`/${TEST_WORKSPACE_SLUG}/${TEST_PROJECT_SLUG}/database/browser/default/public/${secondTableName}`,
);
await expect(
page.getByRole('link', { name: secondTableName, exact: true }),
).toBeVisible();
// try to delete the first table that is referenced by the second table
await deleteTable({
page,
name: firstTableName,
});
await expect(
page.getByText(
/constraint [a-zA-Z_]+ on table [a-zA-Z_]+ depends on table [a-zA-Z_]+/i,
),
).toBeVisible();
});

48
dashboard/e2e/env.ts Normal file
View File

@@ -0,0 +1,48 @@
import slugify from 'slugify';
/**
* URL of the dashboard to test against.
*/
export const TEST_DASHBOARD_URL = process.env.NHOST_TEST_DASHBOARD_URL;
/**
* Name of the workspace to test against.
*/
export const TEST_WORKSPACE_NAME = process.env.NHOST_TEST_WORKSPACE_NAME;
/**
* Slugified name of the workspace to test against.
*/
export const TEST_WORKSPACE_SLUG = slugify(TEST_WORKSPACE_NAME, {
lower: true,
strict: true,
});
/**
* Name of the project to test against.
*/
export const TEST_PROJECT_NAME = process.env.NHOST_TEST_PROJECT_NAME;
/**
* Slugified name of the project to test against.
*/
export const TEST_PROJECT_SLUG = slugify(TEST_PROJECT_NAME, {
lower: true,
strict: true,
});
/**
* Hasura admin secret of the test project to use.
*/
export const TEST_PROJECT_ADMIN_SECRET =
process.env.NHOST_TEST_PROJECT_ADMIN_SECRET;
/**
* Email of the test account to use.
*/
export const TEST_USER_EMAIL = process.env.NHOST_TEST_USER_EMAIL;
/**
* Password of the test account to use.
*/
export const TEST_USER_PASSWORD = process.env.NHOST_TEST_USER_PASSWORD;

View File

@@ -0,0 +1,109 @@
import {
TEST_PROJECT_NAME,
TEST_PROJECT_SLUG,
TEST_WORKSPACE_NAME,
TEST_WORKSPACE_SLUG,
} from '@/e2e/env';
import { openProject } from '@/e2e/utils';
import type { Page } from '@playwright/test';
import { expect, test } from '@playwright/test';
let page: Page;
test.beforeAll(async ({ browser }) => {
page = await browser.newPage();
await page.goto('/');
await openProject({
page,
projectName: TEST_PROJECT_NAME,
workspaceSlug: TEST_WORKSPACE_SLUG,
projectSlug: TEST_PROJECT_SLUG,
});
});
test.afterAll(async () => {
await page.close();
});
test('should show a sidebar with menu items', async () => {
const navLocator = page.getByRole('navigation', { name: /main navigation/i });
await expect(navLocator).toBeVisible();
await expect(navLocator.getByRole('list').getByRole('listitem')).toHaveCount(
10,
);
await expect(
navLocator.getByRole('link', { name: /overview/i }),
).toBeVisible();
await expect(
navLocator.getByRole('link', { name: /database/i }),
).toBeVisible();
await expect(
navLocator.getByRole('link', { name: /graphql/i }),
).toBeVisible();
await expect(navLocator.getByRole('link', { name: /hasura/i })).toBeVisible();
await expect(navLocator.getByRole('link', { name: /auth/i })).toBeVisible();
await expect(
navLocator.getByRole('link', { name: /storage/i }),
).toBeVisible();
await expect(
navLocator.getByRole('link', { name: /deployments/i }),
).toBeVisible();
await expect(
navLocator.getByRole('link', { name: /backups/i }),
).toBeVisible();
await expect(navLocator.getByRole('link', { name: /logs/i })).toBeVisible();
await expect(
navLocator.getByRole('link', { name: /settings/i }),
).toBeVisible();
});
test('should show a header with a logo, the workspace name, and the project name', async () => {
await expect(
page.getByRole('banner').getByRole('link', { name: TEST_WORKSPACE_NAME }),
).toBeVisible();
await expect(
page.getByRole('banner').getByRole('link', { name: TEST_PROJECT_NAME }),
).toBeVisible();
});
test("should show the project's name, the Upgrade button and the Settings button", async () => {
await expect(
page.getByRole('heading', { name: TEST_PROJECT_NAME }),
).toBeVisible();
await expect(page.getByText(/free plan/i)).toBeVisible();
await expect(page.getByRole('button', { name: /upgrade/i })).toBeVisible();
await expect(
page.getByRole('main').getByRole('link', { name: /settings/i }),
).toBeVisible();
});
test("should show the project's region and subdomain", async () => {
await expect(page.locator('p:has-text("Region") + div p').nth(0)).toHaveText(
/frankfurt \(eu-central-1\)/i,
);
await expect(
page.locator('p:has-text("Subdomain") + div p').nth(0),
).toHaveText(/[a-z]{20}/i);
});
test('should not have a GitHub repository connected', async () => {
await expect(
page.getByRole('button', { name: /connect to github/i }),
).toBeVisible();
});
test('should show proper limits for the free project', async () => {
// Limit for Database
await expect(page.getByText(/of 500 MB/i)).toBeVisible();
// Limit for Storage
await expect(page.getByText(/of 1 GB/i)).toBeVisible();
// Limit for Users
await expect(page.getByText(/of 10000/i)).toBeVisible();
// Limit for Functions
await expect(page.getByText(/of 10$/i, { exact: true })).toBeVisible();
});

150
dashboard/e2e/utils.ts Normal file
View File

@@ -0,0 +1,150 @@
import type { Page } from '@playwright/test';
/**
* Open a project by navigating to the project's overview page.
*
* @param page - The Playwright page object.
* @param workspaceSlug - The slug of the workspace that contains the project.
* @param projectSlug - The slug of the project to open.
* @param projectName - The name of the project to open.
* @returns A promise that resolves when the project is opened.
*/
export async function openProject({
page,
projectName,
workspaceSlug,
projectSlug,
}: {
page: Page;
workspaceSlug: string;
projectSlug: string;
projectName: string;
}) {
await page.getByRole('link', { name: projectName }).click();
await page.waitForURL(`/${workspaceSlug}/${projectSlug}`);
}
/**
* Prepares a table by filling out the form.
*
* @param page - The Playwright page object.
* @param name - The name of the table to create.
* @param columns - The columns to create in the table.
* @returns A promise that resolves when the table is prepared.
*/
export async function prepareTable({
page,
name: tableName,
primaryKey,
columns,
}: {
page: Page;
name: string;
primaryKey: string;
columns: Array<{
name: string;
type: string;
nullable?: boolean;
unique?: boolean;
defaultValue?: string;
}>;
}) {
if (!columns.some(({ name }) => name === primaryKey)) {
throw new Error('Primary key must be one of the columns.');
}
await page.getByRole('textbox', { name: /name/i }).first().fill(tableName);
await Promise.all(
columns.map(
async (
{ name: columnName, type, nullable, unique, defaultValue },
index,
) => {
// set name
await page.getByPlaceholder(/name/i).nth(index).fill(columnName);
// set type
await page
.getByRole('table')
.getByRole('combobox', { name: /type/i })
.nth(index)
.type(type);
await page
.getByRole('table')
.getByRole('option', { name: type })
.first()
.click();
// optionally set default value
if (defaultValue) {
await page
.getByRole('table')
.getByRole('combobox', { name: /default value/i })
.nth(index)
.type(defaultValue);
await page
.getByRole('table')
.getByRole('option', { name: defaultValue })
.first()
.click();
}
// optionally check unique
if (unique) {
await page
.getByRole('checkbox', { name: /unique/i })
.nth(index)
.check();
}
// optionally check nullable
if (nullable) {
await page
.getByRole('checkbox', { name: /nullable/i })
.nth(index)
.check();
}
// add new column if not last
if (index < columns.length - 1) {
await page.getByRole('button', { name: /add column/i }).click();
}
},
),
);
// select the first column as primary key
await page.getByRole('button', { name: /primary key/i }).click();
await page.getByRole('option', { name: primaryKey, exact: true }).click();
}
/**
* Deletes a table with the given name.
*
* @param page - The Playwright page object.
* @param name - The name of the table to delete.
* @returns A promise that resolves when the table is deleted.
*/
export async function deleteTable({
page,
name,
}: {
page: Page;
name: string;
}) {
const tableLink = page.getByRole('link', {
name,
exact: true,
});
await tableLink.hover();
await page
.getByRole('listitem')
.filter({ hasText: name })
.getByRole('button')
.click();
await page.getByRole('menuitem', { name: /delete table/i }).click();
await page.getByRole('button', { name: /delete/i }).click();
}

27
dashboard/global-setup.ts Normal file
View File

@@ -0,0 +1,27 @@
import {
TEST_DASHBOARD_URL,
TEST_USER_EMAIL,
TEST_USER_PASSWORD,
} from '@/e2e/env';
import { chromium } from '@playwright/test';
async function globalSetup() {
const browser = await chromium.launch();
const page = await browser.newPage({ baseURL: TEST_DASHBOARD_URL });
await page.goto('/');
await page.waitForURL('/signin');
await page.getByRole('link', { name: /continue with email/i }).click();
await page.waitForURL('/signin/email');
await page.getByLabel('Email').fill(TEST_USER_EMAIL);
await page.getByLabel('Password').fill(TEST_USER_PASSWORD);
await page.getByRole('button', { name: /sign in/i }).click();
await page.waitForURL(TEST_DASHBOARD_URL);
await page.context().storageState({ path: 'storageState.json' });
await browser.close();
}
export default globalSetup;

View File

@@ -0,0 +1,66 @@
import {
TEST_DASHBOARD_URL,
TEST_PROJECT_ADMIN_SECRET,
TEST_PROJECT_NAME,
TEST_PROJECT_SLUG,
TEST_WORKSPACE_SLUG,
} from '@/e2e/env';
import { openProject } from '@/e2e/utils';
import { chromium } from '@playwright/test';
async function globalTeardown() {
const browser = await chromium.launch();
const context = await browser.newContext({
baseURL: TEST_DASHBOARD_URL,
storageState: 'storageState.json',
});
const page = await context.newPage();
await page.goto('/');
await openProject({
page,
projectName: TEST_PROJECT_NAME,
workspaceSlug: TEST_WORKSPACE_SLUG,
projectSlug: TEST_PROJECT_SLUG,
});
const pagePromise = context.waitForEvent('page');
await page.getByRole('link', { name: /hasura/i }).click();
await page.getByRole('link', { name: /open hasura/i }).click();
const hasuraPage = await pagePromise;
await hasuraPage.waitForLoadState();
const adminSecretInput = hasuraPage.getByPlaceholder(/enter admin-secret/i);
// note: a more ideal way would be to paste from clipboard, but Playwright
// doesn't support that yet
await adminSecretInput.fill(TEST_PROJECT_ADMIN_SECRET);
await adminSecretInput.press('Enter');
// note: getByRole doesn't work here
await hasuraPage.locator('a', { hasText: /data/i }).click();
await hasuraPage.getByRole('link', { name: /sql/i }).click();
await hasuraPage.getByRole('textbox').fill(`
DO $$ DECLARE
tablename text;
BEGIN
FOR tablename IN
SELECT table_name FROM information_schema.tables
WHERE table_schema = 'public'
LOOP
EXECUTE 'DROP TABLE IF EXISTS public.' || quote_ident(tablename) || ' CASCADE';
END LOOP;
END $$;
`);
await hasuraPage.getByRole('button', { name: /run!/i }).click();
await hasuraPage.getByText(/sql executed!/i).waitFor();
}
export default globalTeardown;

View File

@@ -1,5 +1,5 @@
schema:
- http://localhost:1337/v1/graphql:
- https://local.graphql.nhost.run/v1:
headers:
x-hasura-admin-secret: nhost-admin-secret
generates:

View File

@@ -2,6 +2,7 @@ const path = require('path');
const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true',
});
const { version } = require('./package.json');
module.exports = withBundleAnalyzer({
reactStrictMode: true,
@@ -10,6 +11,9 @@ module.exports = withBundleAnalyzer({
experimental: {
outputFileTracingRoot: path.join(__dirname, '../../'),
},
publicRuntimeConfig: {
version,
},
eslint: {
dirs: ['src'],
},

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/dashboard",
"version": "0.11.3",
"version": "0.14.1",
"private": true,
"scripts": {
"preinstall": "npx only-allow pnpm",
@@ -14,10 +14,11 @@
"nhost:dev": "nhost dev -d",
"format": "prettier --write \"src/**/*.{js,ts,tsx,jsx,json,md}\" --plugin-search-dir=.",
"storybook": "start-storybook -p 6006 -s public",
"build-storybook": "build-storybook"
"build-storybook": "build-storybook",
"e2e": "npx playwright@1.31.2 install --with-deps && playwright test"
},
"dependencies": {
"@apollo/client": "^3.7.3",
"@apollo/client": "^3.7.10",
"@codemirror/language": "^6.3.0",
"@emotion/cache": "^11.10.5",
"@emotion/react": "^11.10.5",
@@ -25,11 +26,11 @@
"@emotion/styled": "^11.10.5",
"@fontsource/inter": "^4.5.14",
"@fontsource/roboto-mono": "^4.5.8",
"@graphiql/react": "^0.15.0",
"@graphiql/toolkit": "^0.8.0",
"@graphiql/react": "^0.17.0",
"@graphiql/toolkit": "^0.8.2",
"@headlessui/react": "^1.6.5",
"@heroicons/react": "^1.0.6",
"@hookform/resolvers": "^2.9.10",
"@hookform/resolvers": "^3.0.0",
"@mui/base": "^5.0.0-alpha.106",
"@mui/material": "^5.10.14",
"@mui/system": "^5.10.14",
@@ -37,20 +38,18 @@
"@nhost/nextjs": "workspace:*",
"@nhost/react-apollo": "workspace:*",
"@segment/snippet": "^4.15.3",
"@stripe/react-stripe-js": "^1.10.0",
"@stripe/react-stripe-js": "^2.0.0",
"@stripe/stripe-js": "^1.35.0",
"@tailwindcss/forms": "^0.5.3",
"@tanstack/react-query": "^4.16.1",
"@tanstack/react-table": "^8.5.30",
"@tanstack/react-virtual": "^3.0.0-beta.23",
"analytics-node": "^6.2.0",
"axios": "^0.27.2",
"bcryptjs": "^2.4.3",
"clsx": "^1.2.1",
"cross-fetch": "^3.1.5",
"date-fns": "^2.29.3",
"generate-password": "^1.7.0",
"graphiql": "^2.2.0",
"graphiql": "^2.4.0",
"graphql": "^16.6.0",
"graphql-request": "^4.3.0",
"graphql-tag": "^2.12.6",
@@ -64,31 +63,33 @@
"prettysize": "^2.0.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-error-boundary": "^3.1.4",
"react-hook-form": "^7.39.5",
"react-error-boundary": "^4.0.0",
"react-hook-form": "^7.42.1",
"react-hot-toast": "^2.4.0",
"react-is": "17.0.2",
"react-is": "18.2.0",
"react-loading-skeleton": "^2.2.0",
"react-merge-refs": "^1.1.0",
"react-syntax-highlighter": "^15.4.5",
"react-table": "^7.8.0",
"sharp": "^0.31.2",
"sharp": "^0.32.0",
"slugify": "^1.6.5",
"stripe": "^10.17.0",
"tailwind-merge": "^1.8.0",
"utility-types": "^3.10.0",
"validator": "^13.7.0",
"yup": "^0.32.11",
"yup": "^1.0.2",
"yup-password": "^0.2.2"
},
"devDependencies": {
"@babel/core": "^7.20.2",
"@graphql-codegen/cli": "^2.8.0",
"@graphql-codegen/typescript": "^2.7.1",
"@faker-js/faker": "^7.6.0",
"@graphql-codegen/cli": "^3.0.0",
"@graphql-codegen/typescript": "^3.0.0",
"@graphql-codegen/typescript-graphql-request": "^4.5.1",
"@graphql-codegen/typescript-operations": "^2.5.1",
"@graphql-codegen/typescript-operations": "^3.0.0",
"@graphql-codegen/typescript-react-apollo": "^3.3.1",
"@next/bundle-analyzer": "^12.3.1",
"@playwright/test": "^1.31.2",
"@storybook/addon-actions": "^6.5.14",
"@storybook/addon-essentials": "^6.5.14",
"@storybook/addon-interactions": "^6.5.14",
@@ -98,26 +99,28 @@
"@storybook/manager-webpack5": "^6.5.14",
"@storybook/react": "^6.5.14",
"@storybook/testing-library": "^0.0.13",
"@testing-library/dom": "^8.19.0",
"@testing-library/dom": "^9.0.0",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^14.4.3",
"@types/lodash.debounce": "^4.0.7",
"@types/node": "^16.11.7",
"@types/pluralize": "^0.0.29",
"@types/react": "18.0.25",
"@types/react-dom": "18.0.10",
"@types/react": "18.0.30",
"@types/react-dom": "18.0.11",
"@types/react-table": "^7.7.12",
"@types/testing-library__jest-dom": "^5.14.5",
"@types/validator": "^13.7.10",
"@typescript-eslint/eslint-plugin": "^5.43.0",
"@typescript-eslint/parser": "^5.43.0",
"@vitejs/plugin-react": "^3.0.0",
"@vitest/coverage-c8": "^0.27.0",
"@vitest/coverage-c8": "^0.29.0",
"autoprefixer": "^10.4.13",
"babel-loader": "^8.3.0",
"babel-plugin-transform-remove-console": "^6.9.4",
"csstype": "^3.0.10",
"dotenv": "^16.0.3",
"encoding": "^0.1.13",
"eslint": "^8.28.0",
"eslint-config-airbnb": "19.0.4",
"eslint-config-airbnb-typescript": "^17.0.0",
@@ -129,22 +132,23 @@
"eslint-plugin-react-hooks": "^4.6.0",
"jsdom": "^21.0.0",
"lint-staged": ">=13",
"msw": "^0.49.0",
"msw": "^1.0.1",
"msw-storybook-addon": "^1.6.3",
"node-fetch": "^3.3.0",
"postcss": "^8.4.19",
"prettier": "^2.7.1",
"prettier-plugin-organize-imports": "^3.2.0",
"prettier-plugin-tailwindcss": "^0.2.0",
"react-date-fns-hooks": "^0.9.4",
"require-from-string": "^2.0.2",
"snake-case": "^3.0.4",
"storybook-addon-next-router": "^4.0.1",
"tailwindcss": "^3.1.2",
"ts-node": "^10.9.1",
"tsconfig-paths-webpack-plugin": "^4.0.0",
"typescript": "^4.8.4",
"vite": "^4.0.2",
"vite-tsconfig-paths": "^4.0.3",
"vitest": "^0.27.0",
"vitest": "^0.29.0",
"webpack": "^5.75.0"
},
"browserslist": {
@@ -162,4 +166,4 @@
"msw": {
"workerDirectory": "public"
}
}
}

View File

@@ -0,0 +1,33 @@
import { defineConfig, devices } from '@playwright/test';
import dotenv from 'dotenv';
import path from 'path';
dotenv.config({ path: path.resolve(__dirname, '.env.test') });
export default defineConfig({
testDir: './e2e',
timeout: 30 * 1000,
expect: {
timeout: 5000,
},
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: 'html',
globalSetup: require.resolve('./global-setup'),
globalTeardown: require.resolve('./global-teardown'),
use: {
actionTimeout: 0,
trace: 'on-first-retry',
storageState: 'storageState.json',
baseURL: process.env.NHOST_TEST_DASHBOARD_URL,
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
],
});

View File

@@ -1,17 +0,0 @@
<svg width="142" height="48" viewBox="0 0 142 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M75.985 22.8273H83.1731V17.1251H86.9756V31.7529H83.1731V26.0506H75.985V31.7529H72.3164V17.1251H75.985V22.8273ZM101.48 17.1251H95.6099C93.9842 17.1251 92.9947 17.4319 92.2458 18.1792C91.4999 18.9235 91.2137 19.8684 91.2137 21.5362V27.3478C91.2137 29.0157 91.4999 29.9575 92.2458 30.7048C92.9917 31.4522 93.9811 31.759 95.6099 31.759H101.48C103.105 31.759 104.095 31.4522 104.844 30.7048C105.593 29.9605 105.876 29.0157 105.876 27.3478V21.5362C105.876 19.8684 105.59 18.9266 104.844 18.1792C104.095 17.4319 103.105 17.1251 101.48 17.1251ZM102.204 27.4329C102.204 28.2896 101.918 28.5296 100.886 28.5296H96.2036C95.1715 28.5296 94.8853 28.2896 94.8853 27.4329V21.4451C94.8853 20.5884 95.1715 20.3484 96.2036 20.3484H100.886C101.942 20.3484 102.204 20.5671 102.204 21.4451V27.4329ZM114.972 22.9792H120.224C121.85 22.9792 122.861 23.2861 123.588 24.0334C124.246 24.6927 124.62 25.7651 124.62 26.9286V27.8066C124.62 28.9701 124.246 30.0213 123.588 30.7018C122.861 31.4491 121.871 31.756 120.224 31.756H110.202V28.5327H119.609C120.641 28.5327 120.927 28.2927 120.927 27.4359V26.9985C120.927 26.1418 120.641 25.9018 119.609 25.9018H114.357C112.729 25.9018 111.718 25.5919 110.993 24.8476C110.336 24.1884 109.961 23.1159 109.961 21.9524V21.0744C109.961 19.9109 110.333 18.8597 110.993 18.1792C111.721 17.4319 112.707 17.1251 114.357 17.1251H123.856V20.3484H114.972C113.94 20.3484 113.654 20.5884 113.654 21.4451V21.8825C113.654 22.7392 113.94 22.9792 114.972 22.9792ZM126.946 20.3484V17.1251H141.891V20.3484H136.265V31.7529H132.594V20.3484H126.946Z" fill="#21324B"/>
<path d="M63.5321 17.0096H57.6624C56.0366 17.0096 55.0471 17.3164 54.2982 18.0638C53.5523 18.8081 53.2661 19.7529 53.2661 21.4177V23.6385V24.322V31.7499H56.9378V24.3251V23.6415V21.3327C56.9378 20.4759 57.224 20.2359 58.256 20.2359H62.9385C63.9949 20.2359 64.2567 20.4547 64.2567 21.3327V23.6415V24.3251V31.7529H67.9284V24.3251V23.6415V21.4208C67.9284 19.7529 67.6422 18.8111 66.8963 18.0668C66.1504 17.3164 65.1609 17.0096 63.5321 17.0096Z" fill="#0052CD"/>
<g clip-path="url(#clip1)">
<path d="M40.8114 10.2866L24.0819 0.647089C22.581 -0.215696 20.7178 -0.215696 19.2138 0.647089C17.7129 1.51291 16.7813 3.12304 16.7813 4.85165V6.10937L15.6913 5.48051C14.1904 4.61772 12.3272 4.61772 10.8232 5.48051C9.32224 6.34633 8.39063 7.95646 8.39063 9.6881V10.9458L7.3007 10.317C5.79976 9.45418 3.93653 9.45418 2.43255 10.317C0.931612 11.1828 0 12.7929 0 14.5246V44.7281C0 45.597 0.505383 46.4051 1.29086 46.7818C2.0733 47.1615 3.02318 47.0582 3.70515 46.5205L12.0014 39.9919L24.7944 47.362C25.1475 47.5656 25.5433 47.6658 25.9391 47.6658C26.3349 47.6658 26.7307 47.5625 27.0838 47.362C27.7901 46.9549 28.2285 46.1985 28.2285 45.3843V27.2081C28.2285 24.2248 26.6211 21.4481 24.0332 19.9565L19.8379 17.5382V4.85468C19.8379 4.21063 20.185 3.60911 20.7452 3.28709C21.3054 2.96506 21.9995 2.96506 22.5597 3.28709L39.2892 12.9235C40.9363 13.8714 41.9592 15.6425 41.9592 17.5382V40.1711C41.9592 40.8152 41.6121 41.4167 41.052 41.7387L36.6192 44.2937V22.3716C36.6192 19.3884 35.0117 16.6116 32.4239 15.12L22.1243 9.18684V12.7018L30.8986 17.757C32.5456 18.7048 33.5686 20.4729 33.5686 22.3716V45.6091C33.5686 46.4203 34.007 47.1797 34.7133 47.5868C35.0665 47.7904 35.4623 47.8906 35.8581 47.8906C36.2538 47.8906 36.6496 47.7873 37.0028 47.5868L42.5803 44.3727C44.0812 43.5068 45.0128 41.8967 45.0128 40.1651V17.5322C45.0068 14.558 43.3993 11.7782 40.8114 10.2866ZM22.5019 22.5934C24.1489 23.5413 25.1719 25.3094 25.1719 27.2081V44.0689L14.577 37.9656L17.9777 35.2921C19.156 34.3656 19.8318 32.9772 19.8318 31.4795V21.0592L22.5019 22.5934ZM16.7813 19.2972V31.4734C16.7813 32.0324 16.5286 32.5519 16.0902 32.8952L3.05058 43.1544V14.5215C3.05058 13.8775 3.39766 13.2759 3.95784 12.9539C4.51803 12.6319 5.21217 12.6319 5.77236 12.9539L8.39063 14.4608V36.0456L11.4412 33.6456V9.6881C11.4412 9.04405 11.7883 8.44253 12.3485 8.12051C12.9087 7.79848 13.6028 7.79848 14.163 8.12051L16.7813 9.62734V15.7792L13.7307 14.0203V17.5382L16.7813 19.2972Z" fill="#0052CD"/>
</g>
</g>
<defs>
<clipPath id="clip0">
<rect width="141.873" height="48" fill="white"/>
</clipPath>
<clipPath id="clip1">
<rect width="45.0128" height="47.8906" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 4.3 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.5 KiB

View File

@@ -1 +0,0 @@
<svg width="150" height="30" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M123.477 14.573c0-2.369 1.633-3.936 3.759-3.936s3.758 1.567 3.758 3.936c0 2.369-1.632 3.936-3.758 3.936-2.126-.037-3.759-1.604-3.759-3.936Zm4.252 7.361c3.758 0 7.023-3.134 7.023-7.398 0-4.263-3.265-7.397-7.023-7.397-2.468 0-3.91 1.42-3.91 1.42V2h-3.797v19.789h2.772l.645-1.422c.038 0 1.671 1.567 4.29 1.567Zm-14.73-7.361c0 2.369-1.632 3.936-3.758 3.936-2.127 0-3.759-1.567-3.759-3.936 0-2.369 1.632-3.936 3.759-3.936 2.126 0 3.758 1.567 3.758 3.936Zm-4.252 7.361c2.62 0 4.252-1.567 4.252-1.567l.645 1.422h2.772V7.357h-2.772l-.645 1.421s-1.632-1.567-4.252-1.567c-3.759 0-7.024 3.134-7.024 7.398 0 4.264 3.265 7.325 7.024 7.325ZM98.952 2h-3.758v19.789h3.758V2Zm-7.365 5.175c-2.278 0-3.606 1.713-3.606 1.713l-.646-1.567h-2.771v14.431h3.758V14.1c0-1.895 1.29-3.134 3.113-3.134.835 0 1.291.146 1.291.146V7.357s-.493-.182-1.139-.182Zm-17.008 3.462c1.974 0 3.265 1.24 3.607 2.843h-7.214c.304-1.604 1.633-2.843 3.607-2.843Zm2.771 6.742s-.835 1.093-2.771 1.093-3.113-1.093-3.417-2.514H81.64s.152-.802.152-1.421c0-4.41-3.265-7.399-7.213-7.399-4.1 0-7.517 3.28-7.517 7.399 0 4.118 3.417 7.397 7.517 7.397 3.417 0 5.885-2.368 6.72-4.555H77.35Zm-23.575-2.806c0-2.369 1.632-3.936 3.758-3.936 2.126 0 3.758 1.567 3.758 3.936 0 2.369-1.632 3.936-3.758 3.936-2.126-.037-3.758-1.604-3.758-3.936Zm4.252-7.398c-2.62 0-4.252 1.567-4.252 1.567l-.646-1.421h-2.771v19.46h3.758v-6.268s1.48 1.421 3.91 1.421c3.759 0 7.024-3.134 7.024-7.398 0-4.263-3.265-7.361-7.023-7.361ZM39.081 21.169l-.341.802c-.456 1.093-1.291 1.895-2.962 1.895v2.988s.646.146 1.291.146c2.468 0 3.759-1.239 5.24-4.701.341-.802 6.036-14.905 6.036-14.905h-3.873l-3.416 9.438-3.797-9.475h-3.91l5.732 13.812ZM16 4.515v17.274h3.91v-7.216h7.365v7.216h3.91V4.515h-3.91v6.596H19.91V4.515H16Z" fill="#000"/></svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.5 KiB

View File

@@ -1 +0,0 @@
<svg width="150" height="30" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M123.477 14.573c0-2.369 1.633-3.936 3.759-3.936s3.758 1.567 3.758 3.936c0 2.369-1.632 3.936-3.758 3.936-2.126-.037-3.759-1.604-3.759-3.936Zm4.252 7.361c3.758 0 7.023-3.134 7.023-7.398 0-4.263-3.265-7.397-7.023-7.397-2.468 0-3.91 1.42-3.91 1.42V2h-3.797v19.789h2.772l.645-1.422c.038 0 1.671 1.567 4.29 1.567Zm-14.73-7.361c0 2.369-1.632 3.936-3.758 3.936-2.127 0-3.759-1.567-3.759-3.936 0-2.369 1.632-3.936 3.759-3.936 2.126 0 3.758 1.567 3.758 3.936Zm-4.252 7.361c2.62 0 4.252-1.567 4.252-1.567l.645 1.422h2.772V7.357h-2.772l-.645 1.421s-1.632-1.567-4.252-1.567c-3.759 0-7.024 3.134-7.024 7.398 0 4.264 3.265 7.325 7.024 7.325ZM98.952 2h-3.758v19.789h3.758V2Zm-7.365 5.175c-2.278 0-3.606 1.713-3.606 1.713l-.646-1.567h-2.771v14.431h3.758V14.1c0-1.895 1.29-3.134 3.113-3.134.835 0 1.291.146 1.291.146V7.357s-.493-.182-1.139-.182Zm-17.008 3.462c1.974 0 3.265 1.24 3.607 2.843h-7.214c.304-1.604 1.633-2.843 3.607-2.843Zm2.771 6.742s-.835 1.093-2.771 1.093-3.113-1.093-3.417-2.514H81.64s.152-.802.152-1.421c0-4.41-3.265-7.399-7.213-7.399-4.1 0-7.517 3.28-7.517 7.399 0 4.118 3.417 7.397 7.517 7.397 3.417 0 5.885-2.368 6.72-4.555H77.35Zm-23.575-2.806c0-2.369 1.632-3.936 3.758-3.936 2.126 0 3.758 1.567 3.758 3.936 0 2.369-1.632 3.936-3.758 3.936-2.126-.037-3.758-1.604-3.758-3.936Zm4.252-7.398c-2.62 0-4.252 1.567-4.252 1.567l-.646-1.421h-2.771v19.46h3.758v-6.268s1.48 1.421 3.91 1.421c3.759 0 7.024-3.134 7.024-7.398 0-4.263-3.265-7.361-7.023-7.361ZM39.081 21.169l-.341.802c-.456 1.093-1.291 1.895-2.962 1.895v2.988s.646.146 1.291.146c2.468 0 3.759-1.239 5.24-4.701.341-.802 6.036-14.905 6.036-14.905h-3.873l-3.416 9.438-3.797-9.475h-3.91l5.732 13.812ZM16 4.515v17.274h3.91v-7.216h7.365v7.216h3.91V4.515h-3.91v6.596H19.91V4.515H16Z" fill="#fff"/></svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="142" height="48" fill="none"><g clip-path="url(#a)"><path fill="#fff" fill-rule="evenodd" d="M75.985 22.827h7.188v-5.702h3.803v14.628h-3.803V26.05h-7.188v5.702h-3.669V17.125h3.669v5.702Zm25.495-5.702h-5.87c-1.626 0-2.615.307-3.364 1.054-.746.745-1.032 1.69-1.032 3.357v5.812c0 1.668.286 2.61 1.032 3.357.746.747 1.735 1.054 3.364 1.054h5.87c1.625 0 2.615-.307 3.364-1.054.749-.744 1.032-1.69 1.032-3.357v-5.812c0-1.668-.286-2.61-1.032-3.357-.749-.747-1.739-1.054-3.364-1.054Zm.724 10.308c0 .857-.286 1.097-1.318 1.097h-4.682c-1.032 0-1.319-.24-1.319-1.097v-5.988c0-.857.286-1.097 1.319-1.097h4.682c1.056 0 1.318.22 1.318 1.097v5.988Zm12.768-4.454h5.252c1.626 0 2.637.307 3.364 1.054.658.66 1.032 1.732 1.032 2.896v.878c0 1.163-.374 2.214-1.032 2.895-.727.747-1.717 1.054-3.364 1.054h-10.022v-3.223h9.407c1.032 0 1.318-.24 1.318-1.097v-.438c0-.856-.286-1.096-1.318-1.096h-5.252c-1.628 0-2.639-.31-3.364-1.054-.657-.66-1.032-1.732-1.032-2.896v-.878c0-1.163.372-2.214 1.032-2.895.728-.747 1.714-1.054 3.364-1.054h9.499v3.223h-8.884c-1.032 0-1.318.24-1.318 1.097v.438c0 .856.286 1.096 1.318 1.096Zm11.974-2.63v-3.224h14.945v3.223h-5.626v11.405h-3.671V20.348h-5.648Z" clip-rule="evenodd"/><path fill="#3888ff" d="M63.532 17.01h-5.87c-1.625 0-2.615.306-3.364 1.054-.746.744-1.032 1.689-1.032 3.354V31.75h3.672V21.332c0-.856.286-1.096 1.318-1.096h4.682c1.057 0 1.319.219 1.319 1.097v10.42h3.671V21.42c0-1.668-.286-2.61-1.032-3.354-.746-.75-1.735-1.057-3.364-1.057Z"/><g clip-path="url(#b)"><path fill="#3888ff" d="M40.811 10.287 24.081.647a4.901 4.901 0 0 0-4.867 0 4.868 4.868 0 0 0-2.433 4.205v1.257l-1.09-.628a4.901 4.901 0 0 0-4.868 0 4.869 4.869 0 0 0-2.432 4.207v1.258l-1.09-.629a4.901 4.901 0 0 0-4.868 0A4.869 4.869 0 0 0 0 14.525v30.203a2.29 2.29 0 0 0 1.29 2.054c.783.38 1.733.276 2.415-.261l8.296-6.53 12.793 7.371a2.29 2.29 0 0 0 1.145.304 2.288 2.288 0 0 0 2.29-2.281V27.207a8.392 8.392 0 0 0-4.196-7.252l-4.195-2.418V4.855a1.813 1.813 0 0 1 2.722-1.568l16.73 9.637a5.342 5.342 0 0 1 2.67 4.614v22.633c0 .644-.348 1.246-.908 1.568l-4.433 2.555V22.372a8.393 8.393 0 0 0-4.195-7.252l-10.3-5.933v3.515l8.775 5.055a5.338 5.338 0 0 1 2.67 4.615v23.237c0 .811.438 1.57 1.144 1.978a2.29 2.29 0 0 0 1.145.304c.396 0 .792-.104 1.145-.304l5.577-3.214a4.87 4.87 0 0 0 2.433-4.208V17.532a8.412 8.412 0 0 0-4.202-7.245Zm-18.31 12.306a5.339 5.339 0 0 1 2.67 4.615v16.86l-10.594-6.102 3.4-2.674a4.82 4.82 0 0 0 1.855-3.813V21.06l2.67 1.534Zm-5.72-3.296v12.176c0 .56-.252 1.079-.69 1.422L3.05 43.155V14.52a1.814 1.814 0 0 1 2.721-1.567l2.619 1.507v21.585l3.05-2.4V9.688a1.813 1.813 0 0 1 2.722-1.567l2.618 1.506v6.152l-3.05-1.759v3.518l3.05 1.76Z"/></g></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h141.873v48H0z"/></clipPath><clipPath id="b"><path fill="#fff" d="M0 0h45.013v47.891H0z"/></clipPath></defs></svg>

Before

Width:  |  Height:  |  Size: 2.8 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 6.1 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 4.9 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.5 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="142" height="48" fill="none"><g clip-path="url(#a)"><path fill="#21324B" fill-rule="evenodd" d="M75.985 22.827h7.188v-5.702h3.803v14.628h-3.803V26.05h-7.188v5.702h-3.669V17.125h3.669v5.702Zm25.495-5.702h-5.87c-1.626 0-2.615.307-3.364 1.054-.746.745-1.032 1.69-1.032 3.357v5.812c0 1.668.286 2.61 1.032 3.357.746.747 1.735 1.054 3.364 1.054h5.87c1.625 0 2.615-.307 3.364-1.054.749-.744 1.032-1.69 1.032-3.357v-5.812c0-1.668-.286-2.61-1.032-3.357-.749-.747-1.739-1.054-3.364-1.054Zm.724 10.308c0 .857-.286 1.097-1.318 1.097h-4.682c-1.032 0-1.319-.24-1.319-1.097v-5.988c0-.857.286-1.097 1.319-1.097h4.682c1.056 0 1.318.22 1.318 1.097v5.988Zm12.768-4.454h5.252c1.626 0 2.637.307 3.364 1.054.658.66 1.032 1.732 1.032 2.896v.878c0 1.163-.374 2.214-1.032 2.895-.727.747-1.717 1.054-3.364 1.054h-10.022v-3.223h9.407c1.032 0 1.318-.24 1.318-1.097v-.438c0-.856-.286-1.096-1.318-1.096h-5.252c-1.628 0-2.639-.31-3.364-1.054-.657-.66-1.032-1.732-1.032-2.896v-.878c0-1.163.372-2.214 1.032-2.895.728-.747 1.714-1.054 3.364-1.054h9.499v3.223h-8.884c-1.032 0-1.318.24-1.318 1.097v.438c0 .856.286 1.096 1.318 1.096Zm11.974-2.63v-3.224h14.945v3.223h-5.626v11.405h-3.671V20.348h-5.648Z" clip-rule="evenodd"/><path fill="#0052CD" d="M63.532 17.01h-5.87c-1.625 0-2.615.306-3.364 1.054-.746.744-1.032 1.689-1.032 3.354V31.75h3.672V21.332c0-.856.286-1.096 1.318-1.096h4.682c1.057 0 1.319.219 1.319 1.097v10.42h3.671V21.42c0-1.668-.286-2.61-1.032-3.354-.746-.75-1.735-1.057-3.364-1.057Z"/><g clip-path="url(#b)"><path fill="#0052CD" d="M40.811 10.287 24.081.647a4.901 4.901 0 0 0-4.867 0 4.868 4.868 0 0 0-2.433 4.205v1.257l-1.09-.628a4.901 4.901 0 0 0-4.868 0 4.869 4.869 0 0 0-2.432 4.207v1.258l-1.09-.629a4.901 4.901 0 0 0-4.868 0A4.869 4.869 0 0 0 0 14.525v30.203a2.29 2.29 0 0 0 1.29 2.054c.783.38 1.733.276 2.415-.261l8.296-6.53 12.793 7.371a2.29 2.29 0 0 0 1.145.304 2.288 2.288 0 0 0 2.29-2.281V27.207a8.392 8.392 0 0 0-4.196-7.252l-4.195-2.418V4.855a1.813 1.813 0 0 1 2.722-1.568l16.73 9.637a5.342 5.342 0 0 1 2.67 4.614v22.633c0 .644-.348 1.246-.908 1.568l-4.433 2.555V22.372a8.393 8.393 0 0 0-4.195-7.252l-10.3-5.933v3.515l8.775 5.055a5.338 5.338 0 0 1 2.67 4.615v23.237c0 .811.438 1.57 1.144 1.978a2.29 2.29 0 0 0 1.145.304c.396 0 .792-.104 1.145-.304l5.577-3.214a4.87 4.87 0 0 0 2.433-4.208V17.532a8.412 8.412 0 0 0-4.202-7.245Zm-18.31 12.306a5.339 5.339 0 0 1 2.67 4.615v16.86l-10.594-6.102 3.4-2.674a4.82 4.82 0 0 0 1.855-3.813V21.06l2.67 1.534Zm-5.72-3.296v12.176c0 .56-.252 1.079-.69 1.422L3.05 43.155V14.52a1.814 1.814 0 0 1 2.721-1.567l2.619 1.507v21.585l3.05-2.4V9.688a1.813 1.813 0 0 1 2.722-1.567l2.618 1.506v6.152l-3.05-1.759v3.518l3.05 1.76Z"/></g></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h141.873v48H0z"/></clipPath><clipPath id="b"><path fill="#fff" d="M0 0h45.013v47.891H0z"/></clipPath></defs></svg>

Before

Width:  |  Height:  |  Size: 2.8 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 6.1 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 4.9 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.5 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -0,0 +1 @@
<svg width="1003" height="644" fill="none" xmlns="http://www.w3.org/2000/svg"><g opacity=".24"><mask id="b" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="128" y="0" width="921" height="644"><ellipse cx="588.5" cy="322" rx="460.5" ry="322" fill="url(#a)" fill-opacity=".32"/></mask><g mask="url(#b)" stroke="#fff" stroke-opacity=".88"><path d="M141.5 17v609m32-609v609m32-609v609m32-609v609m32-609v609m32-609v609m32-609v609m32-609v609m32-609v609m32-609v609m32-609v609m32-609v609m32-609v609m32-609v609m32-609v609m32-609v609m32-609v609m32-609v609m32-609v609m32-609v609m32-609v609m32-609v609m32-609v609m32-609v609m32-609v609m32-609v609m32-609v609M-51 33.5h1280m-1280 32h1280m-1280 32h1280m-1280 32h1280m-1280 32h1280m-1280 32h1280m-1280 32h1280m-1280 32h1280m-1280 32h1280m-1280 32h1280m-1280 32h1280m-1280 32h1280m-1280 32h1280m-1280 32h1280m-1280 32h1280m-1280 32h1280m-1280 32h1280m-1280 32h1280m-1280 32h1280"/></g></g><defs><radialGradient id="a" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 322 -460.5 0 588.5 322)"><stop/><stop offset="1" stop-opacity="0"/></radialGradient></defs></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1 @@
<svg width="119" height="40" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#a)" fill="#fff"><path fill-rule="evenodd" clip-rule="evenodd" d="M63.32 19.023h5.99V14.27h3.17v12.19h-3.17V21.71h-5.99v4.752h-3.058v-12.19h3.057v4.752h.002Zm21.245-4.752h-4.89c-1.356 0-2.18.255-2.804.879-.622.62-.86 1.408-.86 2.798v4.842c0 1.39.237 2.175.86 2.797.62.623 1.446.88 2.803.88h4.891c1.356 0 2.18-.257 2.804-.88.625-.62.86-1.407.86-2.797v-4.842c0-1.39-.237-2.175-.86-2.8-.625-.622-1.448-.877-2.803-.877Zm.604 8.59c0 .713-.237.913-1.099.913h-3.9c-.86 0-1.1-.2-1.1-.913v-4.99c0-.713.24-.913 1.1-.913h3.9c.882 0 1.1.18 1.1.912v4.991Zm10.64-3.712h4.376c1.355 0 2.198.256 2.804.878.549.55.86 1.444.86 2.413v.732c0 .97-.312 1.845-.86 2.413-.606.622-1.431.879-2.804.879h-8.35v-2.688h7.838c.86 0 1.1-.2 1.1-.912v-.365c0-.714-.24-.914-1.1-.914h-4.375c-1.359 0-2.2-.259-2.804-.879-.549-.55-.861-1.442-.861-2.412v-.732c0-.97.31-1.846.861-2.412.606-.624 1.428-.879 2.803-.879h7.916v2.686h-7.404c-.86 0-1.099.2-1.099.913v.365c0 .715.24.915 1.1.915v-.001Zm9.979-2.192V14.27h12.454v2.688h-4.688v9.503h-3.06v-9.503h-4.707.001Z"/><path d="M52.946 14.175h-4.892c-1.355 0-2.18.255-2.803.879-.622.62-.86 1.407-.86 2.795v8.61h3.058v-8.684c0-.712.24-.912 1.1-.912h3.902c.88 0 1.098.182 1.098.912v8.685h3.06v-8.61c0-1.39-.238-2.175-.86-2.795-.622-.625-1.446-.881-2.803-.881v.001ZM34.01 8.573 20.069.538a4.085 4.085 0 0 0-4.058 0 4.057 4.057 0 0 0-2.026 3.503V5.09l-.909-.525a4.085 4.085 0 0 0-4.057 0 4.058 4.058 0 0 0-2.027 3.51v1.048l-.908-.524a4.085 4.085 0 0 0-4.056 0A4.058 4.058 0 0 0 0 12.104v25.17a1.907 1.907 0 0 0 3.087 1.494L10 33.325l10.663 6.143a1.936 1.936 0 0 0 1.907 0c.587-.34.954-.97.954-1.65V22.676a6.995 6.995 0 0 0-3.497-6.044l-3.496-2.015V4.046A1.513 1.513 0 0 1 18.8 2.738l13.941 8.031a4.452 4.452 0 0 1 2.225 3.845v18.861c0 .538-.29 1.038-.756 1.307l-3.694 2.128V18.643A6.994 6.994 0 0 0 27.02 12.6l-8.582-4.944v2.93l7.31 4.212a4.448 4.448 0 0 1 2.226 3.845v19.365c0 .675.365 1.308.953 1.648a1.936 1.936 0 0 0 1.908 0l4.649-2.678a4.058 4.058 0 0 0 2.027-3.507v-18.86a7.01 7.01 0 0 0-3.501-6.038ZM18.75 18.828a4.448 4.448 0 0 1 2.225 3.846v14.05l-8.828-5.086 2.834-2.228a4.018 4.018 0 0 0 1.545-3.177V17.55l2.225 1.279-.001-.001Zm-4.766-2.747v10.147c0 .466-.211.9-.576 1.185L2.54 35.963V12.1a1.512 1.512 0 0 1 2.268-1.306l2.183 1.256v17.988l2.542-2V8.073a1.511 1.511 0 0 1 2.268-1.307l2.182 1.255v5.128l-2.54-1.465v2.931l2.542 1.466h-.002Z"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h118.75v40H0z"/></clipPath></defs></svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 210 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

View File

@@ -1,6 +0,0 @@
<svg width="200" height="200" viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="200" height="200" fill="white" fill-opacity="0.15"/>
<rect width="200" height="200" fill="#263245" fill-opacity="0.08"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M71 84C71 67.9837 83.9837 55 100 55C116.016 55 129 67.9837 129 84C129 100.016 116.016 113 100 113C83.9837 113 71 100.016 71 84ZM100 49C80.67 49 65 64.67 65 84C65 97.6014 72.7585 109.391 84.0914 115.184C79.3584 116.509 74.7892 118.425 70.496 120.903C61.5257 126.08 54.0757 133.527 48.8946 142.495C48.0657 143.929 48.5568 145.764 49.9914 146.593C51.4261 147.422 53.261 146.931 54.0898 145.496C58.7443 137.44 65.4368 130.75 73.4952 126.099C81.5536 121.448 90.694 119 99.9982 119C109.302 119 118.443 121.449 126.501 126.1C134.559 130.751 141.252 137.441 145.906 145.497C146.735 146.932 148.57 147.423 150.004 146.594C151.439 145.765 151.93 143.93 151.101 142.496C145.92 133.527 138.471 126.081 129.5 120.903C125.208 118.426 120.639 116.509 115.907 115.185C127.241 109.392 135 97.6021 135 84C135 64.67 119.33 49 100 49Z" fill="white" fill-opacity="0.15"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M71 84C71 67.9837 83.9837 55 100 55C116.016 55 129 67.9837 129 84C129 100.016 116.016 113 100 113C83.9837 113 71 100.016 71 84ZM100 49C80.67 49 65 64.67 65 84C65 97.6014 72.7585 109.391 84.0914 115.184C79.3584 116.509 74.7892 118.425 70.496 120.903C61.5257 126.08 54.0757 133.527 48.8946 142.495C48.0657 143.929 48.5568 145.764 49.9914 146.593C51.4261 147.422 53.261 146.931 54.0898 145.496C58.7443 137.44 65.4368 130.75 73.4952 126.099C81.5536 121.448 90.694 119 99.9982 119C109.302 119 118.443 121.449 126.501 126.1C134.559 130.751 141.252 137.441 145.906 145.497C146.735 146.932 148.57 147.423 150.004 146.594C151.439 145.765 151.93 143.93 151.101 142.496C145.92 133.527 138.471 126.081 129.5 120.903C125.208 118.426 120.639 116.509 115.907 115.185C127.241 109.392 135 97.6021 135 84C135 64.67 119.33 49 100 49Z" fill="#263245" fill-opacity="0.25"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -111,9 +111,9 @@ export default function AppDeployments(props: AppDeploymentsProps) {
throw error;
}
const { deployments } = deploymentPageData || {};
const { deployments } = deploymentPageData || { deployments: [] };
const { deployments: scheduledOrPendingDeployments } =
scheduledOrPendingDeploymentsData || {};
scheduledOrPendingDeploymentsData || { deployments: [] };
const latestDeployment = latestDeploymentData?.deployments[0];
const latestLiveDeployment = latestLiveDeploymentData?.deployments[0];
@@ -135,7 +135,7 @@ export default function AppDeployments(props: AppDeploymentsProps) {
deployment={deployment}
isLive={liveDeploymentId === deployment.id}
showRedeploy={latestDeployment.id === deployment.id}
disableRedeploy={scheduledOrPendingDeployments.length > 0}
disableRedeploy={scheduledOrPendingDeployments?.length > 0}
/>
{index !== deployments.length - 1 && <Divider component="li" />}
@@ -143,7 +143,7 @@ export default function AppDeployments(props: AppDeploymentsProps) {
))}
</List>
<div className="mt-8 flex w-full justify-center">
<div className="grid grid-flow-col gap-2 items-center">
<div className="grid grid-flow-col items-center gap-2">
<NextPrevPageLink
direction="prev"
prevAllowed={page !== 1}

View File

@@ -58,7 +58,7 @@ export default function ApplicationErrored() {
const { currentDate } = useCurrentDate();
const user = useUserData();
const isOwner = currentWorkspace.members.some(
({ userId, type }) => userId === user.id && type === 'owner',
({ userId, type }) => userId === user?.id && type === 'owner',
);
const { appCreatedAt } = useAppCreatedAt();

View File

@@ -1,4 +1,7 @@
import { useDeleteApplicationMutation } from '@/generated/graphql';
import {
GetOneUserDocument,
useDeleteApplicationMutation,
} from '@/generated/graphql';
import { useCurrentWorkspaceAndApplication } from '@/hooks/useCurrentWorkspaceAndApplication';
import Button from '@/ui/v2/Button';
import ArrowRightIcon from '@/ui/v2/icons/ArrowRightIcon';
@@ -6,26 +9,39 @@ import Link from '@/ui/v2/Link';
import Text from '@/ui/v2/Text';
import { copy } from '@/utils/copy';
import { getApplicationStatusString } from '@/utils/helpers';
import { triggerToast } from '@/utils/toast';
import getServerError from '@/utils/settings/getServerError';
import { formatDistance } from 'date-fns';
import { useRouter } from 'next/router';
import { toast } from 'react-hot-toast';
export default function ApplicationInfo() {
const { currentApplication } = useCurrentWorkspaceAndApplication();
const [deleteApplication, { client }] = useDeleteApplicationMutation();
const [deleteApplication] = useDeleteApplicationMutation({
refetchQueries: [GetOneUserDocument],
});
const router = useRouter();
async function handleClickRemove() {
await deleteApplication({
variables: {
appId: currentApplication.id,
},
});
await router.push('/');
await client.refetchQueries({
include: ['getOneUser'],
});
triggerToast(`${currentApplication.name} deleted`);
try {
await toast.promise(
deleteApplication({
variables: {
appId: currentApplication.id,
},
}),
{
loading: 'Deleting project...',
success: 'The project has been deleted successfully.',
error: getServerError(
'An error occurred while deleting the project. Please try again.',
),
},
);
await router.push('/');
} catch {
// Note: The toast will handle the error.
}
}
return (

View File

@@ -1,3 +1,5 @@
import MaintenanceAlert from '@/components/common/MaintenanceAlert';
import RetryableErrorBoundary from '@/components/common/RetryableErrorBoundary';
import Container from '@/components/layout/Container';
import { features } from '@/components/overview/features';
import { frameworks } from '@/components/overview/frameworks';
@@ -51,11 +53,14 @@ export default function ApplicationLive() {
return (
<Container>
<MaintenanceAlert />
<OverviewTopBar />
<div className="grid grid-cols-1 gap-12 pt-3 lg:grid-cols-3">
<div className="order-2 grid grid-flow-row gap-12 lg:order-1 lg:col-span-2">
<OverviewDeployments />
<RetryableErrorBoundary>
<OverviewDeployments />
</RetryableErrorBoundary>
<OverviewDocumentation
title="Pick your favorite framework and start learning"

View File

@@ -3,54 +3,81 @@ import { ChangePlanModal } from '@/components/applications/ChangePlanModal';
import { StagingMetadata } from '@/components/applications/StagingMetadata';
import { useDialog } from '@/components/common/DialogProvider';
import Container from '@/components/layout/Container';
import { useUpdateApplicationMutation } from '@/generated/graphql';
import {
GetOneUserDocument,
useGetFreeAndActiveProjectsQuery,
useUnpauseApplicationMutation,
} from '@/generated/graphql';
import { useCurrentWorkspaceAndApplication } from '@/hooks/useCurrentWorkspaceAndApplication';
import { ApplicationStatus } from '@/types/application';
import { Modal } from '@/ui';
import { Alert } from '@/ui/Alert';
import ActivityIndicator from '@/ui/v2/ActivityIndicator';
import Box from '@/ui/v2/Box';
import Button from '@/ui/v2/Button';
import Text from '@/ui/v2/Text';
import { discordAnnounce } from '@/utils/discordAnnounce';
import { triggerToast } from '@/utils/toast';
import { updateOwnCache } from '@/utils/updateOwnCache';
import { MAX_FREE_PROJECTS } from '@/utils/CONSTANTS';
import { getToastStyleProps } from '@/utils/settings/settingsConstants';
import type { ApolloError } from '@apollo/client';
import { useUserData } from '@nhost/nextjs';
import Image from 'next/image';
import { useState } from 'react';
import { toast } from 'react-hot-toast';
import { RemoveApplicationModal } from './RemoveApplicationModal';
export default function ApplicationPaused() {
const { openAlertDialog } = useDialog();
const { currentWorkspace, currentApplication } =
useCurrentWorkspaceAndApplication();
const [changingApplicationStateLoading, setChangingApplicationStateLoading] =
useState(false);
const [updateApplication, { client }] = useUpdateApplicationMutation();
const { id, email } = useUserData();
const { id } = useUserData();
const isOwner = currentWorkspace.members.some(
({ userId, type }) => userId === id && type === 'owner',
);
const isPro = currentApplication.plan.name === 'Pro';
const [showDeletingModal, setShowDeletingModal] = useState(false);
const [unpauseApplication, { loading: changingApplicationStateLoading }] =
useUnpauseApplicationMutation({
refetchQueries: [GetOneUserDocument],
});
const { data, loading } = useGetFreeAndActiveProjectsQuery({
variables: { userId: id },
fetchPolicy: 'cache-and-network',
});
const numberOfFreeAndLiveProjects = data?.freeAndActiveProjects.length || 0;
const wakeUpDisabled = numberOfFreeAndLiveProjects >= MAX_FREE_PROJECTS;
async function handleTriggerUnpausing() {
setChangingApplicationStateLoading(true);
try {
await updateApplication({
variables: {
appId: currentApplication.id,
app: {
desiredState: ApplicationStatus.Live,
await toast.promise(
unpauseApplication({ variables: { appId: currentApplication.id } }),
{
loading: 'Starting the project...',
success: `The project has been started successfully.`,
error: (arg: ApolloError) => {
// we need to get the internal error message from the GraphQL error
const { internal } = arg.graphQLErrors[0]?.extensions || {};
const { message } = (internal as Record<string, any>)?.error || {};
// we use the default Apollo error message if we can't find the
// internal error message
return (
message ||
arg.message ||
'An error occurred while waking up the project. Please try again.'
);
},
},
});
await updateOwnCache(client);
discordAnnounce(
`App ${currentApplication.name} (${email}) set to awake.`,
getToastStyleProps(),
);
triggerToast(`${currentApplication.name} set to awake.`);
} catch (e) {
triggerToast(`Error trying to awake ${currentApplication.name}`);
} catch {
// Note: The toast will handle the error.
}
}
if (loading) {
return <ActivityIndicator label="Loading user data..." delay={1000} />;
}
return (
<>
<Modal
@@ -65,7 +92,7 @@ export default function ApplicationPaused() {
/>
</Modal>
<Container className="mx-auto mt-20 grid max-w-sm grid-flow-row gap-2 text-center">
<Container className="mx-auto mt-20 grid max-w-lg grid-flow-row gap-4 text-center">
<div className="mx-auto flex w-centImage flex-col text-center">
<Image
src="/assets/PausedApp.svg"
@@ -75,16 +102,18 @@ export default function ApplicationPaused() {
/>
</div>
<Text variant="h3" component="h1" className="mt-4">
{currentApplication.name} is sleeping
</Text>
<Box className="grid grid-flow-row gap-1">
<Text variant="h3" component="h1">
{currentApplication.name} is sleeping
</Text>
<Text className="mt-1">
Projects on the free plan stop responding to API calls after 7 days of
no traffic.
</Text>
<Text>
Starter projects stop responding to API calls after 7 days of
inactivity. Upgrade to Pro to avoid autosleep.
</Text>
</Box>
{!isPro && (
<Box className="grid grid-flow-row gap-2">
<Button
className="mx-auto w-full max-w-[280px]"
onClick={() => {
@@ -101,32 +130,41 @@ export default function ApplicationPaused() {
});
}}
>
Upgrade to Pro to avoid autosleep
</Button>
)}
<div className="grid grid-flow-row gap-2">
<Button
variant="borderless"
className="mx-auto w-full max-w-[280px]"
loading={changingApplicationStateLoading}
disabled={changingApplicationStateLoading}
onClick={handleTriggerUnpausing}
>
Wake Up
Upgrade to Pro
</Button>
{isOwner && (
<div className="grid grid-flow-row gap-2">
<Button
color="error"
variant="borderless"
className="mx-auto w-full max-w-[280px]"
onClick={() => setShowDeletingModal(true)}
loading={changingApplicationStateLoading}
disabled={changingApplicationStateLoading || wakeUpDisabled}
onClick={handleTriggerUnpausing}
>
Delete Project
Wake Up
</Button>
)}
</div>
{wakeUpDisabled && (
<Alert severity="warning" className="mx-auto max-w-xs text-left">
Note: Only one free project can be active at any given time.
Please pause your active free project before unpausing{' '}
{currentApplication.name}.
</Alert>
)}
{isOwner && (
<Button
color="error"
variant="borderless"
className="mx-auto w-full max-w-[280px]"
onClick={() => setShowDeletingModal(true)}
>
Delete Project
</Button>
)}
</div>
</Box>
<StagingMetadata>
<ApplicationInfo />
</StagingMetadata>

View File

@@ -18,7 +18,7 @@ export default function ApplicationUnknown() {
const [showDeleteModal, setShowDeleteModal] = useState(false);
const user = useUserData();
const isOwner = currentWorkspace.members.some(
({ userId, type }) => userId === user.id && type === 'owner',
({ userId, type }) => userId === user?.id && type === 'owner',
);
return (

View File

@@ -32,12 +32,12 @@ function Plan({
return (
<button
type="button"
className="my-4 grid w-full grid-flow-col items-center justify-between px-1"
className="my-4 grid w-full grid-flow-col items-center justify-between gap-2 px-1"
onClick={setPlan}
tabIndex={-1}
>
<div className="grid grid-flow-row gap-y-0.5">
<div className="flex flex-row items-center">
<div className="grid grid-flow-col items-center justify-start gap-2">
<Checkbox
onChange={setPlan}
checked={selectedPlanId === planId}
@@ -47,12 +47,13 @@ function Plan({
<Text
variant="h3"
component="p"
className="ml-2 self-center font-medium"
className="self-center text-left font-medium"
>
{currentPlan.price > price ? 'Downgrade' : 'Upgrade'} to {planName}
</Text>
</div>
<Text variant="subtitle2" className="w-64 text-start">
<Text variant="subtitle2" className="w-full max-w-[256px] text-start">
{planDescriptions[planName]}
</Text>
</div>
@@ -142,7 +143,7 @@ export function ChangePlanModalWithData({ app, plans, close }: any) {
};
return (
<Box className="w-welcome rounded-lg p-6 text-left">
<Box className="w-full max-w-xl rounded-lg p-6 text-left">
<Modal
showModal={paymentModal}
close={closePaymentModal}

View File

@@ -12,7 +12,7 @@ import generateAppServiceUrl, {
defaultRemoteBackendSlugs,
} from '@/utils/common/generateAppServiceUrl';
import { copy } from '@/utils/copy';
import { LOCAL_HASURA_URL } from '@/utils/env';
import { getHasuraConsoleServiceUrl } from '@/utils/env';
import Image from 'next/image';
interface HasuraDataProps {
@@ -22,17 +22,15 @@ interface HasuraDataProps {
export function HasuraData({ close }: HasuraDataProps) {
const { currentApplication } = useCurrentWorkspaceAndApplication();
const isPlatform = useIsPlatform();
const projectAdminSecret = currentApplication?.config?.hasura.adminSecret;
if (
!currentApplication?.subdomain ||
!currentApplication?.hasuraGraphqlAdminSecret
) {
if (!currentApplication?.subdomain || !projectAdminSecret) {
return <LoadingScreen />;
}
const hasuraUrl =
process.env.NEXT_PUBLIC_ENV === 'dev' || !isPlatform
? `${LOCAL_HASURA_URL}/console`
? `${getHasuraConsoleServiceUrl()}`
: generateAppServiceUrl(
currentApplication?.subdomain,
currentApplication?.region.awsName,
@@ -71,18 +69,11 @@ export function HasuraData({ close }: HasuraDataProps) {
<div className="col-span-1 grid grid-flow-col items-center justify-center gap-2 sm:col-span-2 sm:justify-end">
<Text className="font-medium" variant="subtitle2">
{Array(currentApplication.hasuraGraphqlAdminSecret.length)
.fill('•')
.join('')}
{Array(projectAdminSecret.length).fill('•').join('')}
</Text>
<IconButton
onClick={() =>
copy(
currentApplication.hasuraGraphqlAdminSecret,
'Hasura admin secret',
)
}
onClick={() => copy(projectAdminSecret, 'Hasura admin secret')}
variant="borderless"
color="secondary"
className="min-w-0 p-1"

View File

@@ -6,7 +6,10 @@ import Divider from '@/ui/v2/Divider';
import Text from '@/ui/v2/Text';
import { discordAnnounce } from '@/utils/discordAnnounce';
import { triggerToast } from '@/utils/toast';
import { useDeleteApplicationMutation } from '@/utils/__generated__/graphql';
import {
GetOneUserDocument,
useDeleteApplicationMutation,
} from '@/utils/__generated__/graphql';
import router from 'next/router';
import { useState } from 'react';
import { twMerge } from 'tailwind-merge';
@@ -42,7 +45,9 @@ export function RemoveApplicationModal({
description,
className,
}: RemoveApplicationModalProps) {
const [deleteApplication, { client }] = useDeleteApplicationMutation();
const [deleteApplication] = useDeleteApplicationMutation({
refetchQueries: [GetOneUserDocument],
});
const [loadingRemove, setLoadingRemove] = useState(false);
const { currentApplication } = useCurrentWorkspaceAndApplication();
@@ -73,9 +78,6 @@ export function RemoveApplicationModal({
}
close();
await router.push('/');
await client.refetchQueries({
include: ['getOneUser'],
});
triggerToast(`${currentApplication.name} deleted`);
}

View File

@@ -1,8 +1,8 @@
import DeploymentStatusMessage from '@/components/deployments/DeploymentStatusMessage';
import { FindOldApps } from '@/components/home';
import type { UserData } from '@/hooks/useGetAllUserWorkspacesAndApplications';
import type { Application, ApplicationState } from '@/types/application';
import type { ApplicationState } from '@/types/application';
import { ApplicationStatus } from '@/types/application';
import { Avatar } from '@/ui/Avatar';
import StateBadge from '@/ui/StateBadge';
import type { DeploymentStatus } from '@/ui/StatusCircle';
import { StatusCircle } from '@/ui/StatusCircle';
@@ -10,59 +10,11 @@ import Divider from '@/ui/v2/Divider';
import Link from '@/ui/v2/Link';
import List from '@/ui/v2/List';
import { ListItem } from '@/ui/v2/ListItem';
import Text from '@/ui/v2/Text';
import { getApplicationStatusString } from '@/utils/helpers';
import { formatDistance } from 'date-fns';
import Image from 'next/image';
import NavLink from 'next/link';
import { Fragment } from 'react';
function ApplicationCreatedAt({ createdAt }: any) {
return (
<Text component="span" className="text-sm">
created{' '}
{formatDistance(new Date(createdAt), new Date(), {
addSuffix: true,
})}
</Text>
);
}
function LastSuccessfulDeployment({ deployment }: any) {
return (
<span className="flex flex-row">
<Avatar
component="span"
name={deployment.commitUserName}
avatarUrl={deployment.commitUserAvatarUrl}
className="mr-1 h-4 w-4 self-center"
/>
<Text component="span" className="self-center text-sm">
{deployment.commitUserName} deployed{' '}
{formatDistance(new Date(deployment.deploymentEndedAt), new Date(), {
addSuffix: true,
})}
</Text>
</span>
);
}
function CurrentDeployment({ deployment }: any) {
return (
<span className="flex flex-row">
<Avatar
component="span"
name={deployment.commitUserName}
avatarUrl={deployment.commitUserAvatarUrl}
className="mr-1 h-4 w-4 self-center"
/>
<Text className="self-center text-sm">
{deployment.commitUserName} updated just now
</Text>
</span>
);
}
export function checkStatusOfTheApplication(
stateHistory: ApplicationState[] | [],
) {
@@ -103,7 +55,7 @@ export function RenderWorkspacesWithApps({
}
const workspaceProjects = workspace.applications
.filter((app: Application) =>
.filter((app) =>
app.name.toLowerCase().includes(query.toLowerCase()),
)
.sort((appA, appB) => {
@@ -141,29 +93,26 @@ export function RenderWorkspacesWithApps({
</NavLink>
<List className="grid grid-flow-row border-y">
{workspaceProjects.map((app, index) => {
const isDeployingToProduction = app.deployments[0]
? app.deployments[0].deploymentStatus === 'DEPLOYING'
: false;
const [latestDeployment] = app.deployments;
return (
<Fragment key={app.slug}>
<ListItem.Root
secondaryAction={
<div className="grid grid-flow-col gap-px">
{app.deployments[0] && (
{latestDeployment && (
<div className="mr-2 flex self-center align-middle">
<StatusCircle
status={
app.deployments[0]
.deploymentStatus as DeploymentStatus
latestDeployment.deploymentStatus as DeploymentStatus
}
/>
</div>
)}
<StateBadge
status={checkStatusOfTheApplication(
app.appStates,
)}
state={checkStatusOfTheApplication(app.appStates)}
desiredState={app.desiredState}
title={getApplicationStatusString(
checkStatusOfTheApplication(app.appStates),
)}
@@ -190,27 +139,10 @@ export function RenderWorkspacesWithApps({
<ListItem.Text
primary={app.name}
secondary={
<>
{isDeployingToProduction && (
<CurrentDeployment
deployment={app.deployments[0]}
/>
)}
{!isDeployingToProduction &&
app.deployments[0] && (
<LastSuccessfulDeployment
deployment={app.deployments[0]}
/>
)}
{!isDeployingToProduction &&
!app.deployments[0] && (
<ApplicationCreatedAt
createdAt={app.createdAt}
/>
)}
</>
<DeploymentStatusMessage
appCreatedAt={app.createdAt}
deployment={latestDeployment}
/>
}
/>
</ListItem.Button>

View File

@@ -6,7 +6,7 @@ import type { PropsWithChildren } from 'react';
export function StagingMetadata({ children }: PropsWithChildren<unknown>) {
return (
isDevOrStaging() && (
<div className="mt-10">
<div className="mx-auto mt-10 max-w-sm">
<Box className="mx-auto flex flex-col rounded-md border p-5 text-center">
<Status status={StatusEnum.Deploying}>Internal info</Status>
{children}

View File

@@ -33,11 +33,10 @@ export function UnlockFeatureByUpgrading({
title: 'Upgrade your plan.',
payload: <ChangePlanModal />,
props: {
PaperProps: { className: 'p-0' },
PaperProps: { className: 'p-0 max-w-xl w-full' },
hidePrimaryAction: true,
hideSecondaryAction: true,
hideTitle: true,
maxWidth: 'lg',
},
});
}}

View File

@@ -1,3 +1,4 @@
import { useCurrentWorkspaceAndApplication } from '@/hooks/useCurrentWorkspaceAndApplication';
import { useRemoteApplicationGQLClient } from '@/hooks/useRemoteApplicationGQLClient';
import ActivityIndicator from '@/ui/v2/ActivityIndicator';
import Option from '@/ui/v2/Option';
@@ -18,10 +19,12 @@ export interface UserSelectProps {
}
export function UserSelect({ onUserChange, ...props }: UserSelectProps) {
const { currentApplication } = useCurrentWorkspaceAndApplication();
const userApplicationClient = useRemoteApplicationGQLClient();
const { data, loading, error } = useRemoteAppGetUsersCustomQuery({
client: userApplicationClient,
variables: { where: {}, limit: 250, offset: 0 },
skip: !currentApplication,
});
if (loading) {
@@ -36,8 +39,6 @@ export function UserSelect({ onUserChange, ...props }: UserSelectProps) {
throw error;
}
const { users } = data;
return (
<Select
{...props}
@@ -57,7 +58,7 @@ export function UserSelect({ onUserChange, ...props }: UserSelectProps) {
return;
}
const user: RemoteAppGetUsersCustomQuery['users'][0] = users.find(
const user: RemoteAppGetUsersCustomQuery['users'][0] = data?.users.find(
({ id }) => id === userId,
);
@@ -68,7 +69,7 @@ export function UserSelect({ onUserChange, ...props }: UserSelectProps) {
>
<Option value="admin">Admin</Option>
{users.map(({ id, displayName, email, phoneNumber }) => (
{data?.users.map(({ id, displayName, email, phoneNumber }) => (
<Option key={id} value={id}>
{displayName || email || phoneNumber || id}
</Option>

View File

@@ -22,7 +22,9 @@ import {
import { loadStripe } from '@stripe/stripe-js';
import React, { useState } from 'react';
const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PK!);
const stripePromise = process.env.NEXT_PUBLIC_STRIPE_PK
? loadStripe(process.env.NEXT_PUBLIC_STRIPE_PK)
: null;
type AddPaymentMethodFormProps = {
close: () => void;
@@ -74,7 +76,8 @@ function AddPaymentMethodForm({
if (createPaymentMethodError) {
throw new Error(
createPaymentMethodError.message || 'Unknown error occurred.',
createPaymentMethodError.message ||
'An unknown error occurred. Please try again.',
);
}
@@ -88,7 +91,10 @@ function AddPaymentMethodForm({
);
if (attachPaymentMethodError) {
throw Error((attachPaymentMethodError as any).response.data);
throw new Error(
(attachPaymentMethodError as any)?.response?.data ||
'An unknown error occurred. Please try again.',
);
}
// update workspace with new country code in database
@@ -149,7 +155,7 @@ function AddPaymentMethodForm({
};
return (
<Box className="w-modal2 px-6 pt-6 pb-6 text-left rounded-lg">
<Box className="w-modal2 rounded-lg px-6 pt-6 pb-6 text-left">
<div className="flex flex-col">
<form onSubmit={handleSubmit}>
<Text className="text-center text-lg font-medium">
@@ -201,7 +207,7 @@ function AddPaymentMethodForm({
type BillingPaymentMethodFormProps = {
close: () => void;
onPaymentMethodAdded?: () => Promise<void>;
onPaymentMethodAdded?: (e?: any) => Promise<void>;
workspaceId: string;
};

View File

@@ -31,6 +31,7 @@ export default function Breadcrumbs({ className, ...props }: BreadcrumbsProps) {
<NavLink
href="/local/local"
className="truncate text-[13px] hover:underline sm:text-sm"
sx={{ color: 'text.primary' }}
>
local
</NavLink>
@@ -53,6 +54,7 @@ export default function Breadcrumbs({ className, ...props }: BreadcrumbsProps) {
<NavLink
href={`/${currentWorkspace.slug}`}
className="truncate text-[13px] hover:underline sm:text-sm"
sx={{ color: 'text.primary' }}
>
{currentWorkspace.name}
</NavLink>
@@ -66,6 +68,7 @@ export default function Breadcrumbs({ className, ...props }: BreadcrumbsProps) {
<NavLink
href={`/${currentWorkspace.slug}/${currentApplication.slug}`}
className="truncate text-[13px] hover:underline sm:text-sm"
sx={{ color: 'text.primary' }}
>
{currentApplication.name}
</NavLink>

View File

@@ -52,7 +52,9 @@ function ControlledAutocomplete(
return (
<Autocomplete
inputValue={typeof field.value === 'string' ? field.value : undefined}
inputValue={
typeof field.value !== 'object' ? field.value.toString() : undefined
}
{...props}
{...field}
ref={mergeRefs([field.ref, ref])}

View File

@@ -46,7 +46,7 @@ export default function DataGridDateCell<TData extends object>({
: undefined;
const { year, month, day, hour, minute, second } = getDateComponents(date, {
adjustTimezone: specificType === 'timetz' || specificType === 'timestamptz',
adjustTimezone: ['date', 'timetz', 'timestamptz'].includes(specificType),
});
const { inputRef, focusCell, isEditing, cancelEditCell } =

View File

@@ -205,7 +205,7 @@ export default function DataGridPreviewCell<TData extends object>({
}
const { presignedUrl } = await appClient.storage
.setAdminSecret(currentApplication.hasuraGraphqlAdminSecret)
.setAdminSecret(currentApplication.config?.hasura.adminSecret)
.getPresignedUrl({ fileId: id });
if (!presignedUrl) {

View File

@@ -1,31 +1,8 @@
import type { DialogFormProps } from '@/types/common';
import type { CommonDialogProps } from '@/ui/v2/Dialog';
import type { ReactNode } from 'react';
import type { ReactElement, ReactNode } from 'react';
import { createContext } from 'react';
/**
* Available dialog types.
*/
export type DialogType =
| 'EDIT_WORKSPACE_NAME'
| 'CREATE_RECORD'
| 'CREATE_COLUMN'
| 'EDIT_COLUMN'
| 'CREATE_TABLE'
| 'EDIT_TABLE'
| 'EDIT_PERMISSIONS'
| 'CREATE_FOREIGN_KEY'
| 'EDIT_FOREIGN_KEY'
| 'CREATE_ROLE'
| 'EDIT_ROLE'
| 'CREATE_USER'
| 'CREATE_PERMISSION_VARIABLE'
| 'EDIT_PERMISSION_VARIABLE'
| 'CREATE_ENVIRONMENT_VARIABLE'
| 'EDIT_ENVIRONMENT_VARIABLE'
| 'EDIT_USER'
| 'EDIT_USER_PASSWORD'
| 'EDIT_JWT_SECRET';
export interface DialogConfig<TPayload = unknown> {
/**
* Title of the dialog.
@@ -41,21 +18,36 @@ export interface DialogConfig<TPayload = unknown> {
payload?: TPayload;
}
export interface OpenDialogOptions {
/**
* Title of the dialog.
*/
title: ReactNode;
/**
* Component to render inside the dialog skeleton.
*/
component: ReactElement<{
location?: 'drawer' | 'dialog';
onCancel?: () => void;
onSubmit?: (args?: any) => Promise<any> | void;
}>;
/**
* Props to pass to the root dialog component.
*/
props?: Partial<CommonDialogProps>;
}
export interface DialogContextProps {
/**
* Call this function to open a dialog.
* Call this function to open a dialog. It will automatically apply the
* necessary functionality to the dialog.
*/
openDialog: <TPayload = unknown>(
type: DialogType,
config?: DialogConfig<TPayload>,
) => void;
openDialog: (options: OpenDialogOptions) => void;
/**
* Call this function to open a drawer.
* Call this function to open a drawer. It will automatically apply the
* necessary functionality to the drawer.
*/
openDrawer: <TPayload = unknown>(
type: DialogType,
config?: DialogConfig<TPayload>,
) => void;
openDrawer: (options: OpenDialogOptions) => void;
/**
* Call this function to open an alert dialog.
*/
@@ -87,7 +79,7 @@ export interface DialogContextProps {
*/
onDirtyStateChange: (
isDirty: boolean,
location?: 'drawer' | 'dialog',
location?: DialogFormProps['location'],
) => void;
/**
* Call this function to open a dirty confirmation dialog.

View File

@@ -1,30 +1,12 @@
import RetryableErrorBoundary from '@/components/common/RetryableErrorBoundary';
import CreateForeignKeyForm from '@/components/dataBrowser/CreateForeignKeyForm';
import EditForeignKeyForm from '@/components/dataBrowser/EditForeignKeyForm';
import EditWorkspaceNameForm from '@/components/home/EditWorkspaceNameForm';
import CreateEnvironmentVariableForm from '@/components/settings/environmentVariables/CreateEnvironmentVariableForm';
import EditEnvironmentVariableForm from '@/components/settings/environmentVariables/EditEnvironmentVariableForm';
import EditJwtSecretForm from '@/components/settings/environmentVariables/EditJwtSecretForm';
import CreatePermissionVariableForm from '@/components/settings/permissions/CreatePermissionVariableForm';
import EditPermissionVariableForm from '@/components/settings/permissions/EditPermissionVariableForm';
import CreateRoleForm from '@/components/settings/roles/CreateRoleForm';
import EditRoleForm from '@/components/settings/roles/EditRoleForm';
import CreateUserForm from '@/components/users/CreateUserForm';
import EditUserForm from '@/components/users/EditUserForm';
import EditUserPasswordForm from '@/components/users/EditUserPasswordForm';
import ActivityIndicator from '@/ui/v2/ActivityIndicator';
import AlertDialog from '@/ui/v2/AlertDialog';
import { BaseDialog } from '@/ui/v2/Dialog';
import Drawer from '@/ui/v2/Drawer';
import dynamic from 'next/dynamic';
import { useRouter } from 'next/router';
import type {
BaseSyntheticEvent,
DetailedHTMLProps,
HTMLProps,
PropsWithChildren,
} from 'react';
import type { BaseSyntheticEvent, PropsWithChildren } from 'react';
import {
cloneElement,
isValidElement,
useCallback,
useEffect,
useMemo,
@@ -33,7 +15,7 @@ import {
useState,
} from 'react';
import { twMerge } from 'tailwind-merge';
import type { DialogConfig, DialogType } from './DialogContext';
import type { DialogConfig, OpenDialogOptions } from './DialogContext';
import DialogContext from './DialogContext';
import {
alertDialogReducer,
@@ -41,67 +23,11 @@ import {
drawerReducer,
} from './dialogReducers';
function LoadingComponent({
className,
...props
}: DetailedHTMLProps<HTMLProps<HTMLDivElement>, HTMLDivElement> = {}) {
return (
<div
{...props}
className={twMerge(
'grid items-center justify-center px-6 py-4',
className,
)}
>
<ActivityIndicator
circularProgressProps={{ className: 'w-5 h-5' }}
label="Loading form..."
/>
</div>
);
}
const CreateRecordForm = dynamic(
() => import('@/components/dataBrowser/CreateRecordForm'),
{ ssr: false, loading: () => LoadingComponent() },
);
const CreateColumnForm = dynamic(
() => import('@/components/dataBrowser/CreateColumnForm'),
{ ssr: false, loading: () => LoadingComponent() },
);
const EditColumnForm = dynamic(
() => import('@/components/dataBrowser/EditColumnForm'),
{ ssr: false, loading: () => LoadingComponent() },
);
const CreateTableForm = dynamic(
() => import('@/components/dataBrowser/CreateTableForm'),
{ ssr: false, loading: () => LoadingComponent() },
);
const EditTableForm = dynamic(
() => import('@/components/dataBrowser/EditTableForm'),
{ ssr: false, loading: () => LoadingComponent() },
);
const EditPermissionsForm = dynamic(
() => import('@/components/dataBrowser/EditPermissionsForm'),
{ ssr: false, loading: () => LoadingComponent() },
);
function DialogProvider({ children }: PropsWithChildren<unknown>) {
const router = useRouter();
const [
{
open: dialogOpen,
activeDialogType,
dialogProps,
title: dialogTitle,
payload: dialogPayload,
},
{ open: dialogOpen, title: dialogTitle, activeDialog, dialogProps },
dialogDispatch,
] = useReducer(dialogReducer, {
open: false,
@@ -110,10 +36,9 @@ function DialogProvider({ children }: PropsWithChildren<unknown>) {
const [
{
open: drawerOpen,
activeDialogType: activeDrawerType,
dialogProps: drawerProps,
title: drawerTitle,
payload: drawerPayload,
activeDialog: activeDrawer,
dialogProps: drawerProps,
},
drawerDispatch,
] = useReducer(drawerReducer, {
@@ -136,12 +61,9 @@ function DialogProvider({ children }: PropsWithChildren<unknown>) {
const isDialogDirty = useRef(false);
const [showDirtyConfirmation, setShowDirtyConfirmation] = useState(false);
const openDialog = useCallback(
<TConfig,>(type: DialogType, config?: DialogConfig<TConfig>) => {
dialogDispatch({ type: 'OPEN_DIALOG', payload: { type, config } });
},
[],
);
const openDialog = useCallback((options: OpenDialogOptions) => {
dialogDispatch({ type: 'OPEN_DIALOG', payload: options });
}, []);
const closeDialog = useCallback(() => {
dialogDispatch({ type: 'HIDE_DIALOG' });
@@ -152,12 +74,9 @@ function DialogProvider({ children }: PropsWithChildren<unknown>) {
dialogDispatch({ type: 'CLEAR_DIALOG_CONTENT' });
}, []);
const openDrawer = useCallback(
<TConfig,>(type: DialogType, config?: DialogConfig<TConfig>) => {
drawerDispatch({ type: 'OPEN_DRAWER', payload: { type, config } });
},
[],
);
const openDrawer = useCallback((options: OpenDialogOptions) => {
drawerDispatch({ type: 'OPEN_DRAWER', payload: options });
}, []);
const closeDrawer = useCallback(() => {
drawerDispatch({ type: 'HIDE_DRAWER' });
@@ -228,9 +147,6 @@ function DialogProvider({ children }: PropsWithChildren<unknown>) {
[closeDialog, openDirtyConfirmation],
);
// We are coupling this logic with the location of the dialog content which is
// not ideal. We shoule figure out a better logic for tracking the dirty
// state in the future.
const onDirtyStateChange = useCallback(
(dirty: boolean, location: 'drawer' | 'dialog' = 'drawer') => {
if (location === 'dialog') {
@@ -271,25 +187,6 @@ function DialogProvider({ children }: PropsWithChildren<unknown>) {
],
);
const sharedDialogProps = {
...dialogPayload,
onSubmit: async (values: any) => {
await dialogPayload?.onSubmit?.(values);
closeDialog();
},
onCancel: closeDialogWithDirtyGuard,
};
const sharedDrawerProps = {
onSubmit: async () => {
await drawerPayload?.onSubmit();
closeDrawer();
},
onCancel: closeDrawerWithDirtyGuard,
};
useEffect(() => {
function handleCloseDrawerAndDialog() {
if (isDrawerDirty.current || isDialogDirty.current) {
@@ -367,56 +264,20 @@ function DialogProvider({ children }: PropsWithChildren<unknown>) {
<RetryableErrorBoundary
errorMessageProps={{ className: 'pt-0 pb-5 px-6' }}
>
{activeDialogType === 'EDIT_WORKSPACE_NAME' && (
<EditWorkspaceNameForm {...sharedDialogProps} />
)}
{activeDialogType === 'CREATE_FOREIGN_KEY' && (
<CreateForeignKeyForm {...sharedDialogProps} />
)}
{activeDialogType === 'EDIT_FOREIGN_KEY' && (
<EditForeignKeyForm {...sharedDialogProps} />
)}
{activeDialogType === 'CREATE_ROLE' && (
<CreateRoleForm {...sharedDialogProps} />
)}
{activeDialogType === 'EDIT_ROLE' && (
<EditRoleForm {...sharedDialogProps} />
)}
{activeDialogType === 'CREATE_USER' && (
<CreateUserForm {...sharedDialogProps} />
)}
{activeDialogType === 'CREATE_PERMISSION_VARIABLE' && (
<CreatePermissionVariableForm {...sharedDialogProps} />
)}
{activeDialogType === 'EDIT_PERMISSION_VARIABLE' && (
<EditPermissionVariableForm {...sharedDialogProps} />
)}
{activeDialogType === 'CREATE_ENVIRONMENT_VARIABLE' && (
<CreateEnvironmentVariableForm {...sharedDialogProps} />
)}
{activeDialogType === 'EDIT_ENVIRONMENT_VARIABLE' && (
<EditEnvironmentVariableForm {...sharedDialogProps} />
)}
{activeDialogType === 'EDIT_USER_PASSWORD' && (
<EditUserPasswordForm
{...sharedDialogProps}
user={sharedDialogProps?.user}
/>
)}
{activeDialogType === 'EDIT_JWT_SECRET' && (
<EditJwtSecretForm {...sharedDialogProps} />
)}
{isValidElement(activeDialog)
? cloneElement(activeDialog, {
...activeDialog.props,
location: 'dialog',
onSubmit: async (values?: any) => {
await activeDialog?.props?.onSubmit?.(values);
closeDialog();
},
onCancel: () => {
activeDialog?.props?.onCancel?.();
closeDialogWithDirtyGuard();
},
})
: null}
</RetryableErrorBoundary>
</BaseDialog>
@@ -436,51 +297,20 @@ function DialogProvider({ children }: PropsWithChildren<unknown>) {
}}
>
<RetryableErrorBoundary>
{activeDrawerType === 'CREATE_RECORD' && (
<CreateRecordForm
{...sharedDrawerProps}
columns={drawerPayload?.columns}
/>
)}
{activeDrawerType === 'CREATE_COLUMN' && (
<CreateColumnForm {...sharedDrawerProps} />
)}
{activeDrawerType === 'EDIT_COLUMN' && (
<EditColumnForm
{...sharedDrawerProps}
column={drawerPayload?.column}
/>
)}
{activeDrawerType === 'CREATE_TABLE' && (
<CreateTableForm
{...sharedDrawerProps}
schema={drawerPayload?.schema}
/>
)}
{activeDrawerType === 'EDIT_TABLE' && (
<EditTableForm
{...sharedDrawerProps}
table={drawerPayload?.table}
schema={drawerPayload?.schema}
/>
)}
{activeDrawerType === 'EDIT_PERMISSIONS' && (
<EditPermissionsForm
{...sharedDrawerProps}
disabled={drawerPayload?.disabled}
schema={drawerPayload?.schema}
table={drawerPayload?.table}
/>
)}
{activeDrawerType === 'EDIT_USER' && (
<EditUserForm {...sharedDrawerProps} {...drawerPayload} />
)}
{isValidElement(activeDrawer)
? cloneElement(activeDrawer, {
...activeDrawer.props,
location: 'drawer',
onSubmit: async (values?: any) => {
await activeDrawer?.props?.onSubmit?.(values);
closeDrawer();
},
onCancel: () => {
activeDrawer?.props?.onCancel?.();
closeDrawerWithDirtyGuard();
},
})
: null}
</RetryableErrorBoundary>
</Drawer>

View File

@@ -1,6 +1,6 @@
import type { CommonDialogProps } from '@/ui/v2/Dialog';
import type { ReactNode } from 'react';
import type { DialogConfig, DialogType } from './DialogContext';
import type { ReactElement, ReactNode } from 'react';
import type { DialogConfig, OpenDialogOptions } from './DialogContext';
export interface DialogState {
/**
@@ -12,9 +12,13 @@ export interface DialogState {
*/
open?: boolean;
/**
* Type of the currently active dialog.
* Component to render inside the dialog skeleton.
*/
activeDialogType?: DialogType;
activeDialog?: ReactElement<{
location?: 'drawer' | 'dialog';
onCancel?: () => void;
onSubmit?: (args?: any) => Promise<any> | void;
}>;
/**
* Props passed to the currently active dialog.
*/
@@ -27,10 +31,7 @@ export interface DialogState {
}
export type DialogAction =
| {
type: 'OPEN_DIALOG';
payload: { type: DialogType; config?: DialogConfig };
}
| { type: 'OPEN_DIALOG'; payload: OpenDialogOptions }
| { type: 'HIDE_DIALOG' }
| { type: 'CLEAR_DIALOG_CONTENT' };
@@ -50,10 +51,9 @@ export function dialogReducer(
return {
...state,
open: true,
activeDialogType: action.payload?.type,
dialogProps: action.payload.config?.props,
title: action.payload.config?.title,
payload: action.payload.config?.payload,
title: action.payload.title,
activeDialog: action.payload.component,
dialogProps: action.payload.props,
};
case 'HIDE_DIALOG':
return {
@@ -64,8 +64,7 @@ export function dialogReducer(
return {
...state,
title: undefined,
payload: undefined,
activeDialogType: undefined,
activeDialog: undefined,
dialogProps: undefined,
};
default:
@@ -74,10 +73,7 @@ export function dialogReducer(
}
export type DrawerAction =
| {
type: 'OPEN_DRAWER';
payload: { type: DialogType; config?: DialogConfig };
}
| { type: 'OPEN_DRAWER'; payload: OpenDialogOptions }
| { type: 'HIDE_DRAWER' }
| { type: 'CLEAR_DRAWER_CONTENT' };
@@ -97,10 +93,9 @@ export function drawerReducer(
return {
...state,
open: true,
activeDialogType: action.payload?.type,
dialogProps: action.payload.config?.props,
title: action.payload.config?.title,
payload: action.payload.config?.payload,
title: action.payload.title,
activeDialog: action.payload.component,
dialogProps: action.payload.props,
};
case 'HIDE_DRAWER':
return {
@@ -111,8 +106,7 @@ export function drawerReducer(
return {
...state,
title: undefined,
payload: undefined,
activeDialogType: undefined,
activeDialog: undefined,
dialogProps: undefined,
};
default:

View File

@@ -1,6 +1,7 @@
import type { BoxProps } from '@/ui/v2/Box';
import Box from '@/ui/v2/Box';
import type { KeyboardEvent } from 'react';
import { useRef } from 'react';
import { useFormContext } from 'react-hook-form';
export interface FormProps extends BoxProps {
@@ -11,6 +12,7 @@ export interface FormProps extends BoxProps {
}
export default function Form({ onSubmit, onKeyDown, ...props }: FormProps) {
const formRef = useRef<HTMLDivElement>();
const {
handleSubmit,
formState: { isSubmitting },
@@ -25,6 +27,15 @@ export default function Form({ onSubmit, onKeyDown, ...props }: FormProps) {
return;
}
const submitButton = Array.from(
formRef.current.getElementsByTagName('button'),
).find((item) => item.type === 'submit');
// Disabling submit if the submit button is disabled
if (submitButton?.disabled) {
return;
}
event.preventDefault();
handleSubmit(onSubmit)(event);
@@ -35,6 +46,7 @@ export default function Form({ onSubmit, onKeyDown, ...props }: FormProps) {
// so keyboard events must be handled on the form element itself.
// eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions
<Box
ref={formRef}
component="form"
{...props}
onKeyDown={(event) => {

View File

@@ -0,0 +1,26 @@
import ActivityIndicator from '@/ui/v2/ActivityIndicator';
import type { BoxProps } from '@/ui/v2/Box';
import Box from '@/ui/v2/Box';
import { twMerge } from 'tailwind-merge';
export interface FormActivityIndicatorProps extends BoxProps {}
export default function FormActivityIndicator({
className,
...props
}: FormActivityIndicatorProps) {
return (
<Box
{...props}
className={twMerge(
'grid items-center justify-center px-6 py-4',
className,
)}
>
<ActivityIndicator
circularProgressProps={{ className: 'w-5 h-5' }}
label="Loading form..."
/>
</Box>
);
}

View File

@@ -0,0 +1,2 @@
export * from './FormActivityIndicator';
export { default } from './FormActivityIndicator';

View File

@@ -1,14 +1,13 @@
import Breadcrumbs from '@/components/common/Breadcrumbs';
import FeedbackForm from '@/components/common/FeedbackForm';
import LocalAccountMenu from '@/components/common/LocalAccountMenu';
import Logo from '@/components/common/Logo';
import MobileNav from '@/components/common/MobileNav';
import ThemeSwitcher from '@/components/common/ThemeSwitcher';
import NavLink from '@/components/common/NavLink';
import { AccountMenu } from '@/components/dashboard/AccountMenu';
import useIsPlatform from '@/hooks/common/useIsPlatform';
import Box from '@/ui/v2/Box';
import { Dropdown } from '@/ui/v2/Dropdown';
import Link from '@/ui/v2/Link';
import NavLink from 'next/link';
import { useRouter } from 'next/router';
import type { DetailedHTMLProps, HTMLProps, PropsWithoutRef } from 'react';
import { twMerge } from 'tailwind-merge';
@@ -24,6 +23,7 @@ export default function Header({ className, ...props }: HeaderProps) {
return (
<Box
component="header"
className={twMerge(
'z-40 grid w-full transform-gpu grid-flow-col items-center justify-between gap-2 border-b-1 px-4 py-3',
className,
@@ -32,10 +32,8 @@ export default function Header({ className, ...props }: HeaderProps) {
{...props}
>
<div className="grid grid-flow-col items-center gap-3">
<NavLink href="/" passHref>
<Link href="/" className="w-12">
<Logo className="mx-auto cursor-pointer" />
</Link>
<NavLink href="/" className="w-12">
<Logo className="mx-auto cursor-pointer" />
</NavLink>
{(router.query.workspaceSlug || router.query.appSlug) && (
@@ -63,25 +61,20 @@ export default function Header({ className, ...props }: HeaderProps) {
)}
<NavLink
underline="none"
href="https://docs.nhost.io"
passHref
className="mr-2 rounded-md px-2.5 py-1.5 text-sm motion-safe:transition-colors"
sx={{
color: 'text.primary',
'&:hover': { backgroundColor: 'grey.200' },
}}
target="_blank"
rel="noopener noreferrer"
>
<Link
underline="none"
href="https://docs.nhost.io"
className="mr-2 rounded-md px-2.5 py-1.5 text-sm motion-safe:transition-colors"
sx={{
color: 'text.primary',
'&:hover': { backgroundColor: 'grey.200' },
}}
>
Docs
</Link>
Docs
</NavLink>
{isPlatform ? <AccountMenu /> : <ThemeSwitcher className="w-52" />}
{isPlatform ? <AccountMenu /> : <LocalAccountMenu />}
</div>
<MobileNav className="sm:hidden" />

View File

@@ -1,12 +1,11 @@
import type { NavLinkProps } from '@/components/common/NavLink';
import NavLink from '@/components/common/NavLink';
import type { SvgIconProps } from '@/ui/v2/icons/SvgIcon';
import Link from '@/ui/v2/Link';
import NavLink from 'next/link';
import type { ForwardedRef, ReactElement } from 'react';
import type { ForwardedRef, PropsWithoutRef, ReactElement } from 'react';
import { cloneElement, forwardRef, isValidElement } from 'react';
import { twMerge } from 'tailwind-merge';
export interface IconLinkProps extends Omit<NavLinkProps, 'ref'> {
export interface IconLinkProps extends PropsWithoutRef<NavLinkProps> {
/**
* The icon to display.
*/
@@ -39,6 +38,12 @@ function IconLink(
: [icon.props?.sx]),
{
color: (theme) => {
if (props.disabled) {
return theme.palette.mode === 'dark'
? 'text.secondary'
: 'text.primary';
}
if (active) {
return 'primary.main';
}
@@ -58,49 +63,49 @@ function IconLink(
}
return (
<NavLink ref={ref} passHref href={href} {...props}>
<Link
href={href}
underline="none"
className={twMerge(
'grid grid-flow-row justify-items-center gap-1 rounded-md py-2.5 px-0.5 text-center font-medium motion-safe:transition-colors',
className,
)}
sx={{
fontSize: (theme) => theme.typography.pxToRem(10),
lineHeight: (theme) => theme.typography.pxToRem(15),
backgroundColor: active ? 'primary.light' : 'transparent',
color: active ? 'primary.main' : 'text.primary',
[`&:hover`]: {
backgroundColor: active ? 'primary.light' : 'action.hover',
},
}}
>
{isValidElement(icon)
? cloneElement(icon, {
...icon.props,
className: twMerge('w-4 h-4', icon.props.className),
sx: [
...(Array.isArray(icon.props?.sx)
? icon.props.sx
: [icon.props?.sx]),
{
color: (theme) => {
if (active) {
return 'primary.main';
}
<NavLink
ref={ref}
href={href}
underline="none"
className={twMerge(
'grid grid-flow-row justify-items-center gap-1 rounded-md py-2.5 px-0.5 text-center font-medium motion-safe:transition-colors',
className,
)}
sx={{
fontSize: (theme) => theme.typography.pxToRem(10),
lineHeight: (theme) => theme.typography.pxToRem(15),
backgroundColor: active ? 'primary.light' : 'transparent',
color: active ? 'primary.main' : 'text.primary',
[`&:hover`]: {
backgroundColor: active ? 'primary.light' : 'action.hover',
},
}}
{...props}
>
{isValidElement(icon)
? cloneElement(icon, {
...icon.props,
className: twMerge('w-4 h-4', icon.props.className),
sx: [
...(Array.isArray(icon.props?.sx)
? icon.props.sx
: [icon.props?.sx]),
{
color: (theme) => {
if (active) {
return 'primary.main';
}
return theme.palette.mode === 'dark'
? 'text.secondary'
: 'text.primary';
},
return theme.palette.mode === 'dark'
? 'text.secondary'
: 'text.primary';
},
],
})
: null}
},
],
})
: null}
{children}
</Link>
{children}
</NavLink>
);
}

View File

@@ -1,10 +1,50 @@
import type { ActivityIndicatorProps } from '@/ui/v2/ActivityIndicator';
import ActivityIndicator from '@/ui/v2/ActivityIndicator';
import type { BoxProps } from '@/ui/v2/Box';
import Box from '@/ui/v2/Box';
import { twMerge } from 'tailwind-merge';
export function LoadingScreen() {
export interface LoadingScreenProps extends BoxProps {
/**
* Props passed to individual component slots.
*/
slotProps?: {
/**
* Props passed to the `<Box />` component.
*/
root?: BoxProps;
/**
* Props passed to the `<ActivityIndicator />` component.
*/
activityIndicator?: ActivityIndicatorProps;
};
}
export function LoadingScreen({
className,
slotProps = { root: {}, activityIndicator: {} },
...props
}: LoadingScreenProps) {
return (
<Box className="absolute top-0 left-0 bottom-0 right-0 flex items-center justify-center z-50 h-full w-full">
<ActivityIndicator circularProgressProps={{ className: 'w-5 h-5' }} />
<Box
className={twMerge(
'absolute top-0 left-0 bottom-0 right-0 z-50 flex h-full w-full items-center justify-center',
className,
slotProps?.root?.className,
)}
{...slotProps?.root}
{...props}
>
<ActivityIndicator
{...slotProps?.activityIndicator}
circularProgressProps={{
...slotProps?.activityIndicator?.circularProgressProps,
className: twMerge(
'w-5 h-5',
slotProps?.activityIndicator?.circularProgressProps?.className,
),
}}
/>
</Box>
);
}

View File

@@ -0,0 +1,39 @@
import ThemeSwitcher from '@/components/common/ThemeSwitcher';
import { Dropdown } from '@/ui/v2/Dropdown';
import IconButton from '@/ui/v2/IconButton';
import UserIcon from '@/ui/v2/icons/UserIcon';
import Text from '@/ui/v2/Text';
import getConfig from 'next/config';
export default function LocalAccountMenu() {
const { publicRuntimeConfig } = getConfig();
return (
<Dropdown.Root className="justify-self-center">
<Dropdown.Trigger hideChevron asChild>
<IconButton
variant="borderless"
color="secondary"
className="h-7 w-7 rounded-full"
sx={{
backgroundColor: (theme) => `${theme.palette.grey[300]} !important`,
}}
>
<UserIcon className="h-4 w-4" />
</IconButton>
</Dropdown.Trigger>
<Dropdown.Content
PaperProps={{
className: 'mt-1 p-6 grid grid-flow-row gap-4 w-full max-w-xs',
}}
>
<ThemeSwitcher label="Theme" />
<Text className="text-center text-xs" color="disabled">
Dashboard Version: {publicRuntimeConfig?.version || 'n/a'}
</Text>
</Dropdown.Content>
</Dropdown.Root>
);
}

View File

@@ -0,0 +1 @@
export { default } from './LocalAccountMenu';

View File

@@ -0,0 +1,46 @@
import { useUI } from '@/context/UIContext';
import { Alert } from '@/ui/Alert';
export default function MaintenanceAlert() {
const { maintenanceActive, maintenanceEndDate } = useUI();
if (!maintenanceActive) {
return null;
}
const dateTimeFormat = Intl.DateTimeFormat(undefined, {
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
day: '2-digit',
month: '2-digit',
year: 'numeric',
timeZoneName: 'short',
});
const parts = dateTimeFormat.formatToParts(maintenanceEndDate);
const year = parts.find((part) => part.type === 'year')?.value;
const month = parts.find((part) => part.type === 'month')?.value;
const day = parts.find((part) => part.type === 'day')?.value;
const hour = parts.find((part) => part.type === 'hour')?.value;
const minute = parts.find((part) => part.type === 'minute')?.value;
const timeZone = parts.find((part) => part.type === 'timeZoneName')?.value;
return (
<Alert severity="warning" className="mt-4">
<p>
We&apos;re currently doing maintenance on our infrastructure. Project
creation and project settings are temporarily disabled during the
maintenance period.
</p>
{maintenanceEndDate && (
<p>
Maintenance is expected to be completed at {year}-{month}-{day} {hour}
:{minute} {timeZone}.
</p>
)}
</Alert>
);
}

View File

@@ -0,0 +1 @@
export { default } from './MaintenanceAlert';

View File

@@ -20,6 +20,7 @@ import type { ListItemButtonProps } from '@/ui/v2/ListItem';
import { ListItem } from '@/ui/v2/ListItem';
import Text from '@/ui/v2/Text';
import { useSignOut } from '@nhost/nextjs';
import getConfig from 'next/config';
import { useRouter } from 'next/router';
import type { ReactNode } from 'react';
import { cloneElement, Fragment, isValidElement, useState } from 'react';
@@ -89,6 +90,7 @@ export default function MobileNav({ className, ...props }: MobileNavProps) {
const { signOut } = useSignOut();
const { setUserContext } = useUserDataContext();
const router = useRouter();
const { publicRuntimeConfig } = getConfig();
return (
<>
@@ -256,6 +258,10 @@ export default function MobileNav({ className, ...props }: MobileNavProps) {
</ListItem.Button>
</ListItem.Root>
</List>
<Text className="text-center text-xs" color="secondary">
Dashboard Version: {publicRuntimeConfig?.version || 'n/a'}
</Text>
</section>
)}
</Drawer>

View File

@@ -1,21 +1,27 @@
import Link from 'next/link';
import type { DetailedHTMLProps, ForwardedRef, HTMLProps } from 'react';
import type { LinkProps } from '@/ui/v2/Link';
import Link from '@/ui/v2/Link';
import NextLink from 'next/link';
import type { ForwardedRef, PropsWithoutRef } from 'react';
import { forwardRef } from 'react';
import { twMerge } from 'tailwind-merge';
export interface NavLinkProps
extends DetailedHTMLProps<HTMLProps<HTMLAnchorElement>, HTMLAnchorElement> {}
export interface NavLinkProps extends PropsWithoutRef<LinkProps> {
/**
* Determines whether or not the link should be disabled.
*/
disabled?: boolean;
}
function NavLink(
{ className, children, href, ...props }: NavLinkProps,
ref: ForwardedRef<HTMLAnchorElement>,
) {
return (
<Link href={href} passHref>
<a className={twMerge('font-display', className)} ref={ref} {...props}>
<NextLink href={href} passHref>
<Link className={twMerge('font-display', className)} ref={ref} {...props}>
{children}
</a>
</Link>
</Link>
</NextLink>
);
}

View File

@@ -21,6 +21,13 @@ export default function ThemeSwitcher({
onChange?.(event, value);
}}
slotProps={{
listbox: { className: 'min-w-0 w-full' },
popper: {
disablePortal: false,
className: 'z-[10000] w-[270px] w-full',
},
}}
>
<Option value="light">Light</Option>
<Option value="dark">Dark</Option>

View File

@@ -10,6 +10,7 @@ import Text from '@/ui/v2/Text';
import { nhost } from '@/utils/nhost';
import { useApolloClient } from '@apollo/client';
import { useUserData } from '@nhost/nextjs';
import getConfig from 'next/config';
import { useRouter } from 'next/router';
import { useEffect, useState } from 'react';
@@ -24,23 +25,10 @@ function AccountMenuContent({
const router = useRouter();
const client = useApolloClient();
const { handleClose } = useDropdown();
const { publicRuntimeConfig } = getConfig();
return (
<Box className="relative grid w-account grid-flow-row gap-5 p-6">
<Button
variant="borderless"
color="secondary"
className="absolute top-6 right-4 grid grid-flow-col items-center gap-px self-start font-medium"
onClick={async () => {
router.push('/signin');
await nhost.auth.signOut();
await client.resetStore();
}}
endIcon={<PowerIcon className="w-4 h-4 mr-1" />}
>
Sign Out
</Button>
<Box className="relative grid w-full grid-flow-row gap-5 p-6">
<div className="grid grid-flow-row justify-center">
<Avatar
className="mx-auto mb-2 h-16 w-16 rounded-full"
@@ -72,9 +60,26 @@ function AccountMenuContent({
<Button color="error" disabled>
Remove Account
</Button>
<Button
variant="outlined"
color="secondary"
onClick={async () => {
await nhost.auth.signOut();
router.push('/signin');
await client.resetStore();
}}
endIcon={<PowerIcon className="mr-1 h-4 w-4" />}
>
Sign Out
</Button>
</div>
<ThemeSwitcher label="Theme" fullWidth />
<ThemeSwitcher label="Theme" />
<Text className="text-center text-xs" color="disabled">
Dashboard Version: {publicRuntimeConfig?.version || 'n/a'}
</Text>
</Box>
);
}
@@ -107,7 +112,7 @@ export function AccountMenu() {
/>
</Dropdown.Trigger>
<Dropdown.Content PaperProps={{ className: 'mt-1' }}>
<Dropdown.Content PaperProps={{ className: 'mt-1 max-w-xs w-full' }}>
<AccountMenuContent
onChangePasswordClick={() => setChangePasswordModal(true)}
/>

View File

@@ -24,7 +24,7 @@ export function CountrySelector({ value, onChange }: CountrySelectorProps) {
placeholder="Select Country"
>
{countries?.map((country) => (
<Option key={country.name} value={country.name}>
<Option key={country.name} value={country.code}>
{country.name}
</Option>
))}

View File

@@ -3,6 +3,7 @@ import ControlledCheckbox from '@/components/common/ControlledCheckbox';
import { useDialog } from '@/components/common/DialogProvider';
import Form from '@/components/common/Form';
import InlineCode from '@/components/common/InlineCode';
import type { DialogFormProps } from '@/types/common';
import type { ColumnType, DatabaseColumn } from '@/types/dataBrowser';
import Box from '@/ui/v2/Box';
import Button from '@/ui/v2/Button';
@@ -22,7 +23,7 @@ import ForeignKeyEditor from './ForeignKeyEditor';
export type BaseColumnFormValues = DatabaseColumn;
export interface BaseColumnFormProps {
export interface BaseColumnFormProps extends DialogFormProps {
/**
* Function to be called when the form is submitted.
*/
@@ -60,6 +61,7 @@ export default function BaseColumnForm({
onSubmit: handleExternalSubmit,
onCancel,
submitButtonText = 'Save',
location,
}: BaseColumnFormProps) {
const { onDirtyStateChange } = useDialog();
@@ -91,8 +93,8 @@ export default function BaseColumnForm({
const isDirty = Object.keys(dirtyFields).length > 0;
useEffect(() => {
onDirtyStateChange(isDirty, 'drawer');
}, [isDirty, onDirtyStateChange]);
onDirtyStateChange(isDirty, location);
}, [isDirty, location, onDirtyStateChange]);
return (
<Form

View File

@@ -1,5 +1,6 @@
import { useDialog } from '@/components/common/DialogProvider';
import type { BaseForeignKeyFormValues } from '@/components/dataBrowser/BaseForeignKeyForm';
import CreateForeignKeyForm from '@/components/dataBrowser/CreateForeignKeyForm';
import EditForeignKeyForm from '@/components/dataBrowser/EditForeignKeyForm';
import type { DatabaseColumn } from '@/types/dataBrowser';
import Box from '@/ui/v2/Box';
import Button from '@/ui/v2/Button';
@@ -29,7 +30,7 @@ const ForeignKeyEditorInput = forwardRef(
) => {
const { openDialog } = useDialog();
const { setValue } = useFormContext();
const column = useWatch<Partial<DatabaseColumn>>();
const column = useWatch() as DatabaseColumn;
const { foreignKeyRelation } = column;
if (!column.foreignKeyRelation) {
@@ -39,8 +40,8 @@ const ForeignKeyEditorInput = forwardRef(
className="py-1"
disabled={!column.name || !column.type}
ref={ref}
onClick={() =>
openDialog('CREATE_FOREIGN_KEY', {
onClick={() => {
openDialog({
title: (
<span className="grid grid-flow-row">
<span>Add a Foreign Key Relation</span>
@@ -51,16 +52,18 @@ const ForeignKeyEditorInput = forwardRef(
</Text>
</span>
),
payload: {
selectedColumn: column.name,
availableColumns: [column],
onSubmit: (values: BaseForeignKeyFormValues) => {
setValue('foreignKeyRelation', values);
onCreateSubmit();
},
},
})
}
component: (
<CreateForeignKeyForm
selectedColumn={column.name}
availableColumns={[column]}
onSubmit={(values) => {
setValue('foreignKeyRelation', values);
onCreateSubmit();
}}
/>
),
});
}}
>
Add Foreign Key
</Button>
@@ -86,20 +89,22 @@ const ForeignKeyEditorInput = forwardRef(
<div className="grid grid-flow-col">
<Button
ref={ref}
onClick={() =>
openDialog('EDIT_FOREIGN_KEY', {
onClick={() => {
openDialog({
title: 'Edit Foreign Key Relation',
payload: {
foreignKeyRelation,
availableColumns: [column],
selectedColumn: column.name,
onSubmit: (values: BaseForeignKeyFormValues) => {
setValue('foreignKeyRelation', values);
onEditSubmit();
},
},
})
}
component: (
<EditForeignKeyForm
foreignKeyRelation={foreignKeyRelation}
selectedColumn={column.name}
availableColumns={[column]}
onSubmit={(values) => {
setValue('foreignKeyRelation', values);
onEditSubmit();
}}
/>
),
});
}}
variant="borderless"
className="min-w-[initial] py-1 px-2"
>

View File

@@ -2,6 +2,7 @@ import ControlledSelect from '@/components/common/ControlledSelect';
import { useDialog } from '@/components/common/DialogProvider';
import Form from '@/components/common/Form';
import useDatabaseQuery from '@/hooks/dataBrowser/useDatabaseQuery';
import type { DialogFormProps } from '@/types/common';
import type { DatabaseColumn, ForeignKeyRelation } from '@/types/dataBrowser';
import Box from '@/ui/v2/Box';
import Button from '@/ui/v2/Button';
@@ -23,7 +24,7 @@ export interface BaseForeignKeyFormValues extends ForeignKeyRelation {
disableOriginColumn?: boolean;
}
export interface BaseForeignKeyFormProps {
export interface BaseForeignKeyFormProps extends DialogFormProps {
/**
* Available columns in the table.
*/
@@ -64,6 +65,7 @@ export function BaseForeignKeyForm({
onSubmit: handleExternalSubmit,
onCancel,
submitButtonText = 'Save',
location,
}: BaseForeignKeyFormProps) {
const { onDirtyStateChange } = useDialog();
@@ -86,8 +88,8 @@ export function BaseForeignKeyForm({
const isDirty = Object.keys(dirtyFields).length > 0;
useEffect(() => {
onDirtyStateChange(isDirty, 'dialog');
}, [isDirty, onDirtyStateChange]);
onDirtyStateChange(isDirty, location);
}, [isDirty, location, onDirtyStateChange]);
return (
<Form

View File

@@ -1,6 +1,7 @@
import { useDialog } from '@/components/common/DialogProvider';
import Form from '@/components/common/Form';
import DatabaseRecordInputGroup from '@/components/dataBrowser/DatabaseRecordInputGroup';
import type { DialogFormProps } from '@/types/common';
import type {
ColumnInsertOptions,
DataBrowserGridColumn,
@@ -10,7 +11,7 @@ import Button from '@/ui/v2/Button';
import { useEffect } from 'react';
import { useFormContext } from 'react-hook-form';
export interface BaseRecordFormProps {
export interface BaseRecordFormProps extends DialogFormProps {
/**
* The columns of the table.
*/
@@ -36,6 +37,7 @@ export default function BaseRecordForm({
onSubmit: handleExternalSubmit,
onCancel,
submitButtonText = 'Save',
location,
}: BaseRecordFormProps) {
const { onDirtyStateChange } = useDialog();
const { requiredColumns, optionalColumns } = columns.reduce(
@@ -70,8 +72,8 @@ export default function BaseRecordForm({
const isDirty = Object.keys(dirtyFields).length > 0;
useEffect(() => {
onDirtyStateChange(isDirty, 'drawer');
}, [isDirty, onDirtyStateChange]);
onDirtyStateChange(isDirty, location);
}, [isDirty, location, onDirtyStateChange]);
// Stores columns in a map to have constant time lookup. This is necessary
// for tables with many columns.

View File

@@ -1,6 +1,7 @@
import { useDialog } from '@/components/common/DialogProvider';
import Form from '@/components/common/Form';
import { baseColumnValidationSchema } from '@/components/dataBrowser/BaseColumnForm';
import type { DialogFormProps } from '@/types/common';
import type { DatabaseTable, ForeignKeyRelation } from '@/types/dataBrowser';
import Box from '@/ui/v2/Box';
import Button from '@/ui/v2/Button';
@@ -30,7 +31,7 @@ export interface BaseTableFormValues
foreignKeyRelations?: ForeignKeyRelation[];
}
export interface BaseTableFormProps {
export interface BaseTableFormProps extends DialogFormProps {
/**
* Function to be called when the form is submitted.
*/
@@ -99,7 +100,9 @@ function NameInput() {
function FormFooter({
onCancel,
submitButtonText,
}: Pick<BaseTableFormProps, 'onCancel' | 'submitButtonText'>) {
location,
}: Pick<BaseTableFormProps, 'onCancel' | 'submitButtonText'> &
Pick<DialogFormProps, 'location'>) {
const { onDirtyStateChange } = useDialog();
const { isSubmitting, dirtyFields } = useFormState();
@@ -108,8 +111,8 @@ function FormFooter({
const isDirty = Object.keys(dirtyFields).length > 0;
useEffect(() => {
onDirtyStateChange(isDirty, 'drawer');
}, [isDirty, onDirtyStateChange]);
onDirtyStateChange(isDirty, location);
}, [isDirty, location, onDirtyStateChange]);
return (
<Box className="grid flex-shrink-0 grid-flow-col justify-between gap-3 border-t-1 p-2">
@@ -135,6 +138,7 @@ function FormFooter({
}
export default function BaseTableForm({
location,
onSubmit: handleExternalSubmit,
onCancel,
submitButtonText = 'Save',
@@ -168,7 +172,11 @@ export default function BaseTableForm({
<ForeignKeyEditorSection />
</div>
<FormFooter onCancel={onCancel} submitButtonText={submitButtonText} />
<FormFooter
onCancel={onCancel}
submitButtonText={submitButtonText}
location={location}
/>
</Form>
);
}

View File

@@ -1,5 +1,7 @@
import { useDialog } from '@/components/common/DialogProvider';
import type { BaseForeignKeyFormValues } from '@/components/dataBrowser/BaseForeignKeyForm';
import CreateForeignKeyForm from '@/components/dataBrowser/CreateForeignKeyForm';
import EditForeignKeyForm from '@/components/dataBrowser/EditForeignKeyForm';
import type { DatabaseColumn, ForeignKeyRelation } from '@/types/dataBrowser';
import Button from '@/ui/v2/Button';
import PlusIcon from '@/ui/v2/icons/PlusIcon';
@@ -68,18 +70,19 @@ export default function ForeignKeyEditorSection() {
onEdit={() => {
const primaryKeyIndex = getValues('primaryKeyIndex');
openDialog('EDIT_FOREIGN_KEY', {
openDialog({
title: 'Edit Foreign Key Relation',
payload: {
foreignKeyRelation: fields[index],
availableColumns: columns.map((column, columnIndex) =>
columnIndex === primaryKeyIndex
? { ...column, isPrimary: true }
: column,
),
onSubmit: (values: BaseForeignKeyFormValues) =>
handleEdit(values, index),
},
component: (
<EditForeignKeyForm
foreignKeyRelation={fields[index] as ForeignKeyRelation}
availableColumns={columns.map((column, columnIndex) =>
columnIndex === primaryKeyIndex
? { ...column, isPrimary: true }
: column,
)}
onSubmit={(values) => handleEdit(values, index)}
/>
),
});
}}
onDelete={() => remove(index)}
@@ -105,7 +108,7 @@ export default function ForeignKeyEditorSection() {
onClick={() => {
const primaryKeyIndex = getValues('primaryKeyIndex');
openDialog('CREATE_FOREIGN_KEY', {
openDialog({
title: (
<span className="grid grid-flow-row">
<span>Add a Foreign Key Relation</span>
@@ -116,14 +119,16 @@ export default function ForeignKeyEditorSection() {
</Text>
</span>
),
payload: {
availableColumns: columns.map((column, index) =>
index === primaryKeyIndex
? { ...column, isPrimary: true }
: column,
),
onSubmit: handleCreate,
},
component: (
<CreateForeignKeyForm
availableColumns={columns.map((column, index) =>
index === primaryKeyIndex
? { ...column, isPrimary: true }
: column,
)}
onSubmit={handleCreate}
/>
),
});
}}
>

View File

@@ -1,4 +1,4 @@
import customClaimsQuery from '@/utils/msw/mocks/graphql/customClaimsQuery';
import permissionVariablesQuery from '@/utils/msw/mocks/graphql/permissionVariablesQuery';
import hasuraMetadataQuery from '@/utils/msw/mocks/rest/hasuraMetadataQuery';
import tableQuery from '@/utils/msw/mocks/rest/tableQuery';
import { render, screen } from '@/utils/testUtils';
@@ -6,7 +6,11 @@ import { setupServer } from 'msw/node';
import { test, vi } from 'vitest';
import ColumnAutocomplete from './ColumnAutocomplete';
const server = setupServer(tableQuery, hasuraMetadataQuery, customClaimsQuery);
const server = setupServer(
tableQuery,
hasuraMetadataQuery,
permissionVariablesQuery,
);
beforeAll(() => server.listen({ onUnhandledRequest: 'warn' }));
afterEach(() => server.resetHandlers());

View File

@@ -15,11 +15,11 @@ import { useRouter } from 'next/router';
import { FormProvider, useForm } from 'react-hook-form';
export interface CreateColumnFormProps
extends Pick<BaseColumnFormProps, 'onCancel'> {
extends Pick<BaseColumnFormProps, 'onCancel' | 'location'> {
/**
* Function to be called when the form is submitted.
*/
onSubmit?: () => Promise<void>;
onSubmit?: (args?: any) => Promise<any>;
}
export default function CreateColumnForm({

View File

@@ -13,7 +13,10 @@ import { useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
export interface CreateForeignKeyFormProps
extends Pick<BaseForeignKeyFormProps, 'onCancel' | 'availableColumns'> {
extends Pick<
BaseForeignKeyFormProps,
'onCancel' | 'availableColumns' | 'location'
> {
/**
* Column selected by default.
*/
@@ -21,7 +24,7 @@ export interface CreateForeignKeyFormProps
/**
* Function to be called when the form is submitted.
*/
onSubmit?: (values: BaseForeignKeyFormValues) => Promise<void>;
onSubmit?: (values: BaseForeignKeyFormValues) => Promise<void> | void;
}
export default function CreateForeignKeyForm({
@@ -51,9 +54,7 @@ export default function CreateForeignKeyForm({
setError(undefined);
try {
if (onSubmit) {
await onSubmit(values);
}
await onSubmit?.(values);
} catch (submitError) {
if (submitError && submitError instanceof Error) {
setError(submitError);

View File

@@ -10,11 +10,11 @@ import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form';
export interface CreateRecordFormProps
extends Pick<BaseRecordFormProps, 'columns' | 'onCancel'> {
extends Pick<BaseRecordFormProps, 'columns' | 'onCancel' | 'location'> {
/**
* Function to be called when the form is submitted.
*/
onSubmit?: () => Promise<void>;
onSubmit?: (args?: any) => Promise<any>;
}
export default function CreateRecordForm({

View File

@@ -17,7 +17,7 @@ import { useRouter } from 'next/router';
import { FormProvider, useForm } from 'react-hook-form';
export interface CreateTableFormProps
extends Pick<BaseTableFormProps, 'onCancel'> {
extends Pick<BaseTableFormProps, 'onCancel' | 'location'> {
/**
* Schema where the table should be created.
*/
@@ -25,7 +25,7 @@ export interface CreateTableFormProps
/**
* Function to be called when the form is submitted.
*/
onSubmit?: () => Promise<void>;
onSubmit?: (args?: any) => Promise<any>;
}
export default function CreateTableForm({

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