Compare commits

..

86 Commits

Author SHA1 Message Date
github-actions[bot]
c8a8d4fca3 chore: update versions (#2609)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @nhost/hasura-auth-js@2.4.0

### Minor Changes

- 311374e: fix: ensure that the user remains signed in even after being
redirected with an error following an attempt to connect with a social
provider

### Patch Changes

-   1623e9b: chore: update `@simplewebauthn/browser` to `9.0.1`

## @nhost/vue@2.4.0

### Minor Changes

-   311374e: feat: add `connect` param to `useProviderLink` hook

### Patch Changes

-   @nhost/nhost-js@3.0.10

## @nhost/apollo@6.1.2

### Patch Changes

-   @nhost/nhost-js@3.0.10

## @nhost/react-apollo@10.0.2

### Patch Changes

-   Updated dependencies [311374e]
    -   @nhost/react@3.3.2
    -   @nhost/apollo@6.1.2

## @nhost/react-urql@7.0.2

### Patch Changes

-   Updated dependencies [311374e]
    -   @nhost/react@3.3.2

## @nhost/nextjs@2.1.8

### Patch Changes

-   Updated dependencies [311374e]
    -   @nhost/react@3.3.2

## @nhost/nhost-js@3.0.10

### Patch Changes

-   Updated dependencies [1623e9b]
-   Updated dependencies [311374e]
    -   @nhost/hasura-auth-js@2.4.0

## @nhost/react@3.3.2

### Patch Changes

-   311374e: feat: add `connect` param to `useProviderLink` hook
    -   @nhost/nhost-js@3.0.10

## @nhost-examples/docker-compose@0.3.0

### Minor Changes

- e40a452: chore: clarification on greyed-out options in the dashboard
when self-hosting

## @nhost-examples/react-apollo@0.7.0

### Minor Changes

- 311374e: feat: add example of how to connect a social auth provider to
an existing account

### Patch Changes

-   Updated dependencies [311374e]
    -   @nhost/react@3.3.2
    -   @nhost/react-apollo@10.0.2

## @nhost-examples/vue-apollo@0.5.0

### Minor Changes

- 311374e: feat: add example of how to connect a social auth provider to
an existing account

### Patch Changes

-   Updated dependencies [311374e]
    -   @nhost/vue@2.4.0
    -   @nhost/nhost-js@3.0.10
    -   @nhost/apollo@6.1.2

## @nhost/dashboard@1.11.2

### Patch Changes

-   @nhost/react-apollo@10.0.2
-   @nhost/nextjs@2.1.8

## @nhost/docs@2.7.2

### Patch Changes

-   5c47e8e: feat: added hasura's stringifyNumericTypes setting

## @nhost-examples/cli@0.2.2

### Patch Changes

-   @nhost/nhost-js@3.0.10

## @nhost-examples/codegen-react-apollo@0.3.1

### Patch Changes

-   Updated dependencies [311374e]
    -   @nhost/react@3.3.2
    -   @nhost/react-apollo@10.0.2

## @nhost-examples/codegen-react-query@0.3.1

### Patch Changes

-   Updated dependencies [311374e]
    -   @nhost/react@3.3.2

## @nhost-examples/codegen-react-urql@0.2.1

### Patch Changes

-   Updated dependencies [311374e]
    -   @nhost/react@3.3.2
    -   @nhost/react-urql@7.0.2

## @nhost-examples/multi-tenant-one-to-many@2.1.2

### Patch Changes

-   @nhost/nhost-js@3.0.10

## @nhost-examples/nextjs@0.2.2

### Patch Changes

-   Updated dependencies [311374e]
    -   @nhost/react@3.3.2
    -   @nhost/react-apollo@10.0.2
    -   @nhost/nextjs@2.1.8

## @nhost-examples/node-storage@0.1.2

### Patch Changes

-   @nhost/nhost-js@3.0.10

## @nhost-examples/nextjs-server-components@0.3.2

### Patch Changes

-   @nhost/nhost-js@3.0.10

## @nhost-examples/react-gqty@1.1.2

### Patch Changes

-   Updated dependencies [311374e]
    -   @nhost/react@3.3.2

## @nhost-examples/vue-quickstart@0.1.2

### Patch Changes

-   Updated dependencies [311374e]
    -   @nhost/vue@2.4.0
    -   @nhost/apollo@6.1.2

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-21 17:54:02 +01:00
Hassan Ben Jobrane
311374e3fb feat: react-apollo: add example of how to connect github to an existing account (#2615)
fixes https://github.com/nhost/nhost/issues/2582
2024-03-21 17:38:54 +01:00
Seth Deegan
e40a4529b4 chore (examples/docker-compose): clarification on greyed-out options in the dashboard when self-hosting (#2564) 2024-03-18 11:03:10 +01:00
Hassan Ben Jobrane
1623e9bd20 chore: hasura-auth-js: upgrade @simplewebauthn/browser to 9.0.1 (#2611)
fixes https://github.com/nhost/nhost/issues/2597
2024-03-13 17:25:29 +01:00
David Barroso
5c47e8e675 feat (docs): added hasura's stringifyNumericTypes setting (#2608) 2024-03-12 11:29:53 +01:00
github-actions[bot]
9f9f1c64f4 chore: update versions (#2605)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @nhost/dashboard@1.11.1

### Patch Changes

-   981404f: fix: set default value for healthCheck field validation

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-11 11:02:17 +01:00
Hassan Ben Jobrane
981404f0b9 fix(dashboard): set default value for healthCheck field validation (#2604) 2024-03-11 10:45:33 +01:00
github-actions[bot]
4ad27e9d72 chore: update versions (#2599)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @nhost/apollo@6.1.1

### Patch Changes

-   @nhost/nhost-js@3.0.9

## @nhost/react-apollo@10.0.1

### Patch Changes

-   @nhost/apollo@6.1.1
-   @nhost/react@3.3.1

## @nhost/react-urql@7.0.1

### Patch Changes

-   @nhost/react@3.3.1

## @nhost/stripe-graphql-js@1.1.1

### Patch Changes

-   7789469: chore: address linter errors and remove unnecessary imports

## @nhost/graphql-js@0.1.9

### Patch Changes

- 7789469: fix: resolve process is undefined error when running with
vitejs

## @nhost/nextjs@2.1.7

### Patch Changes

-   @nhost/react@3.3.1

## @nhost/nhost-js@3.0.9

### Patch Changes

-   Updated dependencies [7789469]
    -   @nhost/graphql-js@0.1.9

## @nhost/react@3.3.1

### Patch Changes

-   @nhost/nhost-js@3.0.9

## @nhost/vue@2.3.1

### Patch Changes

-   @nhost/nhost-js@3.0.9

## @nhost/dashboard@1.11.0

### Minor Changes

- 7789469: chore: upgrade dependency `@graphql-codegen/cli` to `5.0.2`
to address vulnerability
- 6c11b75: feat: add update user displayName section in account settings

### Patch Changes

-   @nhost/react-apollo@10.0.1
-   @nhost/nextjs@2.1.7

## @nhost-examples/codegen-react-apollo@0.3.0

### Minor Changes

- 7789469: chore: upgrade dependency `@graphql-codegen/cli` to `5.0.2`
to address vulnerability

### Patch Changes

-   @nhost/react@3.3.1
-   @nhost/react-apollo@10.0.1

## @nhost-examples/codegen-react-query@0.3.0

### Minor Changes

- 7789469: chore: upgrade dependency `@graphql-codegen/cli` to `5.0.2`
to address vulnerability

### Patch Changes

-   @nhost/react@3.3.1

## @nhost-examples/codegen-react-urql@0.2.0

### Minor Changes

- 7789469: chore: upgrade dependency `@graphql-codegen/cli` to `5.0.2`
to address vulnerability

### Patch Changes

-   @nhost/react@3.3.1
-   @nhost/react-urql@7.0.1

## @nhost-examples/react-apollo@0.6.0

### Minor Changes

- 7789469: chore: upgrade dependency `@graphql-codegen/cli` to `5.0.2`
to address vulnerability

### Patch Changes

-   @nhost/react@3.3.1
-   @nhost/react-apollo@10.0.1

## @nhost-examples/cli@0.2.1

### Patch Changes

-   @nhost/nhost-js@3.0.9

## @nhost-examples/multi-tenant-one-to-many@2.1.1

### Patch Changes

-   @nhost/nhost-js@3.0.9

## @nhost-examples/nextjs@0.2.1

### Patch Changes

-   @nhost/react@3.3.1
-   @nhost/react-apollo@10.0.1
-   @nhost/nextjs@2.1.7

## @nhost-examples/node-storage@0.1.1

### Patch Changes

-   @nhost/nhost-js@3.0.9

## @nhost-examples/nextjs-server-components@0.3.1

### Patch Changes

-   @nhost/nhost-js@3.0.9

## @nhost-examples/react-gqty@1.1.1

### Patch Changes

-   @nhost/react@3.3.1

## @nhost-examples/serverless-functions@0.1.1

### Patch Changes

-   Updated dependencies [7789469]
    -   @nhost/stripe-graphql-js@1.1.1

## @nhost-examples/vue-apollo@0.4.1

### Patch Changes

-   7789469: chore: address linter errors and remove unnecessary imports
    -   @nhost/nhost-js@3.0.9
    -   @nhost/apollo@6.1.1
    -   @nhost/vue@2.3.1

## @nhost-examples/vue-quickstart@0.1.1

### Patch Changes

-   @nhost/apollo@6.1.1
-   @nhost/vue@2.3.1

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-08 15:51:16 +01:00
Hassan Ben Jobrane
778946998a fix: graphql-js: resolve process is undefined error when running with vitejs (#2601)
fixes https://github.com/nhost/nhost/issues/2600
2024-03-08 15:23:13 +01:00
Hassan Ben Jobrane
6c11b75807 feat: dashboard: add update user displayName section in account settings (#2598)
fixes https://github.com/nhost/nhost/issues/1489
2024-03-07 17:23:35 +01:00
github-actions[bot]
2dc031d16c chore: update versions (#2592)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @nhost-examples/react-apollo@0.5.0

### Minor Changes

- 08a7dd9: feat: add example workaround to the reset password ticket
expired issue

### Patch Changes

- f0a994a: fix: update allowedUrls and redirectTo to point to the
profile page

## @nhost-examples/vue-apollo@0.4.0

### Minor Changes

- 08a7dd9: feat: add example workaround to the reset password ticket
expired issue

### Patch Changes

- f0a994a: fix: update allowedUrls and redirectTo to point to the
profile page

## @nhost/docs@2.7.1

### Patch Changes

-   6cb2b63: feat: added nhost run env documentation
-   40bd3e4: fix: fixed wrong links in documentation

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-06 16:56:26 +01:00
Nicolas Bourdin
40bd3e4572 doc(link): fix wrong links in documentation (#2596)
Co-authored-by: Nicolas Bourdin <nicolas@epeak.co>
Co-authored-by: David Barroso <dbarrosop@dravetech.com>
2024-03-06 14:50:32 +01:00
David Barroso
6cb2b6331a feat (docs): added nhost run env documentation (#2594) 2024-03-06 14:13:02 +01:00
Hassan Ben Jobrane
08a7dd9894 feat(examples): add reset password ticket expired workarounds in the examples (#2590)
fixes https://github.com/nhost/nhost/issues/2314
2024-03-05 15:48:46 +01:00
Hassan Ben Jobrane
f0a994a26e fix(examples): update allowedUrls and redirectTo to point to /profile (#2591) 2024-03-05 14:17:01 +01:00
Hassan Ben Jobrane
4fbd6bd4fa chore: fix release with missing changeset (#2588)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-04 16:51:57 +01:00
github-actions[bot]
67fc77486c chore: update versions (#2578)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @nhost/apollo@6.1.0

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

-   @nhost/nhost-js@3.0.8

## @nhost/google-translation@0.1.0

### Minor Changes

-   49a80c2: chore: update dependencies

## @nhost/react-apollo@10.0.0

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

-   Updated dependencies [49a80c2]
    -   @nhost/apollo@6.1.0
    -   @nhost/react@3.3.0

## @nhost/react-urql@7.0.0

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

-   Updated dependencies [49a80c2]
    -   @nhost/react@3.3.0

## @nhost/stripe-graphql-js@1.1.0

### Minor Changes

-   49a80c2: chore: update dependencies

## @nhost/react@3.3.0

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

-   @nhost/nhost-js@3.0.8

## @nhost/vue@2.3.0

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

-   @nhost/nhost-js@3.0.8

## @nhost/nextjs@2.1.6

### Patch Changes

-   Updated dependencies [49a80c2]
    -   @nhost/react@3.3.0

## @nhost/dashboard@1.10.0

### Minor Changes

-   49a80c2: chore: update dependencies
-   150c04a: feat: add healthcheck config to run services

### Patch Changes

- e03f141: fix: allow insert, update and delete on tables in `auth` and
`storage` schemas
- 28676f4: feat: add min postgres version check to enable the ai service
-   Updated dependencies [49a80c2]
    -   @nhost/react-apollo@10.0.0
    -   @nhost/nextjs@2.1.6

## @nhost/docs@2.7.0

### Minor Changes

-   49a80c2: chore: update dependencies

## @nhost-examples/cli@0.2.0

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

-   @nhost/nhost-js@3.0.8

## @nhost-examples/codegen-react-apollo@0.2.0

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

-   Updated dependencies [49a80c2]
    -   @nhost/react-apollo@10.0.0
    -   @nhost/react@3.3.0

## @nhost-examples/codegen-react-query@0.2.0

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

-   Updated dependencies [49a80c2]
    -   @nhost/react@3.3.0

## @nhost-examples/codegen-react-urql@0.1.0

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

-   Updated dependencies [49a80c2]
    -   @nhost/react-urql@7.0.0
    -   @nhost/react@3.3.0

## @nhost-examples/docker-compose@0.2.0

### Minor Changes

-   49a80c2: chore: update dependencies

## @nhost-examples/multi-tenant-one-to-many@2.1.0

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

-   @nhost/nhost-js@3.0.8

## @nhost-examples/nextjs@0.2.0

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

-   Updated dependencies [49a80c2]
    -   @nhost/react-apollo@10.0.0
    -   @nhost/react@3.3.0
    -   @nhost/nextjs@2.1.6

## @nhost-examples/node-storage@0.1.0

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

-   @nhost/nhost-js@3.0.8

## @nhost-examples/nextjs-server-components@0.3.0

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

-   @nhost/nhost-js@3.0.8

## @nhost-examples/sveltekit@0.3.0

### Minor Changes

-   49a80c2: chore: update dependencies

## @nhost-examples/react-apollo@0.4.0

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

- 4f3fb34: fix: set redirectTo when doing sign in with github and
include vercel previews in allowed redirect URLs
-   Updated dependencies [49a80c2]
    -   @nhost/react-apollo@10.0.0
    -   @nhost/react@3.3.0

## @nhost-examples/react-gqty@1.1.0

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

-   Updated dependencies [49a80c2]
    -   @nhost/react@3.3.0

## @nhost-examples/serverless-functions@0.1.0

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

-   Updated dependencies [49a80c2]
    -   @nhost/stripe-graphql-js@1.1.0

## @nhost-examples/vue-apollo@0.3.0

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

- 4f3fb34: fix: set redirectTo when doing sign in with github and
include vercel previews in allowed redirect URLs
-   Updated dependencies [49a80c2]
    -   @nhost/apollo@6.1.0
    -   @nhost/vue@2.3.0
    -   @nhost/nhost-js@3.0.8

## @nhost-examples/vue-quickstart@0.1.0

### Minor Changes

-   49a80c2: chore: update dependencies

### Patch Changes

-   Updated dependencies [49a80c2]
    -   @nhost/apollo@6.1.0
    -   @nhost/vue@2.3.0

## @nhost/docgen@0.2.0

### Minor Changes

-   49a80c2: chore: update dependencies

## @nhost/sync-versions@0.1.0

### Minor Changes

-   49a80c2: chore: update dependencies

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Hassan Ben Jobrane <hsanbenjobrane@gmail.com>
2024-03-04 16:16:06 +01:00
Hassan Ben Jobrane
4f3fb3446e fix: set redirectTo in oauth examples (#2586) 2024-03-04 15:33:24 +01:00
Hassan Ben Jobrane
49a80c22be chore: add changeset (#2584)
adds missing changeset for this PR
https://github.com/nhost/nhost/pull/2574
2024-03-04 13:52:38 +01:00
Hassan Ben Jobrane
28676f4cdc feat: dashboard: add min postgres version check to enable the ai service (#2576)
fixes https://github.com/nhost/nhost/issues/2439
2024-03-02 22:33:49 +01:00
Hassan Ben Jobrane
e03f14133c fix: dashboard: refactor database datagrid to allow insert/update/delete for tables auth and storage (#2577)
fixes https://github.com/nhost/nhost/issues/2476
2024-03-02 22:04:23 +01:00
Hassan Ben Jobrane
150c04a4f4 feat: dashboard: add healthcheck config to run services (#2575)
fixes https://github.com/nhost/nhost/issues/2410
2024-03-02 19:28:13 +01:00
github-actions[bot]
bccd67b1b1 [Scheduled] Update dependencies (#2574)
Dependencies updated

Note - If you see this PR and the checks haven't run, close and reopen
the PR. See
https://github.com/peter-evans/create-pull-request/blob/main/docs/concepts-guidelines.md#triggering-further-workflow-runs

---------

Co-authored-by: David Barroso <dbarrosop@dravetech.com>
Co-authored-by: dbarrosop <dbarrosop@users.noreply.github.com>
Co-authored-by: Hassan Ben Jobrane <hsanbenjobrane@gmail.com>
2024-03-02 18:40:03 +01:00
David Barroso
b14fd2f14c chore: fix role to assume in gen update dependencies (#2573) 2024-03-01 12:21:38 +01:00
github-actions[bot]
68b3d23cd9 chore: update versions (#2572)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @nhost/dashboard@1.9.0

### Minor Changes

-   d86e5c9: feat: add support for filtering the logs using a RegExp

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-02-29 17:54:02 +01:00
Hassan Ben Jobrane
d86e5c9c16 feat(dashboard): query services list from be and filter the logs using a regex (#2552)
fixes: https://github.com/nhost/nhost/issues/2391
2024-02-29 17:38:38 +01:00
github-actions[bot]
b2cc1411d7 chore: update versions (#2571)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @nhost/apollo@6.0.8

### Patch Changes

-   @nhost/nhost-js@3.0.8

## @nhost/react-apollo@9.0.3

### Patch Changes

-   @nhost/apollo@6.0.8
-   @nhost/react@3.2.3

## @nhost/react-urql@6.0.3

### Patch Changes

-   @nhost/react@3.2.3

## @nhost/graphql-js@0.1.8

### Patch Changes

- 407feea: fix: replace `jwt-decode` with `jose` to decode access tokens
in a non browser environment

## @nhost/nextjs@2.1.5

### Patch Changes

-   @nhost/react@3.2.3

## @nhost/nhost-js@3.0.8

### Patch Changes

-   Updated dependencies [407feea]
    -   @nhost/graphql-js@0.1.8

## @nhost/react@3.2.3

### Patch Changes

-   @nhost/nhost-js@3.0.8

## @nhost/vue@2.2.3

### Patch Changes

-   @nhost/nhost-js@3.0.8

## @nhost/dashboard@1.8.3

### Patch Changes

-   @nhost/react-apollo@9.0.3
-   @nhost/nextjs@2.1.5

## @nhost-examples/cli@0.1.9

### Patch Changes

-   @nhost/nhost-js@3.0.8

## @nhost-examples/codegen-react-apollo@0.1.17

### Patch Changes

-   @nhost/react@3.2.3
-   @nhost/react-apollo@9.0.3

## @nhost-examples/codegen-react-query@0.1.18

### Patch Changes

-   @nhost/react@3.2.3

## @nhost-examples/codegen-react-urql@0.0.14

### Patch Changes

-   @nhost/react@3.2.3
-   @nhost/react-urql@6.0.3

## @nhost-examples/multi-tenant-one-to-many@2.0.7

### Patch Changes

-   @nhost/nhost-js@3.0.8

## @nhost-examples/nextjs@0.1.19

### Patch Changes

-   @nhost/react@3.2.3
-   @nhost/react-apollo@9.0.3
-   @nhost/nextjs@2.1.5

## @nhost-examples/node-storage@0.0.11

### Patch Changes

-   @nhost/nhost-js@3.0.8

## @nhost-examples/nextjs-server-components@0.2.5

### Patch Changes

-   @nhost/nhost-js@3.0.8

## @nhost-examples/react-apollo@0.3.3

### Patch Changes

-   @nhost/react@3.2.3
-   @nhost/react-apollo@9.0.3

## @nhost-examples/react-gqty@1.0.7

### Patch Changes

-   @nhost/react@3.2.3

## @nhost-examples/vue-apollo@0.2.4

### Patch Changes

-   @nhost/nhost-js@3.0.8
-   @nhost/apollo@6.0.8
-   @nhost/vue@2.2.3

## @nhost-examples/vue-quickstart@0.0.16

### Patch Changes

-   @nhost/apollo@6.0.8
-   @nhost/vue@2.2.3

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-02-29 15:43:48 +01:00
Hassan Ben Jobrane
407feeac37 fix: sdk: graphql-js: replace jwt-decode with jose to decode access tokens in both node and the browser (#2570) 2024-02-29 14:51:33 +01:00
github-actions[bot]
7b25c37c26 chore: update versions (#2569)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @nhost/dashboard@1.8.2

### Patch Changes

- 6df4f02: fix: use custom error toast and show correct message when
sending an invite

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-02-29 13:10:09 +01:00
Hassan Ben Jobrane
6df4f02e95 fix(dashboard): show correct message when sending invite fails (#2567) 2024-02-29 12:52:25 +01:00
github-actions[bot]
aaae98f019 chore: update versions (#2559)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @nhost/docs@2.6.0

### Minor Changes

-   dc23dc0: fix: docs run references

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-02-25 23:02:36 -01:00
Nuno Pato
dc23dc0f49 fix: docs run references (#2558) 2024-02-25 22:47:38 -01:00
github-actions[bot]
82728da100 chore: update versions (#2556)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @nhost/apollo@6.0.7

### Patch Changes

-   @nhost/nhost-js@3.0.7

## @nhost/react-apollo@9.0.2

### Patch Changes

-   @nhost/apollo@6.0.7
-   @nhost/react@3.2.2

## @nhost/react-urql@6.0.2

### Patch Changes

-   @nhost/react@3.2.2

## @nhost/graphql-js@0.1.7

### Patch Changes

- 2d68fee: fix: resolve an issue where unauthenticated graphql requests
are not sent

## @nhost/nextjs@2.1.4

### Patch Changes

-   @nhost/react@3.2.2

## @nhost/nhost-js@3.0.7

### Patch Changes

-   Updated dependencies [2d68fee]
    -   @nhost/graphql-js@0.1.7

## @nhost/react@3.2.2

### Patch Changes

-   @nhost/nhost-js@3.0.7

## @nhost/vue@2.2.2

### Patch Changes

-   @nhost/nhost-js@3.0.7

## @nhost/dashboard@1.8.1

### Patch Changes

-   @nhost/react-apollo@9.0.2
-   @nhost/nextjs@2.1.4

## @nhost-examples/cli@0.1.8

### Patch Changes

-   @nhost/nhost-js@3.0.7

## @nhost-examples/codegen-react-apollo@0.1.16

### Patch Changes

-   @nhost/react@3.2.2
-   @nhost/react-apollo@9.0.2

## @nhost-examples/codegen-react-query@0.1.17

### Patch Changes

-   @nhost/react@3.2.2

## @nhost-examples/codegen-react-urql@0.0.13

### Patch Changes

-   @nhost/react@3.2.2
-   @nhost/react-urql@6.0.2

## @nhost-examples/multi-tenant-one-to-many@2.0.6

### Patch Changes

-   @nhost/nhost-js@3.0.7

## @nhost-examples/nextjs@0.1.18

### Patch Changes

-   @nhost/react@3.2.2
-   @nhost/react-apollo@9.0.2
-   @nhost/nextjs@2.1.4

## @nhost-examples/node-storage@0.0.10

### Patch Changes

-   @nhost/nhost-js@3.0.7

## @nhost-examples/nextjs-server-components@0.2.4

### Patch Changes

-   @nhost/nhost-js@3.0.7

## @nhost-examples/react-apollo@0.3.2

### Patch Changes

-   @nhost/react@3.2.2
-   @nhost/react-apollo@9.0.2

## @nhost-examples/react-gqty@1.0.6

### Patch Changes

-   @nhost/react@3.2.2

## @nhost-examples/vue-apollo@0.2.3

### Patch Changes

-   @nhost/nhost-js@3.0.7
-   @nhost/apollo@6.0.7
-   @nhost/vue@2.2.2

## @nhost-examples/vue-quickstart@0.0.15

### Patch Changes

-   @nhost/apollo@6.0.7
-   @nhost/vue@2.2.2

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-02-23 21:14:11 +01:00
Hassan Ben Jobrane
2d68fee54c fix(graphql-js): allow graphql requests with no access token (#2555) 2024-02-23 21:09:45 +01:00
github-actions[bot]
35010353c7 chore: update versions (#2547)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @nhost/apollo@6.0.6

### Patch Changes

-   e0ab6d9: fix: add extra logic to check and wait for a valid JWT
    -   @nhost/nhost-js@3.0.6

## @nhost/react-apollo@9.0.1

### Patch Changes

-   Updated dependencies [e0ab6d9]
    -   @nhost/apollo@6.0.6
    -   @nhost/react@3.2.1

## @nhost/react-urql@6.0.1

### Patch Changes

-   @nhost/react@3.2.1

## @nhost/graphql-js@0.1.6

### Patch Changes

-   e0ab6d9: fix: add extra logic to check and wait for a valid JWT

## @nhost/hasura-auth-js@2.3.1

### Patch Changes

- 7baee8a: fix(hasura-auth-js): replace `jwt-decode` with `jose` for
decoding access tokens that works on both the browser and Node.js
-   e0ab6d9: fix: add extra logic to check and wait for a valid JWT

## @nhost/nextjs@2.1.3

### Patch Changes

-   @nhost/react@3.2.1

## @nhost/nhost-js@3.0.6

### Patch Changes

-   Updated dependencies [7baee8a]
-   Updated dependencies [e0ab6d9]
    -   @nhost/hasura-auth-js@2.3.1
    -   @nhost/graphql-js@0.1.6

## @nhost/react@3.2.1

### Patch Changes

-   @nhost/nhost-js@3.0.6

## @nhost/vue@2.2.1

### Patch Changes

-   @nhost/nhost-js@3.0.6

## @nhost/dashboard@1.8.0

### Minor Changes

- 713d53c: feat: add catch-all route for workspace/project - useful for
documentation

### Patch Changes

-   3db2999: fix: refresh table list after running SQL using the editor
- 3c4dd55: fix: handle `Error` objects properly in the `ErrorToast`
component
- 92b434e: fix: resolve an issue where the checkbox in the data-grid
header did not select all rows
    -   @nhost/react-apollo@9.0.1
    -   @nhost/nextjs@2.1.3

## @nhost-examples/cli@0.1.7

### Patch Changes

-   @nhost/nhost-js@3.0.6

## @nhost-examples/codegen-react-apollo@0.1.15

### Patch Changes

-   @nhost/react-apollo@9.0.1
-   @nhost/react@3.2.1

## @nhost-examples/codegen-react-query@0.1.16

### Patch Changes

-   @nhost/react@3.2.1

## @nhost-examples/codegen-react-urql@0.0.12

### Patch Changes

-   @nhost/react@3.2.1
-   @nhost/react-urql@6.0.1

## @nhost-examples/docker-compose@0.1.1

### Patch Changes

-   aff059e: fix: timers

## @nhost-examples/multi-tenant-one-to-many@2.0.5

### Patch Changes

-   @nhost/nhost-js@3.0.6

## @nhost-examples/nextjs@0.1.17

### Patch Changes

-   @nhost/react-apollo@9.0.1
-   @nhost/react@3.2.1
-   @nhost/nextjs@2.1.3

## @nhost-examples/node-storage@0.0.9

### Patch Changes

-   @nhost/nhost-js@3.0.6

## @nhost-examples/nextjs-server-components@0.2.3

### Patch Changes

-   @nhost/nhost-js@3.0.6

## @nhost-examples/react-apollo@0.3.1

### Patch Changes

-   @nhost/react-apollo@9.0.1
-   @nhost/react@3.2.1

## @nhost-examples/react-gqty@1.0.5

### Patch Changes

-   @nhost/react@3.2.1

## @nhost-examples/vue-apollo@0.2.2

### Patch Changes

-   Updated dependencies [e0ab6d9]
    -   @nhost/apollo@6.0.6
    -   @nhost/nhost-js@3.0.6
    -   @nhost/vue@2.2.1

## @nhost-examples/vue-quickstart@0.0.14

### Patch Changes

-   Updated dependencies [e0ab6d9]
    -   @nhost/apollo@6.0.6
    -   @nhost/vue@2.2.1

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-02-23 10:07:53 +01:00
David Barroso
aff059ec71 fix (examples/docker-compose): timers (#2553) 2024-02-23 10:04:20 +01:00
Nuno Pato
713d53cfc0 feat: dashboard: add catch-all route (#2545) 2024-02-22 17:59:24 -01:00
Hassan Ben Jobrane
e0ab6d9a37 fix: JWT expired bug (#2533)
fixes: https://github.com/nhost/nhost/issues/2348

---------

Co-authored-by: David Barroso <dbarrosop@dravetech.com>
2024-02-22 18:44:43 +01:00
Hassan Ben Jobrane
7baee8a9cc fix(hasura-auth-js): use jose instead of jwt-decode to decode the accessToken and get the Hasura claims (#2550)
fixes https://github.com/nhost/nhost/issues/2513
2024-02-21 11:17:03 +01:00
Hassan Ben Jobrane
3db2999f60 fix(dashboard): refresh table list after running a SQL stmt using the editor (#2549)
fixes https://github.com/nhost/projects/issues/52
2024-02-20 13:40:46 +01:00
Hassan Ben Jobrane
3c4dd55045 fix(dashboard): handle Error alongside ApolloError properly in the ErrorToast component (#2548)
fixes https://github.com/nhost/nhost/issues/2525
2024-02-20 12:16:26 +01:00
Hassan Ben Jobrane
92b434e840 fix: refactor DataGridHeader component to allow for selecting all rows (#2546)
fixes https://github.com/nhost/nhost/issues/2526
2024-02-19 17:30:59 +01:00
github-actions[bot]
13d359602f chore: update versions (#2540)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @nhost/dashboard@1.7.0

### Minor Changes

-   0d8d0eb: Update docs and dashboard references

## @nhost/docs@2.5.0

### Minor Changes

-   0d8d0eb: Update docs and dashboard references

### Patch Changes

-   41617b9: feat: added elevated permissions docs
- 7db095f: chore: added a note about disk performance and CDN
information

## @nhost-examples/docker-compose@0.1.0

### Minor Changes

-   ed9df85: updated docker-compose.yaml and .env-example

## @nhost-examples/vue-apollo@0.2.1

### Patch Changes

-   c5c904b: fix: update signin methods settings

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-02-16 20:44:28 -01:00
Nuno Pato
0d8d0eb10f chore: update docs and fix dashboard references (#2543) 2024-02-16 18:21:30 -01:00
Seth Deegan
ed9df85778 Update docker-compose and .env-example (#2397)
The docker-compose example is severely outdated and the past
configuration used a docker image for the dashboard that did not allow
you to configure the URLs to the various API endpoints if you
self-hosted your own dashboard publicly.

The newest dashboard image allows you to do this so the docker-compose
has been updated to use this image and the env variables have been
updated accordingly.

Other variables have been updated in the docker-compose to support
self-hosting a public instance.

A commented traefik configuration in the docker-compose for the
dashboard service also allows the user to configure basic auth to
protect a publicly-facing dashboard.

---------

Co-authored-by: David Barroso <dbarrosop@dravetech.com>
Co-authored-by: Hassan Ben Jobrane <hsanbenjobrane@gmail.com>
2024-02-16 08:52:58 +01:00
David Barroso
41617b970a feat (docs): added elevated permissions docs (#2519)
Co-authored-by: Nuno Pato <nunopato@gmail.com>
2024-02-15 16:00:44 +01:00
Hassan Ben Jobrane
c5c904b716 fix(vue-apollo): update signin methods settings (#2541) 2024-02-15 13:48:41 +01:00
David Barroso
7db095fe92 chore: docs: added a note about disk performance and CDN information (#2539)
Fixes #2504
2024-02-15 11:47:33 +01:00
github-actions[bot]
f33e07b191 chore: update versions (#2538)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @nhost/hasura-auth-js@2.3.0

### Minor Changes

-   017f1a6: feat: add elevated permission examples

## @nhost/react@3.2.0

### Minor Changes

-   017f1a6: feat: add elevated permission examples

### Patch Changes

-   @nhost/nhost-js@3.0.5

## @nhost/vue@2.2.0

### Minor Changes

-   017f1a6: feat: add elevated permission examples

### Patch Changes

-   @nhost/nhost-js@3.0.5

## @nhost/apollo@6.0.5

### Patch Changes

-   @nhost/nhost-js@3.0.5

## @nhost/react-apollo@9.0.0

### Patch Changes

-   Updated dependencies [017f1a6]
    -   @nhost/react@3.2.0
    -   @nhost/apollo@6.0.5

## @nhost/react-urql@6.0.0

### Patch Changes

-   Updated dependencies [017f1a6]
    -   @nhost/react@3.2.0

## @nhost/nextjs@2.1.2

### Patch Changes

-   Updated dependencies [017f1a6]
    -   @nhost/react@3.2.0

## @nhost/nhost-js@3.0.5

### Patch Changes

-   Updated dependencies [017f1a6]
    -   @nhost/hasura-auth-js@2.3.0

## @nhost-examples/react-apollo@0.3.0

### Minor Changes

-   017f1a6: feat: add elevated permission examples

### Patch Changes

-   Updated dependencies [017f1a6]
    -   @nhost/react@3.2.0
    -   @nhost/react-apollo@9.0.0

## @nhost-examples/vue-apollo@0.2.0

### Minor Changes

-   017f1a6: feat: add elevated permission examples

### Patch Changes

-   Updated dependencies [017f1a6]
    -   @nhost/vue@2.2.0
    -   @nhost/nhost-js@3.0.5
    -   @nhost/apollo@6.0.5

## @nhost/dashboard@1.6.9

### Patch Changes

-   @nhost/react-apollo@9.0.0
-   @nhost/nextjs@2.1.2

## @nhost-examples/cli@0.1.6

### Patch Changes

-   @nhost/nhost-js@3.0.5

## @nhost-examples/codegen-react-apollo@0.1.14

### Patch Changes

-   Updated dependencies [017f1a6]
    -   @nhost/react@3.2.0
    -   @nhost/react-apollo@9.0.0

## @nhost-examples/codegen-react-query@0.1.15

### Patch Changes

-   Updated dependencies [017f1a6]
    -   @nhost/react@3.2.0

## @nhost-examples/codegen-react-urql@0.0.11

### Patch Changes

-   Updated dependencies [017f1a6]
    -   @nhost/react@3.2.0
    -   @nhost/react-urql@6.0.0

## @nhost-examples/multi-tenant-one-to-many@2.0.4

### Patch Changes

-   @nhost/nhost-js@3.0.5

## @nhost-examples/nextjs@0.1.16

### Patch Changes

-   Updated dependencies [017f1a6]
    -   @nhost/react@3.2.0
    -   @nhost/react-apollo@9.0.0
    -   @nhost/nextjs@2.1.2

## @nhost-examples/node-storage@0.0.8

### Patch Changes

-   @nhost/nhost-js@3.0.5

## @nhost-examples/nextjs-server-components@0.2.2

### Patch Changes

-   @nhost/nhost-js@3.0.5

## @nhost-examples/react-gqty@1.0.4

### Patch Changes

-   Updated dependencies [017f1a6]
    -   @nhost/react@3.2.0

## @nhost-examples/vue-quickstart@0.0.13

### Patch Changes

-   Updated dependencies [017f1a6]
    -   @nhost/vue@2.2.0
    -   @nhost/apollo@6.0.5

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-02-14 15:12:34 +01:00
Hassan Ben Jobrane
017f1a6c7b feat: add elevate workflow to react-apollo and vue-apollo example projects (#2521)
part-2 of https://github.com/nhost/nhost/issues/2394

---------

Co-authored-by: David Barroso <dbarrosop@dravetech.com>
2024-02-14 14:52:43 +01:00
github-actions[bot]
93957c8af3 chore: update versions (#2537)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @nhost/hasura-storage-js@2.4.0

### Minor Changes

-   2505b2e: fix: fix headers sent with getPresignedUrl

## @nhost/apollo@6.0.4

### Patch Changes

-   @nhost/nhost-js@3.0.4

## @nhost/react-apollo@8.0.1

### Patch Changes

-   @nhost/apollo@6.0.4
-   @nhost/react@3.1.1

## @nhost/react-urql@5.0.1

### Patch Changes

-   @nhost/react@3.1.1

## @nhost/nextjs@2.1.1

### Patch Changes

-   @nhost/react@3.1.1

## @nhost/nhost-js@3.0.4

### Patch Changes

-   Updated dependencies [2505b2e]
    -   @nhost/hasura-storage-js@2.4.0

## @nhost/react@3.1.1

### Patch Changes

-   @nhost/nhost-js@3.0.4

## @nhost/vue@2.1.1

### Patch Changes

-   @nhost/nhost-js@3.0.4

## @nhost/dashboard@1.6.8

### Patch Changes

-   @nhost/react-apollo@8.0.1
-   @nhost/nextjs@2.1.1

## @nhost-examples/cli@0.1.5

### Patch Changes

-   @nhost/nhost-js@3.0.4

## @nhost-examples/codegen-react-apollo@0.1.13

### Patch Changes

-   @nhost/react@3.1.1
-   @nhost/react-apollo@8.0.1

## @nhost-examples/codegen-react-query@0.1.14

### Patch Changes

-   @nhost/react@3.1.1

## @nhost-examples/codegen-react-urql@0.0.10

### Patch Changes

-   @nhost/react@3.1.1
-   @nhost/react-urql@5.0.1

## @nhost-examples/multi-tenant-one-to-many@2.0.3

### Patch Changes

-   @nhost/nhost-js@3.0.4

## @nhost-examples/nextjs@0.1.15

### Patch Changes

-   @nhost/react@3.1.1
-   @nhost/react-apollo@8.0.1
-   @nhost/nextjs@2.1.1

## @nhost-examples/node-storage@0.0.7

### Patch Changes

-   @nhost/nhost-js@3.0.4

## @nhost-examples/nextjs-server-components@0.2.1

### Patch Changes

-   @nhost/nhost-js@3.0.4

## @nhost-examples/react-apollo@0.2.1

### Patch Changes

-   @nhost/react@3.1.1
-   @nhost/react-apollo@8.0.1

## @nhost-examples/react-gqty@1.0.3

### Patch Changes

-   @nhost/react@3.1.1

## @nhost-examples/vue-apollo@0.1.1

### Patch Changes

-   @nhost/nhost-js@3.0.4
-   @nhost/apollo@6.0.4
-   @nhost/vue@2.1.1

## @nhost-examples/vue-quickstart@0.0.12

### Patch Changes

-   @nhost/apollo@6.0.4
-   @nhost/vue@2.1.1

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-02-14 10:29:57 +01:00
Nuno Pato
2505b2e26b fix: fix headers sent with getPresignedUrl (#2535) 2024-02-13 23:33:09 -01:00
Nuno Pato
5f4b4d2acc chore: update dependencies (#2536)
Co-authored-by: Hassan Ben Jobrane <hsanbenjobrane@gmail.com>
2024-02-13 20:29:47 -01:00
github-actions[bot]
71a8ce4446 chore: update versions (#2524)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @nhost/docs@2.4.0

### Minor Changes

-   791b729: fix: remove auth method

## @nhost/dashboard@1.6.7

### Patch Changes

-   5ef5189: fix: update `@apollo/client` to `3.9.4` to fix a cache bug

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-02-12 16:33:16 +01:00
Hassan Ben Jobrane
5ef5189898 fix(dashboard): resolve change plan modal cache issue (#2532)
related to https://github.com/nhost/nhost/issues/2530
2024-02-12 16:08:22 +01:00
Nuno Pato
791b7295fb fix: docs: remove auth method (#2475)
- https://github.com/nhost/nhost/issues/2474
2024-02-08 10:36:51 -01:00
github-actions[bot]
25bc4b7fd6 chore: update versions (#2501)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @nhost/hasura-auth-js@2.2.0

### Minor Changes

- 1a61c65: feat: add 'elevateEmailSecurityKey' to the SDKs along with
integration into react-apollo and vue-apollo examples

## @nhost/hasura-storage-js@2.3.0

### Minor Changes

-   d3d1424: feat: Add support for authenticated download of files

### Patch Changes

-   e5bab6a: chore: update dependencies

## @nhost/nextjs@2.1.0

### Minor Changes

-   b19ffed: chore: update peerDependency to support nextjs 14

### Patch Changes

-   e5bab6a: chore: update dependencies
-   Updated dependencies [1a61c65]
-   Updated dependencies [e5bab6a]
    -   @nhost/react@3.1.0

## @nhost/react@3.1.0

### Minor Changes

- 1a61c65: feat: add 'elevateEmailSecurityKey' to the SDKs along with
integration into react-apollo and vue-apollo examples

### Patch Changes

-   e5bab6a: chore: update dependencies
    -   @nhost/nhost-js@3.0.3

## @nhost/vue@2.1.0

### Minor Changes

- 1a61c65: feat: add 'elevateEmailSecurityKey' to the SDKs along with
integration into react-apollo and vue-apollo examples

### Patch Changes

-   e5bab6a: chore: update dependencies
    -   @nhost/nhost-js@3.0.3

## @nhost/apollo@6.0.3

### Patch Changes

-   e5bab6a: chore: update dependencies
    -   @nhost/nhost-js@3.0.3

## @nhost/google-translation@0.0.8

### Patch Changes

-   e5bab6a: chore: update dependencies

## @nhost/react-apollo@8.0.0

### Patch Changes

-   e5bab6a: chore: update dependencies
-   Updated dependencies [1a61c65]
-   Updated dependencies [e5bab6a]
    -   @nhost/react@3.1.0
    -   @nhost/apollo@6.0.3

## @nhost/react-urql@5.0.0

### Patch Changes

-   e5bab6a: chore: update dependencies
-   Updated dependencies [1a61c65]
-   Updated dependencies [e5bab6a]
    -   @nhost/react@3.1.0

## @nhost/stripe-graphql-js@1.0.7

### Patch Changes

-   e5bab6a: chore: update dependencies

## @nhost/nhost-js@3.0.3

### Patch Changes

-   Updated dependencies [1a61c65]
-   Updated dependencies [e5bab6a]
-   Updated dependencies [d3d1424]
    -   @nhost/hasura-auth-js@2.2.0
    -   @nhost/hasura-storage-js@2.3.0
    -   @nhost/graphql-js@0.1.5

## @nhost/docs@2.3.0

### Minor Changes

-   d3d1424: feat: Add support for authenticated download of files

### Patch Changes

-   e5bab6a: chore: update dependencies
- 2ae5ea8: fix: indicate that custom domains for postgres doesn't
require configuration

## @nhost-examples/nextjs-server-components@0.2.0

### Minor Changes

-   d3d1424: feat: Add support for authenticated download of files

### Patch Changes

-   e5bab6a: chore: update dependencies
    -   @nhost/nhost-js@3.0.3

## @nhost-examples/react-apollo@0.2.0

### Minor Changes

- 1a61c65: feat: add 'elevateEmailSecurityKey' to the SDKs along with
integration into react-apollo and vue-apollo examples

### Patch Changes

-   e5bab6a: chore: update dependencies
-   Updated dependencies [1a61c65]
-   Updated dependencies [e5bab6a]
    -   @nhost/react@3.1.0
    -   @nhost/react-apollo@8.0.0

## @nhost-examples/vue-apollo@0.1.0

### Minor Changes

- 1a61c65: feat: add 'elevateEmailSecurityKey' to the SDKs along with
integration into react-apollo and vue-apollo examples

### Patch Changes

-   e5bab6a: chore: update dependencies
-   Updated dependencies [1a61c65]
-   Updated dependencies [e5bab6a]
    -   @nhost/vue@2.1.0
    -   @nhost/apollo@6.0.3
    -   @nhost/nhost-js@3.0.3

## @nhost/dashboard@1.6.6

### Patch Changes

-   3ba485e: fix: added discord.com to connect-src
-   e5bab6a: chore: update dependencies
-   Updated dependencies [b19ffed]
-   Updated dependencies [e5bab6a]
    -   @nhost/nextjs@2.1.0
    -   @nhost/react-apollo@8.0.0

## @nhost-examples/cli@0.1.4

### Patch Changes

-   e5bab6a: chore: update dependencies
    -   @nhost/nhost-js@3.0.3

## @nhost-examples/codegen-react-apollo@0.1.12

### Patch Changes

-   e5bab6a: chore: update dependencies
-   Updated dependencies [1a61c65]
-   Updated dependencies [e5bab6a]
    -   @nhost/react@3.1.0
    -   @nhost/react-apollo@8.0.0

## @nhost-examples/codegen-react-query@0.1.13

### Patch Changes

-   e5bab6a: chore: update dependencies
-   Updated dependencies [1a61c65]
-   Updated dependencies [e5bab6a]
    -   @nhost/react@3.1.0

## @nhost-examples/codegen-react-urql@0.0.9

### Patch Changes

-   e5bab6a: chore: update dependencies
-   Updated dependencies [1a61c65]
-   Updated dependencies [e5bab6a]
    -   @nhost/react@3.1.0
    -   @nhost/react-urql@5.0.0

## @nhost-examples/multi-tenant-one-to-many@2.0.2

### Patch Changes

-   e5bab6a: chore: update dependencies
    -   @nhost/nhost-js@3.0.3

## @nhost-examples/nextjs@0.1.14

### Patch Changes

-   e5bab6a: chore: update dependencies
-   Updated dependencies [1a61c65]
-   Updated dependencies [b19ffed]
-   Updated dependencies [e5bab6a]
    -   @nhost/react@3.1.0
    -   @nhost/nextjs@2.1.0
    -   @nhost/react-apollo@8.0.0

## @nhost-examples/node-storage@0.0.6

### Patch Changes

-   e5bab6a: chore: update dependencies
    -   @nhost/nhost-js@3.0.3

## @nhost-examples/sveltekit@0.2.3

### Patch Changes

-   e5bab6a: chore: update dependencies

## @nhost-examples/react-gqty@1.0.2

### Patch Changes

-   e5bab6a: chore: update dependencies
-   Updated dependencies [1a61c65]
-   Updated dependencies [e5bab6a]
    -   @nhost/react@3.1.0

## @nhost-examples/serverless-functions@0.0.11

### Patch Changes

-   8c34c69: chore: update nodemailer version to `6.9.9`
-   Updated dependencies [e5bab6a]
    -   @nhost/stripe-graphql-js@1.0.7

## @nhost-examples/vue-quickstart@0.0.11

### Patch Changes

-   e5bab6a: chore: update dependencies
-   Updated dependencies [1a61c65]
-   Updated dependencies [e5bab6a]
    -   @nhost/vue@2.1.0
    -   @nhost/apollo@6.0.3

## @nhost/docgen@0.1.13

### Patch Changes

-   e5bab6a: chore: update dependencies

## @nhost/sync-versions@0.0.10

### Patch Changes

-   e5bab6a: chore: update dependencies

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Hassan Ben Jobrane <hsanbenjobrane@gmail.com>
2024-02-06 14:41:47 +01:00
Hassan Ben Jobrane
da20159ec5 chore(examples): update auth version to 0.25.0 in nhost.toml (#2518) 2024-02-06 14:09:30 +01:00
David Barroso
2ae5ea8bc1 fix (docs): indicate that custom domains for postgres doesn't require configuration (#2506) 2024-02-06 11:54:18 +01:00
David Barroso
3ba485e582 fix (dashboard): added discord.com to connect-src (#2516) 2024-02-06 11:29:27 +01:00
David Barroso
e5bab6a061 chore: update dependencies (#2505)
Co-authored-by: Hassan Ben Jobrane <hsanbenjobrane@gmail.com>
2024-02-06 10:25:48 +01:00
David Barroso
be64353145 Create SECURITY.md (#2515) 2024-02-06 10:00:38 +01:00
Hassan Ben Jobrane
2f5913c78d fix(examples): revert back auth version to 0.24.1 (#2512) 2024-02-05 17:18:52 +01:00
Nuno Pato
757ddd901c chore: docs: use hyphen instead of underscore (#2511) 2024-02-05 13:46:13 -01:00
Hassan Ben Jobrane
1a61c658a7 feat: add elevate func to the SDKs and the react-apollo example project (#2500)
part-1 of https://github.com/nhost/nhost/issues/2394
2024-02-05 13:25:14 +01:00
Nuno Pato
d3d14245c7 feat: hasura-storage-js: add authenticated download of files (#2507) 2024-02-05 11:24:34 -01:00
Alexander Mart
53d2f9d3e0 doc: fix method name in example code at refresh-session.mdx doc page (#2468)
Co-authored-by: Nuno Pato <nunopato@gmail.com>
2024-02-03 15:54:08 +01:00
Hassan Ben Jobrane
8c34c69e79 chore: update nodemailer (#2510) 2024-02-02 20:31:29 +01:00
Jared Prather
b19ffed273 chore: Update peerDependency next to ^14.0.0 (#2354)
Fixes: #2351 

Summary of next 14 changes
[here](https://nextjs.org/docs/pages/building-your-application/upgrading/version-14#v14-summary)

---------

Co-authored-by: Hassan Ben Jobrane <hsanbenjobrane@gmail.com>
2024-01-30 18:25:02 +01:00
Nuno Pato
859efa988a fix: docs: small fixes (#2486) 2024-01-26 17:15:06 -01:00
github-actions[bot]
3202b6b897 chore: update versions (#2495)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @nhost/dashboard@1.6.5

### Patch Changes

- ba73bb4: fix: update ErrorToast component to show the internal graphql
error
- d5337ff: fix: utilize accumulator in the creation of validation schema
within data grid utils

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-01-26 18:32:57 +01:00
Hassan Ben Jobrane
ba73bb4003 fix(dashboard): show internal error in toast message (#2496) 2024-01-26 17:42:18 +01:00
Hassan Ben Jobrane
d5337ff5bd fix(dashboard): fix bug with validation schema for create record form (#2494) 2024-01-26 16:50:28 +01:00
github-actions[bot]
511ab19755 chore: update versions (#2492)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @nhost/docs@2.2.0

### Minor Changes

- 5c9b8f0: feat: added docs regarding local development for Run services

## @nhost/dashboard@1.6.4

### Patch Changes

-   7c2a1c2: feat: show error and debug info in the error toast

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-01-25 17:23:36 +01:00
Hassan Ben Jobrane
7c2a1c29fd feat(dashboard): add custom error toast (#2463)
fixes https://github.com/nhost/nhost/issues/2435
2024-01-25 16:48:54 +01:00
David Barroso
5c9b8f0a3f feat (docs): added docs regarding local development for Run services (#2488) 2024-01-25 12:40:04 +01:00
github-actions[bot]
b3f1f5f6ea chore: update versions (#2491)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @nhost/dashboard@1.6.3

### Patch Changes

-   6b8aad5: fix: add bare nhost.run to CSP

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-01-25 12:14:56 +01:00
David Barroso
6b8aad5c84 fix(dashboard): add bare nhost.run to CSP (#2490) 2024-01-25 11:28:15 +01:00
github-actions[bot]
c36132c9bb chore: update versions (#2489)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @nhost/dashboard@1.6.2

### Patch Changes

-   b18edc0: feat: added CSP and X-Frame-Options

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-01-25 11:00:06 +01:00
David Barroso
b18edc0532 feat (dashboard): added CSP and X-Frame-Options (#2479) 2024-01-25 10:46:41 +01:00
David Barroso
1d55d3ea38 chore (general): added mintlify to docs devDependencies and manage node_modules with nix (#2487)
Co-authored-by: Nuno Pato <nunopato@gmail.com>
2024-01-24 10:43:59 +01:00
github-actions[bot]
fdc50b32d8 chore: update versions (#2484)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @nhost/apollo@6.0.2

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/nhost-js@3.0.2

## @nhost/google-translation@0.0.7

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit

## @nhost/react-apollo@7.0.2

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/apollo@6.0.2
    -   @nhost/react@3.0.2

## @nhost/react-urql@4.0.2

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/react@3.0.2

## @nhost/stripe-graphql-js@1.0.6

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit

## @nhost/graphql-js@0.1.5

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit

## @nhost/hasura-auth-js@2.1.11

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit

## @nhost/hasura-storage-js@2.2.6

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit

## @nhost/nextjs@2.0.2

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/react@3.0.2

## @nhost/nhost-js@3.0.2

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/hasura-storage-js@2.2.6
    -   @nhost/hasura-auth-js@2.1.11
    -   @nhost/graphql-js@0.1.5

## @nhost/react@3.0.2

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/nhost-js@3.0.2

## @nhost/vue@2.0.3

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/nhost-js@3.0.2

## @nhost/dashboard@1.6.1

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
- 3b8473b: chore: update turbo to `1.11.3` and pnpm to `8.10.5` in
Dockerfile
-   Updated dependencies [8d91f71]
    -   @nhost/react-apollo@7.0.2
    -   @nhost/nextjs@2.0.2

## @nhost-examples/cli@0.1.3

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/nhost-js@3.0.2

## @nhost-examples/codegen-react-apollo@0.1.11

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/react-apollo@7.0.2
    -   @nhost/react@3.0.2

## @nhost-examples/codegen-react-query@0.1.12

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/react@3.0.2

## @nhost-examples/codegen-react-urql@0.0.8

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/react-urql@4.0.2
    -   @nhost/react@3.0.2

## @nhost-examples/docker-compose@0.0.7

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit

## @nhost-examples/multi-tenant-one-to-many@2.0.1

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/nhost-js@3.0.2

## @nhost-examples/nextjs@0.1.13

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/react-apollo@7.0.2
    -   @nhost/nextjs@2.0.2
    -   @nhost/react@3.0.2

## @nhost-examples/node-storage@0.0.5

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/nhost-js@3.0.2

## @nhost-examples/nextjs-server-components@0.1.5

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/nhost-js@3.0.2

## @nhost-examples/sveltekit@0.2.2

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit

## @nhost-examples/react-apollo@0.1.18

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/react-apollo@7.0.2
    -   @nhost/react@3.0.2

## @nhost-examples/react-gqty@1.0.1

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/react@3.0.2

## @nhost-examples/serverless-functions@0.0.10

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/stripe-graphql-js@1.0.6

## @nhost-examples/vue-apollo@0.0.10

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/apollo@6.0.2
    -   @nhost/nhost-js@3.0.2
    -   @nhost/vue@2.0.3

## @nhost-examples/vue-quickstart@0.0.10

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
-   Updated dependencies [8d91f71]
    -   @nhost/apollo@6.0.2
    -   @nhost/vue@2.0.3

## @nhost/docgen@0.1.12

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit

## @nhost/sync-versions@0.0.9

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Hassan Ben Jobrane <hsanbenjobrane@gmail.com>
2024-01-23 20:04:39 +01:00
Hassan Ben Jobrane
3cdca8d4b3 chore: update sveltekit pnpm-lockl.yaml (#2485) 2024-01-23 19:18:44 +01:00
Hassan Ben Jobrane
c425c9f265 fix(quickstarts): use turbo to build nextjs-server-components and fix sveltekit lockfile (#2483) 2024-01-23 18:53:21 +01:00
Hassan Ben Jobrane
3b8473b168 chore: update pnpm and turbo versions in Dockerfile (#2482) 2024-01-23 16:51:14 +01:00
David Barroso
8d91f7103f chore: update deps and enable pnpm audit (#2466)
Co-authored-by: Hassan Ben Jobrane <hsanbenjobrane@gmail.com>
2024-01-23 13:58:48 +01:00
477 changed files with 22991 additions and 25786 deletions

View File

@@ -14,7 +14,7 @@ runs:
steps: steps:
- uses: pnpm/action-setup@v2.2.4 - uses: pnpm/action-setup@v2.2.4
with: with:
version: 8.6.2 version: 8.10.5
run_install: false run_install: false
- name: Get pnpm cache directory - name: Get pnpm cache directory
id: pnpm-cache-dir id: pnpm-cache-dir

23
.github/renovate.json vendored
View File

@@ -1,23 +0,0 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:base"
],
"docker-compose": {
"enabled": true
},
"ignoreDeps": [
"pnpm",
"node",
"@types/node"
],
"labels": [
"dependencies"
],
"enabledManagers": [
"npm",
"dockerfile",
"docker-compose",
"github-actions"
]
}

View File

@@ -106,6 +106,8 @@ jobs:
# * Run every `lint` script in the workspace . Dependencies build is cached by Turborepo # * Run every `lint` script in the workspace . Dependencies build is cached by Turborepo
- name: Lint - name: Lint
run: pnpm run lint:all run: pnpm run lint:all
- name: Audit for vulnerabilities
run: pnpx audit-ci --config ./audit-ci.jsonc
e2e: e2e:
name: 'E2E (Package: ${{ matrix.package.path }})' name: 'E2E (Package: ${{ matrix.package.path }})'

View File

@@ -0,0 +1,82 @@
---
name: "gen: update depenendencies"
on:
schedule:
- cron: '0 2 1 * *'
jobs:
run:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: write
pull-requests: write
steps:
- name: Check out repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Configure aws
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_PRODUCTION_CORE_ACCOUNT_ID }}:role/github-actions-nhost-${{ github.event.repository.name }}
aws-region: eu-central-1
- uses: nixbuild/nix-quick-install-action@v26
with:
nix_version: 2.16.2
nix_conf: |
experimental-features = nix-command flakes
sandbox = false
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
substituters = https://cache.nixos.org/?priority=40 s3://nhost-nix-cache?region=eu-central-1&priority=50
trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= ${{ secrets.NIX_CACHE_PUB_KEY }}
- name: Cache nix store
uses: actions/cache@v4
with:
path: /nix
key: nix-update-deps-${{ hashFiles('flakes.nix', 'flake.lock') }}
- name: Update nix flakes
run: nix flake update
- name: Update dependencies
run: |
nix develop -c bash -c "
pnpm dedupe
pnpm update -r
pnpm dedupe
"
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: Update dependencies
committer: GitHub <noreply@github.com>
author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>
signoff: false
branch: automated/update-deps
delete-branch: true
title: '[Scheduled] Update dependencies'
body: |
Dependencies updated
Note - If you see this PR and the checks haven't run, close and reopen the PR. See https://github.com/peter-evans/create-pull-request/blob/main/docs/concepts-guidelines.md#triggering-further-workflow-runs
labels: |
dependencies
draft: false
- name: "Cache nix store on s3"
run: |
echo ${{ secrets.NIX_CACHE_PRIV_KEY }} > cache-priv-key.pem
nix build .\#devShells.x86_64-linux.default
nix store sign --key-file cache-priv-key.pem --all
nix copy --to s3://nhost-nix-cache\?region=eu-central-1 .\#devShells.x86_64-linux.default
- run: rm cache-priv-key.pem
if: always()

2
.gitignore vendored
View File

@@ -19,7 +19,7 @@ logs/
coverage/ coverage/
dist/ dist/
umd/ umd/
node_modules/ node_modules
tmp/ tmp/
.pnpm-store .pnpm-store
.turbo .turbo

3
.npmrc
View File

@@ -1 +1,2 @@
prefer-workspace-packages = true prefer-workspace-packages = true
auto-install-peers = false

7
SECURITY.md Normal file
View File

@@ -0,0 +1,7 @@
# Security Policy
## Reporting a Vulnerability
At Nhost, we take security vulnerabilities seriously and appreciate the assistance of the community in bringing any issues to our attention. If you discover a security vulnerability, please use the GitHub Security Advisory ["Report a Vulnerability"](https://github.com/nhost/nhost/security/advisories/new) tab.
Once you have submitted the report, we will promptly conduct a thorough investigation within 72 hours. In case we need further information, we may contact you for additional details. Rest assured that addressing the reported vulnerability in a timely manner is our top priority.

6
audit-ci.jsonc Normal file
View File

@@ -0,0 +1,6 @@
{
// $schema provides code completion hints to IDEs.
"$schema": "https://github.com/IBM/audit-ci/raw/main/docs/schema.json",
"moderate": true,
"allowlist": ["trim-newlines"]
}

3
config/.husky/pre-commit Executable file → Normal file
View File

@@ -1,4 +1,7 @@
#!/bin/sh #!/bin/sh
#
[ -n "$CI" ] && exit 0
. "$(dirname "$0")/_/husky.sh" . "$(dirname "$0")/_/husky.sh"
pnpm dlx lint-staged --config config/.lintstagedrc.js pnpm dlx lint-staged --config config/.lintstagedrc.js

View File

@@ -1,5 +1,157 @@
# @nhost/dashboard # @nhost/dashboard
## 1.11.2
### Patch Changes
- @nhost/react-apollo@10.0.2
- @nhost/nextjs@2.1.8
## 1.11.1
### Patch Changes
- 981404f: fix: set default value for healthCheck field validation
## 1.11.0
### Minor Changes
- 7789469: chore: upgrade dependency `@graphql-codegen/cli` to `5.0.2` to address vulnerability
- 6c11b75: feat: add update user displayName section in account settings
### Patch Changes
- @nhost/react-apollo@10.0.1
- @nhost/nextjs@2.1.7
## 1.10.0
### Minor Changes
- 49a80c2: chore: update dependencies
- 150c04a: feat: add healthcheck config to run services
### Patch Changes
- e03f141: fix: allow insert, update and delete on tables in `auth` and `storage` schemas
- 28676f4: feat: add min postgres version check to enable the ai service
- Updated dependencies [49a80c2]
- @nhost/react-apollo@10.0.0
- @nhost/nextjs@2.1.6
## 1.9.0
### Minor Changes
- d86e5c9: feat: add support for filtering the logs using a RegExp
## 1.8.3
### Patch Changes
- @nhost/react-apollo@9.0.3
- @nhost/nextjs@2.1.5
## 1.8.2
### Patch Changes
- 6df4f02: fix: use custom error toast and show correct message when sending an invite
## 1.8.1
### Patch Changes
- @nhost/react-apollo@9.0.2
- @nhost/nextjs@2.1.4
## 1.8.0
### Minor Changes
- 713d53c: feat: add catch-all route for workspace/project - useful for documentation
### Patch Changes
- 3db2999: fix: refresh table list after running SQL using the editor
- 3c4dd55: fix: handle `Error` objects properly in the `ErrorToast` component
- 92b434e: fix: resolve an issue where the checkbox in the data-grid header did not select all rows
- @nhost/react-apollo@9.0.1
- @nhost/nextjs@2.1.3
## 1.7.0
### Minor Changes
- 0d8d0eb: Update docs and dashboard references
## 1.6.9
### Patch Changes
- @nhost/react-apollo@9.0.0
- @nhost/nextjs@2.1.2
## 1.6.8
### Patch Changes
- @nhost/react-apollo@8.0.1
- @nhost/nextjs@2.1.1
## 1.6.7
### Patch Changes
- 5ef5189: fix: update `@apollo/client` to `3.9.4` to fix a cache bug
## 1.6.6
### Patch Changes
- 3ba485e: fix: added discord.com to connect-src
- e5bab6a: chore: update dependencies
- Updated dependencies [b19ffed]
- Updated dependencies [e5bab6a]
- @nhost/nextjs@2.1.0
- @nhost/react-apollo@8.0.0
## 1.6.5
### Patch Changes
- ba73bb4: fix: update ErrorToast component to show the internal graphql error
- d5337ff: fix: utilize accumulator in the creation of validation schema within data grid utils
## 1.6.4
### Patch Changes
- 7c2a1c2: feat: show error and debug info in the error toast
## 1.6.3
### Patch Changes
- 6b8aad5: fix: add bare nhost.run to CSP
## 1.6.2
### Patch Changes
- b18edc0: feat: added CSP and X-Frame-Options
## 1.6.1
### Patch Changes
- 8d91f71: chore: update deps and enable pnpm audit
- 3b8473b: chore: update turbo to `1.11.3` and pnpm to `8.10.5` in Dockerfile
- Updated dependencies [8d91f71]
- @nhost/react-apollo@7.0.2
- @nhost/nextjs@2.0.2
## 1.6.0 ## 1.6.0
### Minor Changes ### Minor Changes

View File

@@ -3,7 +3,7 @@ RUN apk add --no-cache libc6-compat
RUN apk update RUN apk update
WORKDIR /app WORKDIR /app
RUN yarn global add turbo@1.10.11 RUN yarn global add turbo@1.11.3
COPY . . COPY . .
RUN turbo prune --scope="@nhost/dashboard" --docker RUN turbo prune --scope="@nhost/dashboard" --docker
@@ -29,7 +29,7 @@ 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_MIGRATIONS_API_URL __NEXT_PUBLIC_NHOST_HASURA_MIGRATIONS_API_URL__
ENV NEXT_PUBLIC_NHOST_HASURA_API_URL __NEXT_PUBLIC_NHOST_HASURA_API_URL__ ENV NEXT_PUBLIC_NHOST_HASURA_API_URL __NEXT_PUBLIC_NHOST_HASURA_API_URL__
RUN yarn global add pnpm@8.6.2 RUN yarn global add pnpm@8.10.5
COPY .gitignore .gitignore COPY .gitignore .gitignore
COPY --from=pruner /app/out/json/ . COPY --from=pruner /app/out/json/ .
COPY --from=pruner /app/out/pnpm-*.yaml . COPY --from=pruner /app/out/pnpm-*.yaml .

View File

@@ -27,7 +27,7 @@ test('should be able to create then delete a personal access token', async () =>
const patName = faker.lorem.slug(3); const patName = faker.lorem.slug(3);
await page.getByRole('textbox', { name: /name/i }).fill(patName); await page.getByRole('textbox', { name: /name/i }).fill(patName);
await page.getByRole('button', { name: /expiration/i }).click(); await page.getByLabel('Expiration').click();
await page.getByRole('option', { name: /7 days/i }).click(); await page.getByRole('option', { name: /7 days/i }).click();
await page.getByRole('button', { name: /create/i }).click(); await page.getByRole('button', { name: /create/i }).click();

View File

@@ -138,7 +138,8 @@ test('should create a table with an identity column', async () => {
], ],
}); });
await page.getByRole('button', { name: /identity/i }).click(); // await page.getByRole('button', { name: /identity/i }).click();
await page.getByLabel('Identity').click();
await page.getByRole('option', { name: /id/i }).click(); await page.getByRole('option', { name: /id/i }).click();
// create table // create table
@@ -194,26 +195,18 @@ test('should create table with foreign key constraint', async () => {
await page.getByRole('button', { name: /add foreign key/i }).click(); await page.getByRole('button', { name: /add foreign key/i }).click();
// select column in current table await page.locator('#columnName').click();
await page
.getByRole('button', { name: /column/i })
.first()
.click();
await page.getByRole('option', { name: /author_id/i }).click(); await page.getByRole('option', { name: /author_id/i }).click();
// select reference schema // select reference schema
await page.getByRole('button', { name: /schema/i }).click(); await page.getByLabel('Schema').click();
await page.getByRole('option', { name: /public/i }).click(); await page.getByRole('option', { name: /public/i }).click();
// select reference table // select reference table
await page.getByRole('button', { name: /table/i }).click(); await page.getByLabel('Table').click();
await page.getByRole('option', { name: firstTableName, exact: true }).click(); await page.getByRole('option', { name: firstTableName, exact: true }).click();
// select reference column await page.locator('#referencedColumn').click();
await page
.getByRole('button', { name: /column/i })
.nth(1)
.click();
await page.getByRole('option', { name: /id/i }).click(); await page.getByRole('option', { name: /id/i }).click();
await page.getByRole('button', { name: /add/i }).click(); await page.getByRole('button', { name: /add/i }).click();

View File

@@ -113,27 +113,21 @@ test('should not be able to delete a table if other tables have foreign keys ref
await page.getByRole('button', { name: /add foreign key/i }).click(); await page.getByRole('button', { name: /add foreign key/i }).click();
// select column in current table // select column in current table
await page await page.locator('#columnName').click();
.getByRole('button', { name: /column/i })
.first()
.click();
await page.getByRole('option', { name: /author_id/i }).click(); await page.getByRole('option', { name: /author_id/i }).click();
// select reference schema // select reference schema
await page.getByRole('button', { name: /schema/i }).click(); await page.getByLabel('Schema').click();
await page.getByRole('option', { name: /public/i }).click(); await page.getByRole('option', { name: /public/i }).click();
// select reference table // select reference table
await page.getByRole('button', { name: /table/i }).click(); await page.getByLabel('Table').click();
await page.getByRole('option', { name: firstTableName, exact: true }).click(); await page.getByRole('option', { name: firstTableName, exact: true }).click();
// select reference column // select reference column
await page await page.locator('#referencedColumn').click();
.getByRole('button', { name: /column/i })
.nth(1)
.click();
await page.getByRole('option', { name: /id/i }).click(); await page.getByRole('option', { name: /id/i }).click();
await page.getByRole('button', { name: /add/i }).click(); await page.getByRole('button', { name: /add/i }).click();
await expect( await expect(

View File

@@ -93,7 +93,7 @@ test("should show the project's region and subdomain", async () => {
test('should not have a GitHub repository connected', async () => { test('should not have a GitHub repository connected', async () => {
await expect( await expect(
page.getByRole('button', { name: /connect to github/i }), page.getByRole('button', { name: /connect to github/i }).first(),
).toBeVisible(); ).toBeVisible();
}); });

View File

@@ -116,7 +116,8 @@ export async function prepareTable({
); );
// select the first column as primary key // select the first column as primary key
await page.getByRole('button', { name: /primary key/i }).click(); // await page.getByRole('button', { name: /primary key/i }).click();
await page.getByLabel('Primary Key').click();
await page.getByRole('option', { name: primaryKey, exact: true }).click(); await page.getByRole('option', { name: primaryKey, exact: true }).click();
} }

View File

@@ -1,5 +0,0 @@
query InitQuery {
root {
enableServices
}
}

View File

@@ -1,5 +0,0 @@
{
"projectId": 2596,
"token": "U2FsdGVkX19+V8BJnVR0xLEC+42OW5qZl/A0i6beAaRmJoIhFh5Yf6eIKBzLbV9h",
"outputDirectoryPath": "src/hypertune"
}

View File

@@ -4,6 +4,20 @@ const withBundleAnalyzer = require('@next/bundle-analyzer')({
}); });
const { version } = require('./package.json'); const { version } = require('./package.json');
const cspHeader = `
default-src 'self' *.nhost.run ws://*.nhost.run nhost.run ws://nhost.run;
script-src 'self' 'unsafe-eval' 'unsafe-inline' cdn.segment.com js.stripe.com;
connect-src 'self' *.nhost.run ws://*.nhost.run nhost.run ws://nhost.run discord.com;
style-src 'self' 'unsafe-inline';
img-src 'self' blob: data: avatars.githubusercontent.com s.gravatar.com *.nhost.run nhost.run;
font-src 'self' data:;
object-src 'none';
base-uri 'self';
form-action 'self';
frame-ancestors 'none';
frame-src 'self' js.stripe.com;
`;
module.exports = withBundleAnalyzer({ module.exports = withBundleAnalyzer({
reactStrictMode: true, reactStrictMode: true,
swcMinify: false, swcMinify: false,
@@ -17,6 +31,19 @@ module.exports = withBundleAnalyzer({
eslint: { eslint: {
dirs: ['src'], dirs: ['src'],
}, },
async headers() {
return [
{
source: '/(.*)',
headers: [
{
key: 'X-Frame-Options',
value: 'SAMEORIGIN',
},
],
},
];
},
async redirects() { async redirects() {
return [ return [
{ {

View File

@@ -1,6 +1,6 @@
{ {
"name": "@nhost/dashboard", "name": "@nhost/dashboard",
"version": "1.6.0", "version": "1.11.2",
"private": true, "private": true,
"scripts": { "scripts": {
"preinstall": "npx only-allow pnpm", "preinstall": "npx only-allow pnpm",
@@ -15,62 +15,62 @@
"format": "prettier --write \"src/**/*.{js,ts,tsx,jsx,json,md}\" --plugin-search-dir=.", "format": "prettier --write \"src/**/*.{js,ts,tsx,jsx,json,md}\" --plugin-search-dir=.",
"storybook": "start-storybook -p 6006 -s public", "storybook": "start-storybook -p 6006 -s public",
"build-storybook": "build-storybook", "build-storybook": "build-storybook",
"install-browsers": "pnpm dlx playwright@1.31.0 install --with-deps", "install-browsers": "pnpm playwright install && pnpm playwright install-deps",
"e2e": "pnpm install-browsers && pnpm dlx playwright@1.31.0 test" "e2e": "pnpm install-browsers && pnpm playwright test"
}, },
"dependencies": { "dependencies": {
"@apollo/client": "^3.7.10", "@apollo/client": "^3.9.5",
"@codemirror/lang-sql": "^6.5.4", "@codemirror/lang-sql": "^6.6.0",
"@emotion/cache": "^11.10.5", "@emotion/cache": "^11.11.0",
"@emotion/react": "^11.10.5", "@emotion/react": "^11.11.4",
"@emotion/server": "^11.4.0", "@emotion/server": "^11.11.0",
"@emotion/styled": "^11.10.5", "@emotion/styled": "^11.11.0",
"@fontsource/inter": "^5.0.0", "@fontsource/inter": "^5.0.16",
"@fontsource/roboto-mono": "^5.0.0", "@fontsource/roboto-mono": "^5.0.16",
"@graphiql/react": "^0.18.0", "@graphiql/react": "^0.20.3",
"@graphiql/toolkit": "^0.8.2", "@graphiql/toolkit": "^0.9.1",
"@headlessui/react": "^1.6.5", "@headlessui/react": "^1.7.18",
"@heroicons/react": "^1.0.6", "@heroicons/react": "^1.0.6",
"@hookform/resolvers": "^3.0.0", "@hookform/resolvers": "^3.3.4",
"@mui/base": "^5.0.0-alpha.106", "@mui/base": "5.0.0-beta.31",
"@mui/material": "^5.10.14", "@mui/material": "^5.15.11",
"@mui/system": "^5.10.14", "@mui/system": "^5.15.11",
"@mui/x-date-pickers": "^5.0.8", "@mui/x-date-pickers": "^5.0.20",
"@nhost/nextjs": "workspace:*", "@nhost/nextjs": "workspace:*",
"@nhost/react-apollo": "workspace:*", "@nhost/react-apollo": "workspace:*",
"@segment/snippet": "^4.15.3", "@segment/snippet": "^4.16.2",
"@stripe/react-stripe-js": "^2.0.0", "@stripe/react-stripe-js": "^2.5.1",
"@stripe/stripe-js": "^1.35.0", "@stripe/stripe-js": "^1.54.2",
"@tailwindcss/forms": "^0.5.3", "@tailwindcss/forms": "^0.5.7",
"@tanstack/react-query": "^4.16.1", "@tanstack/react-query": "^4.36.1",
"@tanstack/react-table": "^8.5.30", "@tanstack/react-table": "^8.13.2",
"@tanstack/react-virtual": "^3.0.0-beta.23", "@tanstack/react-virtual": "^3.1.3",
"@uiw/codemirror-theme-github": "^4.21.20", "@uiw/codemirror-theme-github": "^4.21.24",
"@uiw/react-codemirror": "^4.21.20", "@uiw/react-codemirror": "^4.21.24",
"analytics-node": "^6.2.0", "analytics-node": "^6.2.0",
"bcryptjs": "^2.4.3", "bcryptjs": "^2.4.3",
"clsx": "^1.2.1", "clsx": "^1.2.1",
"date-fns": "^2.29.3", "date-fns": "^2.30.0",
"generate-password": "^1.7.0", "framer-motion": "^10.18.0",
"graphiql": "^3.0.0", "generate-password": "^1.7.1",
"graphql": "^16.6.0", "graphiql": "^3.1.1",
"graphql-request": "^6.0.0", "graphql": "16.8.1",
"graphql-request": "^6.1.0",
"graphql-tag": "^2.12.6", "graphql-tag": "^2.12.6",
"graphql-ws": "^5.11.2", "graphql-ws": "^5.15.0",
"hypertune": "^1.4.4", "just-kebab-case": "^4.2.0",
"just-kebab-case": "^4.1.1",
"lodash.debounce": "^4.0.8", "lodash.debounce": "^4.0.8",
"next": "^12.3.1", "next": "^14.1.0",
"next-seo": "^6.0.0", "next-seo": "^6.5.0",
"node-pg-format": "^1.3.5", "node-pg-format": "^1.3.5",
"pluralize": "^8.0.0", "pluralize": "^8.0.0",
"react": "18.2.0", "react": "18.2.0",
"react-children-utilities": "^2.9.0", "react-children-utilities": "^2.10.0",
"react-dom": "18.2.0", "react-dom": "18.2.0",
"react-error-boundary": "^4.0.0", "react-error-boundary": "^4.0.13",
"react-hook-form": "^7.42.1", "react-hook-form": "^7.50.1",
"react-hot-toast": "^2.4.0", "react-hot-toast": "^2.4.1",
"react-intersection-observer": "^9.5.2", "react-intersection-observer": "^9.8.1",
"react-is": "18.2.0", "react-is": "18.2.0",
"react-loading-skeleton": "^2.2.0", "react-loading-skeleton": "^2.2.0",
"react-markdown": "^9.0.1", "react-markdown": "^9.0.1",
@@ -82,87 +82,87 @@
"rehype-highlight": "^7.0.0", "rehype-highlight": "^7.0.0",
"remark-gfm": "^4.0.0", "remark-gfm": "^4.0.0",
"shell-quote": "^1.8.1", "shell-quote": "^1.8.1",
"slugify": "^1.6.5", "slugify": "^1.6.6",
"stripe": "^10.17.0", "stripe": "^10.17.0",
"tailwind-merge": "^1.8.0", "tailwind-merge": "^1.14.0",
"utility-types": "^3.10.0", "utility-types": "^3.11.0",
"validator": "^13.7.0", "validator": "^13.11.0",
"yup": "^1.0.2", "yup": "^1.3.3",
"yup-password": "^0.2.2" "yup-password": "^0.2.2"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.20.2", "@babel/core": "^7.24.0",
"@faker-js/faker": "^7.6.0", "@faker-js/faker": "^7.6.0",
"@graphql-codegen/cli": "^3.0.0", "@graphql-codegen/cli": "^5.0.2",
"@graphql-codegen/typescript": "^3.0.0", "@graphql-codegen/typescript": "^3.0.4",
"@graphql-codegen/typescript-operations": "^3.0.0", "@graphql-codegen/typescript-operations": "^3.0.4",
"@graphql-codegen/typescript-react-apollo": "^3.3.1", "@graphql-codegen/typescript-react-apollo": "^3.3.7",
"@next/bundle-analyzer": "^12.3.1", "@next/bundle-analyzer": "^12.3.4",
"@playwright/test": "1.31.0", "@playwright/test": "1.41.0",
"@storybook/addon-actions": "^6.5.14", "@storybook/addon-actions": "^6.5.16",
"@storybook/addon-essentials": "^6.5.14", "@storybook/addon-essentials": "^6.5.16",
"@storybook/addon-interactions": "^6.5.14", "@storybook/addon-interactions": "^6.5.16",
"@storybook/addon-links": "^6.5.14", "@storybook/addon-links": "^6.5.16",
"@storybook/addon-postcss": "^2.0.0", "@storybook/addon-postcss": "^2.0.0",
"@storybook/builder-webpack5": "^6.5.14", "@storybook/builder-webpack5": "^6.5.16",
"@storybook/manager-webpack5": "^6.5.14", "@storybook/manager-webpack5": "^6.5.16",
"@storybook/react": "^6.5.14", "@storybook/react": "^7.6.17",
"@storybook/testing-library": "^0.2.0", "@storybook/testing-library": "^0.2.2",
"@tailwindcss/typography": "^0.5.10", "@tailwindcss/typography": "^0.5.10",
"@testing-library/dom": "^9.0.0", "@testing-library/dom": "^9.3.4",
"@testing-library/jest-dom": "^5.16.5", "@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^14.0.0", "@testing-library/react": "^14.2.1",
"@testing-library/user-event": "^14.4.3", "@testing-library/user-event": "^14.5.2",
"@types/ace": "^0.0.48", "@types/ace": "^0.0.48",
"@types/bcryptjs": "^2.4.2", "@types/bcryptjs": "^2.4.6",
"@types/jest": "^29.5.3", "@types/jest": "^29.5.12",
"@types/lodash.debounce": "^4.0.7", "@types/lodash.debounce": "^4.0.9",
"@types/node": "^16.11.7", "@types/node": "^16.18.86",
"@types/pluralize": "^0.0.30", "@types/pluralize": "^0.0.30",
"@types/react": "^18.2.14", "@types/react": "^18.2.61",
"@types/react-dom": "^18.2.6", "@types/react-dom": "^18.2.19",
"@types/react-table": "^7.7.12", "@types/react-table": "^7.7.19",
"@types/shell-quote": "^1.7.1", "@types/shell-quote": "^1.7.5",
"@types/testing-library__jest-dom": "^5.14.5", "@types/testing-library__jest-dom": "^5.14.9",
"@types/validator": "^13.7.10", "@types/validator": "^13.11.9",
"@typescript-eslint/eslint-plugin": "^6.15.0", "@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^6.15.0", "@typescript-eslint/parser": "^6.21.0",
"@vitejs/plugin-react": "^4.0.0", "@vitejs/plugin-react": "^4.2.1",
"@vitest/coverage-v8": "^0.32.0", "@vitest/coverage-v8": "^0.32.4",
"autoprefixer": "^10.4.13", "autoprefixer": "^10.4.17",
"babel-loader": "^8.3.0", "babel-loader": "^8.3.0",
"babel-plugin-transform-remove-console": "^6.9.4", "babel-plugin-transform-remove-console": "^6.9.4",
"csstype": "^3.0.10", "csstype": "^3.1.3",
"dotenv": "^16.0.3", "dotenv": "^16.4.5",
"encoding": "^0.1.13", "encoding": "^0.1.13",
"eslint": "^8.28.0", "eslint": "^8.57.0",
"eslint-config-airbnb": "19.0.4", "eslint-config-airbnb": "19.0.4",
"eslint-config-airbnb-typescript": "^17.0.0", "eslint-config-airbnb-typescript": "^17.1.0",
"eslint-config-next": "^13.0.2", "eslint-config-next": "^13.5.6",
"eslint-config-prettier": "^8.5.0", "eslint-config-prettier": "^8.10.0",
"eslint-plugin-import": "^2.26.0", "eslint-plugin-import": "^2.29.1",
"eslint-plugin-jsx-a11y": "^6.6.1", "eslint-plugin-jsx-a11y": "^6.8.0",
"eslint-plugin-react": "^7.31.11", "eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-hooks": "^4.6.0",
"jsdom": "^22.0.0", "jsdom": "^22.1.0",
"lint-staged": ">=13", "lint-staged": "^15.2.2",
"msw": "^1.0.1", "msw": "^1.3.2",
"msw-storybook-addon": "^1.6.3", "msw-storybook-addon": "^1.10.0",
"node-fetch": "^3.3.0", "node-fetch": "^3.3.2",
"postcss": "^8.4.19", "postcss": "^8.4.35",
"prettier": "^2.7.1", "prettier": "^2.8.8",
"prettier-plugin-organize-imports": "^3.2.0", "prettier-plugin-organize-imports": "^3.2.4",
"prettier-plugin-tailwindcss": "^0.4.0", "prettier-plugin-tailwindcss": "^0.4.1",
"react-date-fns-hooks": "^0.9.4", "react-date-fns-hooks": "^0.9.4",
"require-from-string": "^2.0.2", "require-from-string": "^2.0.2",
"snake-case": "^3.0.4", "snake-case": "^3.0.4",
"storybook-addon-next-router": "^4.0.1", "storybook-addon-next-router": "^4.0.2",
"tailwindcss": "^3.1.2", "tailwindcss": "^3.4.1",
"ts-node": "^10.9.1", "ts-node": "^10.9.2",
"tsconfig-paths-webpack-plugin": "^4.0.0", "tsconfig-paths-webpack-plugin": "^4.1.0",
"vite": "^4.0.2", "vite": "^5.1.4",
"vite-tsconfig-paths": "^4.0.3", "vite-tsconfig-paths": "^4.3.1",
"vitest": "^0.32.0" "vitest": "^0.32.4"
}, },
"browserslist": { "browserslist": {
"production": [ "production": [

View File

@@ -17,7 +17,7 @@ function NavLink(
ref: ForwardedRef<HTMLAnchorElement>, ref: ForwardedRef<HTMLAnchorElement>,
) { ) {
return ( return (
<NextLink href={href} passHref> <NextLink href={href} passHref legacyBehavior>
<Link className={twMerge('font-display', className)} ref={ref} {...props}> <Link className={twMerge('font-display', className)} ref={ref} {...props}>
{children} {children}
</Link> </Link>

View File

@@ -26,7 +26,7 @@ export default function ThemeSwitcher({
listbox: { className: 'min-w-0 w-full' }, listbox: { className: 'min-w-0 w-full' },
popper: { popper: {
disablePortal: false, disablePortal: false,
className: 'z-[10000] w-[270px] w-full', className: 'z-[10000] w-[270px]',
}, },
}} }}
> >

View File

@@ -26,7 +26,7 @@ export default function UpgradeToProBanner({
return ( return (
<Box <Box
sx={{ backgroundColor: 'primary.light' }} sx={{ backgroundColor: 'primary.light' }}
className="flex flex-col justify-between space-y-4 rounded-md p-4 lg:flex-row lg:items-center lg:space-y-0" className="flex flex-col justify-between p-4 space-y-4 rounded-md lg:flex-row lg:items-center lg:space-y-0"
> >
<div className="flex flex-col justify-between space-y-4"> <div className="flex flex-col justify-between space-y-4">
<div className="space-y-2"> <div className="space-y-2">
@@ -81,13 +81,13 @@ export default function UpgradeToProBanner({
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
underline="hover" underline="hover"
className="text-center font-medium" className="font-medium text-center"
sx={{ sx={{
color: 'text.secondary', color: 'text.secondary',
}} }}
> >
See all features See all features
<ArrowSquareOutIcon className="ml-1 h-4 w-4" /> <ArrowSquareOutIcon className="w-4 h-4 ml-1" />
</Link> </Link>
</div> </div>
</div> </div>
@@ -97,6 +97,7 @@ export default function UpgradeToProBanner({
width={300} width={300}
height={140} height={140}
objectFit="contain" objectFit="contain"
alt='Upgrade to Pro illustration'
/> />
</Box> </Box>
); );

View File

@@ -35,7 +35,7 @@ function InsertPlaceholderTableRow({
...props ...props
}: InsertPlaceholderTableRowProps) { }: InsertPlaceholderTableRowProps) {
return ( return (
<Box className="h-12 border-r-1 border-b-1" {...props}> <Box className="h-12 border-b-1 border-r-1" {...props}>
<Button <Button
onClick={onInsertRow} onClick={onInsertRow}
variant="borderless" variant="borderless"
@@ -209,7 +209,7 @@ export default function DataGridBody<T extends object>({
/> />
) : ( ) : (
<Box <Box
className="inline-flex h-12 items-center border-b-1 border-r-1 py-1.5 px-2 text-xs" className="inline-flex h-12 items-center border-b-1 border-r-1 px-2 py-1.5 text-xs"
sx={{ color: 'text.secondary' }} sx={{ color: 'text.secondary' }}
style={{ style={{
width: allowInsertColumn width: allowInsertColumn
@@ -281,8 +281,8 @@ export default function DataGridBody<T extends object>({
}} }}
className={twMerge( className={twMerge(
'h-12 font-display text-xs motion-safe:transition-colors', 'h-12 font-display text-xs motion-safe:transition-colors',
'border-r-1 border-b-1', 'border-b-1 border-r-1',
'scroll-mt-[57px] scroll-ml-8', 'scroll-ml-8 scroll-mt-[57px]',
column.id === 'selection' && column.id === 'selection' &&
'sticky left-0 z-20 justify-center px-0', 'sticky left-0 z-20 justify-center px-0',
)} )}
@@ -296,7 +296,7 @@ export default function DataGridBody<T extends object>({
})} })}
{allowInsertColumn && ( {allowInsertColumn && (
<Box className="h-12 w-25 border-r-1 border-b-1" /> <Box className="h-12 w-25 border-b-1 border-r-1" />
)} )}
</div> </div>

View File

@@ -8,7 +8,15 @@ import type {
DataBrowserGridCellProps, DataBrowserGridCellProps,
} from '@/features/database/dataGrid/types/dataBrowser'; } from '@/features/database/dataGrid/types/dataBrowser';
import { triggerToast } from '@/utils/toast'; import { triggerToast } from '@/utils/toast';
import type { FocusEvent, KeyboardEvent, MouseEvent } from 'react'; import type {
FocusEvent,
JSXElementConstructor,
KeyboardEvent,
MouseEvent,
ReactElement,
ReactNode,
ReactPortal,
} from 'react';
import { import {
Children, Children,
cloneElement, cloneElement,
@@ -308,7 +316,7 @@ function DataGridCellContent<TData extends object = {}, TValue = unknown>({
isEditable && isEditable &&
'focus-within:outline-none focus-within:ring-0 focus:ring-0', 'focus-within:outline-none focus-within:ring-0 focus:ring-0',
isSelected && 'shadow-outline', isSelected && 'shadow-outline',
isEditing ? 'p-0.5 shadow-outline-dark' : 'py-1.5 px-2', isEditing ? 'p-0.5 shadow-outline-dark' : 'px-2 py-1.5',
className, className,
)} )}
onFocus={handleFocus} onFocus={handleFocus}
@@ -320,20 +328,28 @@ function DataGridCellContent<TData extends object = {}, TValue = unknown>({
sx={{ backgroundColor: 'transparent' }} sx={{ backgroundColor: 'transparent' }}
{...props} {...props}
> >
{Children.map(children, (child) => { {Children.map(
if (!isValidElement(child)) { children,
return null; (
} child:
| ReactNode
| ReactPortal
| ReactElement<unknown, string | JSXElementConstructor<any>>,
) => {
if (!isValidElement(child)) {
return null;
}
return cloneElement(child, { return cloneElement(child, {
...child.props, ...child.props,
onSave: handleSave, onSave: handleSave,
optimisticValue, optimisticValue,
onOptimisticValueChange: setOptimisticValue, onOptimisticValueChange: setOptimisticValue,
temporaryValue, temporaryValue,
onTemporaryValueChange: setTemporaryValue, onTemporaryValueChange: setTemporaryValue,
}); });
})} },
)}
</Box> </Box>
); );

View File

@@ -96,45 +96,52 @@ export default function DataGridHeader<T extends object>({
}} }}
key={column.id} key={column.id}
> >
<Dropdown.Trigger {column.id === 'selection' ? (
className={twMerge(
'focus:outline-none motion-safe:transition-colors',
)}
disabled={
column.isDisabled ||
column.id === 'selection' ||
(column.disableSortBy && !onRemoveColumn)
}
hideChevron
>
<span <span
{...headerProps} {...headerProps}
className="relative grid w-full grid-flow-col items-center justify-between p-2" className="relative grid w-full grid-flow-col items-center justify-between p-2"
> >
{column.render('Header')} {column.render('Header')}
{allowSort && (
<Box component="span" sx={{ color: 'text.primary' }}>
{column.isSorted && !column.isSortedDesc && (
<ArrowUpIcon className="h-3 w-3" />
)}
{column.isSorted && column.isSortedDesc && (
<ArrowDownIcon className="h-3 w-3" />
)}
</Box>
)}
</span> </span>
) : (
{allowResize && !column.disableResizing && ( <Dropdown.Trigger
className={twMerge(
'focus:outline-none motion-safe:transition-colors',
)}
disabled={
column.isDisabled || (column.disableSortBy && !onRemoveColumn)
}
hideChevron
>
<span <span
{...column.getResizerProps({ {...headerProps}
onClick: (event: Event) => event.stopPropagation(), className="relative grid w-full grid-flow-col items-center justify-between p-2"
})} >
className="absolute top-0 bottom-0 -right-0.5 z-10 h-full w-1.5 group-hover:bg-slate-900 group-hover:bg-opacity-20 group-active:bg-slate-900 group-active:bg-opacity-20 motion-safe:transition-colors" {column.render('Header')}
/>
)} {allowSort && (
</Dropdown.Trigger> <Box component="span" sx={{ color: 'text.primary' }}>
{column.isSorted && !column.isSortedDesc && (
<ArrowUpIcon className="h-3 w-3" />
)}
{column.isSorted && column.isSortedDesc && (
<ArrowDownIcon className="h-3 w-3" />
)}
</Box>
)}
</span>
{allowResize && !column.disableResizing && (
<span
{...column.getResizerProps({
onClick: (event: Event) => event.stopPropagation(),
})}
className="absolute -right-0.5 bottom-0 top-0 z-10 h-full w-1.5 group-hover:bg-slate-900 group-hover:bg-opacity-20 group-active:bg-slate-900 group-active:bg-opacity-20 motion-safe:transition-colors"
/>
)}
</Dropdown.Trigger>
)}
<Dropdown.Content <Dropdown.Content
menu menu

View File

@@ -8,9 +8,9 @@ import { Input, inputClasses } from '@/components/ui/v2/Input';
import { OptionBase } from '@/components/ui/v2/Option'; import { OptionBase } from '@/components/ui/v2/Option';
import { OptionGroupBase } from '@/components/ui/v2/OptionGroup'; import { OptionGroupBase } from '@/components/ui/v2/OptionGroup';
import type { StyledComponent } from '@emotion/styled'; import type { StyledComponent } from '@emotion/styled';
import type { UseAutocompleteProps } from '@mui/base/AutocompleteUnstyled'; import type { UseAutocompleteProps } from '@mui/base/useAutocomplete';
import { createFilterOptions } from '@mui/base/AutocompleteUnstyled'; import { createFilterOptions } from '@mui/base/useAutocomplete';
import PopperUnstyled from '@mui/base/PopperUnstyled'; import { Popper } from '@mui/base'
import { styled } from '@mui/material'; import { styled } from '@mui/material';
import type { AutocompleteProps as MaterialAutocompleteProps } from '@mui/material/Autocomplete'; import type { AutocompleteProps as MaterialAutocompleteProps } from '@mui/material/Autocomplete';
import MaterialAutocomplete, { import MaterialAutocomplete, {
@@ -142,7 +142,7 @@ const StyledOptionBase = styled(OptionBase)(({ theme }) => ({
gap: theme.spacing(0.5), gap: theme.spacing(0.5),
})); }));
export const AutocompletePopper = styled(PopperUnstyled)(({ theme }) => ({ export const AutocompletePopper = styled(Popper)(({ theme }) => ({
zIndex: theme.zIndex.modal + 1, zIndex: theme.zIndex.modal + 1,
boxShadow: 'none', boxShadow: 'none',
minWidth: 320, minWidth: 320,

View File

@@ -1,9 +1,7 @@
import { styled } from '@mui/material'; import { styled } from '@mui/material';
import type { import type { BoxProps as MaterialBoxProps } from '@mui/material/Box';
BoxProps as MaterialBoxProps,
BoxTypeMap,
} from '@mui/material/Box';
import MaterialBox from '@mui/material/Box'; import MaterialBox from '@mui/material/Box';
import { type BoxTypeMap } from '@mui/system';
import type { ForwardedRef, PropsWithoutRef } from 'react'; import type { ForwardedRef, PropsWithoutRef } from 'react';
import { forwardRef } from 'react'; import { forwardRef } from 'react';

View File

@@ -1,6 +1,6 @@
import { PlusCircleIcon } from '@/components/ui/v2/icons/PlusCircleIcon'; import { PlusCircleIcon } from '@/components/ui/v2/icons/PlusCircleIcon';
import { PlusIcon } from '@/components/ui/v2/icons/PlusIcon'; import { PlusIcon } from '@/components/ui/v2/icons/PlusIcon';
import type { ComponentMeta, ComponentStory } from '@storybook/react'; import type { Meta, StoryFn } from '@storybook/react';
import type { ButtonProps } from './Button'; import type { ButtonProps } from './Button';
import Button from './Button'; import Button from './Button';
@@ -24,9 +24,9 @@ export default {
control: { type: 'radio' }, control: { type: 'radio' },
}, },
}, },
} as ComponentMeta<typeof Button>; } as Meta<typeof Button>;
const Template: ComponentStory<typeof Button> = function Template( const Template: StoryFn<ButtonProps> = function TemplateFunction(
args: ButtonProps, args: ButtonProps,
) { ) {
return <Button {...args} />; return <Button {...args} />;

View File

@@ -10,7 +10,7 @@ export interface ChipProps extends MaterialChipProps {
/** /**
* Custom component for the root node. * Custom component for the root node.
*/ */
component?: string | ElementType; component?: ElementType;
} }
const Chip = styled(MaterialChip)<ChipProps>(({ theme }) => ({ const Chip = styled(MaterialChip)<ChipProps>(({ theme }) => ({

View File

@@ -0,0 +1,164 @@
import { ChevronDownIcon } from '@/components/ui/v2/icons/ChevronDownIcon';
import { ChevronUpIcon } from '@/components/ui/v2/icons/ChevronUpIcon';
import { CopyIcon } from '@/components/ui/v2/icons/CopyIcon';
import { XIcon } from '@/components/ui/v2/icons/XIcon';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
import { getToastBackgroundColor } from '@/utils/constants/settings';
import { copy } from '@/utils/copy';
import type { ApolloError } from '@apollo/client';
import { useUserData } from '@nhost/nextjs';
import { AnimatePresence, motion } from 'framer-motion';
import { useRouter } from 'next/router';
import { useState } from 'react';
interface ErrorDetails {
info: {
projectId: string;
userId: string;
url?: string;
};
error: any;
}
const getInternalErrorMessage = (
error: Error | ApolloError | undefined,
): string | null => {
if (!error) {
return null;
}
if (error.name === 'ApolloError') {
// @ts-ignore
const internalError = error.graphQLErrors?.[0]?.extensions?.internal as {
error: { message: string };
};
return internalError?.error?.message || null;
}
if (error instanceof Error) {
return error.message;
}
return null;
};
const errorToObject = (error: ApolloError | Error) => {
if (error.name === 'ApolloError') {
return error;
}
if (error instanceof Error) {
return {
name: error.name,
message: error.message,
stack: error.stack,
};
}
return {};
};
export default function ErrorToast({
isVisible,
errorMessage,
error,
close,
}: {
isVisible: boolean;
errorMessage: string;
error: ApolloError | Error;
close: () => void;
}) {
const userData = useUserData();
const { asPath } = useRouter();
const [showInfo, setShowInfo] = useState(false);
const { currentProject } = useCurrentWorkspaceAndProject();
const errorDetails: ErrorDetails = {
info: {
projectId: currentProject?.id,
userId: userData?.id || 'local',
url: asPath,
},
error: errorToObject(error),
};
const msg = getInternalErrorMessage(error) || errorMessage;
return (
<AnimatePresence>
{isVisible && (
<motion.div
style={{
backgroundColor: getToastBackgroundColor(),
}}
className="flex w-full max-w-xl flex-col space-y-4 rounded-lg p-4 text-white"
initial={{
opacity: 0,
y: 100,
}}
animate={{
opacity: 1,
scale: 1,
y: 0,
}}
exit={{
opacity: 0,
scale: 0,
y: 100,
}}
transition={{
bounce: 0.1,
}}
>
<div className="flex w-full flex-row items-center justify-between space-x-4">
<button onClick={close} type="button" aria-label="Close">
<XIcon className="h-4 w-4 text-white" />
</button>
<span>
{msg ?? 'An unkown error has occured, please try again later!'}
</span>
<button
type="button"
onClick={() => setShowInfo(!showInfo)}
className="flex flex-row items-center justify-center space-x-2 text-white"
>
<span>Info</span>
{showInfo ? (
<ChevronUpIcon className="h-3 w-3 text-white" />
) : (
<ChevronDownIcon className="h-3 w-3 text-white" />
)}
</button>
</div>
{showInfo && (
<div className="flex flex-col space-y-4">
<div className="relative flex flex-col">
<div className="relative flex max-h-[400px] w-full max-w-xl flex-row justify-between overflow-x-auto rounded-lg bg-black p-4">
<pre>{JSON.stringify(errorDetails, null, 2)}</pre>
</div>
<button
type="button"
aria-label="Copy error details"
className="absolute right-2 top-2"
onClick={(event) => {
event.stopPropagation();
copy(
JSON.stringify(errorDetails, null, 2),
'Error details',
);
}}
>
<CopyIcon className="h-4 w-4" />
</button>
</div>
</div>
)}
</motion.div>
)}
</AnimatePresence>
);
}

View File

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

View File

@@ -7,7 +7,7 @@ export interface HelperTextProps extends MaterialFormHelperTextProps {
/** /**
* Custom component for the root node. * Custom component for the root node.
*/ */
component?: string | ElementType; component?: ElementType;
} }
const HelperText = styled(MaterialFormHelperText)<HelperTextProps>({ const HelperText = styled(MaterialFormHelperText)<HelperTextProps>({

View File

@@ -1,41 +1,42 @@
import type { OptionUnstyledProps } from '@mui/base/OptionUnstyled'; import {
import OptionUnstyled, { Option as BaseOption,
optionUnstyledClasses, optionClasses as baseOptionClasses,
} from '@mui/base/OptionUnstyled'; type OptionProps as BaseOptionProps,
} from '@mui/base';
import { darken, styled } from '@mui/material'; import { darken, styled } from '@mui/material';
import type { ForwardedRef } from 'react'; import type { ForwardedRef } from 'react';
import { forwardRef } from 'react'; import { forwardRef } from 'react';
import OptionBase from './OptionBase'; import OptionBase from './OptionBase';
export interface OptionProps<TValue extends {}> export interface OptionProps<TValue extends {}>
extends OptionUnstyledProps<TValue> {} extends BaseOptionProps<TValue> {}
const StyledOption = styled(OptionUnstyled)(({ theme }) => ({ const StyledOption = styled(BaseOption)(({ theme }) => ({
transition: theme.transitions.create(['background-color']), transition: theme.transitions.create(['background-color']),
color: theme.palette.text.primary, color: theme.palette.text.primary,
[`&.${optionUnstyledClasses.selected}`]: { [`&.${baseOptionClasses.selected}`]: {
backgroundColor: backgroundColor:
theme.palette.mode === 'dark' theme.palette.mode === 'dark'
? `${darken(theme.palette.action.hover, 0.1)} !important` ? `${darken(theme.palette.action.hover, 0.1)} !important`
: `${darken(theme.palette.action.hover, 0.05)} !important`, : `${darken(theme.palette.action.hover, 0.05)} !important`,
}, },
[`&.${optionUnstyledClasses.selected}:hover, &.${optionUnstyledClasses.selected}.${optionUnstyledClasses.highlighted}`]: [`&.${baseOptionClasses.selected}:hover, &.${baseOptionClasses.selected}.${baseOptionClasses.highlighted}`]:
{ {
backgroundColor: backgroundColor:
theme.palette.mode === 'dark' theme.palette.mode === 'dark'
? `${darken(theme.palette.action.hover, 0.25)} !important` ? `${darken(theme.palette.action.hover, 0.25)} !important`
: `${darken(theme.palette.action.hover, 0.075)} !important`, : `${darken(theme.palette.action.hover, 0.075)} !important`,
}, },
[`&.${optionUnstyledClasses.highlighted}, &:hover`]: { [`&.${baseOptionClasses.highlighted}, &:hover`]: {
backgroundColor: backgroundColor:
theme.palette.mode === 'dark' theme.palette.mode === 'dark'
? `${darken(theme.palette.action.hover, 0.15)} !important` ? `${darken(theme.palette.action.hover, 0.15)} !important`
: `${theme.palette.action.hover} !important`, : `${theme.palette.action.hover} !important`,
}, },
[`&.${optionUnstyledClasses.disabled}`]: { [`&.${baseOptionClasses.disabled}`]: {
color: theme.palette.text.disabled, color: theme.palette.text.disabled,
}, },
[`&.${optionUnstyledClasses.disabled}:hover`]: { [`&.${baseOptionClasses.disabled}:hover`]: {
backgroundColor: 'transparent !important', backgroundColor: 'transparent !important',
}, },
})); }));

View File

@@ -1,11 +1,13 @@
import type { OptionGroupUnstyledProps } from '@mui/base/OptionGroupUnstyled'; import {
import OptionGroupUnstyled from '@mui/base/OptionGroupUnstyled'; OptionGroup as BaseOptionGroup,
type OptionGroupProps as BaseOptionGroupProps,
} from '@mui/base';
import { styled } from '@mui/material'; import { styled } from '@mui/material';
import type { ForwardedRef } from 'react'; import type { ForwardedRef } from 'react';
import { forwardRef } from 'react'; import { forwardRef } from 'react';
import OptionGroupBase from './OptionGroupBase'; import OptionGroupBase from './OptionGroupBase';
export interface OptionGroupProps extends OptionGroupUnstyledProps {} export interface OptionGroupProps extends BaseOptionGroupProps {}
const StyledGroupRoot = styled('li')(({ theme }) => ({ const StyledGroupRoot = styled('li')(({ theme }) => ({
listStyle: 'none', listStyle: 'none',
@@ -25,7 +27,7 @@ function OptionGroup(
...externalSlots, ...externalSlots,
}; };
return <OptionGroupUnstyled {...props} ref={ref} slots={slots} />; return <BaseOptionGroup {...props} ref={ref} slots={slots} />;
} }
OptionGroup.displayName = 'NhostOptionGroup'; OptionGroup.displayName = 'NhostOptionGroup';

View File

@@ -1,5 +1,5 @@
import { Option } from '@/components/ui/v2/Option'; import { Option } from '@/components/ui/v2/Option';
import type { ComponentMeta, ComponentStory } from '@storybook/react'; import type { Meta, StoryFn } from '@storybook/react';
import type { SelectProps } from './Select'; import type { SelectProps } from './Select';
import Select from './Select'; import Select from './Select';
@@ -7,11 +7,9 @@ export default {
title: 'UI Library / Select', title: 'UI Library / Select',
component: Select, component: Select,
argTypes: {}, argTypes: {},
} as ComponentMeta<typeof Select>; } as Meta<typeof Select>;
const Template: ComponentStory<typeof Select> = function Template( const Template: StoryFn<SelectProps<any>> = function TemplateFunction(args) {
args: SelectProps<any>,
) {
return ( return (
<Select className="w-64" {...args}> <Select className="w-64" {...args}>
<Option value="value1">Value 1</Option> <Option value="value1">Value 1</Option>

View File

@@ -1,9 +1,9 @@
import type { FormControlProps } from '@/components/ui/v2/FormControl'; import type { FormControlProps } from '@/components/ui/v2/FormControl';
import { FormControl } from '@/components/ui/v2/FormControl'; import { FormControl } from '@/components/ui/v2/FormControl';
import PopperUnstyled from '@mui/base/PopperUnstyled'; import { Popper as BasePopper } from '@mui/base/Popper';
import type { SelectUnstyledProps } from '@mui/base/SelectUnstyled'; import type { SelectProps as BaseSelectProps } from '@mui/base/Select';
import SelectUnstyled from '@mui/base/SelectUnstyled'; import { Select as BaseSelect } from '@mui/base/Select';
import { styled } from '@mui/material'; import { styled } from '@mui/system';
import clsx from 'clsx'; import clsx from 'clsx';
import type { ForwardedRef, PropsWithoutRef } from 'react'; import type { ForwardedRef, PropsWithoutRef } from 'react';
import { forwardRef } from 'react'; import { forwardRef } from 'react';
@@ -11,7 +11,7 @@ import type { ToggleButtonProps } from './ToggleButton';
import ToggleButton from './ToggleButton'; import ToggleButton from './ToggleButton';
export interface SelectProps<TValue extends {}> export interface SelectProps<TValue extends {}>
extends SelectUnstyledProps<TValue>, extends BaseSelectProps<TValue, false>,
Pick< Pick<
FormControlProps, FormControlProps,
| 'fullWidth' | 'fullWidth'
@@ -25,7 +25,7 @@ export interface SelectProps<TValue extends {}>
/** /**
* Props for component slots. * Props for component slots.
*/ */
slotProps?: SelectUnstyledProps<TValue>['slotProps'] & { slotProps?: BaseSelectProps<TValue, false>['slotProps'] & {
root?: Partial<PropsWithoutRef<ToggleButtonProps>>; root?: Partial<PropsWithoutRef<ToggleButtonProps>>;
label?: Partial<FormControlProps['labelProps']>; label?: Partial<FormControlProps['labelProps']>;
formControl?: Partial<FormControlProps>; formControl?: Partial<FormControlProps>;
@@ -59,8 +59,8 @@ const StyledListbox = styled('ul')(({ theme }) => ({
}, },
})); }));
const StyledPopper = styled(PopperUnstyled)` const StyledPopper = styled(BasePopper)`
z-index: 10; z-index: 9999;
`; `;
function Select<TValue>( function Select<TValue>(
@@ -80,7 +80,7 @@ function Select<TValue>(
}: SelectProps<TValue>, }: SelectProps<TValue>,
ref: ForwardedRef<HTMLButtonElement>, ref: ForwardedRef<HTMLButtonElement>,
) { ) {
const slots: SelectUnstyledProps<TValue>['slots'] = { const slots: BaseSelectProps<TValue, false>['slots'] = {
root: ToggleButton, root: ToggleButton,
popper: StyledPopper, popper: StyledPopper,
listbox: StyledListbox, listbox: StyledListbox,
@@ -107,7 +107,7 @@ function Select<TValue>(
htmlFor: props.id, htmlFor: props.id,
}} }}
> >
<SelectUnstyled <BaseSelect
aria-label={typeof label === 'string' ? label : undefined} aria-label={typeof label === 'string' ? label : undefined}
{...props} {...props}
className={clsx(error && 'error')} className={clsx(error && 'error')}
@@ -117,7 +117,6 @@ function Select<TValue>(
...slotProps, ...slotProps,
root: { root: {
...slotProps?.root, ...slotProps?.root,
placeholder,
}, },
listbox: { listbox: {
...slotProps?.listbox, ...slotProps?.listbox,
@@ -132,7 +131,7 @@ function Select<TValue>(
placeholder={placeholder} placeholder={placeholder}
> >
{children} {children}
</SelectUnstyled> </BaseSelect>
</FormControl> </FormControl>
); );
} }

View File

@@ -1,8 +1,10 @@
import { ChevronDownIcon } from '@/components/ui/v2/icons/ChevronDownIcon'; import { ChevronDownIcon } from '@/components/ui/v2/icons/ChevronDownIcon';
import { ChevronUpIcon } from '@/components/ui/v2/icons/ChevronUpIcon'; import { ChevronUpIcon } from '@/components/ui/v2/icons/ChevronUpIcon';
import type { ButtonUnstyledProps } from '@mui/base/ButtonUnstyled'; import {
import ButtonUnstyled from '@mui/base/ButtonUnstyled'; Button as ButtonUnstyled,
import { selectUnstyledClasses } from '@mui/base/SelectUnstyled'; type ButtonProps as ButtonUnstyledProps,
} from '@mui/base';
import { selectClasses as selectUnstyledClasses } from '@mui/base/Select';
import type { SxProps } from '@mui/material'; import type { SxProps } from '@mui/material';
import { styled } from '@mui/material'; import { styled } from '@mui/material';
import type { Theme } from '@mui/system'; import type { Theme } from '@mui/system';
@@ -24,6 +26,7 @@ export interface ToggleButtonProps
Omit<DetailedHTMLProps<HTMLProps<HTMLSpanElement>, HTMLSpanElement>, 'as'> Omit<DetailedHTMLProps<HTMLProps<HTMLSpanElement>, HTMLSpanElement>, 'as'>
>; >;
}; };
placeholder?: string;
} }
const StyledButton = styled(ButtonUnstyled)(({ theme }) => ({ const StyledButton = styled(ButtonUnstyled)(({ theme }) => ({

View File

@@ -1,4 +1,4 @@
import type { ComponentMeta, ComponentStory } from '@storybook/react'; import type { Meta, StoryFn } from '@storybook/react';
import type { SwitchProps } from './Switch'; import type { SwitchProps } from './Switch';
import Switch from './Switch'; import Switch from './Switch';
@@ -6,9 +6,9 @@ export default {
title: 'UI Library / Switch', title: 'UI Library / Switch',
component: Switch, component: Switch,
argTypes: {}, argTypes: {},
} as ComponentMeta<typeof Switch>; } as Meta<typeof Switch>;
const Template: ComponentStory<typeof Switch> = function Template( const Template: StoryFn<SwitchProps> = function TemplateFunction(
args: SwitchProps, args: SwitchProps,
) { ) {
return <Switch label="Accept Rules" {...args} />; return <Switch label="Accept Rules" {...args} />;

View File

@@ -1,14 +1,15 @@
import type { FormControlLabelProps } from '@/components/ui/v2/FormControlLabel'; import type { FormControlLabelProps } from '@/components/ui/v2/FormControlLabel';
import { FormControlLabel } from '@/components/ui/v2/FormControlLabel'; import { FormControlLabel } from '@/components/ui/v2/FormControlLabel';
import SwitchUnstyled, { import {
switchUnstyledClasses, Switch as BaseSwitch,
} from '@mui/base/SwitchUnstyled'; switchClasses as baseSwitchClasses,
import type { SwitchUnstyledProps } from '@mui/base/SwitchUnstyled/SwitchUnstyled.types'; } from '@mui/base';
import type { SwitchProps as BaseSwitchProps } from '@mui/base/Switch';
import { styled } from '@mui/material'; import { styled } from '@mui/material';
import type { ForwardedRef, PropsWithoutRef } from 'react'; import type { ForwardedRef, PropsWithoutRef } from 'react';
import { forwardRef } from 'react'; import { forwardRef } from 'react';
export interface SwitchProps extends SwitchUnstyledProps { export interface SwitchProps extends BaseSwitchProps {
/** /**
* Label to be displayed next to the checkbox. * Label to be displayed next to the checkbox.
*/ */
@@ -16,11 +17,11 @@ export interface SwitchProps extends SwitchUnstyledProps {
/** /**
* Props to be passed to the internal components. * Props to be passed to the internal components.
*/ */
slotProps?: SwitchUnstyledProps['slotProps'] & { slotProps?: BaseSwitchProps['slotProps'] & {
/** /**
* Props to be passed to the `Switch` component. * Props to be passed to the `Switch` component.
*/ */
root?: Partial<SwitchUnstyledProps>; root?: Partial<BaseSwitchProps>;
/** /**
* Props to be passed to the `FormControlLabel` component. * Props to be passed to the `FormControlLabel` component.
*/ */
@@ -35,23 +36,23 @@ const StyledFormControlLabel = styled(FormControlLabel)(({ theme }) => ({
justifyContent: 'start', justifyContent: 'start',
})); }));
const StyledSwitch = styled(SwitchUnstyled)(({ theme }) => ({ const StyledSwitch = styled(BaseSwitch)(({ theme }) => ({
position: 'relative', position: 'relative',
display: 'inline-block', display: 'inline-block',
width: '40px', width: '40px',
height: '24px', height: '24px',
cursor: 'pointer', cursor: 'pointer',
[`&.${switchUnstyledClasses.disabled}`]: { [`&.${baseSwitchClasses.disabled}`]: {
cursor: 'not-allowed', cursor: 'not-allowed',
[`& .${switchUnstyledClasses.track}`]: { [`& .${baseSwitchClasses.track}`]: {
backgroundColor: theme.palette.grey[200], backgroundColor: theme.palette.grey[200],
color: theme.palette.grey[200], color: theme.palette.grey[200],
}, },
}, },
[`& .${switchUnstyledClasses.track}`]: { [`& .${baseSwitchClasses.track}`]: {
backgroundColor: backgroundColor:
theme.palette.mode === 'dark' theme.palette.mode === 'dark'
? theme.palette.grey[500] ? theme.palette.grey[500]
@@ -63,7 +64,7 @@ const StyledSwitch = styled(SwitchUnstyled)(({ theme }) => ({
position: 'absolute', position: 'absolute',
}, },
[` & .${switchUnstyledClasses.thumb}`]: { [` & .${baseSwitchClasses.thumb}`]: {
display: 'block', display: 'block',
width: '18px', width: '18px',
height: '18px', height: '18px',
@@ -77,24 +78,24 @@ const StyledSwitch = styled(SwitchUnstyled)(({ theme }) => ({
transitionDuration: '120ms', transitionDuration: '120ms',
}, },
[`&.${switchUnstyledClasses.focusVisible} .${switchUnstyledClasses.thumb}`]: { [`&.${baseSwitchClasses.focusVisible} .${baseSwitchClasses.thumb}`]: {
backgroundColor: theme.palette.action.focus, backgroundColor: theme.palette.action.focus,
boxShadow: '0 0 1px 8px rgba(0, 0, 0, 0.25)', boxShadow: '0 0 1px 8px rgba(0, 0, 0, 0.25)',
}, },
[`&.${switchUnstyledClasses.checked}`]: { [`&.${baseSwitchClasses.checked}`]: {
[`.${switchUnstyledClasses.thumb}`]: { [`.${baseSwitchClasses.thumb}`]: {
left: '19px', left: '19px',
top: '3px', top: '3px',
backgroundColor: theme.palette.common.white, backgroundColor: theme.palette.common.white,
}, },
[`.${switchUnstyledClasses.track}`]: { [`.${baseSwitchClasses.track}`]: {
backgroundColor: theme.palette.primary.main, backgroundColor: theme.palette.primary.main,
}, },
[`&.${switchUnstyledClasses.disabled}`]: { [`&.${baseSwitchClasses.disabled}`]: {
[`.${switchUnstyledClasses.track}`]: { [`.${baseSwitchClasses.track}`]: {
opacity: 0.5, opacity: 0.5,
backgroundColor: backgroundColor:
theme.palette.mode === 'dark' theme.palette.mode === 'dark'
@@ -104,7 +105,7 @@ const StyledSwitch = styled(SwitchUnstyled)(({ theme }) => ({
}, },
}, },
[`& .${switchUnstyledClasses.input}`]: { [`& .${baseSwitchClasses.input}`]: {
cursor: 'inherit', cursor: 'inherit',
position: 'absolute', position: 'absolute',
width: '100%', width: '100%',

View File

@@ -4,16 +4,14 @@ import { Box } from '@/components/ui/v2/Box';
import { Button } from '@/components/ui/v2/Button'; import { Button } from '@/components/ui/v2/Button';
import { Checkbox } from '@/components/ui/v2/Checkbox'; import { Checkbox } from '@/components/ui/v2/Checkbox';
import { Text } from '@/components/ui/v2/Text'; import { Text } from '@/components/ui/v2/Text';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { import {
useDeleteUserAccountMutation, useDeleteUserAccountMutation,
useGetAllWorkspacesAndProjectsQuery, useGetAllWorkspacesAndProjectsQuery,
} from '@/utils/__generated__/graphql'; } from '@/utils/__generated__/graphql';
import { type ApolloError } from '@apollo/client';
import { useSignOut, useUserData } from '@nhost/nextjs'; import { useSignOut, useUserData } from '@nhost/nextjs';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { useState } from 'react'; import { useState } from 'react';
import toast from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
function ConfirmDeleteAccountModal({ function ConfirmDeleteAccountModal({
@@ -44,30 +42,19 @@ function ConfirmDeleteAccountModal({
const onClickConfirm = async () => { const onClickConfirm = async () => {
setLoadingRemove(true); setLoadingRemove(true);
await toast.promise( await execPromiseWithErrorToast(
deleteUserAccount(), async () => {
{ await deleteUserAccount();
loading: 'Deleting your account...', onDelete?.();
success: `The account has been deleted successfully.`, close();
error: (arg: ApolloError) => { },
// we need to get the internal error message from the GraphQL error {
const { internal } = arg.graphQLErrors[0]?.extensions || {}; loadingMessage: 'Deleting your account...',
const { message } = (internal as Record<string, any>)?.error || {}; successMessage: 'The account has been deleted successfully.',
errorMessage:
// we use the default Apollo error message if we can't find the 'An error occurred while deleting your account. Please try again.',
// internal error message
return (
message ||
arg.message ||
'An error occurred while deleting your account. Please try again.'
);
},
}, },
getToastStyleProps(),
); );
onDelete?.();
close();
}; };
return ( return (

View File

@@ -0,0 +1,85 @@
import { Form } from '@/components/form/Form';
import { SettingsContainer } from '@/components/layout/SettingsContainer';
import { Input } from '@/components/ui/v2/Input';
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { useUpdateUserDisplayNameMutation } from '@/utils/__generated__/graphql';
import { yupResolver } from '@hookform/resolvers/yup';
import { useUserData } from '@nhost/nextjs';
import { FormProvider, useForm } from 'react-hook-form';
import * as Yup from 'yup';
const validationSchema = Yup.object({
displayName: Yup.string()
.label('Display Name')
.required('This field is required.'),
});
export type DisplayNameSettingFormValues = Yup.InferType<
typeof validationSchema
>;
export default function DisplayNameSetting() {
const { id: userID, displayName } = useUserData();
const [updateUserDisplayName] = useUpdateUserDisplayNameMutation();
const form = useForm<DisplayNameSettingFormValues>({
reValidateMode: 'onSubmit',
defaultValues: {
displayName,
},
resolver: yupResolver(validationSchema),
});
const { register, formState } = form;
const isDirty = Object.keys(formState.dirtyFields).length > 0;
async function handleSubmit(formValues: DisplayNameSettingFormValues) {
await execPromiseWithErrorToast(
async () => {
await updateUserDisplayName({
variables: {
id: userID,
displayName: formValues.displayName,
},
});
form.reset({ displayName: formValues.displayName });
},
{
loadingMessage: 'Updating your display name...',
successMessage: 'Your display name has been updated successfully.',
errorMessage:
'An error occurred while trying to update your display name. Please try again.',
},
);
}
return (
<FormProvider {...form}>
<Form onSubmit={handleSubmit}>
<SettingsContainer
title="Update your display name"
slotProps={{
submitButton: {
disabled: !isDirty,
loading: formState.isSubmitting,
},
}}
className="grid grid-flow-row lg:grid-cols-5"
>
<Input
{...register('displayName')}
className="col-span-2"
type="text"
id="display-name"
label="Display Name"
fullWidth
helperText={formState.errors.displayName?.message}
error={Boolean(formState.errors.displayName)}
/>
</SettingsContainer>
</Form>
</FormProvider>
);
}

View File

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

View File

@@ -15,15 +15,13 @@ import { ListItem } from '@/components/ui/v2/ListItem';
import { Text } from '@/components/ui/v2/Text'; import { Text } from '@/components/ui/v2/Text';
import { Tooltip } from '@/components/ui/v2/Tooltip'; import { Tooltip } from '@/components/ui/v2/Tooltip';
import { CreatePATForm } from '@/features/account/settings/components/CreatePATForm'; import { CreatePATForm } from '@/features/account/settings/components/CreatePATForm';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getServerError } from '@/utils/getServerError';
import { import {
GetPersonalAccessTokensDocument, GetPersonalAccessTokensDocument,
useDeletePersonalAccessTokenMutation, useDeletePersonalAccessTokenMutation,
useGetPersonalAccessTokensQuery, useGetPersonalAccessTokensQuery,
} from '@/utils/__generated__/graphql'; } from '@/utils/__generated__/graphql';
import { Fragment } from 'react'; import { Fragment } from 'react';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
export default function PATSettings() { export default function PATSettings() {
@@ -59,28 +57,20 @@ export default function PATSettings() {
async function handleDeletePAT({ async function handleDeletePAT({
id, id,
}: typeof availablePersonalAccessTokens[0]) { }: (typeof availablePersonalAccessTokens)[0]) {
const deletePATPromise = deletePAT({ variables: { patId: id } }); await execPromiseWithErrorToast(
() => deletePAT({ variables: { patId: id } }),
try { {
await toast.promise( loadingMessage: 'Deleting personal access token...',
deletePATPromise, successMessage: 'Personal access token has been deleted successfully.',
{ errorMessage:
loading: 'Deleting personal access token...', 'An error occurred while deleting the personal access token.',
success: 'Personal access token has been deleted successfully.', },
error: getServerError( );
'An error occurred while deleting the personal access token.',
),
},
getToastStyleProps(),
);
} catch {
// Note: The toast will handle the error.
}
} }
function handleConfirmDelete( function handleConfirmDelete(
originalPAT: typeof availablePersonalAccessTokens[0], originalPAT: (typeof availablePersonalAccessTokens)[0],
) { ) {
openAlertDialog({ openAlertDialog({
title: 'Delete Personal Access Token', title: 'Delete Personal Access Token',

View File

@@ -1,12 +1,10 @@
import { Form } from '@/components/form/Form'; import { Form } from '@/components/form/Form';
import { SettingsContainer } from '@/components/layout/SettingsContainer'; import { SettingsContainer } from '@/components/layout/SettingsContainer';
import { Input } from '@/components/ui/v2/Input'; import { Input } from '@/components/ui/v2/Input';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getServerError } from '@/utils/getServerError';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { useChangePassword } from '@nhost/nextjs'; import { useChangePassword } from '@nhost/nextjs';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import * as Yup from 'yup'; import * as Yup from 'yup';
const validationSchema = Yup.object({ const validationSchema = Yup.object({
@@ -38,25 +36,19 @@ export default function PasswordSettings() {
const isDirty = Object.keys(formState.dirtyFields).length > 0; const isDirty = Object.keys(formState.dirtyFields).length > 0;
async function handleSubmit(formValues: PasswordSettingsFormValues) { async function handleSubmit(formValues: PasswordSettingsFormValues) {
try { await execPromiseWithErrorToast(
const changePasswordPromise = changePassword(formValues.newPassword); async () => {
// TODO fix changePassword should throw an error if something happens
await toast.promise( await changePassword(formValues.newPassword);
changePasswordPromise, form.reset();
{ },
loading: 'Changing password...', {
success: 'The password has been changed successfully.', loadingMessage: 'Changing password...',
error: getServerError( successMessage: 'The password has been changed successfully.',
'An error occurred while trying to update the password. Please try again.', errorMessage:
), 'An error occurred while trying to update the password. Please try again.',
}, },
getToastStyleProps(), );
);
form.reset();
} catch {
// Note: The error is handled by the toast.
}
} }
return ( return (

View File

@@ -0,0 +1,6 @@
mutation updateUserDisplayName($id: uuid!, $displayName: String!) {
updateUser(pk_columns: { id: $id }, _set: { displayName: $displayName }) {
id
displayName
}
}

View File

@@ -10,26 +10,17 @@ import { Text } from '@/components/ui/v2/Text';
import { Tooltip } from '@/components/ui/v2/Tooltip'; import { Tooltip } from '@/components/ui/v2/Tooltip';
import { GraphqlDataSourcesFormSection } from '@/features/ai/AssistantForm/components/GraphqlDataSourcesFormSection'; import { GraphqlDataSourcesFormSection } from '@/features/ai/AssistantForm/components/GraphqlDataSourcesFormSection';
import { WebhooksDataSourcesFormSection } from '@/features/ai/AssistantForm/components/WebhooksDataSourcesFormSection'; import { WebhooksDataSourcesFormSection } from '@/features/ai/AssistantForm/components/WebhooksDataSourcesFormSection';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject'; import { useAdminApolloClient } from '@/features/projects/common/hooks/useAdminApolloClient';
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
import type { DialogFormProps } from '@/types/common'; import type { DialogFormProps } from '@/types/common';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getHasuraAdminSecret } from '@/utils/env';
import { removeTypename, type DeepRequired } from '@/utils/helpers'; import { removeTypename, type DeepRequired } from '@/utils/helpers';
import { import {
useInsertAssistantMutation, useInsertAssistantMutation,
useUpdateAssistantMutation, useUpdateAssistantMutation,
} from '@/utils/__generated__/graphite.graphql'; } from '@/utils/__generated__/graphite.graphql';
import {
ApolloClient,
HttpLink,
InMemoryCache,
type ApolloError,
} from '@apollo/client';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { useEffect } from 'react'; import { useEffect } from 'react';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import * as Yup from 'yup'; import * as Yup from 'yup';
export const validationSchema = Yup.object({ export const validationSchema = Yup.object({
@@ -101,32 +92,15 @@ export default function AssistantForm({
}: AssistantFormProps) { }: AssistantFormProps) {
const { onDirtyStateChange } = useDialog(); const { onDirtyStateChange } = useDialog();
const { currentProject } = useCurrentWorkspaceAndProject(); const { adminClient } = useAdminApolloClient();
const serviceUrl = generateAppServiceUrl(
currentProject?.subdomain,
currentProject?.region,
'graphql',
);
const client = new ApolloClient({
cache: new InMemoryCache(),
link: new HttpLink({
uri: serviceUrl,
headers: {
'x-hasura-admin-secret':
process.env.NEXT_PUBLIC_ENV === 'dev'
? getHasuraAdminSecret()
: currentProject?.config?.hasura.adminSecret,
},
}),
});
const [insertAssistantMutation] = useInsertAssistantMutation({ const [insertAssistantMutation] = useInsertAssistantMutation({
client, client: adminClient,
}); });
const [updateAssistantMutation] = useUpdateAssistantMutation({ client }); const [updateAssistantMutation] = useUpdateAssistantMutation({
client: adminClient,
});
const form = useForm<AssistantFormValues>({ const form = useForm<AssistantFormValues>({
defaultValues: initialData, defaultValues: initialData,
@@ -186,33 +160,18 @@ export default function AssistantForm({
const handleSubmit = async ( const handleSubmit = async (
values: DeepRequired<AssistantFormValues> & { assistantID: string }, values: DeepRequired<AssistantFormValues> & { assistantID: string },
) => { ) => {
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
createOrUpdateAutoEmbeddings(values), await createOrUpdateAutoEmbeddings(values);
{ onSubmit?.();
loading: 'Configuring the Assistant...', },
success: `The Assistant has been configured successfully.`, {
error: (arg: ApolloError) => { loadingMessage: 'Configuring the Assistant...',
// we need to get the internal error message from the GraphQL error successMessage: 'The Assistant has been configured successfully.',
const { internal } = arg.graphQLErrors[0]?.extensions || {}; errorMessage:
const { message } = (internal as Record<string, any>)?.error || {}; 'An error occurred while configuring the Assistant. Please try again.',
},
// we use the default Apollo error message if we can't find the );
// internal error message
return (
message ||
arg.message ||
'An error occurred while configuring the Assistant. Please try again.'
);
},
},
getToastStyleProps(),
);
onSubmit?.();
} catch {
// Note: The toast will handle the error.
}
}; };
return ( return (

View File

@@ -8,25 +8,16 @@ import { PlusIcon } from '@/components/ui/v2/icons/PlusIcon';
import { Input } from '@/components/ui/v2/Input'; import { Input } from '@/components/ui/v2/Input';
import { Text } from '@/components/ui/v2/Text'; import { Text } from '@/components/ui/v2/Text';
import { Tooltip } from '@/components/ui/v2/Tooltip'; import { Tooltip } from '@/components/ui/v2/Tooltip';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject'; import { useAdminApolloClient } from '@/features/projects/common/hooks/useAdminApolloClient';
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
import type { DialogFormProps } from '@/types/common'; import type { DialogFormProps } from '@/types/common';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getHasuraAdminSecret } from '@/utils/env';
import { import {
useInsertGraphiteAutoEmbeddingsConfigurationMutation, useInsertGraphiteAutoEmbeddingsConfigurationMutation,
useUpdateGraphiteAutoEmbeddingsConfigurationMutation, useUpdateGraphiteAutoEmbeddingsConfigurationMutation,
} from '@/utils/__generated__/graphite.graphql'; } from '@/utils/__generated__/graphite.graphql';
import {
ApolloClient,
HttpLink,
InMemoryCache,
type ApolloError,
} from '@apollo/client';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { useEffect } from 'react'; import { useEffect } from 'react';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import * as Yup from 'yup'; import * as Yup from 'yup';
export const validationSchema = Yup.object({ export const validationSchema = Yup.object({
@@ -70,34 +61,17 @@ export default function AutoEmbeddingsForm({
}: AutoEmbeddingsFormProps) { }: AutoEmbeddingsFormProps) {
const { onDirtyStateChange } = useDialog(); const { onDirtyStateChange } = useDialog();
const { currentProject } = useCurrentWorkspaceAndProject(); const { adminClient } = useAdminApolloClient();
const serviceUrl = generateAppServiceUrl(
currentProject?.subdomain,
currentProject?.region,
'graphql',
);
const client = new ApolloClient({
cache: new InMemoryCache(),
link: new HttpLink({
uri: serviceUrl,
headers: {
'x-hasura-admin-secret':
process.env.NEXT_PUBLIC_ENV === 'dev'
? getHasuraAdminSecret()
: currentProject?.config?.hasura.adminSecret,
},
}),
});
const [insertGraphiteAutoEmbeddingsConfiguration] = const [insertGraphiteAutoEmbeddingsConfiguration] =
useInsertGraphiteAutoEmbeddingsConfigurationMutation({ useInsertGraphiteAutoEmbeddingsConfigurationMutation({
client, client: adminClient,
}); });
const [updateGraphiteAutoEmbeddingsConfiguration] = const [updateGraphiteAutoEmbeddingsConfiguration] =
useUpdateGraphiteAutoEmbeddingsConfigurationMutation({ client }); useUpdateGraphiteAutoEmbeddingsConfigurationMutation({
client: adminClient,
});
const form = useForm<AutoEmbeddingsFormValues>({ const form = useForm<AutoEmbeddingsFormValues>({
defaultValues: initialData, defaultValues: initialData,
@@ -137,33 +111,18 @@ export default function AutoEmbeddingsForm({
}; };
const handleSubmit = async (values: AutoEmbeddingsFormValues) => { const handleSubmit = async (values: AutoEmbeddingsFormValues) => {
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
createOrUpdateAutoEmbeddings(values), await createOrUpdateAutoEmbeddings(values);
{ onSubmit?.();
loading: 'Configuring the Auto-Embeddings...', },
success: `The Auto-Embeddings has been configured successfully.`, {
error: (arg: ApolloError) => { loadingMessage: 'Configuring the Auto-Embeddings...',
// we need to get the internal error message from the GraphQL error successMessage: 'The Auto-Embeddings has been configured successfully.',
const { internal } = arg.graphQLErrors[0]?.extensions || {}; errorMessage:
const { message } = (internal as Record<string, any>)?.error || {}; 'An error occurred while configuring the Auto-Embeddings. Please try again.',
},
// we use the default Apollo error message if we can't find the );
// internal error message
return (
message ||
arg.message ||
'An error occurred while configuring the Auto-Embeddings. Please try again.'
);
},
},
getToastStyleProps(),
);
onSubmit?.();
} catch {
// Note: The toast will handle the error.
}
}; };
return ( return (

View File

@@ -2,20 +2,11 @@ import { Box } from '@/components/ui/v2/Box';
import { Button } from '@/components/ui/v2/Button'; import { Button } from '@/components/ui/v2/Button';
import { Checkbox } from '@/components/ui/v2/Checkbox'; import { Checkbox } from '@/components/ui/v2/Checkbox';
import { Text } from '@/components/ui/v2/Text'; import { Text } from '@/components/ui/v2/Text';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject'; import { useAdminApolloClient } from '@/features/projects/common/hooks/useAdminApolloClient';
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getToastStyleProps } from '@/utils/constants/settings';
import { getHasuraAdminSecret } from '@/utils/env';
import { useDeleteAssistantMutation } from '@/utils/__generated__/graphite.graphql'; import { useDeleteAssistantMutation } from '@/utils/__generated__/graphite.graphql';
import {
ApolloClient,
HttpLink,
InMemoryCache,
type ApolloError,
} from '@apollo/client';
import { type Assistant } from 'pages/[workspaceSlug]/[appSlug]/ai/assistants'; import { type Assistant } from 'pages/[workspaceSlug]/[appSlug]/ai/assistants';
import { useState } from 'react'; import { useState } from 'react';
import toast from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
export interface DeleteAssistantModalProps { export interface DeleteAssistantModalProps {
@@ -32,29 +23,10 @@ export default function DeleteAssistantModal({
const [remove, setRemove] = useState(false); const [remove, setRemove] = useState(false);
const [loadingRemove, setLoadingRemove] = useState(false); const [loadingRemove, setLoadingRemove] = useState(false);
const { currentProject } = useCurrentWorkspaceAndProject(); const { adminClient } = useAdminApolloClient();
const serviceUrl = generateAppServiceUrl(
currentProject?.subdomain,
currentProject?.region,
'graphql',
);
const client = new ApolloClient({
cache: new InMemoryCache(),
link: new HttpLink({
uri: serviceUrl,
headers: {
'x-hasura-admin-secret':
process.env.NEXT_PUBLIC_ENV === 'dev'
? getHasuraAdminSecret()
: currentProject?.config?.hasura.adminSecret,
},
}),
});
const [deleteAssistantMutation] = useDeleteAssistantMutation({ const [deleteAssistantMutation] = useDeleteAssistantMutation({
client, client: adminClient,
}); });
const deleteAssistant = async () => { const deleteAssistant = async () => {
@@ -70,27 +42,12 @@ export default function DeleteAssistantModal({
async function handleClick() { async function handleClick() {
setLoadingRemove(true); setLoadingRemove(true);
await toast.promise( await execPromiseWithErrorToast(deleteAssistant, {
deleteAssistant(), loadingMessage: 'Deleting the assistant...',
{ successMessage: 'The Assistant has been deleted successfully.',
loading: 'Deleting the assistant...', errorMessage:
success: `The Assistant has been deleted successfully.`, 'An error occurred while deleting the Assistant. Please try again.',
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 deleting the Assistant. Please try again.'
);
},
},
getToastStyleProps(),
);
} }
return ( return (

View File

@@ -4,18 +4,12 @@ import { Checkbox } from '@/components/ui/v2/Checkbox';
import { Text } from '@/components/ui/v2/Text'; import { Text } from '@/components/ui/v2/Text';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject'; import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl'; import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
import { getToastStyleProps } from '@/utils/constants/settings';
import { getHasuraAdminSecret } from '@/utils/env'; import { getHasuraAdminSecret } from '@/utils/env';
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { useDeleteGraphiteAutoEmbeddingsConfigurationMutation } from '@/utils/__generated__/graphite.graphql'; import { useDeleteGraphiteAutoEmbeddingsConfigurationMutation } from '@/utils/__generated__/graphite.graphql';
import { import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client';
ApolloClient,
HttpLink,
InMemoryCache,
type ApolloError,
} from '@apollo/client';
import { type AutoEmbeddingsConfiguration } from 'pages/[workspaceSlug]/[appSlug]/ai/auto-embeddings'; import { type AutoEmbeddingsConfiguration } from 'pages/[workspaceSlug]/[appSlug]/ai/auto-embeddings';
import { useState } from 'react'; import { useState } from 'react';
import toast from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
export interface DeleteAutoEmbeddingsModalProps { export interface DeleteAutoEmbeddingsModalProps {
@@ -71,27 +65,13 @@ export default function DeleteAutoEmbeddingsModal({
async function handleClick() { async function handleClick() {
setLoadingRemove(true); setLoadingRemove(true);
await toast.promise( await execPromiseWithErrorToast(deleteAutoEmbeddingsConfig, {
deleteAutoEmbeddingsConfig(), loadingMessage: 'Deleting Auto-Embeddings Configuration...',
{ successMessage:
loading: 'Deleting Auto-Embeddings Configuration...', 'The Auto-Embeddings Configuration has been deleted successfully.',
success: `The Auto-Embeddings Configuration has been deleted successfully.`, errorMessage:
error: (arg: ApolloError) => { 'An error occurred while deleting the Auto-Embeddings Configuration. Please try again.',
// 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 deleting the Auto-Embeddings Configuration. Please try again.'
);
},
},
getToastStyleProps(),
);
} }
return ( return (

View File

@@ -2,6 +2,7 @@ import { UpgradeToProBanner } from '@/components/common/UpgradeToProBanner';
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator'; import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
import { Alert } from '@/components/ui/v2/Alert'; import { Alert } from '@/components/ui/v2/Alert';
import { Box } from '@/components/ui/v2/Box'; import { Box } from '@/components/ui/v2/Box';
import { ErrorToast } from '@/components/ui/v2/ErrorToast';
import { IconButton } from '@/components/ui/v2/IconButton'; import { IconButton } from '@/components/ui/v2/IconButton';
import { ArrowUpIcon } from '@/components/ui/v2/icons/ArrowUpIcon'; import { ArrowUpIcon } from '@/components/ui/v2/icons/ArrowUpIcon';
import { Input } from '@/components/ui/v2/Input'; import { Input } from '@/components/ui/v2/Input';
@@ -17,7 +18,6 @@ import { useAdminApolloClient } from '@/features/projects/common/hooks/useAdminA
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject'; import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
import { useIsGraphiteEnabled } from '@/features/projects/common/hooks/useIsGraphiteEnabled'; import { useIsGraphiteEnabled } from '@/features/projects/common/hooks/useIsGraphiteEnabled';
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform'; import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
import { getToastStyleProps } from '@/utils/constants/settings';
import { import {
useSendDevMessageMutation, useSendDevMessageMutation,
useStartDevSessionMutation, useStartDevSessionMutation,
@@ -122,11 +122,17 @@ export default function DevAssistant() {
setMessages(thread); setMessages(thread);
} catch (error) { } catch (error) {
toast.error( toast.custom(
'Failed to send the message to graphite. Please try again later.', (t) => (
<ErrorToast
isVisible={t.visible}
errorMessage="Failed to send the message. Please try again later."
error={error}
close={() => toast.dismiss()}
/>
),
{ {
style: getToastStyleProps().style, duration: Number.POSITIVE_INFINITY,
...getToastStyleProps().error,
}, },
); );
} finally { } finally {

View File

@@ -24,7 +24,7 @@ function PreComponent(
const { children } = props; const { children } = props;
return ( return (
<div className="group relative"> <div className="relative group">
<pre>{children}</pre> <pre>{children}</pre>
<IconButton <IconButton
sx={{ sx={{
@@ -34,13 +34,13 @@ function PreComponent(
}} }}
color="warning" color="warning"
variant="contained" variant="contained"
className="absolute top-2 right-2 hidden group-hover:flex" className="absolute hidden top-2 right-2 group-hover:flex"
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
copy(onlyText(children), 'Snippet'); copy(onlyText(children), 'Snippet');
}} }}
> >
<CopyIcon className="h-5 w-5" /> <CopyIcon className="w-5 h-5" />
</IconButton> </IconButton>
</div> </div>
); );
@@ -53,7 +53,7 @@ export default function MessageBox({ message }: { message: Message }) {
return ( return (
<Box <Box
className="flex flex-col space-y-4 border-t p-4 first:border-t-0" className="flex flex-col p-4 space-y-4 border-t first:border-t-0"
sx={{ sx={{
backgroundColor: isUserMessage && 'background.default', backgroundColor: isUserMessage && 'background.default',
}} }}
@@ -67,7 +67,7 @@ export default function MessageBox({ message }: { message: Message }) {
) : ( ) : (
<> <>
<Avatar <Avatar
className="h-7 w-7 rounded-full" className="rounded-full h-7 w-7"
alt={user?.displayName} alt={user?.displayName}
src={user?.avatarUrl} src={user?.avatarUrl}
> >

View File

@@ -1,7 +1,6 @@
import { import messagesState, {
messagesState,
type ProjectMessage, type ProjectMessage,
} from '@/features/ai/DevAssistant/state'; } from '@/features/ai/DevAssistant/state/messages';
import { selectorFamily } from 'recoil'; import { selectorFamily } from 'recoil';
const projectMessagesState = selectorFamily<ProjectMessage[], string>({ const projectMessagesState = selectorFamily<ProjectMessage[], string>({

View File

@@ -22,7 +22,7 @@ import {
} from '@/generated/graphql'; } from '@/generated/graphql';
import { RESOURCE_VCPU_MULTIPLIER } from '@/utils/constants/common'; import { RESOURCE_VCPU_MULTIPLIER } from '@/utils/constants/common';
import { getToastStyleProps } from '@/utils/constants/settings'; import { getToastStyleProps } from '@/utils/constants/settings';
import { getServerError } from '@/utils/getServerError'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
@@ -30,6 +30,8 @@ import { toast } from 'react-hot-toast';
import * as Yup from 'yup'; import * as Yup from 'yup';
import { DisableAIServiceConfirmationDialog } from './DisableAIServiceConfirmationDialog'; import { DisableAIServiceConfirmationDialog } from './DisableAIServiceConfirmationDialog';
const MIN_POSTGRES_VERSION_SUPPORTING_AI = '14.6-20231018-1';
const validationSchema = Yup.object({ const validationSchema = Yup.object({
version: Yup.object({ version: Yup.object({
label: Yup.string().required(), label: Yup.string().required(),
@@ -56,7 +58,9 @@ export default function AISettings() {
const [aiServiceEnabled, setAIServiceEnabled] = useState(true); const [aiServiceEnabled, setAIServiceEnabled] = useState(true);
const { const {
data: { config: { ai } = {} } = {}, data: {
config: { ai, postgres: { version: postgresVersion } = {} } = {},
} = {},
loading: loadingAiSettings, loading: loadingAiSettings,
error: errorGettingAiSettings, error: errorGettingAiSettings,
} = useGetAiSettingsQuery({ } = useGetAiSettingsQuery({
@@ -152,6 +156,17 @@ export default function AISettings() {
]); ]);
const toggleAIService = async (enabled: boolean) => { const toggleAIService = async (enabled: boolean) => {
if (postgresVersion < MIN_POSTGRES_VERSION_SUPPORTING_AI) {
toast.error(
'In order to enable the AI service you need to update your database version to 14.6-20231018-1 or newer.',
{
style: getToastStyleProps().style,
...getToastStyleProps().error,
},
);
return;
}
setAIServiceEnabled(enabled); setAIServiceEnabled(enabled);
if (!enabled && ai) { if (!enabled && ai) {
@@ -182,9 +197,9 @@ export default function AISettings() {
} }
async function handleSubmit(formValues: AISettingsFormValues) { async function handleSubmit(formValues: AISettingsFormValues) {
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfig({ await updateConfig({
variables: { variables: {
appId: currentProject.id, appId: currentProject.id,
config: { config: {
@@ -207,21 +222,17 @@ export default function AISettings() {
}, },
}, },
}, },
}), });
{
loading: `AI settings are being updated...`,
success: `AI settings has been updated successfully.`,
error: getServerError(
`An error occurred while trying to update the AI settings!`,
),
},
getToastStyleProps(),
);
form.reset(formValues); form.reset(formValues);
} catch { },
// Note: The toast will handle the error. {
} loadingMessage: 'AI settings are being updated...',
successMessage: 'AI settings has been updated successfully.',
errorMessage:
'An error occurred while trying to update the AI settings!',
},
);
} }
const getAIResourcesCost = () => { const getAIResourcesCost = () => {

View File

@@ -3,11 +3,9 @@ import { Box } from '@/components/ui/v2/Box';
import { Button } from '@/components/ui/v2/Button'; import { Button } from '@/components/ui/v2/Button';
import { Text } from '@/components/ui/v2/Text'; import { Text } from '@/components/ui/v2/Text';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject'; import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { useUpdateConfigMutation } from '@/utils/__generated__/graphql'; import { useUpdateConfigMutation } from '@/utils/__generated__/graphql';
import type { ApolloError } from '@apollo/client';
import { useState } from 'react'; import { useState } from 'react';
import toast from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
export interface DisableAIServiceConfirmationDialogProps { export interface DisableAIServiceConfirmationDialogProps {
@@ -34,37 +32,26 @@ export default function DisableAIServiceConfirmationDialog({
async function handleClick() { async function handleClick() {
setLoading(true); setLoading(true);
await toast.promise( await execPromiseWithErrorToast(
updateConfig({ async () => {
variables: { await updateConfig({
appId: currentProject.id, variables: {
config: { appId: currentProject.id,
ai: null, config: {
ai: null,
},
}, },
}, });
}),
{
loading: 'Disabling the AI service...',
success: () => {
onServiceDisabled();
closeDialog();
return `The service has been disabled.`;
},
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 onServiceDisabled();
// internal error message closeDialog();
return ( },
message || {
arg.message || loadingMessage: 'Disabling the AI service...',
'An error occurred while disabling the AI service. Please try again later.' successMessage: 'The service has been disabled.',
); errorMessage:
}, 'An error occurred while disabling the AI service. Please try again later.',
}, },
getToastStyleProps(),
); );
} }

View File

@@ -1,5 +1,8 @@
query GetAISettings($appId: uuid!) { query GetAISettings($appId: uuid!) {
config(appID: $appId, resolve: false) { config(appID: $appId, resolve: false) {
postgres {
version
}
ai { ai {
version version
webhookSecret webhookSecret

View File

@@ -9,11 +9,9 @@ import {
useGetAuthenticationSettingsQuery, useGetAuthenticationSettingsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getServerError } from '@/utils/getServerError';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
import * as Yup from 'yup'; import * as Yup from 'yup';
@@ -103,21 +101,19 @@ export default function AllowedEmailDomainsSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(values);
loading: `Allowed email settings are being updated...`, },
success: `Allowed email settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'Allowed email settings are being updated...',
`An error occurred while trying to update the project's allowed email settings.`, successMessage:
), 'Allowed email settings have been updated successfully.',
}, errorMessage:
getToastStyleProps(), "An error occurred while trying to update the project's allowed email settings.",
); },
} catch { );
// Note: The toast will handle the error
}
form.reset(values); form.reset(values);
}; };
@@ -134,7 +130,7 @@ export default function AllowedEmailDomainsSettings() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
docsLink="https://docs.nhost.io/authentication#allowed-emails-and-domains" docsLink="https://docs.nhost.io/guides/auth/overview#allowed-emails-and-domains"
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(

View File

@@ -9,11 +9,9 @@ import {
useGetAuthenticationSettingsQuery, useGetAuthenticationSettingsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getServerError } from '@/utils/getServerError';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import * as Yup from 'yup'; import * as Yup from 'yup';
const validationSchema = Yup.object({ const validationSchema = Yup.object({
@@ -80,23 +78,19 @@ export default function AllowedRedirectURLsSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(values);
loading: `Allowed redirect URL settings are being updated...`, },
success: `Allowed redirect URL settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'Allowed redirect URL settings are being updated...',
`An error occurred while trying to update the project's allowed redirect URL settings.`, successMessage:
), 'Allowed redirect URL settings have been updated successfully.',
}, errorMessage:
getToastStyleProps(), "An error occurred while trying to update the project's allowed redirect URL settings.",
); },
);
form.reset(values);
} catch {
// Note: The toast will handle the error.
}
}; };
return ( return (
@@ -111,7 +105,7 @@ export default function AllowedRedirectURLsSettings() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
docsLink="https://docs.nhost.io/authentication#allowed-redirect-urls" docsLink="https://docs.nhost.io/guides/auth/overview#allowed-redirect-urls"
className="grid grid-flow-row px-4 lg:grid-cols-5" className="grid grid-flow-row px-4 lg:grid-cols-5"
> >
<Input <Input

View File

@@ -8,11 +8,9 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getServerError } from '@/utils/getServerError';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import * as Yup from 'yup'; import * as Yup from 'yup';
const validationSchema = Yup.object({ const validationSchema = Yup.object({
@@ -73,23 +71,19 @@ export default function AnonymousSignInSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(values);
loading: `Anonymous sign-in settings are being updated...`, },
success: `Anonymous sign-in settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'Anonymous sign-in settings are being updated...',
`An error occurred while trying to update Anonymous sign-in settings.`, successMessage:
), 'Anonymous sign-in settings have been updated successfully.',
}, errorMessage:
getToastStyleProps(), 'An error occurred while trying to update Anonymous sign-in settings.',
); },
);
form.reset(values);
} catch {
// Note: The toast will handle the error.
}
}; };
return ( return (

View File

@@ -13,13 +13,11 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings';
import { copy } from '@/utils/copy'; import { copy } from '@/utils/copy';
import { getServerError } from '@/utils/getServerError'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { useTheme } from '@mui/material'; import { useTheme } from '@mui/material';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
import * as Yup from 'yup'; import * as Yup from 'yup';
@@ -117,23 +115,18 @@ export default function AppleProviderSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(formValues);
loading: `Apple settings are being updated...`, },
success: `Apple settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'Apple settings are being updated...',
`An error occurred while trying to update the project's Apple settings.`, successMessage: 'Apple settings have been updated successfully.',
), errorMessage:
}, "An error occurred while trying to update the project's Apple settings.",
getToastStyleProps(), },
); );
form.reset(formValues);
} catch {
// Note: The toast will handle the error.
}
} }
return ( return (
@@ -148,7 +141,7 @@ export default function AppleProviderSettings() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
docsLink="https://docs.nhost.io/authentication/sign-in-with-apple" docsLink="https://docs.nhost.io/guides/auth/social/sign-in-apple"
docsTitle="how to sign in users with Apple" docsTitle="how to sign in users with Apple"
icon={ icon={
theme.palette.mode === 'dark' theme.palette.mode === 'dark'
@@ -158,7 +151,7 @@ export default function AppleProviderSettings() {
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(
'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-y-4 gap-x-3 px-4 py-2', 'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-x-3 gap-y-4 px-4 py-2',
!authEnabled && 'hidden', !authEnabled && 'hidden',
)} )}
> >

View File

@@ -11,11 +11,9 @@ import {
useGetSoftwareVersionsQuery, useGetSoftwareVersionsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getServerError } from '@/utils/getServerError';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import * as Yup from 'yup'; import * as Yup from 'yup';
const validationSchema = Yup.object({ const validationSchema = Yup.object({
@@ -95,23 +93,17 @@ export default function AuthServiceVersionSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(formValues);
loading: `Auth version is being updated...`, },
success: `Auth version has been updated successfully.`, {
error: getServerError( loadingMessage: 'Auth version is being updated...',
`An error occurred while trying to update Auth version.`, successMessage: 'Auth version has been updated successfully.',
), errorMessage: 'An error occurred while trying to update Auth version.',
}, },
getToastStyleProps(), );
);
form.reset(formValues);
} catch {
// Note: The toast will handle the error.
}
}; };
return ( return (
@@ -128,7 +120,7 @@ export default function AuthServiceVersionSettings() {
}} }}
docsLink="https://github.com/nhost/hasura-auth/releases" docsLink="https://github.com/nhost/hasura-auth/releases"
docsTitle="the latest releases" docsTitle="the latest releases"
className="grid grid-flow-row gap-y-2 gap-x-4 px-4 lg:grid-cols-5" className="grid grid-flow-row gap-x-4 gap-y-2 px-4 lg:grid-cols-5"
> >
<ControlledAutocomplete <ControlledAutocomplete
id="version" id="version"

View File

@@ -14,12 +14,10 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings';
import { copy } from '@/utils/copy'; import { copy } from '@/utils/copy';
import { getServerError } from '@/utils/getServerError'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
import * as Yup from 'yup'; import * as Yup from 'yup';
@@ -106,23 +104,18 @@ export default function AzureADProviderSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(formValues);
loading: `Azure AD settings are being updated...`, },
success: `Azure AD settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'Azure AD settings are being updated...',
`An error occurred while trying to update the project's Azure AD settings.`, successMessage: 'Azure AD settings have been updated successfully.',
), errorMessage:
}, "An error occurred while trying to update the project's Azure AD settings.",
getToastStyleProps(), },
); );
form.reset(formValues);
} catch {
// Note: The toast will handle the error.
}
} }
return ( return (
@@ -141,7 +134,7 @@ export default function AzureADProviderSettings() {
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(
'grid grid-flow-row grid-cols-2 gap-y-4 gap-x-3 px-4 py-2', 'grid grid-flow-row grid-cols-2 gap-x-3 gap-y-4 px-4 py-2',
!authEnabled && 'hidden', !authEnabled && 'hidden',
)} )}
> >

View File

@@ -18,12 +18,10 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings';
import { copy } from '@/utils/copy'; import { copy } from '@/utils/copy';
import { getServerError } from '@/utils/getServerError'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
export default function BitbucketProviderSettings() { export default function BitbucketProviderSettings() {
@@ -84,23 +82,18 @@ export default function BitbucketProviderSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(formValues);
loading: `Bitbucket settings are being updated...`, },
success: `Bitbucket settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'Bitbucket settings are being updated...',
`An error occurred while trying to update the project's Bitbucket settings.`, successMessage: 'Bitbucket settings have been updated successfully.',
), errorMessage:
}, "An error occurred while trying to update the project's Bitbucket settings.",
getToastStyleProps(), },
); );
form.reset(formValues);
} catch {
// Note: The toast will handle the error.
}
} }
return ( return (
@@ -119,7 +112,7 @@ export default function BitbucketProviderSettings() {
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(
'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-y-4 gap-x-3 px-4 py-2', 'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-x-3 gap-y-4 px-4 py-2',
!authEnabled && 'hidden', !authEnabled && 'hidden',
)} )}
> >

View File

@@ -9,11 +9,9 @@ import {
useGetAuthenticationSettingsQuery, useGetAuthenticationSettingsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getServerError } from '@/utils/getServerError';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
import * as Yup from 'yup'; import * as Yup from 'yup';
@@ -110,23 +108,20 @@ export default function BlockedEmailSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(values);
loading: `Blocked email and domain settings are being updated...`, },
success: `Blocked email and domain settings have been updated successfully.`, {
error: getServerError( loadingMessage:
`An error occurred while trying to update the project's blocked email and domain settings.`, 'Blocked email and domain settings are being updated...',
), successMessage:
}, 'Blocked email and domain settings have been updated successfully.',
getToastStyleProps(), errorMessage:
); "An error occurred while trying to update the project's blocked email and domain settings.",
},
form.reset(values); );
} catch {
// Note: The toast will handle the error.
}
}; };
return ( return (
@@ -141,7 +136,7 @@ export default function BlockedEmailSettings() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
docsLink="https://docs.nhost.io/authentication#blocked-emails-and-domains" docsLink="https://docs.nhost.io/guides/auth/overview#allowed-emails-and-domains"
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(

View File

@@ -9,11 +9,9 @@ import {
useGetAuthenticationSettingsQuery, useGetAuthenticationSettingsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getServerError } from '@/utils/getServerError';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import * as Yup from 'yup'; import * as Yup from 'yup';
const validationSchema = Yup.object({ const validationSchema = Yup.object({
@@ -75,23 +73,18 @@ export default function ClientURLSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(values);
loading: `Client URL is being updated...`, },
success: `Client URL has been updated successfully.`, {
error: getServerError( loadingMessage: 'Client URL is being updated...',
`An error occurred while trying to update the project's Client URL.`, successMessage: 'Client URL has been updated successfully.',
), errorMessage:
}, "An error occurred while trying to update the project's Client URL.",
getToastStyleProps(), },
); );
form.reset(values);
} catch {
// Note: The toast will handle the error.
}
}; };
return ( return (
@@ -106,7 +99,7 @@ export default function ClientURLSettings() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
docsLink="https://docs.nhost.io/authentication#client-url" docsLink="https://docs.nhost.io/guides/auth/overview#client-url"
className="grid grid-flow-row lg:grid-cols-5" className="grid grid-flow-row lg:grid-cols-5"
> >
<Input <Input

View File

@@ -3,15 +3,13 @@ import { Form } from '@/components/form/Form';
import { SettingsContainer } from '@/components/layout/SettingsContainer'; import { SettingsContainer } from '@/components/layout/SettingsContainer';
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator'; import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject'; import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getServerError } from '@/utils/getServerError';
import { import {
GetAuthenticationSettingsDocument, GetAuthenticationSettingsDocument,
useGetAuthenticationSettingsQuery, useGetAuthenticationSettingsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/utils/__generated__/graphql'; } from '@/utils/__generated__/graphql';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import * as Yup from 'yup'; import * as Yup from 'yup';
const validationSchema = Yup.object({ const validationSchema = Yup.object({
@@ -71,23 +69,18 @@ export default function DisableNewUsersSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(values);
loading: `Disabling new user sign ups...`, },
success: `New user sign ups have been disabled successfully.`, {
error: getServerError( loadingMessage: 'Disabling new user sign ups...',
`An error occurred while trying to disable new user sign ups.`, successMessage: 'New user sign ups have been disabled successfully.',
), errorMessage:
}, 'An error occurred while trying to disable new user sign ups.',
getToastStyleProps(), },
); );
form.reset(values);
} catch {
// Note: The toast will handle the error.
}
}; };
return ( return (
@@ -96,7 +89,7 @@ export default function DisableNewUsersSettings() {
<SettingsContainer <SettingsContainer
title="Disable New Users" title="Disable New Users"
description="If set, newly registered users are disabled and won't be able to sign in." description="If set, newly registered users are disabled and won't be able to sign in."
docsLink="https://docs.nhost.io/authentication#disable-new-users" docsLink="https://docs.nhost.io/guides/auth/overview#disable-new-users"
switchId="disabled" switchId="disabled"
showSwitch showSwitch
slotProps={{ slotProps={{

View File

@@ -18,12 +18,10 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings';
import { copy } from '@/utils/copy'; import { copy } from '@/utils/copy';
import { getServerError } from '@/utils/getServerError'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
export default function DiscordProviderSettings() { export default function DiscordProviderSettings() {
@@ -87,23 +85,18 @@ export default function DiscordProviderSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(formValues);
loading: `Discord settings are being updated...`, },
success: `Discord settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'Discord settings are being updated...',
`An error occurred while trying to update the project's Discrod settings.`, successMessage: 'Discord settings have been updated successfully.',
), errorMessage:
}, "An error occurred while trying to update the project's Discrod settings.",
getToastStyleProps(), },
); );
form.reset(formValues);
} catch {
// Note: The toast will handle the error.
}
} }
return ( return (
@@ -118,13 +111,13 @@ export default function DiscordProviderSettings() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
docsLink="https://docs.nhost.io/platform/authentication/sign-in-with-discord" docsLink="https://docs.nhost.io/guides/auth/social/sign-in-discord"
docsTitle="how to sign in users with Discord" docsTitle="how to sign in users with Discord"
icon="/assets/brands/discord.svg" icon="/assets/brands/discord.svg"
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(
'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-y-4 gap-x-3 px-4 py-2', 'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-x-3 gap-y-4 px-4 py-2',
!authEnabled && 'hidden', !authEnabled && 'hidden',
)} )}
> >

View File

@@ -11,11 +11,9 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getServerError } from '@/utils/getServerError';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import * as Yup from 'yup'; import * as Yup from 'yup';
const validationSchema = Yup.object({ const validationSchema = Yup.object({
@@ -85,23 +83,19 @@ export default function EmailAndPasswordSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(formValues);
loading: `Email and password sign-in settings are being updated...`, },
success: `Email and password sign-in settings have been updated successfully.`, {
error: getServerError( loadingMessage: `Email and password sign-in settings are being updated...`,
`An error occurred while trying to update email sign-in settings.`, successMessage:
), 'Email and password sign-in settings have been updated successfully.',
}, errorMessage:
getToastStyleProps(), 'An error occurred while trying to update email sign-in settings.',
); },
);
form.reset(formValues);
} catch {
// Note: The toast will handle the error.
}
} }
return ( return (
@@ -110,7 +104,7 @@ export default function EmailAndPasswordSettings() {
<SettingsContainer <SettingsContainer
title="Email and Password" title="Email and Password"
description="Allow users to sign in with email and password." description="Allow users to sign in with email and password."
docsLink="https://docs.nhost.io/authentication/sign-in-with-email-and-password" docsLink="https://docs.nhost.io/guides/auth/sign-in-email-password"
docsTitle="how to sign in users with email and password" docsTitle="how to sign in users with email and password"
className="grid grid-flow-row" className="grid grid-flow-row"
showSwitch showSwitch

View File

@@ -18,12 +18,10 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings';
import { copy } from '@/utils/copy'; import { copy } from '@/utils/copy';
import { getServerError } from '@/utils/getServerError'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
export default function FacebookProviderSettings() { export default function FacebookProviderSettings() {
@@ -87,23 +85,18 @@ export default function FacebookProviderSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(formValues);
loading: `Facebook settings are being updated...`, },
success: `Facebook settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'Facebook settings are being updated...',
`An error occurred while trying to update the project's Facebook settings.`, successMessage: 'Facebook settings have been updated successfully.',
), errorMessage:
}, "An error occurred while trying to update the project's Facebook settings.",
getToastStyleProps(), },
); );
form.reset(formValues);
} catch {
// Note: The toast will handle the error.
}
} }
return ( return (
@@ -118,13 +111,13 @@ export default function FacebookProviderSettings() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
docsLink="https://docs.nhost.io/platform/authentication/sign-in-with-facebook" docsLink="https://docs.nhost.io/guides/auth/social/sign-in-facebook"
docsTitle="how to sign in users with Facebook" docsTitle="how to sign in users with Facebook"
icon="/assets/brands/facebook.svg" icon="/assets/brands/facebook.svg"
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(
'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-y-4 gap-x-3 px-4 py-2', 'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-x-3 gap-y-4 px-4 py-2',
!authEnabled && 'hidden', !authEnabled && 'hidden',
)} )}
> >

View File

@@ -18,13 +18,11 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings';
import { copy } from '@/utils/copy'; import { copy } from '@/utils/copy';
import { getServerError } from '@/utils/getServerError'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { useTheme } from '@mui/material'; import { useTheme } from '@mui/material';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
export default function GitHubProviderSettings() { export default function GitHubProviderSettings() {
@@ -89,23 +87,18 @@ export default function GitHubProviderSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(formValues);
loading: `GitHub settings are being updated...`, },
success: `GitHub settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'GitHub settings are being updated...',
`An error occurred while trying to update the project's GitHub settings.`, successMessage: 'GitHub settings have been updated successfully.',
), errorMessage:
}, "An error occurred while trying to update the project's GitHub settings.",
getToastStyleProps(), },
); );
form.reset(formValues);
} catch {
// Note: The toast will handle the error.
}
} }
return ( return (
@@ -120,7 +113,7 @@ export default function GitHubProviderSettings() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
docsLink="https://docs.nhost.io/platform/authentication/sign-in-with-github" docsLink="https://docs.nhost.io/guides/auth/social/sign-in-github"
docsTitle="how to sign in users with GitHub" docsTitle="how to sign in users with GitHub"
icon={ icon={
theme.palette.mode === 'dark' theme.palette.mode === 'dark'
@@ -130,7 +123,7 @@ export default function GitHubProviderSettings() {
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(
'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-y-4 gap-x-3 px-4 py-2', 'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-x-3 gap-y-4 px-4 py-2',
!authEnabled && 'hidden', !authEnabled && 'hidden',
)} )}
> >

View File

@@ -18,12 +18,10 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings';
import { copy } from '@/utils/copy'; import { copy } from '@/utils/copy';
import { getServerError } from '@/utils/getServerError'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
export default function GitLabProviderSettings() { export default function GitLabProviderSettings() {
@@ -87,23 +85,18 @@ export default function GitLabProviderSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(values);
loading: `GitLab settings are being updated...`, },
success: `GitLab settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'GitLab settings are being updated...',
`An error occurred while trying to update the project's GitLab settings.`, successMessage: 'GitLab settings have been updated successfully.',
), errorMessage:
}, "An error occurred while trying to update the project's GitLab settings.",
getToastStyleProps(), },
); );
form.reset(values);
} catch {
// Note: The toast will handle the error.
}
} }
return ( return (
@@ -122,7 +115,7 @@ export default function GitLabProviderSettings() {
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(
'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-y-4 gap-x-3 px-4 py-2', 'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-x-3 gap-y-4 px-4 py-2',
!authEnabled && 'hidden', !authEnabled && 'hidden',
)} )}
> >

View File

@@ -18,12 +18,10 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings';
import { copy } from '@/utils/copy'; import { copy } from '@/utils/copy';
import { getServerError } from '@/utils/getServerError'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
export default function GoogleProviderSettings() { export default function GoogleProviderSettings() {
@@ -87,23 +85,18 @@ export default function GoogleProviderSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(formValues);
loading: `Google settings are being updated...`, },
success: `Google settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'Google settings are being updated...',
`An error occurred while trying to update the project's Google settings.`, successMessage: 'Google settings have been updated successfully.',
), errorMessage:
}, "An error occurred while trying to update the project's Google settings.",
getToastStyleProps(), },
); );
form.reset(formValues);
} catch {
// Note: The toast will handle the error.
}
} }
return ( return (
@@ -118,13 +111,13 @@ export default function GoogleProviderSettings() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
docsLink="https://docs.nhost.io/platform/authentication/sign-in-with-google" docsLink="https://docs.nhost.io/guides/auth/social/sign-in-google"
docsTitle="how to sign in users with Google" docsTitle="how to sign in users with Google"
icon="/assets/brands/google.svg" icon="/assets/brands/google.svg"
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(
'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-y-4 gap-x-3 px-4 py-2', 'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-x-3 gap-y-4 px-4 py-2',
!authEnabled && 'hidden', !authEnabled && 'hidden',
)} )}
> >

View File

@@ -13,12 +13,10 @@ import {
import { import {
AUTH_GRAVATAR_DEFAULT, AUTH_GRAVATAR_DEFAULT,
AUTH_GRAVATAR_RATING, AUTH_GRAVATAR_RATING,
getToastStyleProps,
} from '@/utils/constants/settings'; } from '@/utils/constants/settings';
import { getServerError } from '@/utils/getServerError'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
import * as Yup from 'yup'; import * as Yup from 'yup';
@@ -89,23 +87,18 @@ export default function GravatarSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(values);
loading: `Gravatar settings are being updated...`, },
success: `Gravatar settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'Gravatar settings are being updated...',
`An error occurred while trying to update the project's Gravatar settings.`, successMessage: 'Gravatar settings have been updated successfully.',
), errorMessage:
}, "An error occurred while trying to update the project's Gravatar settings.",
getToastStyleProps(), },
); );
form.reset(values);
} catch {
// Note: The toast will handle the error.
}
}; };
return ( return (
@@ -120,7 +113,7 @@ export default function GravatarSettings() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
docsLink="https://docs.nhost.io/authentication#gravatar" docsLink="https://docs.nhost.io/guides/auth/overview#gravatar"
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(

View File

@@ -18,12 +18,10 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings';
import { copy } from '@/utils/copy'; import { copy } from '@/utils/copy';
import { getServerError } from '@/utils/getServerError'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
export default function LinkedInProviderSettings() { export default function LinkedInProviderSettings() {
@@ -87,23 +85,18 @@ export default function LinkedInProviderSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(formValues);
loading: `LinkedIn settings are being updated...`, },
success: `LinkedIn settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'LinkedIn settings are being updated...',
`An error occurred while trying to update the project's LinkedIn settings.`, successMessage: 'LinkedIn settings have been updated successfully.',
), errorMessage:
}, "An error occurred while trying to update the project's LinkedIn settings.",
getToastStyleProps(), },
); );
form.reset(formValues);
} catch {
// Note: The toast will handle the error.
}
} }
return ( return (
@@ -118,13 +111,13 @@ export default function LinkedInProviderSettings() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
docsLink="https://docs.nhost.io/platform/authentication/sign-in-with-linkedin" docsLink="https://docs.nhost.io/guides/auth/social/sign-in-linkedin"
docsTitle="how to sign in users with LinkedIn" docsTitle="how to sign in users with LinkedIn"
icon="/assets/brands/linkedin.svg" icon="/assets/brands/linkedin.svg"
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(
'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-y-4 gap-x-3 px-4 py-2', 'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-x-3 gap-y-4 px-4 py-2',
!authEnabled && 'hidden', !authEnabled && 'hidden',
)} )}
> >

View File

@@ -9,11 +9,9 @@ import {
useGetAuthenticationSettingsQuery, useGetAuthenticationSettingsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getServerError } from '@/utils/getServerError';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
import * as Yup from 'yup'; import * as Yup from 'yup';
@@ -76,23 +74,20 @@ export default function MFASettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(values);
loading: `Multi-factor authentication settings are being updated...`, },
success: `Multi-factor authentication settings have been updated successfully.`, {
error: getServerError( loadingMessage:
`An error occurred while trying to update the project's multi-factor authentication settings.`, 'Multi-factor authentication settings are being updated...',
), successMessage:
}, 'Multi-factor authentication settings have been updated successfully.',
getToastStyleProps(), errorMessage:
); "An error occurred while trying to update the project's multi-factor authentication settings.",
},
form.reset(values); );
} catch {
// Note: The toast will handle the error.
}
}; };
return ( return (
@@ -107,7 +102,7 @@ export default function MFASettings() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
docsLink="https://docs.nhost.io/authentication#multi-factor-authentication" docsLink="https://docs.nhost.io/guides/auth/overview#multi-factor-authentication"
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(

View File

@@ -8,11 +8,9 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getServerError } from '@/utils/getServerError';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import * as Yup from 'yup'; import * as Yup from 'yup';
const validationSchema = Yup.object({ const validationSchema = Yup.object({
@@ -73,23 +71,18 @@ export default function MagicLinkSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(values);
loading: `Magic Link settings are being updated...`, },
success: `Magic Link settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'Magic Link settings are being updated...',
`An error occurred while trying to update the project's Magic Link settings.`, successMessage: 'Magic Link settings have been updated successfully.',
), errorMessage:
}, "An error occurred while trying to update the project's Magic Link settings.",
getToastStyleProps(), },
); );
form.reset(values);
} catch {
// Note: The toast will handle the error.
}
}; };
return ( return (
@@ -104,7 +97,7 @@ export default function MagicLinkSettings() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
docsLink="https://docs.nhost.io/authentication/sign-in-with-magic-link" docsLink="https://docs.nhost.io/guides/auth/sign-in-magic-link"
docsTitle="how to sign in users with Magic Link" docsTitle="how to sign in users with Magic Link"
switchId="enabled" switchId="enabled"
showSwitch showSwitch

View File

@@ -12,12 +12,10 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getServerError } from '@/utils/getServerError';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import Image from 'next/image'; import Image from 'next/image';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
import * as Yup from 'yup'; import * as Yup from 'yup';
@@ -112,23 +110,17 @@ export default function SMSSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(values);
loading: `SMS settings are being updated...`, },
success: `SMS settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'SMS settings are being updated...',
`An error occurred while trying to update SMS settings.`, successMessage: 'SMS settings have been updated successfully.',
), errorMessage: 'An error occurred while trying to update SMS settings.',
}, },
getToastStyleProps(), );
);
form.reset(values);
} catch {
// Note: The toast will handle the error.
}
}; };
return ( return (
@@ -145,10 +137,10 @@ export default function SMSSettings() {
}} }}
switchId="enabled" switchId="enabled"
showSwitch showSwitch
docsLink="https://docs.nhost.io/authentication/sign-in-with-phone-number-sms" docsLink="https://docs.nhost.io/guides/auth/sign-in-phone-number"
docsTitle="how to sign in users with a phone number (SMS)" docsTitle="how to sign in users with a phone number (SMS)"
className={twMerge( className={twMerge(
'grid grid-flow-col grid-cols-2 grid-rows-4 gap-y-4 gap-x-3 px-4 py-2', 'grid grid-flow-col grid-cols-2 grid-rows-4 gap-x-3 gap-y-4 px-4 py-2',
!authSmsPasswordlessEnabled && 'hidden', !authSmsPasswordlessEnabled && 'hidden',
)} )}
> >

View File

@@ -9,11 +9,9 @@ import {
useGetAuthenticationSettingsQuery, useGetAuthenticationSettingsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getServerError } from '@/utils/getServerError';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import * as Yup from 'yup'; import * as Yup from 'yup';
const validationSchema = Yup.object({ const validationSchema = Yup.object({
@@ -84,23 +82,18 @@ export default function SessionSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(formValues);
loading: `Session settings are being updated...`, },
success: `Session settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'Session settings are being updated...',
`An error occurred while trying to update the project's session settings.`, successMessage: 'Session settings have been updated successfully.',
), errorMessage:
}, "An error occurred while trying to update the project's session settings.",
getToastStyleProps(), },
); );
form.reset(formValues);
} catch {
// Note: The toast will handle the error.
}
}; };
return ( return (

View File

@@ -18,12 +18,10 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings';
import { copy } from '@/utils/copy'; import { copy } from '@/utils/copy';
import { getServerError } from '@/utils/getServerError'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
export default function SpotifyProviderSettings() { export default function SpotifyProviderSettings() {
@@ -87,23 +85,18 @@ export default function SpotifyProviderSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(formValues);
loading: `Spotify settings are being updated...`, },
success: `Spotify settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'Spotify settings are being updated...',
`An error occurred while trying to update the project's Spotify settings.`, successMessage: 'Spotify settings have been updated successfully.',
), errorMessage:
}, "An error occurred while trying to update the project's Spotify settings.",
getToastStyleProps(), },
); );
form.reset(formValues);
} catch {
// Note: The toast will handle the error.
}
} }
return ( return (
@@ -118,13 +111,13 @@ export default function SpotifyProviderSettings() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
docsLink="https://docs.nhost.io/platform/authentication/sign-in-with-spotify" docsLink="https://docs.nhost.io/guides/auth/social/sign-in-spotify"
docsTitle="how to sign in users with Spotify" docsTitle="how to sign in users with Spotify"
icon="/assets/brands/spotify.svg" icon="/assets/brands/spotify.svg"
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(
'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-y-4 gap-x-3 px-4 py-2', 'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-x-3 gap-y-4 px-4 py-2',
!authEnabled && 'hidden', !authEnabled && 'hidden',
)} )}
> >

View File

@@ -18,12 +18,10 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings';
import { copy } from '@/utils/copy'; import { copy } from '@/utils/copy';
import { getServerError } from '@/utils/getServerError'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
export default function StravaProviderSettings() { export default function StravaProviderSettings() {
@@ -87,23 +85,18 @@ export default function StravaProviderSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(values);
loading: `Strava settings are being updated...`, },
success: `Strava settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'Strava settings are being updated...',
`An error occurred while trying to update the project's Strava settings.`, successMessage: 'Strava settings have been updated successfully.',
), errorMessage:
}, "An error occurred while trying to update the project's Strava settings.",
getToastStyleProps(), },
); );
form.reset(values);
} catch {
// Note: The toast will handle the error.
}
} }
return ( return (
@@ -122,7 +115,7 @@ export default function StravaProviderSettings() {
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(
'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-y-4 gap-x-3 px-4 py-2', 'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-x-3 gap-y-4 px-4 py-2',
!authEnabled && 'hidden', !authEnabled && 'hidden',
)} )}
> >

View File

@@ -18,13 +18,11 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings';
import { copy } from '@/utils/copy'; import { copy } from '@/utils/copy';
import { getServerError } from '@/utils/getServerError'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { useTheme } from '@mui/material'; import { useTheme } from '@mui/material';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
export default function TwitchProviderSettings() { export default function TwitchProviderSettings() {
@@ -89,23 +87,18 @@ export default function TwitchProviderSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(formValues);
loading: `Twitch settings are being updated...`, },
success: `Twitch settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'Twitch settings are being updated...',
`An error occurred while trying to update the project's Twitch settings.`, successMessage: 'Twitch settings have been updated successfully.',
), errorMessage:
}, "An error occurred while trying to update the project's Twitch settings.",
getToastStyleProps(), },
); );
form.reset(formValues);
} catch {
// Note: The toast will handle the error.
}
} }
return ( return (
@@ -120,7 +113,7 @@ export default function TwitchProviderSettings() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
docsLink="https://docs.nhost.io/platform/authentication/sign-in-with-twitch" docsLink="https://docs.nhost.io/guides/auth/social/sign-in-twitch"
docsTitle="how to sign in users with Twitch" docsTitle="how to sign in users with Twitch"
icon={ icon={
theme.palette.mode === 'dark' theme.palette.mode === 'dark'
@@ -130,7 +123,7 @@ export default function TwitchProviderSettings() {
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(
'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-y-4 gap-x-3 px-4 py-2', 'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-x-3 gap-y-4 px-4 py-2',
!authEnabled && 'hidden', !authEnabled && 'hidden',
)} )}
> >

View File

@@ -13,12 +13,10 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings';
import { copy } from '@/utils/copy'; import { copy } from '@/utils/copy';
import { getServerError } from '@/utils/getServerError'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
import * as Yup from 'yup'; import * as Yup from 'yup';
@@ -98,23 +96,17 @@ export default function TwitterProviderSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(formValues);
loading: `Twitter settings are being updated...`, },
success: `Twitter settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'Twitter settings are being updated...',
`An error occurred while trying to update the project's Twitter settings.`, successMessage: 'Twitter settings have been updated successfully.',
), errorMessage: `An error occurred while trying to update the project's Twitter settings.`,
}, },
getToastStyleProps(), );
);
form.reset(formValues);
} catch {
// Note: The toast will handle the error.
}
} }
return ( return (
@@ -134,7 +126,7 @@ export default function TwitterProviderSettings() {
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(
'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-y-4 gap-x-3 px-4 py-2', 'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-x-3 gap-y-4 px-4 py-2',
!authEnabled && 'hidden', !authEnabled && 'hidden',
)} )}
> >

View File

@@ -8,11 +8,9 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getServerError } from '@/utils/getServerError';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import * as Yup from 'yup'; import * as Yup from 'yup';
const validationSchema = Yup.object({ const validationSchema = Yup.object({
@@ -66,33 +64,29 @@ export default function WebAuthnSettings() {
config: { config: {
auth: { auth: {
method: { method: {
webauthn: {...values, webauthn: {
relyingParty: { ...values,
name: currentProject.name, relyingParty: {
}}, name: currentProject.name,
},
},
}, },
}, },
}, },
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(values);
loading: `WebAuthn settings are being updated...`, },
success: `WebAuthn settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'WebAuthn settings are being updated...',
`An error occurred while trying to update the project's WebAuthn settings.`, successMessage: 'WebAuthn settings have been updated successfully.',
), errorMessage: `An error occurred while trying to update the project's WebAuthn settings.`,
}, },
getToastStyleProps(), );
);
form.reset(values);
} catch {
// Note: The toast will handle the error.
}
}; };
return ( return (
@@ -107,7 +101,7 @@ export default function WebAuthnSettings() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
docsLink="https://docs.nhost.io/authentication/sign-in-with-security-keys" docsLink="https://docs.nhost.io/guides/auth/sign-in-webauthn"
docsTitle="how to sign in users with security keys" docsTitle="how to sign in users with security keys"
switchId="enabled" switchId="enabled"
showSwitch showSwitch

View File

@@ -18,12 +18,10 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings';
import { copy } from '@/utils/copy'; import { copy } from '@/utils/copy';
import { getServerError } from '@/utils/getServerError'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
export default function WindowsLiveProviderSettings() { export default function WindowsLiveProviderSettings() {
@@ -87,23 +85,17 @@ export default function WindowsLiveProviderSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(formValues);
loading: `Windows Live settings are being updated...`, },
success: `Windows Live settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'Windows Live settings are being updated...',
`An error occurred while trying to update the project's Windows Live settings.`, successMessage: 'Windows Live settings have been updated successfully.',
), errorMessage: `An error occurred while trying to update the project's Windows Live settings.`,
}, },
getToastStyleProps(), );
);
form.reset(formValues);
} catch {
// Note: The toast will handle the error.
}
} }
return ( return (
@@ -123,7 +115,7 @@ export default function WindowsLiveProviderSettings() {
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(
'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-y-4 gap-x-3 px-4 py-2', 'grid-flow-rows grid grid-cols-2 grid-rows-2 gap-x-3 gap-y-4 px-4 py-2',
!authEnabled && 'hidden', !authEnabled && 'hidden',
)} )}
> >

View File

@@ -14,12 +14,10 @@ import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
useUpdateConfigMutation, useUpdateConfigMutation,
} from '@/generated/graphql'; } from '@/generated/graphql';
import { getToastStyleProps } from '@/utils/constants/settings';
import { copy } from '@/utils/copy'; import { copy } from '@/utils/copy';
import { getServerError } from '@/utils/getServerError'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
import * as Yup from 'yup'; import * as Yup from 'yup';
@@ -113,23 +111,18 @@ export default function WorkOsProviderSettings() {
}, },
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateConfigPromise, await updateConfigPromise;
{ form.reset(formValues);
loading: `WorkOS settings are being updated...`, },
success: `WorkOS settings have been updated successfully.`, {
error: getServerError( loadingMessage: 'WorkOS settings are being updated...',
`An error occurred while trying to update the project's WorkOS settings.`, successMessage: 'WorkOS settings have been updated successfully.',
), errorMessage:
}, "An error occurred while trying to update the project's WorkOS settings.",
getToastStyleProps(), },
); );
form.reset(formValues);
} catch {
// Note: The toast will handle the error.
}
} }
return ( return (
@@ -144,13 +137,13 @@ export default function WorkOsProviderSettings() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
docsLink="https://docs.nhost.io/authentication/sign-in-with-workos" docsLink="https://docs.nhost.io/guides/auth/social/sign-in-workos"
docsTitle="how to sign in users with WorkOS" docsTitle="how to sign in users with WorkOS"
icon="/assets/brands/workos.svg" icon="/assets/brands/workos.svg"
switchId="enabled" switchId="enabled"
showSwitch showSwitch
className={twMerge( className={twMerge(
'grid grid-flow-row grid-cols-2 gap-y-4 gap-x-3 px-4 py-2', 'grid grid-flow-row grid-cols-2 gap-x-3 gap-y-4 px-4 py-2',
!authEnabled && 'hidden', !authEnabled && 'hidden',
)} )}
> >

View File

@@ -6,12 +6,10 @@ import { Input } from '@/components/ui/v2/Input';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject'; import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl'; import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
import type { DialogFormProps } from '@/types/common'; import type { DialogFormProps } from '@/types/common';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getServerError } from '@/utils/getServerError';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import * as Yup from 'yup'; import * as Yup from 'yup';
export interface CreateUserFormProps extends DialogFormProps { export interface CreateUserFormProps extends DialogFormProps {
@@ -77,9 +75,9 @@ export default function CreateUserForm({
async function handleCreateUser({ email, password }: CreateUserFormValues) { async function handleCreateUser({ email, password }: CreateUserFormValues) {
setCreateUserFormError(null); setCreateUserFormError(null);
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
fetch(signUpUrl, { await fetch(signUpUrl, {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password }), body: JSON.stringify({ email, password }),
@@ -95,21 +93,16 @@ export default function CreateUserForm({
} }
throw new Error(data?.message || 'Something went wrong.'); throw new Error(data?.message || 'Something went wrong.');
}), });
{
loading: 'Creating user...',
success: 'User has been created successfully.',
error: getServerError(
'An error occurred while trying to create the user.',
),
},
getToastStyleProps(),
);
onSubmit?.(); onSubmit?.();
} catch (error) { },
// Note: The error is already handled by the toast promise. {
} loadingMessage: 'Creating user...',
successMessage: 'User has been created successfully.',
errorMessage: 'An error occurred while trying to create the user.',
},
);
} }
return ( return (

View File

@@ -19,9 +19,8 @@ import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/
import { getUserRoles } from '@/features/projects/roles/settings/utils/getUserRoles'; import { getUserRoles } from '@/features/projects/roles/settings/utils/getUserRoles';
import { useRemoteApplicationGQLClient } from '@/hooks/useRemoteApplicationGQLClient'; import { useRemoteApplicationGQLClient } from '@/hooks/useRemoteApplicationGQLClient';
import type { DialogFormProps } from '@/types/common'; import type { DialogFormProps } from '@/types/common';
import { getToastStyleProps } from '@/utils/constants/settings';
import { copy } from '@/utils/copy'; import { copy } from '@/utils/copy';
import { getServerError } from '@/utils/getServerError'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { import {
RemoteAppGetUsersDocument, RemoteAppGetUsersDocument,
useGetProjectLocalesQuery, useGetProjectLocalesQuery,
@@ -36,7 +35,6 @@ import Image from 'next/image';
import type { RemoteAppUser } from 'pages/[workspaceSlug]/[appSlug]/users'; import type { RemoteAppUser } from 'pages/[workspaceSlug]/[appSlug]/users';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import * as Yup from 'yup'; import * as Yup from 'yup';
export interface EditUserFormProps extends DialogFormProps { export interface EditUserFormProps extends DialogFormProps {
@@ -173,21 +171,15 @@ export default function EditUserForm({
}, },
}); });
await toast.promise( await execPromiseWithErrorToast(() => banUser, {
banUser, loadingMessage: shouldBan ? 'Banning user...' : 'Unbanning user...',
{ successMessage: shouldBan
loading: shouldBan ? 'Banning user...' : 'Unbanning user...', ? 'User has been banned successfully.'
success: shouldBan : 'User has been unbanned successfully.',
? 'User has been banned successfully.' errorMessage: shouldBan
: 'User has been unbanned successfully.', ? 'An error occurred while trying to ban the user.'
error: getServerError( : 'An error occurred while trying to unban the user.',
shouldBan });
? 'An error occurred while trying to ban the user.'
: 'An error occurred while trying to unban the user.',
),
},
getToastStyleProps(),
);
} }
return ( return (
@@ -424,6 +416,7 @@ export default function EditUserForm({
} }
width={25} width={25}
height={25} height={25}
alt="Oauth provider logo"
/> />
<Text className="font-medium capitalize"> <Text className="font-medium capitalize">
{getReadableProviderName(provider.providerId)} {getReadableProviderName(provider.providerId)}

View File

@@ -6,8 +6,7 @@ import { Input } from '@/components/ui/v2/Input';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject'; import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
import { useRemoteApplicationGQLClient } from '@/hooks/useRemoteApplicationGQLClient'; import { useRemoteApplicationGQLClient } from '@/hooks/useRemoteApplicationGQLClient';
import type { DialogFormProps } from '@/types/common'; import type { DialogFormProps } from '@/types/common';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getServerError } from '@/utils/getServerError';
import type { RemoteAppGetUsersQuery } from '@/utils/__generated__/graphql'; import type { RemoteAppGetUsersQuery } from '@/utils/__generated__/graphql';
import { import {
useGetSignInMethodsQuery, useGetSignInMethodsQuery,
@@ -17,7 +16,6 @@ import { yupResolver } from '@hookform/resolvers/yup';
import bcrypt from 'bcryptjs'; import bcrypt from 'bcryptjs';
import { useState } from 'react'; import { useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import * as Yup from 'yup'; import * as Yup from 'yup';
export interface EditUserPasswordFormProps extends DialogFormProps { export interface EditUserPasswordFormProps extends DialogFormProps {
@@ -90,23 +88,23 @@ export default function EditUserPasswordForm({
client: remoteProjectGQLClient, client: remoteProjectGQLClient,
}); });
try { await execPromiseWithErrorToast(
await toast.promise( async () => {
updateUserPasswordPromise, await updateUserPasswordPromise;
{ },
loading: 'Updating user password...', {
success: 'User password updated successfully.', loadingMessage: 'Updating user password...',
error: getServerError('Failed to update user password.'), successMessage: 'User password updated successfully.',
errorMessage: 'Failed to update user password.',
onError: (error) => {
setEditUserPasswordFormError(
new Error(error.message || 'Something went wrong.'),
);
}, },
getToastStyleProps(), },
); );
} catch (error) {
setEditUserPasswordFormError( closeDialog();
new Error(error.message || 'Something went wrong.'),
);
} finally {
closeDialog();
}
}; };
const { const {

View File

@@ -17,8 +17,7 @@ import { getReadableProviderName } from '@/features/authentication/users/utils/g
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject'; import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
import { getUserRoles } from '@/features/projects/roles/settings/utils/getUserRoles'; import { getUserRoles } from '@/features/projects/roles/settings/utils/getUserRoles';
import { useRemoteApplicationGQLClient } from '@/hooks/useRemoteApplicationGQLClient'; import { useRemoteApplicationGQLClient } from '@/hooks/useRemoteApplicationGQLClient';
import { getToastStyleProps } from '@/utils/constants/settings'; import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { getServerError } from '@/utils/getServerError';
import { import {
useDeleteRemoteAppUserRolesMutation, useDeleteRemoteAppUserRolesMutation,
useGetRolesPermissionsQuery, useGetRolesPermissionsQuery,
@@ -33,7 +32,6 @@ import dynamic from 'next/dynamic';
import Image from 'next/image'; import Image from 'next/image';
import type { RemoteAppUser } from 'pages/[workspaceSlug]/[appSlug]/users'; import type { RemoteAppUser } from 'pages/[workspaceSlug]/[appSlug]/users';
import { Fragment, useMemo } from 'react'; import { Fragment, useMemo } from 'react';
import toast from 'react-hot-toast';
const EditUserForm = dynamic( const EditUserForm = dynamic(
() => () =>
@@ -153,20 +151,18 @@ export default function UsersBody({ users, onSubmit }: UsersBodyProps) {
}); });
} }
await toast.promise( await execPromiseWithErrorToast(
updateUserMutationPromise, async () => {
{ await updateUserMutationPromise;
loading: `Updating user's settings...`, },
success: 'User settings have been updated successfully.', {
error: getServerError( loadingMessage: `Updating user's settings...`,
`An error occurred while trying to update this user's settings.`, successMessage: 'User settings have been updated successfully.',
), errorMessage: `An error occurred while trying to update this user's settings.`,
}, },
getToastStyleProps(),
); );
await onSubmit?.(); await onSubmit?.();
closeDrawer(); closeDrawer();
} }
@@ -181,20 +177,20 @@ export default function UsersBody({ users, onSubmit }: UsersBodyProps) {
), ),
props: { props: {
onPrimaryAction: async () => { onPrimaryAction: async () => {
await toast.promise( await execPromiseWithErrorToast(
deleteUser({ async () => {
variables: { await deleteUser({
id: user.id, variables: {
}, id: user.id,
}), },
{ });
loading: 'Deleting user...', },
success: 'User deleted successfully.', {
error: getServerError( loadingMessage: 'Deleting user...',
'An error occurred while trying to delete this user.', successMessage: 'User deleted successfully.',
), errorMessage:
'An error occurred while trying to delete this user.',
}, },
getToastStyleProps(),
); );
await onSubmit(); await onSubmit();
@@ -227,7 +223,7 @@ export default function UsersBody({ users, onSubmit }: UsersBodyProps) {
if (!users) { if (!users) {
return ( return (
<div className="h-screen w-screen overflow-hidden"> <div className="h-screen w-screen overflow-hidden">
<div className="absolute top-0 left-0 z-50 block h-full w-full"> <div className="absolute left-0 top-0 z-50 block h-full w-full">
<span className="top50percent relative top-1/2 mx-auto my-0 block"> <span className="top50percent relative top-1/2 mx-auto my-0 block">
<ActivityIndicator <ActivityIndicator
label="Loading users..." label="Loading users..."
@@ -362,6 +358,7 @@ export default function UsersBody({ users, onSubmit }: UsersBodyProps) {
} }
width={16} width={16}
height={16} height={16}
alt="Oauth provider logo"
/> />
} }
/> />

View File

@@ -102,10 +102,10 @@ export default function BaseColumnForm({
return ( return (
<Form <Form
onSubmit={handleExternalSubmit} onSubmit={handleExternalSubmit}
className="flex flex-auto flex-col content-between overflow-hidden border-t-1" className="flex flex-col content-between flex-auto overflow-hidden border-t-1"
> >
<div className="flex-auto overflow-y-auto"> <div className="flex-auto overflow-y-auto">
<section className="grid grid-cols-8 py-3 px-6"> <section className="grid grid-cols-8 px-6 py-3">
<Input <Input
{...register('name', { {...register('name', {
onChange: (event) => { onChange: (event) => {
@@ -184,7 +184,7 @@ export default function BaseColumnForm({
</Text> </Text>
</span> </span>
} }
className="col-span-8 m-0 w-full py-3 sm:col-span-6 sm:col-start-3 sm:ml-1" className="w-full col-span-8 py-3 m-0 sm:col-span-6 sm:col-start-3 sm:ml-1"
onChange={(_event, checked) => { onChange={(_event, checked) => {
if (checked) { if (checked) {
setDefaultValueInputText(''); setDefaultValueInputText('');
@@ -197,7 +197,7 @@ export default function BaseColumnForm({
<Box <Box
component="section" component="section"
className="grid grid-cols-8 border-t-1 py-3 px-6" className="grid grid-cols-8 px-6 py-3 border-t-1"
> >
<ControlledAutocomplete <ControlledAutocomplete
id="defaultValue" id="defaultValue"
@@ -249,7 +249,7 @@ export default function BaseColumnForm({
/> />
<ControlledCheckbox <ControlledCheckbox
className="col-span-8 m-0 w-full py-3 sm:col-span-6 sm:col-start-3 sm:ml-1" className="w-full col-span-8 py-3 m-0 sm:col-span-6 sm:col-start-3 sm:ml-1"
name="isNullable" name="isNullable"
label={ label={
<span className="inline-grid grid-flow-row"> <span className="inline-grid grid-flow-row">
@@ -269,7 +269,7 @@ export default function BaseColumnForm({
/> />
<ControlledCheckbox <ControlledCheckbox
className="col-span-8 m-0 w-full py-3 sm:col-span-6 sm:col-start-3 sm:ml-1" className="w-full col-span-8 py-3 m-0 sm:col-span-6 sm:col-start-3 sm:ml-1"
name="isUnique" name="isUnique"
label={ label={
<span className="inline-grid grid-flow-row"> <span className="inline-grid grid-flow-row">
@@ -306,7 +306,7 @@ export default function BaseColumnForm({
</Box> </Box>
</div> </div>
<Box className="grid flex-shrink-0 grid-flow-col justify-between gap-3 border-t-1 p-2"> <Box className="grid justify-between flex-shrink-0 grid-flow-col gap-3 p-2 border-t-1">
<Button <Button
variant="borderless" variant="borderless"
color="secondary" color="secondary"

View File

@@ -107,9 +107,9 @@ export default function BaseForeignKeyForm({
selectedColumn?.isPrimary || selectedColumn?.isUnique || false, selectedColumn?.isPrimary || selectedColumn?.isUnique || false,
}); });
}} }}
className="flex flex-auto flex-col content-between overflow-hidden pb-4" className="flex flex-col content-between flex-auto pb-4 overflow-hidden"
> >
<Box className="grid flex-auto grid-flow-row gap-4 overflow-y-auto border-t-1 py-4"> <Box className="grid flex-auto grid-flow-row gap-4 py-4 overflow-y-auto border-t-1">
<Box component="section" className="grid grid-flow-row gap-4 px-6"> <Box component="section" className="grid grid-flow-row gap-4 px-6">
<Text variant="h3">From</Text> <Text variant="h3">From</Text>
@@ -185,7 +185,7 @@ export default function BaseForeignKeyForm({
</Box> </Box>
</Box> </Box>
<Box className="grid flex-shrink-0 grid-flow-row gap-2 border-t-1 px-6 pt-4"> <Box className="grid flex-shrink-0 grid-flow-row gap-2 px-6 pt-4 border-t-1">
<Button loading={isSubmitting} disabled={isSubmitting} type="submit"> <Button loading={isSubmitting} disabled={isSubmitting} type="submit">
{submitButtonText} {submitButtonText}
</Button> </Button>

View File

@@ -14,8 +14,8 @@ import { Text } from '@/components/ui/v2/Text';
import { useMetadataQuery } from '@/features/database/dataGrid/hooks/useMetadataQuery'; import { useMetadataQuery } from '@/features/database/dataGrid/hooks/useMetadataQuery';
import { useTableQuery } from '@/features/database/dataGrid/hooks/useTableQuery'; import { useTableQuery } from '@/features/database/dataGrid/hooks/useTableQuery';
import { getTruncatedText } from '@/utils/getTruncatedText'; import { getTruncatedText } from '@/utils/getTruncatedText';
import type { AutocompleteGroupedOption } from '@mui/base/AutocompleteUnstyled'; import type { AutocompleteGroupedOption } from '@mui/base/useAutocomplete';
import { useAutocomplete } from '@mui/base/AutocompleteUnstyled'; import { useAutocomplete } from '@mui/base/useAutocomplete';
import type { AutocompleteRenderGroupParams } from '@mui/material/Autocomplete'; import type { AutocompleteRenderGroupParams } from '@mui/material/Autocomplete';
import { autocompleteClasses } from '@mui/material/Autocomplete'; import { autocompleteClasses } from '@mui/material/Autocomplete';
import type { import type {
@@ -366,11 +366,11 @@ function ColumnAutocomplete(
); );
}} }}
> >
<ArrowLeftIcon className="h-4 w-4" /> <ArrowLeftIcon className="w-4 h-4" />
</IconButton> </IconButton>
)} )}
<Text className="direction-rtl truncate text-left"> <Text className="text-left truncate direction-rtl">
<Text component="span" color="disabled"> <Text component="span" color="disabled">
{defaultTable} {defaultTable}
</Text> </Text>

View File

@@ -14,6 +14,7 @@ import { triggerToast } from '@/utils/toast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import type * as Yup from 'yup';
export interface CreateColumnFormProps export interface CreateColumnFormProps
extends Pick<BaseColumnFormProps, 'onCancel' | 'location'> { extends Pick<BaseColumnFormProps, 'onCancel' | 'location'> {
@@ -50,7 +51,9 @@ export default function CreateColumnForm({
resetForeignKeyError(); resetForeignKeyError();
} }
const form = useForm<BaseColumnFormValues>({ const form = useForm<
BaseColumnFormValues | Yup.InferType<typeof baseColumnValidationSchema>
>({
defaultValues: { defaultValues: {
name: '', name: '',
type: null, type: null,

View File

@@ -11,6 +11,7 @@ import {
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { useState } from 'react'; import { useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import type * as Yup from 'yup';
export interface CreateForeignKeyFormProps export interface CreateForeignKeyFormProps
extends Pick< extends Pick<
@@ -34,7 +35,10 @@ export default function CreateForeignKeyForm({
}: CreateForeignKeyFormProps) { }: CreateForeignKeyFormProps) {
const [error, setError] = useState<Error>(null); const [error, setError] = useState<Error>(null);
const form = useForm<BaseForeignKeyFormValues>({ const form = useForm<
| BaseForeignKeyFormValues
| Yup.InferType<typeof baseForeignKeyValidationSchema>
>({
defaultValues: { defaultValues: {
id: null, id: null,
name: '', name: '',

View File

@@ -16,6 +16,7 @@ import { triggerToast } from '@/utils/toast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import type * as Yup from 'yup';
export interface CreateTableFormProps export interface CreateTableFormProps
extends Pick<BaseTableFormProps, 'onCancel' | 'location'> { extends Pick<BaseTableFormProps, 'onCancel' | 'location'> {
@@ -53,7 +54,9 @@ export default function CreateTableForm({
const error = createTableError || trackTableError || foreignKeyError; const error = createTableError || trackTableError || foreignKeyError;
const form = useForm<BaseTableFormValues>({ const form = useForm<
BaseTableFormValues | Yup.InferType<typeof baseTableValidationSchema>
>({
defaultValues: { defaultValues: {
columns: [ columns: [
{ {

View File

@@ -275,7 +275,7 @@ export default function DataBrowserGrid({
() => () =>
columns columns
.map((column) => ({ .map((column) => ({
...createDataGridColumn(column, isSchemaEditable), ...createDataGridColumn(column, true),
onCellEdit: async (variables: UpdateRecordVariables) => { onCellEdit: async (variables: UpdateRecordVariables) => {
const result = await updateRow(variables); const result = await updateRow(variables);
await queryClient.invalidateQueries([currentTablePath]); await queryClient.invalidateQueries([currentTablePath]);
@@ -288,7 +288,6 @@ export default function DataBrowserGrid({
[ [
columns, columns,
currentTablePath, currentTablePath,
isSchemaEditable,
optimisticlyRemovedColumnId, optimisticlyRemovedColumnId,
queryClient, queryClient,
removableColumnId, removableColumnId,
@@ -422,7 +421,7 @@ export default function DataBrowserGrid({
loading={status === 'loading'} loading={status === 'loading'}
sortBy={sortBy} sortBy={sortBy}
className="pb-17 sm:pb-0" className="pb-17 sm:pb-0"
onInsertRow={isSchemaEditable ? handleInsertRowClick : undefined} onInsertRow={handleInsertRowClick}
onInsertColumn={isSchemaEditable ? handleInsertColumnClick : undefined} onInsertColumn={isSchemaEditable ? handleInsertColumnClick : undefined}
onEditColumn={isSchemaEditable ? handleEditColumnClick : undefined} onEditColumn={isSchemaEditable ? handleEditColumnClick : undefined}
onRemoveColumn={isSchemaEditable ? handleColumnRemoveClick : undefined} onRemoveColumn={isSchemaEditable ? handleColumnRemoveClick : undefined}
@@ -445,7 +444,7 @@ export default function DataBrowserGrid({
onInsertColumnClick={ onInsertColumnClick={
isSchemaEditable ? handleInsertColumnClick : undefined isSchemaEditable ? handleInsertColumnClick : undefined
} }
onInsertRowClick={isSchemaEditable ? handleInsertRowClick : undefined} onInsertRowClick={handleInsertRowClick}
paginationProps={{ paginationProps={{
currentPage: Math.max(currentPage, 1), currentPage: Math.max(currentPage, 1),
totalPages: Math.max(numberOfPages, 1), totalPages: Math.max(numberOfPages, 1),

View File

@@ -12,11 +12,9 @@ import { PlusIcon } from '@/components/ui/v2/icons/PlusIcon';
import { RowIcon } from '@/components/ui/v2/icons/RowIcon'; import { RowIcon } from '@/components/ui/v2/icons/RowIcon';
import { useDeleteRecordMutation } from '@/features/database/dataGrid/hooks/useDeleteRecordMutation'; import { useDeleteRecordMutation } from '@/features/database/dataGrid/hooks/useDeleteRecordMutation';
import type { DataBrowserGridColumn } from '@/features/database/dataGrid/types/dataBrowser'; import type { DataBrowserGridColumn } from '@/features/database/dataGrid/types/dataBrowser';
import { isSchemaLocked } from '@/features/database/dataGrid/utils/schemaHelpers/isSchemaLocked';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject'; import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
import { triggerToast } from '@/utils/toast'; import { triggerToast } from '@/utils/toast';
import { useQueryClient } from '@tanstack/react-query'; import { useQueryClient } from '@tanstack/react-query';
import { useRouter } from 'next/router';
import { useState } from 'react'; import { useState } from 'react';
import type { Row } from 'react-table'; import type { Row } from 'react-table';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
@@ -58,11 +56,6 @@ export default function DataBrowserGridControls({
const { className: paginationClassName, ...restPaginationProps } = const { className: paginationClassName, ...restPaginationProps } =
paginationProps || ({} as DataGridPaginationProps); paginationProps || ({} as DataGridPaginationProps);
const {
query: { schemaSlug },
} = useRouter();
const isSchemaEditable = !isSchemaLocked(schemaSlug as string);
const { const {
selectedFlatRows: selectedRows, selectedFlatRows: selectedRows,
columns, columns,
@@ -126,7 +119,7 @@ export default function DataBrowserGridControls({
numberOfSelectedRows > 0 ? 'justify-between' : 'justify-end', numberOfSelectedRows > 0 ? 'justify-between' : 'justify-end',
)} )}
> >
{isSchemaEditable && numberOfSelectedRows > 0 && ( {numberOfSelectedRows > 0 && (
<div className="grid grid-flow-col place-content-start items-center gap-2"> <div className="grid grid-flow-col place-content-start items-center gap-2">
<Chip <Chip
size="small" size="small"

View File

@@ -241,7 +241,7 @@ function DataBrowserSidebarContent({
) { ) {
openDrawer({ openDrawer({
title: ( title: (
<span className="inline-grid grid-flow-col items-center gap-2"> <span className="inline-grid items-center grid-flow-col gap-2">
Permissions Permissions
<InlineCode className="!text-sm+ font-normal">{table}</InlineCode> <InlineCode className="!text-sm+ font-normal">{table}</InlineCode>
<Chip label="Preview" size="small" color="info" component="span" /> <Chip label="Preview" size="small" color="info" component="span" />
@@ -263,12 +263,12 @@ function DataBrowserSidebarContent({
} }
return ( return (
<Box className="flex h-full flex-col justify-between"> <Box className="flex flex-col justify-between h-full">
<Box className="flex flex-col px-2"> <Box className="flex flex-col px-2">
{schemas && schemas.length > 0 && ( {schemas && schemas.length > 0 && (
<Select <Select
renderValue={(option) => ( renderValue={(option) => (
<span className="grid grid-flow-col items-center gap-1"> <span className="grid items-center grid-flow-col gap-1">
{option?.label} {option?.label}
</span> </span>
)} )}
@@ -281,7 +281,7 @@ function DataBrowserSidebarContent({
> >
{schemas.map((schema) => ( {schemas.map((schema) => (
<Option <Option
className="grid grid-flow-col items-center gap-1" className="grid items-center grid-flow-col gap-1"
value={schema.schema_name} value={schema.schema_name}
key={schema.schema_name} key={schema.schema_name}
> >
@@ -295,7 +295,7 @@ function DataBrowserSidebarContent({
</Text> </Text>
{(isSchemaLocked(schema.schema_name) || isGitHubConnected) && ( {(isSchemaLocked(schema.schema_name) || isGitHubConnected) && (
<LockIcon <LockIcon
className="h-3 w-3" className="w-3 h-3"
sx={{ color: 'text.secondary' }} sx={{ color: 'text.secondary' }}
/> />
)} )}
@@ -317,7 +317,7 @@ function DataBrowserSidebarContent({
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
underline="hover" underline="hover"
className="grid grid-flow-col items-center justify-start gap-1" className="grid items-center justify-start grid-flow-col gap-1"
> >
Learn More <ArrowRightIcon /> Learn More <ArrowRightIcon />
</Link> </Link>
@@ -327,7 +327,7 @@ function DataBrowserSidebarContent({
<Button <Button
variant="borderless" variant="borderless"
endIcon={<PlusIcon />} endIcon={<PlusIcon />}
className="mt-1 w-full justify-between px-2" className="justify-between w-full px-2 mt-1"
onClick={() => { onClick={() => {
openDrawer({ openDrawer({
title: 'Create a New Table', title: 'Create a New Table',
@@ -396,7 +396,7 @@ function DataBrowserSidebarContent({
} }
> >
<UsersIcon <UsersIcon
className="h-4 w-4" className="w-4 h-4"
sx={{ color: 'text.secondary' }} sx={{ color: 'text.secondary' }}
/> />
<span>View Permissions</span> <span>View Permissions</span>
@@ -426,7 +426,7 @@ function DataBrowserSidebarContent({
} }
> >
<PencilIcon <PencilIcon
className="h-4 w-4" className="w-4 h-4"
sx={{ color: 'text.secondary' }} sx={{ color: 'text.secondary' }}
/> />
<span>Edit Table</span> <span>Edit Table</span>
@@ -449,7 +449,7 @@ function DataBrowserSidebarContent({
} }
> >
<UsersIcon <UsersIcon
className="h-4 w-4" className="w-4 h-4"
sx={{ color: 'text.secondary' }} sx={{ color: 'text.secondary' }}
/> />
<span>Edit Permissions</span> <span>Edit Permissions</span>
@@ -473,7 +473,7 @@ function DataBrowserSidebarContent({
} }
> >
<TrashIcon <TrashIcon
className="h-4 w-4" className="w-4 h-4"
sx={{ color: 'error.main' }} sx={{ color: 'error.main' }}
/> />
<span>Delete Table</span> <span>Delete Table</span>
@@ -521,7 +521,7 @@ function DataBrowserSidebarContent({
component={NavLink} component={NavLink}
href={sqlEditorHref} href={sqlEditorHref}
> >
<div className="flex w-full flex-row items-center justify-center space-x-4"> <div className="flex flex-row items-center justify-center w-full space-x-4">
<TerminalIcon /> <TerminalIcon />
<span className="flex">SQL Editor</span> <span className="flex">SQL Editor</span>
</div> </div>

View File

@@ -17,6 +17,7 @@ import { triggerToast } from '@/utils/toast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import type * as Yup from 'yup';
export interface EditColumnFormProps export interface EditColumnFormProps
extends Pick<BaseColumnFormProps, 'onCancel' | 'location'> { extends Pick<BaseColumnFormProps, 'onCancel' | 'location'> {
@@ -78,7 +79,9 @@ export default function EditColumnForm({
comment: originalColumn.comment || null, comment: originalColumn.comment || null,
}; };
const form = useForm<BaseColumnFormValues>({ const form = useForm<
BaseColumnFormValues | Yup.InferType<typeof baseColumnValidationSchema>
>({
defaultValues: columnValues, defaultValues: columnValues,
reValidateMode: 'onSubmit', reValidateMode: 'onSubmit',
resolver: yupResolver(baseColumnValidationSchema), resolver: yupResolver(baseColumnValidationSchema),

View File

@@ -12,6 +12,7 @@ import type { ForeignKeyRelation } from '@/features/database/dataGrid/types/data
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { useState } from 'react'; import { useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import type * as Yup from 'yup';
export interface EditForeignKeyFormProps export interface EditForeignKeyFormProps
extends Pick< extends Pick<
@@ -40,7 +41,10 @@ export default function EditForeignKeyForm({
}: EditForeignKeyFormProps) { }: EditForeignKeyFormProps) {
const [error, setError] = useState<Error>(null); const [error, setError] = useState<Error>(null);
const form = useForm<BaseForeignKeyFormValues>({ const form = useForm<
| BaseForeignKeyFormValues
| Yup.InferType<typeof baseForeignKeyValidationSchema>
>({
defaultValues: { defaultValues: {
id: foreignKeyRelation.id, id: foreignKeyRelation.id,
name: foreignKeyRelation.name, name: foreignKeyRelation.name,

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