Compare commits

...

329 Commits

Author SHA1 Message Date
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
github-actions[bot]
11ce93d64b chore: update versions (#2478)
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.0

### Minor Changes

-   3ff1c2b53: fix: show upgrade option for pro projects

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-01-22 15:08:49 -01:00
Nuno Pato
3ff1c2b531 fix: dashboard: show upgrade option to pro projects (#2477) 2024-01-22 15:03:33 -01:00
github-actions[bot]
e4341c3706 chore: update versions (#2462)
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.5.0

### Minor Changes

-   c2ef17c0a: feat: add support for new Team plan

## @nhost/docs@2.1.0

### Minor Changes

-   65b6a48d5: feat: added graphite/cli documentation

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-01-22 11:31:49 -01:00
Nuno Pato
c2ef17c0a0 feat: dashboard: new Team plan (#2473) 2024-01-22 11:13:26 -01:00
David Barroso
1045ea0a46 fix(docs): set correct hostname for connecting to run service internally (#2471) 2024-01-17 12:34:01 +01:00
Nevada Le Master
5faaf36e26 chore: add maskedErrors param to CreateServerProps (#2129)
this PR addresses https://github.com/nhost/nhost/issues/1218, adding
`maskedErrors` param when creating Stripe and Google Translate GraphQL
Yoga servers

Co-authored-by: David Barroso <dbarrosop@dravetech.com>
2024-01-16 16:36:51 +01:00
David Barroso
65b6a48d51 feat(docs): added graphite/cli documentation (#2457)
Co-authored-by: Nuno Pato <nunopato@gmail.com>
2024-01-10 17:19:58 +01:00
github-actions[bot]
23e18fb734 chore: update versions (#2454)
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.0.0

### Major Changes

-   6d08b3430: New Docs powered by Mintlify

## @nhost/dashboard@1.4.0

### Minor Changes

-   7883bbcbd: feat: don't show deprecated plans
- 44be6dc0a: feat: set redirectTo during sign-in to support preview
environments

### Patch Changes

- 3c3594898: fix: allow access to graphite when configured running in
local dashboard
-   32c246b7a: chore: update docs icon

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-01-10 14:59:31 +01:00
David Barroso
44be6dc0a5 feat (dashboard): set redirectTo during sign-in with twitter to support preview environments (#2461)
Co-authored-by: Hassan Ben Jobrane <hsanbenjobrane@gmail.com>
2024-01-10 14:48:58 +01:00
Hassan Ben Jobrane
3c35948986 fix: refactor plan check when accessing ai services (#2456)
fixes https://github.com/nhost/nhost/issues/2455
2024-01-10 12:47:34 +01:00
David Barroso
7883bbcbd1 feat (dashboard): don't show deprecated plans (#2458) 2024-01-09 16:36:27 +01:00
Nuno Pato
42fddcf790 Merge pull request #2425 from nhost/docs/new-version
chore(docs): new docs
2024-01-09 14:29:15 -01:00
Nuno Pato
5d1a444451 asd 2024-01-09 14:03:36 -01:00
Nuno Pato
98d17a3066 asd 2024-01-09 12:42:14 -01:00
Nuno Pato
f70f36be08 asd 2024-01-09 11:06:13 -01:00
Nuno Pato
50fe08624f Merge branch 'main' into docs/new-version 2024-01-09 10:16:04 -01:00
Nuno Pato
6cb7dd8203 asd 2024-01-08 23:45:49 -01:00
Hassan Ben Jobrane
f859159ef5 Merge pull request #2453 from nhost/chore/update-docs-icon
chore(dashboard): update docs icon
2024-01-08 15:14:37 +01:00
Hassan Ben Jobrane
32c246b7a9 chore: add changeset 2024-01-08 11:24:35 +01:00
Hassan Ben Jobrane
f004fd067a chore: update docs icons 2024-01-08 11:24:03 +01:00
David Barroso
82340b5d54 remove migration step from ai guide (#2450) 2024-01-06 13:05:41 +01:00
Nuno Pato
8fff3e06bd asd 2024-01-05 14:54:40 -01:00
Nuno Pato
527a661222 asd 2024-01-05 14:47:46 -01:00
Hassan Ben Jobrane
172fd8dfed Merge pull request #2448 from nhost/changeset-release/main
chore: update versions
2024-01-05 15:30:30 +01:00
github-actions[bot]
a99ca90279 chore: update versions 2024-01-05 14:19:10 +00:00
Hassan Ben Jobrane
5892fd7f01 Merge pull request #2451 from nhost/fix/graphite/version-setting
fix: remove hardcoded ai settings version
2024-01-05 15:17:07 +01:00
Hassan Ben Jobrane
0344cc9a6d fix: update filterOptions logic in service version selector 2024-01-05 13:56:53 +01:00
Hassan Ben Jobrane
2697e28cf2 Merge pull request #2452 from nhost/fix/default-allowed-roles
chore: change `Allowed Roles` to `Default Allowed Roles`
2024-01-04 17:10:27 +01:00
Hassan Ben Jobrane
54231b119f fix: remove filtering in software version selector 2024-01-04 16:58:19 +01:00
Hassan Ben Jobrane
7c977e7143 chore: add changeset 2024-01-04 11:52:51 +01:00
Hassan Ben Jobrane
7c3019389e chore: change Allowed Roles to Default Allowed Roles 2024-01-04 11:50:14 +01:00
Hassan Ben Jobrane
46f028b9fd chore: add changeset 2024-01-04 11:00:59 +01:00
Hassan Ben Jobrane
683e85b89f fix: remove hardcoded ai settings version 2024-01-04 10:59:00 +01:00
Hassan Ben Jobrane
b0f27c908d Merge pull request #2444 from nhost/chore/fix-graphql-codegen
chore(dashboard): use env variables for graphql codegen
2024-01-03 21:47:28 +01:00
Hassan Ben Jobrane
5f2618e183 chore: run pnpm codegen 2024-01-03 16:59:28 +01:00
Hassan Ben Jobrane
29037147f2 Merge pull request #2447 from nhost/fix/vue-sdk/constructor-params
fix(vue-sdk): include `ServiceUrls` in `NhostVueClientConstructorParams`
2024-01-03 16:09:57 +01:00
Hassan Ben Jobrane
95b630a621 chore: fix pnpm-lock.yaml 2024-01-03 15:54:31 +01:00
Hassan Ben Jobrane
0fdfd8ad81 chore: run pnpm codegen 2024-01-03 15:54:31 +01:00
Hassan Ben Jobrane
174b4165b3 chore: add changeset 2024-01-03 15:54:31 +01:00
Hassan Ben Jobrane
04257bc09c chore: use env variables when running graphql codegen 2024-01-03 15:54:31 +01:00
Hassan Ben Jobrane
184c341f05 chore: add changeset 2024-01-03 15:53:20 +01:00
Hassan Ben Jobrane
52fdce291f fix(vue-sdk): include ServiceUrls in NhostVueClientConstructorParams interface 2024-01-03 15:51:29 +01:00
Hassan Ben Jobrane
c43ff40e1f Merge pull request #2445 from nhost/changeset-release/main
chore: update versions
2024-01-03 14:20:46 +01:00
github-actions[bot]
4ec2f8f186 chore: update versions 2024-01-03 13:19:13 +00:00
Hassan Ben Jobrane
7ece80a39e Merge pull request #2442 from nhost/chore/remove-update-providers-notice
chore: remove backendUrl deprecation notice and update providers alert
2024-01-03 14:17:09 +01:00
Hassan Ben Jobrane
1327351e1b fix: increase ci e2e timeout 2024-01-03 12:48:41 +01:00
Hassan Ben Jobrane
1fbdf630a5 chore: run pnpm codegen 2024-01-03 11:58:54 +01:00
Nestor Manrique
93f573ea98 Merge pull request #2443 from nhost/feat/docs-for-run-services-health-checks
feat(docs): for run services health checks
2024-01-03 10:51:09 +01:00
Nestor Manrique
ac78629414 Remove vscode settings json 2024-01-03 10:23:47 +01:00
Nestor Manrique
3403744c22 wip 2024-01-03 10:09:02 +01:00
Hassan Ben Jobrane
cef11677f4 Merge pull request #2437 from nhost/fix/sveltekit-quickstart
fix(quickstarts): fix auth issue and too many redirects error
2024-01-02 21:40:08 +01:00
Nuno Pato
ddadf3399c Merge pull request #2441 from nhost/feat/docs-for-postgres-wal-settings
feat(docs): add postgres wal settings to docs
2024-01-02 18:52:11 -01:00
Nestor Manrique
c768341ce8 Adjust PR comments and run sections on product page 2024-01-02 16:34:49 +01:00
Nestor Manrique
1396cbe4c0 Add more details to healthcheck docs 2024-01-02 16:05:31 +01:00
Nestor Manrique
76761b4970 Add docs for run health checks config 2024-01-02 16:00:40 +01:00
Hassan Ben Jobrane
af33c21d10 chore: add changeset 2024-01-02 15:19:46 +01:00
Hassan Ben Jobrane
1b01d56e82 chore: remove all references to providersUpdated 2024-01-02 15:17:57 +01:00
Hassan Ben Jobrane
229acb1d60 chore: remove backendUrl deprication notice and update providers alert 2024-01-02 14:56:58 +01:00
Nestor Manrique
0bc9a41e51 Add postgres wal settings to docs 2024-01-02 14:55:26 +01:00
Hassan Ben Jobrane
b4dccd4496 chore: add changeset 2024-01-01 11:23:39 +01:00
Hassan Ben Jobrane
31683fa926 fix(quickstarts): fix auth issue and too many redirects error 2024-01-01 11:17:33 +01:00
Nuno Pato
7107089a29 asd 2023-12-24 11:10:50 -01:00
Hassan Ben Jobrane
e9d5d0a53e Merge pull request #2429 from nhost/changeset-release/main
chore: update versions
2023-12-22 22:53:18 +01:00
github-actions[bot]
4e0b132d20 chore: update versions 2023-12-22 21:35:18 +00:00
Hassan Ben Jobrane
425476759f Merge pull request #2428 from nhost/fix/dashboard-graphite-version
bug: dashboard: fix graphite default version
2023-12-22 22:33:11 +01:00
Nuno Pato
04784d880b asd 2023-12-22 20:08:09 -01:00
Nuno Pato
130131c488 fix graphite default version 2023-12-22 20:05:24 -01:00
Hassan Ben Jobrane
f0da84bbec Merge pull request #2427 from nhost/changeset-release/main
chore: update versions
2023-12-22 16:48:43 +01:00
github-actions[bot]
5efa43aa2e chore: update versions 2023-12-22 15:47:34 +00:00
Hassan Ben Jobrane
2497194dcc Merge pull request #2415 from nhost/feat/project-g
feat: project g
2023-12-22 16:45:30 +01:00
David Barroso
a6c7300e14 asd 2023-12-22 16:34:25 +01:00
Nuno Pato
1a84610b74 asd 2023-12-22 14:34:00 -01:00
Hassan Ben Jobrane
5733162ed6 chore: add changeset 2023-12-22 16:23:53 +01:00
Hassan Ben Jobrane
ab106c9492 chore: run pnpm install 2023-12-22 16:22:50 +01:00
Hassan Ben Jobrane
4d2aac807c chore: refactor dev-assistant and optimize rendering of messages 2023-12-22 16:22:12 +01:00
Hassan Ben Jobrane
a659760724 chore: update content of tooltips 2023-12-22 16:22:12 +01:00
Hassan Ben Jobrane
13086bcae3 feat: show assistantId in the assistants list 2023-12-22 16:22:12 +01:00
Hassan Ben Jobrane
86459468be fix: remove dataSources from assistants form 2023-12-22 16:22:12 +01:00
Hassan Ben Jobrane
34cec77ceb feat: add copy code block button 2023-12-22 16:22:12 +01:00
Hassan Ben Jobrane
abfb42651a feat: add confirmation dialog when disabling graphite 2023-12-22 16:22:12 +01:00
Hassan Ben Jobrane
ec584181cc feat: show cost approximation for ai resources 2023-12-22 16:22:12 +01:00
Hassan Ben Jobrane
70b31358bc feat: add remark-gfm plugin to Markdown rendering 2023-12-22 16:22:12 +01:00
Hassan Ben Jobrane
521f418f8c chore: add pro upgrade banners 2023-12-22 16:22:12 +01:00
Hassan Ben Jobrane
8851416e7a fix: prevent disable ai service from firing on first load 2023-12-22 16:22:12 +01:00
Hassan Ben Jobrane
f98f5a4bca feat: add labels and tooltips to the ai settings 2023-12-22 16:22:12 +01:00
Hassan Ben Jobrane
650a605b61 feat: update settings page 2023-12-22 16:22:12 +01:00
Hassan Ben Jobrane
422e1bbeae fix: make sure to send prevMessageID 2023-12-22 16:22:12 +01:00
Hassan Ben Jobrane
367e86abd2 fix: use empty prevMessageID when starting a new thread 2023-12-22 16:22:12 +01:00
Hassan Ben Jobrane
7e172d6352 fix: use item name to view and delete items in the lists 2023-12-22 16:22:12 +01:00
Hassan Ben Jobrane
e786a6fa84 fix: adjust markdown rendering in dark mode 2023-12-22 16:22:12 +01:00
Hassan Ben Jobrane
f899f4000d feat: add Tailwind Typography plugin and GitHub Dark theme CSS file 2023-12-22 16:22:12 +01:00
Hassan Ben Jobrane
ecd27f34d6 fix: typo in sessionID parameter and reformat code in getAssistants query 2023-12-22 16:22:12 +01:00
Hassan Ben Jobrane
9f488d2739 fix: pull graphite versions from graphql api 2023-12-22 16:22:12 +01:00
Hassan Ben Jobrane
fac066c0cd fix: make sure version field is updated properly 2023-12-22 16:22:12 +01:00
Hassan Ben Jobrane
fdc56e9611 feat: add all graphite settings fields 2023-12-22 16:22:12 +01:00
Hassan Ben Jobrane
7b11f343ac fix: exclude graphite gql files from code generation 2023-12-22 16:22:12 +01:00
Hassan Ben Jobrane
04d39bef90 fix: code line wrapping + show banner when project is on the free plan 2023-12-22 16:22:12 +01:00
Hassan Ben Jobrane
83e21f879f feat: add settings related to project-g 2023-12-22 16:22:12 +01:00
Hassan Ben Jobrane
8e26cdb5ed chore: fix test to account for new nav bar item 2023-12-22 16:22:12 +01:00
Hassan Ben Jobrane
4dc1a5ded3 chore: remove console.log 2023-12-22 16:22:12 +01:00
Hassan Ben Jobrane
b3f6c732dd feat: add feature related to project-g 2023-12-22 16:22:11 +01:00
Hassan Ben Jobrane
a63342d0bd fix: add name field to the GraphQL query 2023-12-22 16:19:09 +01:00
Hassan Ben Jobrane
4913ff7a8b chore: remove unused import 2023-12-22 16:19:09 +01:00
Hassan Ben Jobrane
99cbbbcbf9 chore: remove console.log 2023-12-22 16:19:09 +01:00
Hassan Ben Jobrane
3a11b6a8fa feat(project-g): make inputs resizable and fix the update mutation 2023-12-22 16:19:09 +01:00
Hassan Ben Jobrane
be4b26c65d feat: add basic list and edit func 2023-12-22 16:19:09 +01:00
Hassan Ben Jobrane
33df3c842d wip: feat: add layout and basic crud 2023-12-22 16:19:09 +01:00
Hassan Ben Jobrane
a5bba46b59 fix: UI tweaks 2023-12-22 16:19:09 +01:00
Hassan Ben Jobrane
1358a41dc4 feat: add ui components for project g 2023-12-22 16:19:09 +01:00
Hassan Ben Jobrane
2b7cf59159 feat: add layout for project g 2023-12-22 16:19:09 +01:00
Hassan Ben Jobrane
083c65b775 Merge pull request #2426 from nhost/chore/fix-eslint
chore: update eslint
2023-12-22 15:51:25 +01:00
Nuno Pato
6c43529eff asd 2023-12-22 13:35:45 -01:00
Nuno Pato
63309cbcd6 asd 2023-12-22 13:24:47 -01:00
David Barroso
998b1d5963 asd 2023-12-22 15:21:08 +01:00
Hassan Ben Jobrane
1c940469fb chore: update eslint 2023-12-22 15:20:07 +01:00
David Barroso
42d2a89de3 asd 2023-12-22 15:17:34 +01:00
David Barroso
731f094cf8 asd 2023-12-22 15:17:34 +01:00
David Barroso
3454605582 asd 2023-12-22 15:17:34 +01:00
David Barroso
e4479afab4 asd 2023-12-22 15:17:34 +01:00
David Barroso
6edae34bf0 asd 2023-12-22 15:17:34 +01:00
David Barroso
80b6464f60 asd 2023-12-22 15:17:34 +01:00
David Barroso
e3880dbe8a asd 2023-12-22 15:17:33 +01:00
David Barroso
ea991228e2 asd 2023-12-22 15:17:33 +01:00
Nuno Pato
7cb568be52 asd 2023-12-22 15:17:33 +01:00
Nuno Pato
dacaa7cad7 ads 2023-12-22 15:17:33 +01:00
Nuno Pato
30a688778e asd 2023-12-22 15:17:33 +01:00
Nuno Pato
d4f79c05b4 asd 2023-12-22 15:17:33 +01:00
Nuno Pato
e10d313e37 asd 2023-12-22 15:17:33 +01:00
Nuno Pato
77e8fb471c asd 2023-12-22 15:17:33 +01:00
Nuno Pato
f40a3f23ac asd 2023-12-22 15:17:33 +01:00
Nuno Pato
17dea7e60b asd 2023-12-22 15:17:33 +01:00
Nuno Pato
23527fc388 asd 2023-12-22 15:17:33 +01:00
Nuno Pato
8ec6b85bac asd 2023-12-22 15:17:33 +01:00
Nuno Pato
b067838984 asd 2023-12-22 15:17:33 +01:00
Nuno Pato
7553506e18 asd 2023-12-22 15:17:33 +01:00
Nuno Pato
e58a9f1aaa asd 2023-12-22 15:17:33 +01:00
Nuno Pato
d4bfea963f asd 2023-12-22 15:17:33 +01:00
Nuno Pato
88779ad950 asd 2023-12-22 15:17:33 +01:00
Nuno Pato
90929e9357 asd 2023-12-22 15:17:33 +01:00
David Barroso
2f4d5814ed asd 2023-12-22 15:17:33 +01:00
Nuno Pato
6d08b34309 new docs 2023-12-22 15:17:32 +01:00
github-actions[bot]
e2bf1118f9 chore: update versions (#2424)
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.1.0

### Minor Changes

-   e2b79b5ec: chore: remove sharp from deps

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-12-22 14:51:45 +01:00
Hassan Ben Jobrane
9a1ad43370 Merge pull request #2423 from nhost/chore/new-release
chore: add changeset
2023-12-22 14:48:49 +01:00
Hassan Ben Jobrane
e2b79b5ece chore: add changeset 2023-12-22 14:48:14 +01:00
Hassan Ben Jobrane
c47d47ac9c Merge pull request #2422 from nhost/chore/remove-sharp-package
chore(dashboard): remove sharp package from dependencies
2023-12-22 14:22:52 +01:00
Hassan Ben Jobrane
926590acb5 chore(dashboard): remove sharp package from dependencies 2023-12-22 14:09:49 +01:00
Hassan Ben Jobrane
90e8843314 Merge pull request #2421 from nhost/changeset-release/main
chore: update versions
2023-12-22 11:51:01 +01:00
github-actions[bot]
aa5b360932 chore: update versions 2023-12-22 10:30:28 +00:00
Hassan Ben Jobrane
daa4b8b2ad Merge pull request #2400 from nhost/changeset-release/main
chore: update versions
2023-12-22 11:28:17 +01:00
Seth Deegan
a1c5c97a59 chore (examples/docker-compose): update README.md to explain why hasura-console is needed (#2395) 2023-12-11 20:14:59 +01:00
Alex Nguyen
b338793d6d Update hasura-auth-client.ts (#2408) 2023-12-11 13:44:00 +01:00
Hassan Ben Jobrane
b1fb4b2400 chore: run pnpm install 2023-12-07 19:49:14 +01:00
github-actions[bot]
f75e023672 chore: update versions 2023-12-05 15:18:53 +00:00
Hassan Ben Jobrane
8e78c1ff00 Merge pull request #2406 from nhost/fix/ci/revert
chore(ci): revert ci changes to use `pull_request`
2023-12-05 16:16:39 +01:00
Hassan Ben Jobrane
9cbb0b2986 chore(ci): revert ci changes to use pull_request 2023-12-05 14:09:53 +01:00
Hassan Ben Jobrane
363a3b92e5 Merge pull request #2405 from nhost/fix/ci/checkout-ref
fix(ci): add ref to all checkout steps
2023-12-05 12:58:47 +01:00
Hassan Ben Jobrane
6a078fc972 fix(ci): add ref to all checkout steps 2023-12-05 12:51:47 +01:00
Hassan Ben Jobrane
1091e9674a Merge pull request #2404 from nhost/fix/ci-checkout-step
chore(ci): add ref to checkout step
2023-12-05 12:26:57 +01:00
Hassan Ben Jobrane
9738108d58 chore(ci): add ref to checkout step 2023-12-05 12:13:53 +01:00
Hassan Ben Jobrane
65951e1d1d Merge pull request #2403 from nhost/ci_target
chore(ci): change to pull_request_target to run workflows "locally"
2023-12-05 11:55:30 +01:00
David Barroso
b4af994a58 chore(ci): change pull_request to pull_request_target to run workflows locally 2023-12-05 11:39:58 +01:00
Hassan Ben Jobrane
c6347e10bc Merge pull request #2402 from nhost/fix/ci/pin-install-nhost-dep
fix(ci): pin `@nhost/nhost-js` dep version in sveltekit quickstart
2023-12-04 17:30:10 +01:00
Hassan Ben Jobrane
278a641bc1 fix(ci): pin @nhost/nhost-js dep version in sveltekit quickstart 2023-12-04 16:18:02 +01:00
Hassan Ben Jobrane
3320ddd8c8 Merge pull request #2393 from nhost/chore/sdk/remove-backendUrl
chore: remove support for using `backendUrl`
2023-12-04 15:05:52 +01:00
Hassan Ben Jobrane
bc9eff6e41 chore: update the changeset to reflect a major version increment 2023-12-04 14:38:56 +01:00
Hassan Ben Jobrane
258c608882 Revert "chore: hardcode staging auth URL for testing"
This reverts commit d8c0bb5ea4e073a7131df3726728845b2bc5e1a1.
2023-12-04 14:38:56 +01:00
Hassan Ben Jobrane
ae84f269d4 chore: hardcode staging auth URL for testing 2023-12-04 14:38:56 +01:00
Hassan Ben Jobrane
0327250b19 Revert "chore: test different subdomain"
This reverts commit 9dfd9399a0a0b1ec931e02304dbe62183b2cb500.
2023-12-04 14:38:56 +01:00
Hassan Ben Jobrane
7f56eabd24 chore: test different subdomain 2023-12-04 14:38:56 +01:00
Hassan Ben Jobrane
be110df83a fix: refactor urlFromSubdomain and fix unit tests 2023-12-04 14:38:56 +01:00
Hassan Ben Jobrane
361e648daf chore: add changeset 2023-12-04 14:38:56 +01:00
Hassan Ben Jobrane
8a72e20e3d chore: refactor generateAppServiceUrl function and remove unused code 2023-12-04 14:38:56 +01:00
Hassan Ben Jobrane
125ec390ca chore: add storage service URL to Nhost client
configuration
2023-12-04 14:38:56 +01:00
Hassan Ben Jobrane
7cc788a373 refactor: remove backendUrl from Nhost client initialization 2023-12-04 14:38:56 +01:00
David Barroso
2a04bc9e5d chore(docs): added functions to custom domains documentation (#2399) 2023-12-04 11:11:08 +01:00
Hassan Ben Jobrane
f7c2148ace Merge pull request #2392 from nhost/feat/dashboard/functions-custom-domains
feat(dashboard): add serverless functions custom domain settings
2023-11-30 14:43:18 +01:00
Hassan Ben Jobrane
78d35eed09 feat(dashboard): add serverless functions custom domain settings 2023-11-30 12:11:22 +01:00
Hassan Ben Jobrane
c5ff53c622 Merge pull request #2389 from nhost/changeset-release/main
chore: update versions
2023-11-29 12:51:40 +01:00
github-actions[bot]
d21714d169 chore: update versions 2023-11-29 10:58:39 +00:00
Hassan Ben Jobrane
0d16ad41b8 Merge pull request #2384 from nhost/fix/quickstarts-auth
fix: update auth version and webauthn origins
2023-11-29 11:56:40 +01:00
Hassan Ben Jobrane
82c328eeda Merge pull request #2388 from nhost/fix/dashboard/secrets
fix: make sure secrets are not resolved
2023-11-29 11:26:23 +01:00
Hassan Ben Jobrane
d991cd8c7e chore: run pnpm install 2023-11-29 11:25:09 +01:00
Hassan Ben Jobrane
e469628ebe chore: add changeset 2023-11-29 11:22:07 +01:00
Hassan Ben Jobrane
856bc0a4bb chore: use workspace nhost-js 2023-11-28 17:36:45 +01:00
Hassan Ben Jobrane
9b1fb1ce28 chore: update dependencies in package.json and fix
NHOST_SESSION_KEY constant
2023-11-28 17:34:19 +01:00
Hassan Ben Jobrane
a4d16f1835 fix: update NHOST_SESSION_KEY value for webauthn 2023-11-28 15:43:27 +01:00
Hassan Ben Jobrane
3db8644075 chore: update pnpm-workspace.yaml 2023-11-28 15:03:02 +01:00
Hassan Ben Jobrane
7f667f6acb chore: update auth version to 0.24.0 2023-11-28 11:48:32 +01:00
Hassan Ben Jobrane
685dc6c1e4 chore: update auth version and webauthn id & origins 2023-11-28 11:46:53 +01:00
Hassan Ben Jobrane
6f7f2b0a65 chore: update changeset 2023-11-27 14:49:32 +01:00
Hassan Ben Jobrane
6d0167b33f fix: update config resolve to true in project.gql 2023-11-27 14:41:48 +01:00
David Barroso
3ffb60f0ae fix(docs): typo in Run deploy example script (#2345) 2023-11-27 13:49:32 +01:00
Hassan Ben Jobrane
97ced73a3c chore: add changeset 2023-11-27 13:17:24 +01:00
Hassan Ben Jobrane
39c86cea25 fix: make sure secrets are not resolved 2023-11-27 13:15:52 +01:00
Hassan Ben Jobrane
d2d590db7e Merge pull request #2369 from nhost/changeset-release/main
chore: update versions
2023-11-24 16:37:42 +01:00
github-actions[bot]
3bdbefc015 chore: update versions 2023-11-24 13:05:27 +00:00
Hassan Ben Jobrane
79081b43c2 Merge pull request #2376 from nhost/feat/database/sql-editor
feat(dashboard): add sql editor
2023-11-24 14:03:15 +01:00
Hassan Ben Jobrane
a4b541f100 fix(quickstarts): update webauthn origins 2023-11-24 10:45:03 +01:00
Hassan Ben Jobrane
4523020c33 fix: update auth version and webauthn origins 2023-11-24 10:31:41 +01:00
Hassan Ben Jobrane
2e2248fd44 chore: add changeset 2023-11-24 10:07:21 +01:00
Hassan Ben Jobrane
63358eb80b chore: add comments 2023-11-24 09:59:55 +01:00
Hassan Ben Jobrane
ded674fab6 fix: add min height to codemirror 2023-11-24 09:55:16 +01:00
Hassan Ben Jobrane
85f2f28902 refactor(dashboard): move run-sql logic to a custom hook 2023-11-24 09:55:16 +01:00
Hassan Ben Jobrane
b8e9ad831e refactor(dashboard): add proper error handling 2023-11-24 09:55:16 +01:00
Hassan Ben Jobrane
4e0c5dd1d3 refactor(dashboard): improve SQL parsing in SQLEditor 2023-11-24 09:55:16 +01:00
Hassan Ben Jobrane
b874109c6d fix: rely on error returned from api call to update metadata 2023-11-24 09:55:16 +01:00
Hassan Ben Jobrane
21b926cc07 feat(dashboard): add create migration option to the sql editor 2023-11-24 09:55:16 +01:00
Hassan Ben Jobrane
c35cd47d97 feat: implement track tables in the sql editor 2023-11-24 09:55:16 +01:00
Hassan Ben Jobrane
8dcd801c7c feat(dashboard): add support for resizing the sql query results container 2023-11-24 09:55:16 +01:00
Hassan Ben Jobrane
e3199be749 feat(dashboard): add sql editor tab and basic func 2023-11-24 09:55:16 +01:00
Hassan Ben Jobrane
284b31e036 Merge pull request #2383 from nhost/chore/dashboard/update-node
chore: update node to v18
2023-11-24 09:18:42 +01:00
Hassan Ben Jobrane
e7593c7de8 chore: update node to v18 in Dockerfile 2023-11-23 16:15:07 +01:00
Hassan Ben Jobrane
e6d862ac1b Merge pull request #2342 from nhost/fix/quickstarts-workspace-deps
fix: ensure `pnpm clean` and `pnpm install` work correctly for the quickstarts
2023-11-15 21:30:21 +01:00
Hassan Ben Jobrane
f73672372f chore: update baseURL in playwright.config.js 2023-11-15 21:08:03 +01:00
Hassan Ben Jobrane
7f12b98d94 chore: fix linter issue 2023-11-15 21:01:07 +01:00
Hassan Ben Jobrane
d79b66314d chore: fix linter issues 2023-11-15 20:49:11 +01:00
Hassan Ben Jobrane
2a58266592 chore: add allowedUrls to auth.redirections and set redirect option for Google sign-in 2023-11-15 20:24:53 +01:00
Hassan Ben Jobrane
44c2c5467d fix: replace @apollo/client with graphql-tag 2023-11-15 20:21:54 +01:00
Hassan Ben Jobrane
142752cb79 Revert "fix: update Apollo client import"
This reverts commit 11a46a0db1.
2023-11-15 20:13:48 +01:00
Hassan Ben Jobrane
b05236a23c chore: run pnpm install 2023-11-15 19:53:11 +01:00
Hassan Ben Jobrane
11a46a0db1 fix: update Apollo client import 2023-11-15 19:53:11 +01:00
Hassan Ben Jobrane
cedff501d6 chore: update auth version to 0.22.1 2023-11-15 19:53:11 +01:00
Hassan Ben Jobrane
7c426dafb2 fix: rectify clean scripts 2023-11-15 19:53:11 +01:00
Hassan Ben Jobrane
57e7f794f5 fix: make sure pnpm clean and pnpm install work correctly for the quickstarts 2023-11-15 19:53:11 +01:00
Hassan Ben Jobrane
d4b6cb0acf Merge pull request #2370 from nhost/chore/quickstarts/update-metadata
chore(quickstarts): add virus table metadata
2023-11-15 19:50:17 +01:00
Nuno Pato
5d0cf8814b Merge pull request #2372 from nhost/chore/dashboard-update-storage-capacity-alert
Chore/dashboard update storage capacity alert
2023-11-13 16:30:17 -01:00
Nuno Pato
96cf17bbeb Apply suggestions from code review
fix typos

Co-authored-by: Hassan Ben Jobrane <hsanbenjobrane@gmail.com>
2023-11-13 16:26:16 -01:00
Nuno Pato
ed1a8d458e add changeset 2023-11-13 16:12:20 -01:00
Nuno Pato
8077495c18 Change dashboard alert for volume capacity 2023-11-13 16:09:33 -01:00
Hassan Ben Jobrane
b617ec7186 chore(quickstarts): add virus table metadata 2023-11-13 17:02:43 +01:00
Hassan Ben Jobrane
bb2da11dd4 Merge pull request #2367 from nhost/fix/docs/signin-linkedin-guide
fix(docs): add instructions for enabling Sign In with LinkedIn using OpenID Connect
2023-11-13 16:18:03 +01:00
Hassan Ben Jobrane
94fa824e7d Merge pull request #2366 from nhost/feat/react-apollo/sign-in-with-linked-in
feat(examples): add sign-in with Linked to react-apollo
2023-11-13 15:56:30 +01:00
Hassan Ben Jobrane
32d1ee124f chore(react-apollo): update auth version to 0.22.1 2023-11-13 15:29:28 +01:00
Hassan Ben Jobrane
138bf9eb5a chore: add changeset 2023-11-11 20:26:50 +01:00
Hassan Ben Jobrane
d8d9310e0b fix: add instructions for enabling Sign In with LinkedIn using OpenID Connect 2023-11-11 20:26:05 +01:00
Hassan Ben Jobrane
67b2c044b8 chore: add changeset 2023-11-11 16:14:33 +01:00
Hassan Ben Jobrane
0b7790ca83 feat(examples): add sign-in with Linked to react-apollo 2023-11-11 16:11:56 +01:00
Hassan Ben Jobrane
55267c680e Merge pull request #2358 from nhost/changeset-release/main
chore: update versions
2023-11-10 16:42:15 +01:00
github-actions[bot]
4d856f557f chore: update versions 2023-11-10 15:22:59 +00:00
Hassan Ben Jobrane
64c579cf8c Merge pull request #2365 from nhost/feat/delete-account
feat: delete account
2023-11-10 16:21:04 +01:00
Hassan Ben Jobrane
eae65c715b fix: disable delete account when user has projects 2023-11-10 15:26:38 +01:00
Hassan Ben Jobrane
9e69f9f235 Merge pull request #2362 from spakanati/feat/export-url-helpers
feat: export urlFromSubdomain helper
2023-11-10 14:30:08 +01:00
Hassan Ben Jobrane
8b127fbb62 chore: add changeset 2023-11-10 14:13:27 +01:00
Hassan Ben Jobrane
86ba2081ec chore: fix docusaurus front matter issue 2023-11-10 14:13:20 +01:00
Hassan Ben Jobrane
7c2c31082a chore: add changeset 2023-11-10 11:50:54 +01:00
Hassan Ben Jobrane
60f705b033 feat: add user account deletion functionality 2023-11-10 11:49:22 +01:00
Sheena Pakanati
ea34635eb2 feat: export urlFromSubdomain helper 2023-11-08 11:30:10 -05:00
Hassan Ben Jobrane
2004687044 Merge pull request #2360 from nhost/fix/examples/react-apollo
fix(react-apollo): update Apple OAuth secrets in nhost.toml
2023-11-07 11:24:51 +01:00
Hassan Ben Jobrane
bd025d43ca fix: update Apple OAuth secrets in nhost.toml 2023-11-07 10:54:16 +01:00
Hassan Ben Jobrane
87a05f7374 Merge pull request #2353 from nhost/feat/react-appollo/signin-with-apple
feat(react-apollo): add SignIn with Apple
2023-11-07 08:53:19 +01:00
Hassan Ben Jobrane
798f147db7 chore: remove console.log statement 2023-11-06 20:13:05 +01:00
Hassan Ben Jobrane
62b7fd2376 chore: update auth version to 0.21.4 2023-11-06 20:11:33 +01:00
David Barroso
1ee021b4a3 chore(docs): remove custom domains from roadmap (#2352) 2023-11-04 12:40:18 +01:00
Hassan Ben Jobrane
6e61dce297 chore: add changeset 2023-11-03 17:28:01 +01:00
Hassan Ben Jobrane
bd744e52dc feat(examples): add SignIn with Apple to the react-apollo example 2023-11-03 17:26:23 +01:00
Nestor Manrique
85723d740b Merge pull request #2343 from nhost/nestor/fix/ingress-tenant-dashboard
fix (observability): ingress tenant dashboard
2023-10-26 21:56:18 +02:00
Hassan Ben Jobrane
36e79e7b32 Merge pull request #2344 from nhost/chore/quickstarts/upgrade-storage
chore: bump quickstarts storage to `0.4.0`
2023-10-26 11:39:58 +01:00
Hassan Ben Jobrane
f61264b319 chore: bump quickstarts storage to 0.4.0 2023-10-26 11:22:41 +01:00
Nestor Manrique
e84d9d2576 Fix legends 2023-10-26 11:28:33 +02:00
Hassan Ben Jobrane
ea69d4f0f1 Merge pull request #2341 from nhost/changeset-release/main
chore: update versions
2023-10-25 14:53:21 +01:00
github-actions[bot]
212d58bee5 chore: update versions 2023-10-25 13:22:09 +00:00
Hassan Ben Jobrane
c3d6b7beec Merge pull request #2333 from nhost/feat/vue-sdk/upload-multiple-files
feat(vue-sdk): add support for uploading multiple files
2023-10-25 14:18:36 +01:00
Hassan Ben Jobrane
5d5d8ef4f3 chore: use @nhost/nhost-js from workspace 2023-10-25 13:31:12 +01:00
Hassan Ben Jobrane
deb61fe97c chore: add @nhost/nhost-js to vue-apollo example 2023-10-25 13:21:36 +01:00
Nestor Manrique
04d36154b0 Merge pull request #2334 from nhost/nestor/feat/add-ingress-dashboard
feat(observability): Add ingress metrics dashboard for tenants
2023-10-25 14:21:01 +02:00
Hassan Ben Jobrane
203cfb10b9 chore: fix JSDoc 2023-10-25 12:43:54 +01:00
Hassan Ben Jobrane
9690f871fa chore: fix JSDoc 2023-10-25 11:44:45 +01:00
Hassan Ben Jobrane
74a6b93971 Merge pull request #2335 from nhost/chore/examples/upgrade-to-node18
chore: update toml files to use node 18
2023-10-25 10:36:37 +01:00
Nestor Manrique
dd4c0d2430 wip 2023-10-25 03:30:52 +02:00
Hassan Ben Jobrane
83f2ca5cde chore: update toml files to use node 18 2023-10-24 16:39:09 +01:00
Hassan Ben Jobrane
0c49e757c8 chore: add changeset 2023-10-24 16:25:07 +01:00
Hassan Ben Jobrane
e90a9d7696 feat: add storage page to vue-apollo example 2023-10-24 16:20:02 +01:00
Hassan Ben Jobrane
00a06466f5 fix: return refs from useFileUpload 2023-10-24 16:20:02 +01:00
Hassan Ben Jobrane
8ca9f76cb2 wip: add support for uploading multiple files 2023-10-24 16:20:02 +01:00
Hassan Ben Jobrane
78113dd62a wip: feat: vue-sdk: introduce new composable to upload multiple files 2023-10-24 16:20:02 +01:00
Nestor Manrique
adb0ee82c6 wip 2023-10-24 14:29:25 +02:00
Nestor Manrique
a41bb6cae6 wip 2023-10-24 14:05:42 +02:00
1443 changed files with 61979 additions and 33176 deletions

22
.github/CODEOWNERS vendored
View File

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

View File

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

1
.github/labeler.yml vendored
View File

@@ -4,7 +4,6 @@ dashboard:
documentation:
- any:
- docs/**/*
- '!docs/docs/reference/docgen/**/*'
examples:
- examples/**/*

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
- name: Lint
run: pnpm run lint:all
- name: Audit for vulnerabilities
run: pnpx audit-ci --config ./audit-ci.jsonc
e2e:
name: 'E2E (Package: ${{ matrix.package.path }})'
@@ -146,7 +148,7 @@ jobs:
run: echo "NHOST_TEST_DASHBOARD_URL=https://${{ steps.fetch-dashboard-preview-url.outputs.preview_url }}" >> $GITHUB_ENV
# * Run the `ci` script of the current package of the matrix. Dependencies build is cached by Turborepo
- name: Run e2e tests
timeout-minutes: 15
timeout-minutes: 20
run: pnpm --filter="${{ matrix.package.name }}" run e2e
- id: file-name
if: ${{ failure() }}

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-be
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()

4
.gitignore vendored
View File

@@ -19,11 +19,11 @@ logs/
coverage/
dist/
umd/
node_modules/
node_modules
tmp/
.pnpm-store
.turbo
.env
.env*
.secrets
out/

3
.npmrc
View File

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

View File

@@ -1,7 +0,0 @@
{
"editor.codeActionsOnSave": {
"source.organizeImports": true
},
"eslint.workingDirectories": ["./dashboard"],
"typescript.tsdk": "node_modules/typescript/lib"
}

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"]
}

View File

@@ -16,3 +16,6 @@ NEXT_PUBLIC_STRIPE_PK=<nhost_stripe_public_key>
NEXT_PUBLIC_GITHUB_APP_INSTALL_URL=<github_app_install_url>
NEXT_PUBLIC_ANALYTICS_WRITE_KEY=<analytics_write_key>
NEXT_PUBLIC_NHOST_BRAGI_WEBSOCKET=<nhost_bragi_websocket>
CODEGEN_GRAPHQL_URL=https://local.graphql.nhost.run/v1
CODEGEN_HASURA_ADMIN_SECRET=nhost-admin-secret

View File

@@ -1,5 +1,187 @@
# @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
## 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
### Minor Changes
- 3ff1c2b53: fix: show upgrade option for pro projects
## 1.5.0
### Minor Changes
- c2ef17c0a: feat: add support for new Team plan
## 1.4.0
### Minor Changes
- 7883bbcbd: feat: don't show deprecated plans
- 44be6dc0a: feat: set redirectTo during sign-in to support preview environments
### Patch Changes
- 3c3594898: fix: allow access to graphite when configured running in local dashboard
- 32c246b7a: chore: update docs icon
## 1.3.2
### Patch Changes
- 174b4165b: chore: use env variables when running graphql codegen
- 7c977e714: chore: change `Allowed Roles` to `Default Allowed Roles`
- 46f028b9f: fix: remove hardcoded ai version setting
## 1.3.1
### Patch Changes
- af33c21d1: chore: remove backendUrl deprecation notice and remove all references to `providersUpdated`
## 1.3.0
### Minor Changes
- 04784d880: Fix graphite's default version
## 1.2.0
### Minor Changes
- 5733162ed: feat: add settings and ui for graphite
## 1.1.0
### Minor Changes
- e2b79b5ec: chore: remove sharp from deps
## 1.0.1
### Patch Changes
- @nhost/react-apollo@7.0.1
- @nhost/nextjs@2.0.1
## 1.0.0
### Major Changes
- bc9eff6e4: chore: remove support for using backendUrl when instantiating the Nhost client
### Patch Changes
- Updated dependencies [bc9eff6e4]
- @nhost/nextjs@2.0.0
- @nhost/react-apollo@7.0.0
## 0.21.1
### Patch Changes
- 97ced73a3: fix(dashboard): prevent dashboard from resolving secrets
## 0.21.0
### Minor Changes
- ed1a8d458: Update alert message on increasing PostgreSQL's volume capacity
- 2e2248fd4: feat(dashboard): add SQL editor
## 0.20.28
### Patch Changes
- 7c2c31082: feat: add support for users to delete their account
- @nhost/react-apollo@6.0.1
- @nhost/nextjs@1.13.40
## 0.20.27
### Patch Changes

View File

@@ -1,13 +1,13 @@
FROM node:16-alpine AS pruner
FROM node:18-alpine AS pruner
RUN apk add --no-cache libc6-compat
RUN apk update
WORKDIR /app
RUN yarn global add turbo@1.10.11
RUN yarn global add turbo@1.11.3
COPY . .
RUN turbo prune --scope="@nhost/dashboard" --docker
FROM node:16-alpine AS builder
FROM node:18-alpine AS builder
ARG TURBO_TOKEN
ARG TURBO_TEAM
@@ -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_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 --from=pruner /app/out/json/ .
COPY --from=pruner /app/out/pnpm-*.yaml .
@@ -40,7 +40,7 @@ COPY turbo.json turbo.json
COPY config/ config/
RUN pnpm build:dashboard
FROM node:16-alpine AS runner
FROM node:18-alpine AS runner
WORKDIR /app
RUN addgroup --system --gid 1001 nodejs

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);
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('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();
// 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();
// select column in current table
await page
.getByRole('button', { name: /column/i })
.first()
.click();
await page.locator('#columnName').click();
await page.getByRole('option', { name: /author_id/i }).click();
// select reference schema
await page.getByRole('button', { name: /schema/i }).click();
await page.getByLabel('Schema').click();
await page.getByRole('option', { name: /public/i }).click();
// 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();
// select reference column
await page
.getByRole('button', { name: /column/i })
.nth(1)
.click();
await page.locator('#referencedColumn').click();
await page.getByRole('option', { name: /id/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();
// select column in current table
await page
.getByRole('button', { name: /column/i })
.first()
.click();
await page.locator('#columnName').click();
await page.getByRole('option', { name: /author_id/i }).click();
// select reference schema
await page.getByRole('button', { name: /schema/i }).click();
await page.getByLabel('Schema').click();
await page.getByRole('option', { name: /public/i }).click();
// 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();
// select reference column
await page
.getByRole('button', { name: /column/i })
.nth(1)
.click();
await page.locator('#referencedColumn').click();
await page.getByRole('option', { name: /id/i }).click();
await page.getByRole('button', { name: /add/i }).click();
await expect(

View File

@@ -30,7 +30,7 @@ test('should show a sidebar with menu items', async () => {
const navLocator = page.getByRole('navigation', { name: /main navigation/i });
await expect(navLocator).toBeVisible();
await expect(navLocator.getByRole('list').getByRole('listitem')).toHaveCount(
12,
13,
);
await expect(
navLocator.getByRole('link', { name: /overview/i }),
@@ -93,7 +93,7 @@ test("should show the project's region and subdomain", async () => {
test('should not have a GitHub repository connected', async () => {
await expect(
page.getByRole('button', { name: /connect to github/i }),
page.getByRole('button', { name: /connect to github/i }).first(),
).toBeVisible();
});

View File

@@ -116,7 +116,8 @@ export async function prepareTable({
);
// 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();
}

View File

@@ -0,0 +1,14 @@
schema:
- https://local.graphql.nhost.run/v1:
headers:
x-hasura-admin-secret: nhost-admin-secret
generates:
src/utils/__generated__/graphite.graphql.ts:
documents:
- 'src/gql/graphite/**/*.gql'
plugins:
- 'typescript'
- 'typescript-operations'
- 'typescript-react-apollo'
config:
withRefetchFn: true

View File

@@ -1,12 +1,13 @@
schema:
- https://local.graphql.nhost.run/v1:
- ${CODEGEN_GRAPHQL_URL}:
headers:
x-hasura-admin-secret: nhost-admin-secret
x-hasura-admin-secret: ${CODEGEN_HASURA_ADMIN_SECRET}
generates:
src/utils/__generated__/graphql.ts:
documents:
- 'src/**/*.graphql'
- 'src/**/*.gql'
- '!src/gql/graphite/**/*.gql'
plugins:
- 'typescript'
- 'typescript-operations'

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,22 @@ const withBundleAnalyzer = require('@next/bundle-analyzer')({
});
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;
block-all-mixed-content;
upgrade-insecure-requests;
`;
module.exports = withBundleAnalyzer({
reactStrictMode: true,
swcMinify: false,
@@ -17,6 +33,23 @@ module.exports = withBundleAnalyzer({
eslint: {
dirs: ['src'],
},
async headers() {
return [
{
source: '/(.*)',
headers: [
{
key: 'X-Frame-Options',
value: 'SAMEORIGIN',
},
{
key: 'Content-Security-Policy',
value: cspHeader.replace(/\n/g, ''),
},
],
},
];
},
async redirects() {
return [
{

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/dashboard",
"version": "0.20.27",
"version": "1.8.0",
"private": true,
"scripts": {
"preinstall": "npx only-allow pnpm",
@@ -10,150 +10,159 @@
"start": "next start",
"lint": "next lint --max-warnings 0",
"test": "vitest",
"codegen": "graphql-codegen --config graphql.config.yaml --errors-only",
"codegen": "DOTENV_CONFIG_PATH=./.env.local graphql-codegen -r dotenv/config --config graphql.config.yaml --errors-only",
"codegen-graphite": "graphql-codegen --config graphite.graphql.config.yaml --errors-only",
"format": "prettier --write \"src/**/*.{js,ts,tsx,jsx,json,md}\" --plugin-search-dir=.",
"storybook": "start-storybook -p 6006 -s public",
"build-storybook": "build-storybook",
"install-browsers": "pnpm dlx playwright@1.31.0 install --with-deps",
"e2e": "pnpm install-browsers && pnpm dlx playwright@1.31.0 test"
"install-browsers": "pnpm playwright install && pnpm playwright install-deps",
"e2e": "pnpm install-browsers && pnpm playwright test"
},
"dependencies": {
"@apollo/client": "^3.7.10",
"@codemirror/language": "^6.3.0",
"@emotion/cache": "^11.10.5",
"@emotion/react": "^11.10.5",
"@emotion/server": "^11.4.0",
"@emotion/styled": "^11.10.5",
"@fontsource/inter": "^5.0.0",
"@fontsource/roboto-mono": "^5.0.0",
"@graphiql/react": "^0.18.0",
"@graphiql/toolkit": "^0.8.2",
"@headlessui/react": "^1.6.5",
"@apollo/client": "^3.9.4",
"@codemirror/lang-sql": "^6.5.5",
"@emotion/cache": "^11.11.0",
"@emotion/react": "^11.11.3",
"@emotion/server": "^11.11.0",
"@emotion/styled": "^11.11.0",
"@fontsource/inter": "^5.0.16",
"@fontsource/roboto-mono": "^5.0.16",
"@graphiql/react": "^0.20.2",
"@graphiql/toolkit": "^0.9.1",
"@headlessui/react": "^1.7.18",
"@heroicons/react": "^1.0.6",
"@hookform/resolvers": "^3.0.0",
"@mui/base": "^5.0.0-alpha.106",
"@mui/material": "^5.10.14",
"@mui/system": "^5.10.14",
"@mui/x-date-pickers": "^5.0.8",
"@hookform/resolvers": "^3.3.4",
"@mui/base": "5.0.0-beta.31",
"@mui/material": "^5.15.7",
"@mui/system": "^5.15.7",
"@mui/x-date-pickers": "^5.0.20",
"@nhost/nextjs": "workspace:*",
"@nhost/react-apollo": "workspace:*",
"@segment/snippet": "^4.15.3",
"@stripe/react-stripe-js": "^2.0.0",
"@stripe/stripe-js": "^1.35.0",
"@tailwindcss/forms": "^0.5.3",
"@tanstack/react-query": "^4.16.1",
"@tanstack/react-table": "^8.5.30",
"@tanstack/react-virtual": "^3.0.0-beta.23",
"@segment/snippet": "^4.16.2",
"@stripe/react-stripe-js": "^2.4.0",
"@stripe/stripe-js": "^1.54.2",
"@tailwindcss/forms": "^0.5.7",
"@tanstack/react-query": "^4.36.1",
"@tanstack/react-table": "^8.11.7",
"@tanstack/react-virtual": "^3.0.2",
"@uiw/codemirror-theme-github": "^4.21.21",
"@uiw/react-codemirror": "^4.21.21",
"analytics-node": "^6.2.0",
"bcryptjs": "^2.4.3",
"clsx": "^1.2.1",
"date-fns": "^2.29.3",
"generate-password": "^1.7.0",
"graphiql": "^3.0.0",
"graphql": "^16.6.0",
"graphql-request": "^6.0.0",
"date-fns": "^2.30.0",
"framer-motion": "^10.18.0",
"generate-password": "^1.7.1",
"graphiql": "^3.1.0",
"graphql": "16.8.1",
"graphql-request": "^6.1.0",
"graphql-tag": "^2.12.6",
"graphql-ws": "^5.11.2",
"hypertune": "^1.4.4",
"just-kebab-case": "^4.1.1",
"graphql-ws": "^5.14.3",
"just-kebab-case": "^4.2.0",
"lodash.debounce": "^4.0.8",
"next": "^12.3.1",
"next-seo": "^6.0.0",
"next": "^14.1.0",
"next-seo": "^6.4.0",
"node-pg-format": "^1.3.5",
"pluralize": "^8.0.0",
"react": "18.2.0",
"react-children-utilities": "^2.10.0",
"react-dom": "18.2.0",
"react-error-boundary": "^4.0.0",
"react-hook-form": "^7.42.1",
"react-hot-toast": "^2.4.0",
"react-intersection-observer": "^9.5.2",
"react-error-boundary": "^4.0.12",
"react-hook-form": "^7.50.0",
"react-hot-toast": "^2.4.1",
"react-intersection-observer": "^9.5.4",
"react-is": "18.2.0",
"react-loading-skeleton": "^2.2.0",
"react-markdown": "^9.0.1",
"react-merge-refs": "^1.1.0",
"react-syntax-highlighter": "^15.4.5",
"react-resizable-layout": "^0.7.2",
"react-table": "^7.8.0",
"sharp": "^0.32.0",
"recoil": "^0.7.7",
"recoil-persist": "^5.1.0",
"rehype-highlight": "^7.0.0",
"remark-gfm": "^4.0.0",
"shell-quote": "^1.8.1",
"slugify": "^1.6.5",
"slugify": "^1.6.6",
"stripe": "^10.17.0",
"tailwind-merge": "^1.8.0",
"utility-types": "^3.10.0",
"validator": "^13.7.0",
"yup": "^1.0.2",
"tailwind-merge": "^1.14.0",
"utility-types": "^3.11.0",
"validator": "^13.11.0",
"yup": "^1.3.3",
"yup-password": "^0.2.2"
},
"devDependencies": {
"@babel/core": "^7.20.2",
"@babel/core": "^7.23.9",
"@faker-js/faker": "^7.6.0",
"@graphql-codegen/cli": "^3.0.0",
"@graphql-codegen/typescript": "^3.0.0",
"@graphql-codegen/typescript-operations": "^3.0.0",
"@graphql-codegen/typescript-react-apollo": "^3.3.1",
"@next/bundle-analyzer": "^12.3.1",
"@playwright/test": "1.31.0",
"@storybook/addon-actions": "^6.5.14",
"@storybook/addon-essentials": "^6.5.14",
"@storybook/addon-interactions": "^6.5.14",
"@storybook/addon-links": "^6.5.14",
"@graphql-codegen/cli": "^3.3.1",
"@graphql-codegen/typescript": "^3.0.4",
"@graphql-codegen/typescript-operations": "^3.0.4",
"@graphql-codegen/typescript-react-apollo": "^3.3.7",
"@next/bundle-analyzer": "^12.3.4",
"@playwright/test": "1.41.0",
"@storybook/addon-actions": "^6.5.16",
"@storybook/addon-essentials": "^6.5.16",
"@storybook/addon-interactions": "^6.5.16",
"@storybook/addon-links": "^6.5.16",
"@storybook/addon-postcss": "^2.0.0",
"@storybook/builder-webpack5": "^6.5.14",
"@storybook/manager-webpack5": "^6.5.14",
"@storybook/react": "^6.5.14",
"@storybook/testing-library": "^0.2.0",
"@testing-library/dom": "^9.0.0",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^14.4.3",
"@storybook/builder-webpack5": "^6.5.16",
"@storybook/manager-webpack5": "^6.5.16",
"@storybook/react": "^7.6.15",
"@storybook/testing-library": "^0.2.2",
"@tailwindcss/typography": "^0.5.10",
"@testing-library/dom": "^9.3.4",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^14.2.0",
"@testing-library/user-event": "^14.5.2",
"@types/ace": "^0.0.48",
"@types/bcryptjs": "^2.4.2",
"@types/jest": "^29.5.3",
"@types/lodash.debounce": "^4.0.7",
"@types/node": "^16.11.7",
"@types/bcryptjs": "^2.4.6",
"@types/jest": "^29.5.11",
"@types/lodash.debounce": "^4.0.9",
"@types/node": "^16.18.78",
"@types/pluralize": "^0.0.30",
"@types/react": "^18.2.14",
"@types/react-dom": "^18.2.6",
"@types/react-table": "^7.7.12",
"@types/shell-quote": "^1.7.1",
"@types/testing-library__jest-dom": "^5.14.5",
"@types/validator": "^13.7.10",
"@typescript-eslint/eslint-plugin": "^5.43.0",
"@typescript-eslint/parser": "^5.43.0",
"@vitejs/plugin-react": "^4.0.0",
"@vitest/coverage-v8": "^0.32.0",
"autoprefixer": "^10.4.13",
"@types/react": "^18.2.50",
"@types/react-dom": "^18.2.18",
"@types/react-table": "^7.7.19",
"@types/shell-quote": "^1.7.5",
"@types/testing-library__jest-dom": "^5.14.9",
"@types/validator": "^13.11.8",
"@typescript-eslint/eslint-plugin": "^6.20.0",
"@typescript-eslint/parser": "^6.20.0",
"@vitejs/plugin-react": "^4.2.1",
"@vitest/coverage-v8": "^0.32.4",
"autoprefixer": "^10.4.17",
"babel-loader": "^8.3.0",
"babel-plugin-transform-remove-console": "^6.9.4",
"csstype": "^3.0.10",
"dotenv": "^16.0.3",
"csstype": "^3.1.3",
"dotenv": "^16.4.1",
"encoding": "^0.1.13",
"eslint": "^8.28.0",
"eslint": "^8.56.0",
"eslint-config-airbnb": "19.0.4",
"eslint-config-airbnb-typescript": "^17.0.0",
"eslint-config-next": "^13.0.2",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jsx-a11y": "^6.6.1",
"eslint-plugin-react": "^7.31.11",
"eslint-config-airbnb-typescript": "^17.1.0",
"eslint-config-next": "^13.5.6",
"eslint-config-prettier": "^8.10.0",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-jsx-a11y": "^6.8.0",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
"jsdom": "^22.0.0",
"lint-staged": ">=13",
"msw": "^1.0.1",
"msw-storybook-addon": "^1.6.3",
"node-fetch": "^3.3.0",
"postcss": "^8.4.19",
"prettier": "^2.7.1",
"prettier-plugin-organize-imports": "^3.2.0",
"prettier-plugin-tailwindcss": "^0.4.0",
"jsdom": "^22.1.0",
"lint-staged": "^15.2.1",
"msw": "^1.3.2",
"msw-storybook-addon": "^1.10.0",
"node-fetch": "^3.3.2",
"postcss": "^8.4.33",
"prettier": "^2.8.8",
"prettier-plugin-organize-imports": "^3.2.4",
"prettier-plugin-tailwindcss": "^0.4.1",
"react-date-fns-hooks": "^0.9.4",
"require-from-string": "^2.0.2",
"snake-case": "^3.0.4",
"storybook-addon-next-router": "^4.0.1",
"tailwindcss": "^3.1.2",
"ts-node": "^10.9.1",
"tsconfig-paths-webpack-plugin": "^4.0.0",
"vite": "^4.0.2",
"vite-tsconfig-paths": "^4.0.3",
"vitest": "^0.32.0"
"storybook-addon-next-router": "^4.0.2",
"tailwindcss": "^3.4.1",
"ts-node": "^10.9.2",
"tsconfig-paths-webpack-plugin": "^4.1.0",
"vite": "^5.0.12",
"vite-tsconfig-paths": "^4.3.1",
"vitest": "^0.32.4"
},
"browserslist": {
"production": [

View File

@@ -0,0 +1,7 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6 6H10" stroke="#21324B" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6 8H10" stroke="#21324B" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6 10H8" stroke="#21324B" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9.79289 13.5H3C2.86739 13.5 2.74021 13.4473 2.64645 13.3536C2.55268 13.2598 2.5 13.1326 2.5 13V3C2.5 2.86739 2.55268 2.74021 2.64645 2.64645C2.74021 2.55268 2.86739 2.5 3 2.5H13C13.1326 2.5 13.2598 2.55268 13.3536 2.64645C13.4473 2.74021 13.5 2.86739 13.5 3V9.79289C13.5 9.85855 13.4871 9.92357 13.4619 9.98423C13.4368 10.0449 13.4 10.1 13.3536 10.1464L10.1464 13.3536C10.1 13.4 10.0449 13.4368 9.98423 13.4619C9.92357 13.4871 9.85855 13.5 9.79289 13.5V13.5Z" stroke="#21324B" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13.4548 9.99948H10V13.4545" stroke="#21324B" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,7 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6 6H10" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6 8H10" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6 10H8" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9.79289 13.5H3C2.86739 13.5 2.74021 13.4473 2.64645 13.3536C2.55268 13.2598 2.5 13.1326 2.5 13V3C2.5 2.86739 2.55268 2.74021 2.64645 2.64645C2.74021 2.55268 2.86739 2.5 3 2.5H13C13.1326 2.5 13.2598 2.55268 13.3536 2.64645C13.4473 2.74021 13.5 2.86739 13.5 3V9.79289C13.5 9.85855 13.4871 9.92357 13.4619 9.98423C13.4368 10.0449 13.4 10.1 13.3536 10.1464L10.1464 13.3536C10.1 13.4 10.0449 13.4368 9.98423 13.4619C9.92357 13.4871 9.85855 13.5 9.79289 13.5V13.5Z" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13.4548 9.99948H10V13.4545" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -4,9 +4,17 @@ import type { DetailedHTMLProps, HTMLProps } from 'react';
import { twMerge } from 'tailwind-merge';
export interface ContactUsProps
extends DetailedHTMLProps<HTMLProps<HTMLDivElement>, HTMLDivElement> {}
extends DetailedHTMLProps<HTMLProps<HTMLDivElement>, HTMLDivElement> {
isTeam?: boolean;
isOwner?: boolean;
}
export default function FeedbackForm({ className, ...props }: ContactUsProps) {
export default function FeedbackForm({
className,
isTeam,
isOwner,
...props
}: ContactUsProps) {
return (
<div
className={twMerge(
@@ -19,6 +27,30 @@ export default function FeedbackForm({ className, ...props }: ContactUsProps) {
Contact us
</Text>
{isTeam && isOwner && (
<Text>
If this is a new Team project, or you need to manage members, reach
out to us on discord or via email at{' '}
<Link
href="mailto:support@nhost.io"
target="_blank"
rel="noopener noreferrer"
underline="hover"
>
support@nhost.io
</Link>{' '}
so we can have your dedicated channel set up.
</Text>
)}
{isTeam && !isOwner && (
<Text>
As part of a team plan you can reach out to us on the private channel
for this workspace. If you haven&apos;t been added to the channel, ask
the workspace owner to add you.
</Text>
)}
<Text>
To report issues with Nhost, please open a GitHub issue in the{' '}
<Link

View File

@@ -1,28 +0,0 @@
import { Alert } from '@/components/ui/v2/Alert';
import { Text } from '@/components/ui/v2/Text';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
export default function DepricationNotice() {
const { currentProject } = useCurrentWorkspaceAndProject();
return (
!currentProject?.providersUpdated && (
<Alert severity="warning" className="grid place-content-center">
<Text color="warning" className="max-w-3xl text-sm">
On December 1st the old backend domain will cease to work. You need to
make sure your client is instantiated using the subdomain and region
and update your oauth2 settings. You can find more information{' '}
<a
target="_blank"
rel="noopener noreferrer"
className="underline"
href="https://github.com/nhost/nhost/discussions/2303"
>
here
</a>
.
</Text>
</Alert>
)
);
}

View File

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

View File

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

View File

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

View File

@@ -9,10 +9,11 @@ import { ChangePlanModal } from '@/features/projects/common/components/ChangePla
import { useIsCurrentUserOwner } from '@/features/projects/common/hooks/useIsCurrentUserOwner';
import Image from 'next/image';
import { type ReactNode } from 'react';
interface UpgradeToProBannerProps {
title: string;
description: string;
description: string | ReactNode;
}
export default function UpgradeToProBanner({
@@ -25,7 +26,7 @@ export default function UpgradeToProBanner({
return (
<Box
sx={{ backgroundColor: 'primary.light' }}
className="flex flex-col p-4 space-y-4 rounded-md 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="space-y-2">
@@ -39,7 +40,11 @@ export default function UpgradeToProBanner({
</div>
</div>
<Text variant="h3">{title}</Text>
<Text>{description}</Text>
{typeof description === 'string' ? (
<Text>{description}</Text>
) : (
description
)}
</div>
<div className="flex flex-col space-y-2 lg:flex-row lg:items-center lg:space-y-0 lg:space-x-2">
@@ -87,14 +92,13 @@ export default function UpgradeToProBanner({
</div>
</div>
<div className="max-w-xs mx-auto">
<Image
src="/illustration-unbox.png"
width={400}
height={260}
objectFit="contain"
/>
</div>
<Image
src="/illustration-unbox.png"
width={300}
height={140}
objectFit="contain"
alt='Upgrade to Pro illustration'
/>
</Box>
);
}

View File

@@ -8,7 +8,7 @@ import type {
DataBrowserGridCellProps,
} from '@/features/database/dataGrid/types/dataBrowser';
import { triggerToast } from '@/utils/toast';
import type { FocusEvent, KeyboardEvent, MouseEvent } from 'react';
import type { FocusEvent, JSXElementConstructor, KeyboardEvent, MouseEvent, ReactElement, ReactNode, ReactPortal } from 'react';
import {
Children,
cloneElement,
@@ -320,7 +320,7 @@ function DataGridCellContent<TData extends object = {}, TValue = unknown>({
sx={{ backgroundColor: 'transparent' }}
{...props}
>
{Children.map(children, (child) => {
{Children.map(children, (child: ReactNode | ReactPortal | ReactElement<unknown, string | JSXElementConstructor<any>>) => {
if (!isValidElement(child)) {
return null;
}

View File

@@ -96,45 +96,52 @@ export default function DataGridHeader<T extends object>({
}}
key={column.id}
>
<Dropdown.Trigger
className={twMerge(
'focus:outline-none motion-safe:transition-colors',
)}
disabled={
column.isDisabled ||
column.id === 'selection' ||
(column.disableSortBy && !onRemoveColumn)
}
hideChevron
>
{column.id === 'selection' ? (
<span
{...headerProps}
className="relative grid w-full grid-flow-col items-center justify-between p-2"
>
{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>
{allowResize && !column.disableResizing && (
) : (
<Dropdown.Trigger
className={twMerge(
'focus:outline-none motion-safe:transition-colors',
)}
disabled={
column.isDisabled || (column.disableSortBy && !onRemoveColumn)
}
hideChevron
>
<span
{...column.getResizerProps({
onClick: (event: Event) => event.stopPropagation(),
})}
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"
/>
)}
</Dropdown.Trigger>
{...headerProps}
className="relative grid w-full grid-flow-col items-center justify-between p-2"
>
{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>
{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
menu

View File

@@ -0,0 +1,46 @@
import { AISidebar } from '@/components/layout/AISidebar';
import type { ProjectLayoutProps } from '@/components/layout/ProjectLayout';
import { ProjectLayout } from '@/components/layout/ProjectLayout';
import type { SettingsSidebarProps } from '@/components/layout/SettingsSidebar';
import { RetryableErrorBoundary } from '@/components/presentational/RetryableErrorBoundary';
import { Box } from '@/components/ui/v2/Box';
import { twMerge } from 'tailwind-merge';
export interface AILayoutProps extends ProjectLayoutProps {
/**
* Props passed to the sidebar component.
*/
sidebarProps?: SettingsSidebarProps;
}
export default function AILayout({
children,
mainContainerProps: {
className: mainContainerClassName,
...mainContainerProps
} = {},
sidebarProps: { className: sidebarClassName, ...sidebarProps } = {},
...props
}: AILayoutProps) {
return (
<ProjectLayout
mainContainerProps={{
className: twMerge('flex h-full', mainContainerClassName),
...mainContainerProps,
}}
{...props}
>
<AISidebar
className={twMerge('w-full max-w-sidebar', sidebarClassName)}
{...sidebarProps}
/>
<Box
sx={{ backgroundColor: 'background.default' }}
className="flex w-full flex-auto flex-col overflow-scroll overflow-x-hidden"
>
<RetryableErrorBoundary>{children}</RetryableErrorBoundary>
</Box>
</ProjectLayout>
);
}

View File

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

View File

@@ -0,0 +1,143 @@
import { NavLink } from '@/components/common/NavLink';
import { Backdrop } from '@/components/ui/v2/Backdrop';
import type { BoxProps } from '@/components/ui/v2/Box';
import { Box } from '@/components/ui/v2/Box';
import { IconButton } from '@/components/ui/v2/IconButton';
import { List } from '@/components/ui/v2/List';
import type { ListItemButtonProps } from '@/components/ui/v2/ListItem';
import { ListItem } from '@/components/ui/v2/ListItem';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
import Image from 'next/image';
import { useRouter } from 'next/router';
import { useEffect, useState } from 'react';
import { twMerge } from 'tailwind-merge';
export interface AISidebarProps extends Omit<BoxProps, 'children'> {}
interface AINavLinkProps extends ListItemButtonProps {
/**
* Link to navigate to.
*/
href: string;
/**
* Determines whether or not the link should be active if it's href exactly
* matches the current route.
*
* @default true
*/
exact?: boolean;
}
function AINavLink({ exact = true, href, children, ...props }: AINavLinkProps) {
const router = useRouter();
const baseUrl = `/${router.query.workspaceSlug}/${router.query.appSlug}/ai`;
const finalUrl = href && href !== '/' ? `${baseUrl}${href}` : baseUrl;
const active = exact
? router.asPath === finalUrl
: router.asPath.startsWith(finalUrl);
return (
<ListItem.Root>
<ListItem.Button
dense
href={finalUrl}
component={NavLink}
selected={active}
{...props}
>
<ListItem.Text>{children}</ListItem.Text>
</ListItem.Button>
</ListItem.Root>
);
}
export default function AISidebar({ className, ...props }: AISidebarProps) {
const [expanded, setExpanded] = useState(false);
const { currentProject } = useCurrentWorkspaceAndProject();
function toggleExpanded() {
setExpanded(!expanded);
}
function handleSelect() {
setExpanded(false);
}
function closeSidebarWhenEscapeIsPressed(event: KeyboardEvent) {
if (event.key === 'Escape') {
setExpanded(false);
}
}
useEffect(() => {
if (typeof document !== 'undefined') {
document.addEventListener('keydown', closeSidebarWhenEscapeIsPressed);
}
return () =>
document.removeEventListener('keydown', closeSidebarWhenEscapeIsPressed);
}, []);
if (!currentProject) {
return null;
}
return (
<>
<Backdrop
open={expanded}
className="absolute top-0 left-0 bottom-0 right-0 z-[34] md:hidden"
role="button"
tabIndex={-1}
onClick={() => setExpanded(false)}
aria-label="Close sidebar overlay"
onKeyDown={(event) => {
if (event.key !== 'Enter' && event.key !== ' ') {
return;
}
setExpanded(false);
}}
/>
<Box
component="aside"
className={twMerge(
'absolute top-0 z-[35] h-full w-full overflow-auto border-r-1 px-2 pt-2 pb-17 motion-safe:transition-transform md:relative md:z-0 md:h-full md:py-2.5 md:transition-none',
expanded ? 'translate-x-0' : '-translate-x-full md:translate-x-0',
className,
)}
{...props}
>
<nav aria-label="Settings navigation">
<List className="grid gap-2">
<AINavLink
href="/auto-embeddings"
exact={false}
onClick={handleSelect}
>
Auto-Embeddings
</AINavLink>
<AINavLink href="/assistants" exact={false} onClick={handleSelect}>
Assistants
</AINavLink>
</List>
</nav>
</Box>
<IconButton
className="absolute bottom-4 left-4 z-[38] h-11 w-11 rounded-full md:hidden"
onClick={toggleExpanded}
aria-label="Toggle sidebar"
>
<Image
width={16}
height={16}
src="/assets/table.svg"
alt="A monochrome table"
/>
</IconButton>
</>
);
}

View File

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

View File

@@ -1,4 +1,5 @@
import { ContactUs } from '@/components/common/ContactUs';
import { useDialog } from '@/components/common/DialogProvider';
import { NavLink } from '@/components/common/NavLink';
import { AccountMenu } from '@/components/layout/AccountMenu';
import { Breadcrumbs } from '@/components/layout/Breadcrumbs';
@@ -6,14 +7,20 @@ import { LocalAccountMenu } from '@/components/layout/LocalAccountMenu';
import { MobileNav } from '@/components/layout/MobileNav';
import { Logo } from '@/components/presentational/Logo';
import { Box } from '@/components/ui/v2/Box';
import { Button } from '@/components/ui/v2/Button';
import { Chip } from '@/components/ui/v2/Chip';
import { Dropdown } from '@/components/ui/v2/Dropdown';
import { GraphiteIcon } from '@/components/ui/v2/icons/GraphiteIcon';
import { DevAssistant } from '@/features/ai/DevAssistant';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
import { useIsCurrentUserOwner } from '@/features/projects/common/hooks/useIsCurrentUserOwner';
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
import { ApplicationStatus } from '@/types/application';
import { getToastStyleProps } from '@/utils/constants/settings';
import { useRouter } from 'next/router';
import type { DetailedHTMLProps, HTMLProps, PropsWithoutRef } from 'react';
import { useEffect } from 'react';
import { toast } from 'react-hot-toast';
import { twMerge } from 'tailwind-merge';
export interface HeaderProps
@@ -23,9 +30,16 @@ export interface HeaderProps
export default function Header({ className, ...props }: HeaderProps) {
const router = useRouter();
const isPlatform = useIsPlatform();
const { openDrawer } = useDialog();
const { currentProject, refetch: refetchProject } =
useCurrentWorkspaceAndProject();
const isOwner = useIsCurrentUserOwner();
const isProjectUpdating =
currentProject?.appStates[0]?.stateId === ApplicationStatus.Updating;
@@ -44,6 +58,23 @@ export default function Header({ className, ...props }: HeaderProps) {
};
}, [isProjectUpdating, refetchProject]);
const openDevAssistant = () => {
// The dev assistant can be only answer questions related to a particular project
if (!currentProject) {
toast.error('You need to be inside a project to open the Assistant', {
style: getToastStyleProps().style,
...getToastStyleProps().error,
});
return;
}
openDrawer({
title: <GraphiteIcon />,
component: <DevAssistant />,
});
};
return (
<Box
component="header"
@@ -54,7 +85,7 @@ export default function Header({ className, ...props }: HeaderProps) {
sx={{ backgroundColor: 'background.paper' }}
{...props}
>
<div className="grid grid-flow-col items-center gap-3 ">
<div className="grid grid-flow-col items-center gap-3">
<NavLink href="/" className="w-12">
<Logo className="mx-auto cursor-pointer" />
</NavLink>
@@ -69,6 +100,10 @@ export default function Header({ className, ...props }: HeaderProps) {
</div>
<div className="hidden grid-flow-col items-center gap-2 sm:grid">
<Button className="rounded-full" onClick={openDevAssistant}>
<GraphiteIcon />
</Button>
{isPlatform && (
<Dropdown.Root>
<Dropdown.Trigger
@@ -82,7 +117,11 @@ export default function Header({ className, ...props }: HeaderProps) {
transformOrigin={{ vertical: 'top', horizontal: 'right' }}
anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
>
<ContactUs className="max-w-md" />
<ContactUs
className="max-w-md"
isTeam={currentProject?.plan?.name === 'Team'}
isOwner={isOwner}
/>
</Dropdown.Content>
</Dropdown.Root>
)}

View File

@@ -1,4 +1,3 @@
import DepricationNotice from '@/components/common/DepricationNotice/DepricationNotice';
import type { ProjectLayoutProps } from '@/components/layout/ProjectLayout';
import { ProjectLayout } from '@/components/layout/ProjectLayout';
import type { SettingsSidebarProps } from '@/components/layout/SettingsSidebar';
@@ -50,7 +49,6 @@ export default function SettingsLayout({
>
<RetryableErrorBoundary>
<div className="flex flex-col space-y-2">
<DepricationNotice />
{hasGitRepo && (
<Alert
severity="warning"

View File

@@ -208,6 +208,9 @@ export default function SettingsSidebar({
>
Custom Domains
</SettingsNavLink>
<SettingsNavLink href="/ai" exact={false} onClick={handleSelect}>
AI
</SettingsNavLink>
</List>
</nav>
</Box>

View File

@@ -1,100 +0,0 @@
import { useDialog } from '@/components/common/DialogProvider';
import { Alert } from '@/components/ui/v2/Alert';
import { Button } from '@/components/ui/v2/Button';
import { ArrowSquareOutIcon } from '@/components/ui/v2/icons/ArrowSquareOutIcon';
import { Link } from '@/components/ui/v2/Link';
import { Text } from '@/components/ui/v2/Text';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
import { getToastStyleProps } from '@/utils/constants/settings';
import { useConfirmProvidersUpdatedMutation } from '@/utils/__generated__/graphql';
import { useTheme } from '@mui/material';
import { useState } from 'react';
import toast from 'react-hot-toast';
export default function ProvidersUpdatedAlert() {
const theme = useTheme();
const { openAlertDialog } = useDialog();
const [confirmed, setConfirmed] = useState(true);
const { currentProject } = useCurrentWorkspaceAndProject();
const [confirmProvidersUpdated] = useConfirmProvidersUpdatedMutation({
variables: { id: currentProject?.id },
});
async function handleSubmitConfirmation() {
const confirmProvidersUpdatedPromise = confirmProvidersUpdated();
await toast.promise(
confirmProvidersUpdatedPromise,
{
loading: 'Confirming...',
success: 'Your settings have been updated successfully.',
error: 'An error occurred while trying to confirm the message.',
},
getToastStyleProps(),
);
setConfirmed(false);
}
function handleOpenConfirmationDialog() {
openAlertDialog({
title: 'Confirm all providers updated?',
payload: (
<Text variant="subtitle1" component="span">
Please make sure to update all providers before continuing. Your
sign-in flows might break if you don&apos;t.
</Text>
),
props: {
onPrimaryAction: handleSubmitConfirmation,
},
});
}
if (!confirmed) {
return null;
}
return (
<Alert
severity="warning"
className="grid items-center grid-flow-row gap-2 p-4 place-items-center lg:grid-flow-col lg:place-content-between"
>
<div className="grid grid-flow-row gap-1 text-left">
<Text className="font-semibold">
Please update the Redirect URL for all providers being used
</Text>
<Text className="text-sm+">
We are deprecating your project&apos;s old DNS name in favor of
individual DNS names for each service. Please make sure to update your
providers to use the new auth specific URL under <b>Redirect URL</b>{' '}
before the 1st of February 2023.{' '}
<Link
href="https://github.com/nhost/nhost/discussions/1319"
target="_blank"
rel="noopener noreferrer"
underline="hover"
className="font-medium"
>
Read the discussion here.
<ArrowSquareOutIcon className="w-4 h-4 ml-1" />
</Link>
</Text>
</div>
<Button
variant="borderless"
className={
theme.palette.mode === 'dark'
? 'text-white hover:bg-brown'
: 'text-black hover:bg-orange-300'
}
onClick={handleOpenConfirmationDialog}
>
I have updated all Redirect URLs
</Button>
</Alert>
);
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,163 @@
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 { 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 instanceof ApolloError) {
const internalError = error.graphQLErrors?.[0]?.extensions?.internal as
| { error: { message: string } }
| undefined;
return internalError?.error?.message || null;
}
if (error instanceof Error) {
return error.message;
}
return null;
};
const errorToObject = (error: ApolloError | Error) => {
if (error instanceof 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.
*/
component?: string | ElementType;
component?: ElementType;
}
const HelperText = styled(MaterialFormHelperText)<HelperTextProps>({

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because one or more lines are too long

View File

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

View File

@@ -0,0 +1,32 @@
import type { IconProps } from '@/components/ui/v2/icons';
import { SvgIcon } from '@/components/ui/v2/icons/SvgIcon';
function ArrowElbowRightUp(props: IconProps) {
return (
<SvgIcon
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M8 6L11 3L14 6"
stroke="currentColor"
strokeWidth="1.5"
strokeLinejoin="round"
/>
<path
d="M2 12H11V3"
stroke="currentColor"
strokeWidth="1.5"
strokeLinejoin="round"
/>
</SvgIcon>
);
}
ArrowElbowRightUp.displayName = 'NhostArrowElbowRightUp';
export default ArrowElbowRightUp;

View File

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

View File

@@ -0,0 +1,33 @@
import type { IconProps } from '@/components/ui/v2/icons';
import { SvgIcon } from '@/components/ui/v2/icons/SvgIcon';
function EmbeddingsIcon(props: IconProps) {
return (
<SvgIcon
width="17"
height="17"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 17 17"
fill="none"
aria-label="Embeddings Icon"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M0.178057 4.04687L4.04687 0.178057C4.28428 -0.0593522 4.6692 -0.0593522 4.90661 0.178057L8.77542 4.04687C9.01283 4.28428 9.01283 4.6692 8.77542 4.90661C8.53801 5.14402 8.15309 5.14402 7.91568 4.90661L5.08466 2.07559L5.08466 12.7664H3.86881L3.86881 2.07559L1.03779 4.90661C0.800384 5.14402 0.415467 5.14402 0.178057 4.90661C-0.0593524 4.6692 -0.0593524 4.28428 0.178057 4.04687Z"
fill="currentColor"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M12.9531 8.22458L16.8219 12.0934C17.0594 12.3308 17.0594 12.7157 16.8219 12.9531L12.9531 16.8219C12.7157 17.0594 12.3308 17.0594 12.0934 16.8219C11.856 16.5845 11.856 16.1996 12.0934 15.9622L14.9244 13.1312H4.23357V11.9153H14.9244L12.0934 9.08432C11.856 8.84691 11.856 8.46199 12.0934 8.22458C12.3308 7.98717 12.7157 7.98717 12.9531 8.22458Z"
fill="currentColor"
/>
</SvgIcon>
);
}
EmbeddingsIcon.displayName = 'NhostEmbeddingsIcon';
export default EmbeddingsIcon;

View File

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

View File

@@ -0,0 +1,36 @@
import type { IconProps } from '@/components/ui/v2/icons';
import { SvgIcon } from '@/components/ui/v2/icons/SvgIcon';
function GraphiteIcon(props: IconProps) {
return (
<SvgIcon
width="22"
height="25"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 22 25"
aria-label="Graphite"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M9.39873 13.0137C12.2825 13.0137 14.6203 10.7138 14.6203 7.87671C14.6203 5.03963 12.2825 2.73973 9.39873 2.73973C6.51497 2.73973 4.17722 5.03963 4.17722 7.87671C4.17722 10.7138 6.51497 13.0137 9.39873 13.0137ZM9.39873 15.7534C13.8205 15.7534 17.4051 12.2269 17.4051 7.87671C17.4051 3.52652 13.8205 0 9.39873 0C4.97696 0 1.39241 3.52652 1.39241 7.87671C1.39241 12.2269 4.97696 15.7534 9.39873 15.7534Z"
fill="currentColor"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M2.78481 15.7534C2.78481 19.3471 5.74597 22.2603 9.39873 22.2603C13.0515 22.2603 16.0127 19.3471 16.0127 15.7534H18.7975C18.7975 20.8602 14.5895 25 9.39873 25C4.20796 25 0 20.8602 0 15.7534H2.78481Z"
fill="currentColor"
/>
<path
d="M7.37975 1.36986C7.37975 0.613309 8.00315 0 8.77215 0H20.6076C21.3766 0 22 0.613309 22 1.36986C22 2.12642 21.3766 2.73973 20.6076 2.73973H8.77215C8.00315 2.73973 7.37975 2.12642 7.37975 1.36986Z"
fill="currentColor"
/>
</SvgIcon>
);
}
GraphiteIcon.displayName = 'NhostGraphiteIcon';
export default GraphiteIcon;

View File

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

View File

@@ -0,0 +1,26 @@
import type { IconProps } from '@/components/ui/v2/icons';
import { SvgIcon } from '@/components/ui/v2/icons/SvgIcon';
function TerminalIcon(props: IconProps) {
return (
<SvgIcon
width="16"
height="16"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
aria-label="Trash"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M3.49851 3.43968L2.93795 2.94141L1.94141 4.06252L2.50196 4.56079L6.37134 8.00024L2.50196 11.4397L1.94141 11.938L2.93795 13.0591L3.49851 12.5608L7.99851 8.56079C8.15863 8.41847 8.25024 8.21446 8.25024 8.00024C8.25024 7.78601 8.15863 7.582 7.99851 7.43968L3.49851 3.43968ZM7.99987 11.2502H7.24987V12.7502H7.99987H13.9999H14.7499V11.2502H13.9999H7.99987Z"
fill="currentColor"
/>
</SvgIcon>
);
}
TerminalIcon.displayName = 'NhostTerminalIcon';
export default TerminalIcon;

View File

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

View File

@@ -0,0 +1,148 @@
import { useDialog } from '@/components/common/DialogProvider';
import { SettingsContainer } from '@/components/layout/SettingsContainer';
import { Box } from '@/components/ui/v2/Box';
import { Button } from '@/components/ui/v2/Button';
import { Checkbox } from '@/components/ui/v2/Checkbox';
import { Text } from '@/components/ui/v2/Text';
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import {
useDeleteUserAccountMutation,
useGetAllWorkspacesAndProjectsQuery,
} from '@/utils/__generated__/graphql';
import { useSignOut, useUserData } from '@nhost/nextjs';
import { useRouter } from 'next/router';
import { useState } from 'react';
import { twMerge } from 'tailwind-merge';
function ConfirmDeleteAccountModal({
close,
onDelete,
}: {
onDelete?: () => Promise<any>;
close: () => void;
}) {
const [remove, setRemove] = useState(false);
const [loadingRemove, setLoadingRemove] = useState(false);
const user = useUserData();
const { data, loading } = useGetAllWorkspacesAndProjectsQuery({
skip: !user,
});
const userHasProjects =
!loading && data?.workspaces.some((workspace) => workspace.projects.length);
const userData = useUserData();
const [deleteUserAccount] = useDeleteUserAccountMutation({
variables: { id: userData?.id },
});
const onClickConfirm = async () => {
setLoadingRemove(true);
await execPromiseWithErrorToast(
async () => {
await deleteUserAccount();
onDelete?.();
close();
},
{
loadingMessage: 'Deleting your account...',
successMessage: 'The account has been deleted successfully.',
errorMessage:
'An error occurred while deleting your account. Please try again.',
},
);
};
return (
<Box className={twMerge('w-full rounded-lg p-6 text-left')}>
<div className="grid grid-flow-row gap-1">
<Text variant="h3" component="h2">
Delete Account?
</Text>
{userHasProjects && (
<Text
variant="subtitle2"
className="font-bold"
sx={{ color: (theme) => `${theme.palette.error.main} !important` }}
>
You still have active projects. Please delete your projects before
proceeding with the account deletion.
</Text>
)}
<Box className="my-4">
<Checkbox
id="accept-1"
label={`I'm sure I want to delete my account`}
className="py-2"
checked={remove}
onChange={(_event, checked) => setRemove(checked)}
aria-label="Confirm Delete Project #1"
/>
</Box>
<div className="grid grid-flow-row gap-2">
<Button
color="error"
onClick={onClickConfirm}
disabled={userHasProjects}
loading={loadingRemove}
>
Delete
</Button>
<Button variant="outlined" color="secondary" onClick={close}>
Cancel
</Button>
</div>
</div>
</Box>
);
}
export default function DeleteAccount() {
const router = useRouter();
const { signOut } = useSignOut();
const { openDialog, closeDialog } = useDialog();
const onDelete = async () => {
await signOut();
await router.push('/signin');
};
const confirmDeleteAccount = async () => {
openDialog({
component: (
<ConfirmDeleteAccountModal close={closeDialog} onDelete={onDelete} />
),
});
};
return (
<SettingsContainer
title="Delete Account"
description="Please proceed with caution as the removal of your Personal Account and its contents from the Nhost platform is irreversible. This action will permanently delete your account and all associated data."
className="px-0"
slotProps={{
submitButton: { className: 'hidden' },
footer: { className: 'hidden' },
}}
>
<Box className="grid grid-flow-row border-t-1">
<Button
color="error"
className="mx-4 mt-4 justify-self-end"
onClick={confirmDeleteAccount}
>
Delete Personal Account
</Button>
</Box>
</SettingsContainer>
);
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,5 @@
mutation deleteUserAccount($id: uuid!) {
deleteUser(id: $id) {
__typename
}
}

View File

@@ -0,0 +1,304 @@
import { useDialog } from '@/components/common/DialogProvider';
import { Form } from '@/components/form/Form';
import { Box } from '@/components/ui/v2/Box';
import { Button } from '@/components/ui/v2/Button';
import { ArrowsClockwise } from '@/components/ui/v2/icons/ArrowsClockwise';
import { InfoIcon } from '@/components/ui/v2/icons/InfoIcon';
import { PlusIcon } from '@/components/ui/v2/icons/PlusIcon';
import { Input } from '@/components/ui/v2/Input';
import { Text } from '@/components/ui/v2/Text';
import { Tooltip } from '@/components/ui/v2/Tooltip';
import { GraphqlDataSourcesFormSection } from '@/features/ai/AssistantForm/components/GraphqlDataSourcesFormSection';
import { WebhooksDataSourcesFormSection } from '@/features/ai/AssistantForm/components/WebhooksDataSourcesFormSection';
import { useAdminApolloClient } from '@/features/projects/common/hooks/useAdminApolloClient';
import type { DialogFormProps } from '@/types/common';
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { removeTypename, type DeepRequired } from '@/utils/helpers';
import {
useInsertAssistantMutation,
useUpdateAssistantMutation,
} from '@/utils/__generated__/graphite.graphql';
import { yupResolver } from '@hookform/resolvers/yup';
import { useEffect } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import * as Yup from 'yup';
export const validationSchema = Yup.object({
name: Yup.string().required('The name is required.'),
description: Yup.string(),
instructions: Yup.string().required('The instructions are required'),
model: Yup.string().required('The model is required'),
graphql: Yup.array().of(
Yup.object().shape({
name: Yup.string().required(),
description: Yup.string().required(),
query: Yup.string().required(),
arguments: Yup.array().of(
Yup.object().shape({
name: Yup.string().required(),
description: Yup.string().required(),
type: Yup.string().required(),
required: Yup.bool().required(),
}),
),
}),
),
webhooks: Yup.array().of(
Yup.object().shape({
name: Yup.string().required(),
description: Yup.string().required(),
URL: Yup.string().required(),
arguments: Yup.array().of(
Yup.object().shape({
name: Yup.string().required(),
description: Yup.string().required(),
type: Yup.string().required(),
required: Yup.bool().required(),
}),
),
}),
),
});
export type AssistantFormValues = Yup.InferType<typeof validationSchema>;
export interface AssistantFormProps extends DialogFormProps {
/**
* To use in conjunction with initialData to allow for updating the autoEmbeddingsConfiguration
*/
assistantId?: string;
/**
* if there is initialData then it's an update operation
*/
initialData?: AssistantFormValues;
/**
* Function to be called when the operation is cancelled.
*/
onCancel?: VoidFunction;
/**
* Function to be called when the submit is successful.
*/
onSubmit?: VoidFunction | ((args?: any) => Promise<any>);
}
export default function AssistantForm({
assistantId,
initialData,
onSubmit,
onCancel,
location,
}: AssistantFormProps) {
const { onDirtyStateChange } = useDialog();
const { adminClient } = useAdminApolloClient();
const [insertAssistantMutation] = useInsertAssistantMutation({
client: adminClient,
});
const [updateAssistantMutation] = useUpdateAssistantMutation({
client: adminClient,
});
const form = useForm<AssistantFormValues>({
defaultValues: initialData,
reValidateMode: 'onSubmit',
resolver: yupResolver(validationSchema),
});
const {
register,
formState: { errors, isSubmitting, dirtyFields },
} = form;
const isDirty = Object.keys(dirtyFields).length > 0;
useEffect(() => {
onDirtyStateChange(isDirty, location);
}, [isDirty, location, onDirtyStateChange]);
const createOrUpdateAutoEmbeddings = async (
values: DeepRequired<AssistantFormValues> & { assistantID: string },
) => {
// remove any __typename from the form values
const payload = removeTypename(values);
if (values.webhooks.length === 0) {
delete payload.webhooks;
}
if (values.graphql.length === 0) {
delete payload.graphql;
}
// remove assistantId because the update mutation fails otherwise
delete payload.assistantID;
// If the assistantId is set then we do an update
if (assistantId) {
await updateAssistantMutation({
variables: {
id: assistantId,
data: payload,
},
});
return;
}
await insertAssistantMutation({
variables: {
data: {
...values,
},
},
});
};
const handleSubmit = async (
values: DeepRequired<AssistantFormValues> & { assistantID: string },
) => {
await execPromiseWithErrorToast(
async () => {
await createOrUpdateAutoEmbeddings(values);
onSubmit?.();
},
{
loadingMessage: 'Configuring the Assistant...',
successMessage: 'The Assistant has been configured successfully.',
errorMessage:
'An error occurred while configuring the Assistant. Please try again.',
},
);
};
return (
<FormProvider {...form}>
<Form
onSubmit={handleSubmit}
className="flex h-full flex-col overflow-hidden border-t"
>
<div className="flex flex-1 flex-col space-y-4 overflow-auto p-4">
<Input
{...register('name')}
id="name"
label={
<Box className="flex flex-row items-center space-x-2">
<Text>Name</Text>
<Tooltip title="Name of the assistant">
<InfoIcon
aria-label="Info"
className="h-4 w-4"
color="primary"
/>
</Tooltip>
</Box>
}
placeholder=""
hideEmptyHelperText
error={!!errors.name}
helperText={errors?.name?.message}
fullWidth
autoComplete="off"
autoFocus
/>
<Input
{...register('description')}
id="description"
label={
<Box className="flex flex-row items-center space-x-2">
<Text>Description</Text>
<Tooltip title={<span>Description of the assistant</span>}>
<InfoIcon
aria-label="Info"
className="h-4 w-4"
color="primary"
/>
</Tooltip>
</Box>
}
placeholder=""
hideEmptyHelperText
error={!!errors.description}
helperText={errors?.description?.message}
fullWidth
autoComplete="off"
multiline
inputProps={{
className: 'resize-y min-h-[22px]',
}}
/>
<Input
{...register('instructions')}
id="instructions"
label={
<Box className="flex flex-row items-center space-x-2">
<Text>Instructions</Text>
<Tooltip title="Instructions for the assistant. This is used to instruct the AI assistant on how to behave and respond to the user">
<InfoIcon
aria-label="Info"
className="h-4 w-4"
color="primary"
/>
</Tooltip>
</Box>
}
placeholder=""
hideEmptyHelperText
error={!!errors.instructions}
helperText={errors?.instructions?.message}
fullWidth
autoComplete="off"
multiline
inputProps={{
className: 'resize-y min-h-[22px]',
}}
/>
<Input
{...register('model')}
id="model"
label={
<Box className="flex flex-row items-center space-x-2">
<Text>Model</Text>
<Tooltip title="Model to use for the assistant.">
<InfoIcon
aria-label="Info"
className="h-4 w-4"
color="primary"
/>
</Tooltip>
</Box>
}
placeholder=""
hideEmptyHelperText
error={!!errors.model}
helperText={errors?.model?.message}
fullWidth
autoComplete="off"
autoFocus
/>
<GraphqlDataSourcesFormSection />
<WebhooksDataSourcesFormSection />
</div>
<Box className="flex w-full flex-row justify-between rounded border-t p-4">
<Button variant="outlined" color="secondary" onClick={onCancel}>
Cancel
</Button>
<Button
type="submit"
disabled={isSubmitting}
startIcon={assistantId ? <ArrowsClockwise /> : <PlusIcon />}
>
{assistantId ? 'Update' : 'Create'}
</Button>
</Box>
</Form>
</FormProvider>
);
}

View File

@@ -0,0 +1,165 @@
import { ControlledSelect } from '@/components/form/ControlledSelect';
import { ControlledSwitch } from '@/components/form/ControlledSwitch';
import { Box } from '@/components/ui/v2/Box';
import { Button } from '@/components/ui/v2/Button';
import { InfoIcon } from '@/components/ui/v2/icons/InfoIcon';
import { PlusIcon } from '@/components/ui/v2/icons/PlusIcon';
import { TrashIcon } from '@/components/ui/v2/icons/TrashIcon';
import { Input } from '@/components/ui/v2/Input';
import { Option } from '@/components/ui/v2/Option';
import { Text } from '@/components/ui/v2/Text';
import { Tooltip } from '@/components/ui/v2/Tooltip';
import { type AssistantFormValues } from '@/features/ai/AssistantForm/AssistantForm';
import { useFieldArray, useFormContext } from 'react-hook-form';
interface ArgumentsFormSectionProps {
nestedField: string;
nestIndex: number;
}
export default function ArgumentsFormSection({
nestedField,
nestIndex,
}: ArgumentsFormSectionProps) {
const form = useFormContext<AssistantFormValues>();
const {
register,
formState: { errors },
} = form;
const { fields, append, remove } = useFieldArray({
name: `${nestedField}.${nestIndex}.arguments`,
});
return (
<Box className="space-y-4">
<div className="flex flex-row items-center justify-between ">
<div className="flex flex-row items-center space-x-2">
<Text variant="h4" className="font-semibold">
Arguments
</Text>
<Tooltip title={<span>Arguments</span>}>
<InfoIcon aria-label="Info" className="h-4 w-4" color="primary" />
</Tooltip>
</div>
<Button variant="borderless" onClick={() => append({})}>
<PlusIcon className="h-5 w-5" />
</Button>
</div>
<div className="flex flex-col space-y-4">
{fields.map((field, index) => (
<Box
key={field.id}
className="flex flex-col space-y-20 rounded border-1 p-4"
sx={{ backgroundColor: 'grey.200' }}
>
<div className="flex w-full flex-col space-y-4">
<Input
// We're putting ts-ignore here so we could use the same components for both graphql and webhooks
// by passing the nestedField = 'graphql' or nestedField = 'webhooks'
{...register(
// @ts-ignore
`${nestedField}.${nestIndex}.arguments.${index}.name`,
)}
id={`${field.id}-name`}
placeholder="Name"
className="w-full"
hideEmptyHelperText
error={
!!errors?.[nestedField]?.[nestIndex]?.arguments[index].name
}
helperText={
errors?.[nestedField]?.[nestIndex]?.arguments[index]?.name
?.message
}
fullWidth
autoComplete="off"
/>
<Input
{...register(
// @ts-ignore
`${nestedField}.${nestIndex}.arguments.${index}.description`,
)}
id={`${field.id}-description`}
placeholder="Description"
className="w-full"
hideEmptyHelperText
error={
!!errors?.[nestedField]?.[nestIndex]?.arguments[index]
.description
}
helperText={
errors?.[nestedField]?.[nestIndex]?.arguments[index]
?.description?.message
}
fullWidth
autoComplete="off"
multiline
inputProps={{
className: 'resize-y min-h-[22px]',
}}
/>
<div className="flex flex-row space-x-2">
<Box className="w-full">
<ControlledSelect
fullWidth
{...register(
// @ts-ignore
`${nestedField}.${nestIndex}.arguments.${index}.type`,
)}
id={`${field.id}-type`}
placeholder="Select argument type"
slotProps={{
listbox: { className: 'min-w-0 w-full' },
popper: {
disablePortal: false,
className: 'z-[10000] w-[270px] w-full',
},
}}
>
{[
'string',
'number',
'integer',
'object',
'array',
'boolean',
]?.map((argumentType) => (
<Option key={argumentType} value={argumentType}>
{argumentType}
</Option>
))}
</ControlledSelect>
</Box>
<ControlledSwitch
{...register(
// @ts-ignore
`${nestedField}.${nestIndex}.arguments.${index}.required`,
)}
disabled={false}
label={
<Text variant="subtitle1" component="span">
Required
</Text>
}
/>
</div>
<Button
variant="borderless"
className="h-10 self-end"
color="error"
onClick={() => remove(index)}
>
<TrashIcon className="h-4 w-4" />
</Button>
</div>
</Box>
))}
</div>
</Box>
);
}

View File

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

View File

@@ -0,0 +1,123 @@
import { Box } from '@/components/ui/v2/Box';
import { Button } from '@/components/ui/v2/Button';
import { Divider } from '@/components/ui/v2/Divider';
import { InfoIcon } from '@/components/ui/v2/icons/InfoIcon';
import { PlusIcon } from '@/components/ui/v2/icons/PlusIcon';
import { TrashIcon } from '@/components/ui/v2/icons/TrashIcon';
import { Input } from '@/components/ui/v2/Input';
import { Text } from '@/components/ui/v2/Text';
import { Tooltip } from '@/components/ui/v2/Tooltip';
import { type AssistantFormValues } from '@/features/ai/AssistantForm/AssistantForm';
import { ArgumentsFormSection } from '@/features/ai/AssistantForm/components/ArgumentsFormSection';
import { useFieldArray, useFormContext } from 'react-hook-form';
export default function GraphqlDataSourcesFormSection() {
const form = useFormContext<AssistantFormValues>();
const {
register,
formState: { errors },
} = form;
const { fields, append, remove } = useFieldArray({
name: 'graphql',
});
return (
<Box className="space-y-4 rounded border-1">
<Box className="flex flex-row items-center justify-between p-4 pb-0">
<Box className="flex flex-row items-center space-x-2">
<Text variant="h4" className="font-semibold">
GraphQL
</Text>
<Tooltip title="GraphQL data sources and tools. Run against the project's GraphQL API">
<InfoIcon aria-label="Info" className="h-4 w-4" color="primary" />
</Tooltip>
</Box>
<Button
variant="borderless"
onClick={() =>
append({
name: '',
description: '',
query: '',
arguments: [],
})
}
>
<PlusIcon className="h-5 w-5" />
</Button>
</Box>
<Box className="flex flex-col space-y-4">
{fields.map((field, index) => (
<Box key={field.id} className="flex flex-col space-y-4">
<Box className="flex w-full flex-col space-y-4 p-4 pt-0">
<Input
{...register(`graphql.${index}.name`)}
id={`${field.id}-name`}
label="Name"
placeholder="Name"
className="w-full"
hideEmptyHelperText
error={!!errors?.graphql?.at(index)?.name}
helperText={errors?.graphql?.at(index)?.message}
fullWidth
autoComplete="off"
/>
<Input
{...register(`graphql.${index}.description`)}
id={`${field.id}-description`}
label="Description"
placeholder="Description"
className="w-full"
hideEmptyHelperText
error={!!errors?.graphql?.at(index)?.description}
helperText={errors?.graphql?.at(index)?.description?.message}
fullWidth
autoComplete="off"
multiline
inputProps={{
className: 'resize-y min-h-[22px]',
}}
/>
<Input
{...register(`graphql.${index}.query`)}
id={`${field.id}-query`}
label="Query"
placeholder="Query"
className="w-full"
hideEmptyHelperText
error={!!errors?.graphql?.at(index)?.query}
helperText={errors?.graphql?.at(index)?.query?.message}
fullWidth
autoComplete="off"
multiline
inputProps={{
className: 'resize-y min-h-[22px]',
}}
/>
<ArgumentsFormSection nestedField="graphql" nestIndex={index} />
<Button
variant="borderless"
className="h-10 self-end"
color="error"
onClick={() => remove(index)}
>
<TrashIcon className="h-4 w-4" />
</Button>
</Box>
{index < fields.length - 1 && (
<Divider className="h-px" sx={{ background: 'grey.200' }} />
)}
</Box>
))}
</Box>
</Box>
);
}

View File

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

View File

@@ -0,0 +1,123 @@
import { Box } from '@/components/ui/v2/Box';
import { Button } from '@/components/ui/v2/Button';
import { Divider } from '@/components/ui/v2/Divider';
import { InfoIcon } from '@/components/ui/v2/icons/InfoIcon';
import { PlusIcon } from '@/components/ui/v2/icons/PlusIcon';
import { TrashIcon } from '@/components/ui/v2/icons/TrashIcon';
import { Input } from '@/components/ui/v2/Input';
import { Text } from '@/components/ui/v2/Text';
import { Tooltip } from '@/components/ui/v2/Tooltip';
import { type AssistantFormValues } from '@/features/ai/AssistantForm/AssistantForm';
import { ArgumentsFormSection } from '@/features/ai/AssistantForm/components/ArgumentsFormSection';
import { useFieldArray, useFormContext } from 'react-hook-form';
export default function WebhooksDataSourcesFormSection() {
const form = useFormContext<AssistantFormValues>();
const {
register,
formState: { errors },
} = form;
const { fields, append, remove } = useFieldArray({
name: 'webhooks',
});
return (
<Box className="space-y-4 rounded border-1">
<Box className="flex flex-row items-center justify-between p-4">
<Box className="flex flex-row items-center space-x-2">
<Text variant="h4" className="font-semibold">
Webhooks
</Text>
<Tooltip title="Webhook data sources and tools">
<InfoIcon aria-label="Info" className="h-4 w-4" color="primary" />
</Tooltip>
</Box>
<Button
variant="borderless"
onClick={() =>
append({
name: '',
description: '',
URL: '',
arguments: [],
})
}
>
<PlusIcon className="h-5 w-5" />
</Button>
</Box>
<Box className="flex flex-col space-y-4">
{fields.map((field, index) => (
<Box key={field.id} className="flex flex-col space-y-4">
<Box className="flex w-full flex-col space-y-4 p-4 pt-0">
<Input
{...register(`webhooks.${index}.name`)}
id={`${field.id}-name`}
label="Name"
placeholder="Name"
className="w-full"
hideEmptyHelperText
error={!!errors?.webhooks?.at(index)?.name}
helperText={errors?.webhooks?.at(index)?.message}
fullWidth
autoComplete="off"
/>
<Input
{...register(`webhooks.${index}.description`)}
id={`${field.id}-description`}
label="Description"
placeholder="Description"
className="w-full"
hideEmptyHelperText
error={!!errors?.webhooks?.at(index)?.description}
helperText={errors?.webhooks?.at(index)?.description?.message}
fullWidth
autoComplete="off"
multiline
inputProps={{
className: 'resize-y min-h-[22px]',
}}
/>
<Input
{...register(`webhooks.${index}.URL`)}
id={`${field.id}-URL`}
label="URL"
placeholder="URL"
className="w-full"
hideEmptyHelperText
error={!!errors?.webhooks?.at(index)?.URL}
helperText={errors?.webhooks?.at(index)?.URL?.message}
fullWidth
autoComplete="off"
multiline
inputProps={{
className: 'resize-y min-h-[22px]',
}}
/>
<ArgumentsFormSection nestedField="webhooks" nestIndex={index} />
<Button
variant="borderless"
className="h-10 self-end"
color="error"
onClick={() => remove(index)}
>
<TrashIcon className="h-4 w-4" />
</Button>
</Box>
{index < fields.length - 1 && (
<Divider className="h-px" sx={{ background: 'grey.200' }} />
)}
</Box>
))}
</Box>
</Box>
);
}

View File

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

View File

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

View File

@@ -0,0 +1,158 @@
import { useDialog } from '@/components/common/DialogProvider';
import { Box } from '@/components/ui/v2/Box';
import { Divider } from '@/components/ui/v2/Divider';
import { Dropdown } from '@/components/ui/v2/Dropdown';
import { IconButton } from '@/components/ui/v2/IconButton';
import { CopyIcon } from '@/components/ui/v2/icons/CopyIcon';
import { DotsHorizontalIcon } from '@/components/ui/v2/icons/DotsHorizontalIcon';
import { TrashIcon } from '@/components/ui/v2/icons/TrashIcon';
import { UserIcon } from '@/components/ui/v2/icons/UserIcon';
import { Text } from '@/components/ui/v2/Text';
import { AssistantForm } from '@/features/ai/AssistantForm';
import { DeleteAssistantModal } from '@/features/ai/DeleteAssistantModal';
import { copy } from '@/utils/copy';
import { type Assistant } from 'pages/[workspaceSlug]/[appSlug]/ai/assistants';
interface AssistantsListProps {
/**
* The run services fetched from entering the users page.
*/
assistants: Assistant[];
/**
* Function to be called after a submitting the form for either creating or updating a service.
*
* @example onDelete={() => refetch()}
*/
onCreateOrUpdate?: () => Promise<any>;
/**
* Function to be called after a successful delete action.
*
*/
onDelete?: () => Promise<any>;
}
export default function AssistantsList({
assistants,
onCreateOrUpdate,
onDelete,
}: AssistantsListProps) {
const { openDrawer, openDialog, closeDialog } = useDialog();
const viewAssistant = async (assistant: Assistant) => {
openDrawer({
title: `Edit ${assistant?.name ?? 'unset'}`,
component: (
<AssistantForm
assistantId={assistant.assistantID}
initialData={{
...assistant,
}}
onSubmit={() => onCreateOrUpdate()}
/>
),
});
};
const deleteAssistant = async (assistant: Assistant) => {
openDialog({
component: (
<DeleteAssistantModal
assistant={assistant}
close={closeDialog}
onDelete={onDelete}
/>
),
});
};
return (
<Box className="flex flex-col">
{assistants.map((assistant) => (
<Box
key={assistant.assistantID}
className="flex h-[64px] w-full cursor-pointer items-center justify-between space-x-4 border-b-1 px-4 py-2 transition-colors"
sx={{
[`&:hover`]: {
backgroundColor: 'action.hover',
},
}}
>
<Box
onClick={() => viewAssistant(assistant)}
className="flex w-full flex-row justify-between"
sx={{ backgroundColor: 'transparent' }}
>
<div className="flex flex-1 flex-row items-center space-x-4">
<span className="text-3xl">🤖</span>
<div className="flex flex-col">
<Text variant="h4" className="font-semibold">
{assistant?.name ?? 'unset'}
</Text>
<div className="hidden flex-row items-center space-x-2 md:flex">
<Text variant="subtitle1" className="font-mono text-xs">
{assistant.assistantID}
</Text>
<IconButton
variant="borderless"
color="secondary"
onClick={(event) => {
copy(assistant.assistantID, 'Assistant Id');
event.stopPropagation();
}}
aria-label="Service Id"
>
<CopyIcon className="h-4 w-4" />
</IconButton>
</div>
</div>
</div>
</Box>
<Dropdown.Root>
<Dropdown.Trigger
asChild
hideChevron
onClick={(event) => event.stopPropagation()}
>
<IconButton
variant="borderless"
color="secondary"
aria-label="More options"
onClick={(event) => event.stopPropagation()}
>
<DotsHorizontalIcon />
</IconButton>
</Dropdown.Trigger>
<Dropdown.Content
menu
PaperProps={{ className: 'w-auto' }}
anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
transformOrigin={{ vertical: 'top', horizontal: 'right' }}
>
<Dropdown.Item
onClick={() => viewAssistant(assistant)}
className="z-50 grid grid-flow-col items-center gap-2 p-2 text-sm+ font-medium"
>
<UserIcon className="h-4 w-4" />
<Text className="font-medium">View {assistant?.name}</Text>
</Dropdown.Item>
<Divider component="li" />
<Dropdown.Item
className="grid grid-flow-col items-center gap-2 p-2 text-sm+ font-medium"
sx={{ color: 'error.main' }}
onClick={() => deleteAssistant(assistant)}
>
<TrashIcon className="h-4 w-4" />
<Text className="font-medium" color="error">
Delete {assistant?.name}
</Text>
</Dropdown.Item>
</Dropdown.Content>
</Dropdown.Root>
</Box>
))}
</Box>
);
}

View File

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

View File

@@ -0,0 +1,289 @@
import { useDialog } from '@/components/common/DialogProvider';
import { Form } from '@/components/form/Form';
import { Box } from '@/components/ui/v2/Box';
import { Button } from '@/components/ui/v2/Button';
import { ArrowsClockwise } from '@/components/ui/v2/icons/ArrowsClockwise';
import { InfoIcon } from '@/components/ui/v2/icons/InfoIcon';
import { PlusIcon } from '@/components/ui/v2/icons/PlusIcon';
import { Input } from '@/components/ui/v2/Input';
import { Text } from '@/components/ui/v2/Text';
import { Tooltip } from '@/components/ui/v2/Tooltip';
import { useAdminApolloClient } from '@/features/projects/common/hooks/useAdminApolloClient';
import type { DialogFormProps } from '@/types/common';
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import {
useInsertGraphiteAutoEmbeddingsConfigurationMutation,
useUpdateGraphiteAutoEmbeddingsConfigurationMutation,
} from '@/utils/__generated__/graphite.graphql';
import { yupResolver } from '@hookform/resolvers/yup';
import { useEffect } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import * as Yup from 'yup';
export const validationSchema = Yup.object({
name: Yup.string().required('The name is required.'),
schemaName: Yup.string().required('The schema is required'),
tableName: Yup.string().required('The table is required'),
columnName: Yup.string().required('The column is required'),
query: Yup.string(),
mutation: Yup.string(),
});
export type AutoEmbeddingsFormValues = Yup.InferType<typeof validationSchema>;
export interface AutoEmbeddingsFormProps extends DialogFormProps {
/**
* To use in conjunction with initialData to allow for updating the autoEmbeddingsConfiguration
*/
autoEmbeddingsId?: string;
/**
* if there is initialData then it's an update operation
*/
initialData?: AutoEmbeddingsFormValues;
/**
* Function to be called when the operation is cancelled.
*/
onCancel?: VoidFunction;
/**
* Function to be called when the submit is successful.
*/
onSubmit?: VoidFunction | ((args?: any) => Promise<any>);
}
export default function AutoEmbeddingsForm({
autoEmbeddingsId,
initialData,
onSubmit,
onCancel,
location,
}: AutoEmbeddingsFormProps) {
const { onDirtyStateChange } = useDialog();
const { adminClient } = useAdminApolloClient();
const [insertGraphiteAutoEmbeddingsConfiguration] =
useInsertGraphiteAutoEmbeddingsConfigurationMutation({
client: adminClient,
});
const [updateGraphiteAutoEmbeddingsConfiguration] =
useUpdateGraphiteAutoEmbeddingsConfigurationMutation({
client: adminClient,
});
const form = useForm<AutoEmbeddingsFormValues>({
defaultValues: initialData,
reValidateMode: 'onSubmit',
resolver: yupResolver(validationSchema),
});
const {
register,
formState: { errors, isSubmitting, dirtyFields },
} = form;
const isDirty = Object.keys(dirtyFields).length > 0;
useEffect(() => {
onDirtyStateChange(isDirty, location);
}, [isDirty, location, onDirtyStateChange]);
const createOrUpdateAutoEmbeddings = async (
values: AutoEmbeddingsFormValues,
) => {
// If the autoEmbeddingsId is set then we do an update
if (autoEmbeddingsId) {
await updateGraphiteAutoEmbeddingsConfiguration({
variables: {
id: autoEmbeddingsId,
...values,
},
});
return;
}
await insertGraphiteAutoEmbeddingsConfiguration({
variables: values,
});
};
const handleSubmit = async (values: AutoEmbeddingsFormValues) => {
await execPromiseWithErrorToast(
async () => {
await createOrUpdateAutoEmbeddings(values);
onSubmit?.();
},
{
loadingMessage: 'Configuring the Auto-Embeddings...',
successMessage: 'The Auto-Embeddings has been configured successfully.',
errorMessage:
'An error occurred while configuring the Auto-Embeddings. Please try again.',
},
);
};
return (
<FormProvider {...form}>
<Form
onSubmit={handleSubmit}
className="flex h-full flex-col gap-4 overflow-hidden"
>
<div className="flex flex-1 flex-col space-y-6 overflow-auto px-6">
<Input
{...register('name')}
id="name"
label={
<Box className="flex flex-row items-center space-x-2">
<Text>Name</Text>
<Tooltip title="Name of the Auto-Embeddings">
<InfoIcon
aria-label="Info"
className="h-4 w-4"
color="primary"
/>
</Tooltip>
</Box>
}
placeholder=""
hideEmptyHelperText
error={!!errors.name}
helperText={errors?.name?.message}
fullWidth
autoComplete="off"
autoFocus
/>
<Input
{...register('schemaName')}
id="schemaName"
label={
<Box className="flex flex-row items-center space-x-2">
<Text>Schema</Text>
<Tooltip title={<span>Schema where the table belongs to</span>}>
<InfoIcon
aria-label="Info"
className="h-4 w-4"
color="primary"
/>
</Tooltip>
</Box>
}
placeholder=""
hideEmptyHelperText
error={!!errors.schemaName}
helperText={errors?.schemaName?.message}
fullWidth
autoComplete="off"
/>
<Input
{...register('tableName')}
id="tableName"
label={
<Box className="flex flex-row items-center space-x-2">
<Text>Table</Text>
<Tooltip title="Table Name">
<InfoIcon
aria-label="Info"
className="h-4 w-4"
color="primary"
/>
</Tooltip>
</Box>
}
placeholder=""
hideEmptyHelperText
error={!!errors.tableName}
helperText={errors?.tableName?.message}
fullWidth
autoComplete="off"
/>
<Input
{...register('columnName')}
id="columnName"
label={
<Box className="flex flex-row items-center space-x-2">
<Text>Column</Text>
<Tooltip title="Column name">
<InfoIcon
aria-label="Info"
className="h-4 w-4"
color="primary"
/>
</Tooltip>
</Box>
}
placeholder=""
hideEmptyHelperText
error={!!errors.columnName}
helperText={errors?.columnName?.message}
fullWidth
autoComplete="off"
/>
<Input
{...register('query')}
id="query"
label={
<Box className="flex flex-row items-center space-x-2">
<Text>Query</Text>
<Tooltip title="Query">
<InfoIcon
aria-label="Info"
className="h-4 w-4"
color="primary"
/>
</Tooltip>
</Box>
}
placeholder=""
hideEmptyHelperText
error={!!errors.query}
helperText={errors?.query?.message}
fullWidth
autoComplete="off"
multiline
rows={6}
/>
<Input
{...register('mutation')}
id="mutation"
label={
<Box className="flex flex-row items-center space-x-2">
<Text>Mutation</Text>
<Tooltip title="Mutation">
<InfoIcon
aria-label="Info"
className="h-4 w-4"
color="primary"
/>
</Tooltip>
</Box>
}
placeholder=""
hideEmptyHelperText
error={!!errors.mutation}
helperText={errors?.mutation?.message}
fullWidth
autoComplete="off"
multiline
rows={6}
/>
</div>
<Box className="flex w-full flex-row justify-between rounded border-t px-6 py-4">
<Button variant="outlined" color="secondary" onClick={onCancel}>
Cancel
</Button>
<Button
type="submit"
disabled={isSubmitting}
startIcon={autoEmbeddingsId ? <ArrowsClockwise /> : <PlusIcon />}
>
{autoEmbeddingsId ? 'Update' : 'Create'}
</Button>
</Box>
</Form>
</FormProvider>
);
}

View File

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

View File

@@ -0,0 +1,172 @@
import { useDialog } from '@/components/common/DialogProvider';
import { Box } from '@/components/ui/v2/Box';
import { Divider } from '@/components/ui/v2/Divider';
import { Dropdown } from '@/components/ui/v2/Dropdown';
import { IconButton } from '@/components/ui/v2/IconButton';
import { CubeIcon } from '@/components/ui/v2/icons/CubeIcon';
import { DotsHorizontalIcon } from '@/components/ui/v2/icons/DotsHorizontalIcon';
import { EmbeddingsIcon } from '@/components/ui/v2/icons/EmbeddingsIcon';
import { TrashIcon } from '@/components/ui/v2/icons/TrashIcon';
import { UserIcon } from '@/components/ui/v2/icons/UserIcon';
import { Text } from '@/components/ui/v2/Text';
import { Tooltip } from '@/components/ui/v2/Tooltip';
import { AutoEmbeddingsForm } from '@/features/ai/AutoEmbeddingsForm';
import { DeleteAutoEmbeddingsModal } from '@/features/ai/DeleteAutoEmbeddingsModal';
import { formatDistanceToNow } from 'date-fns';
import type { AutoEmbeddingsConfiguration } from 'pages/[workspaceSlug]/[appSlug]/ai/auto-embeddings';
interface AutoEmbeddingsConfigurationsListProps {
/**
* The run services fetched from entering the users page.
*/
autoEmbeddingsConfigurations: AutoEmbeddingsConfiguration[];
/**
* Function to be called after a submitting the form for either creating or updating a service.
*
* @example onDelete={() => refetch()}
*/
onCreateOrUpdate?: () => Promise<any>;
/**
* Function to be called after a successful delete action.
*
*/
onDelete?: () => Promise<any>;
}
export default function AutoEmbeddingsList({
autoEmbeddingsConfigurations,
onCreateOrUpdate,
onDelete,
}: AutoEmbeddingsConfigurationsListProps) {
const { openDrawer, openDialog, closeDialog } = useDialog();
const viewAutoEmbeddingsConfiguration = async (
autoEmbeddingsConfiguration: AutoEmbeddingsConfiguration,
) => {
openDrawer({
title: (
<Box className="flex flex-row items-center space-x-2">
<CubeIcon className="h-5 w-5" />
<Text>Edit {autoEmbeddingsConfiguration?.name ?? 'unset'}</Text>
</Box>
),
component: (
<AutoEmbeddingsForm
autoEmbeddingsId={autoEmbeddingsConfiguration.id}
initialData={{
...autoEmbeddingsConfiguration,
}}
onSubmit={() => onCreateOrUpdate()}
/>
),
});
};
const deleteAutoEmbeddingsConfiguration = async (
autoEmbeddingsConfiguration: AutoEmbeddingsConfiguration,
) => {
openDialog({
component: (
<DeleteAutoEmbeddingsModal
autoEmbeddingsConfiguration={autoEmbeddingsConfiguration}
close={closeDialog}
onDelete={onDelete}
/>
),
});
};
return (
<Box className="flex flex-col">
{autoEmbeddingsConfigurations.map((autoEmbeddingsConfiguration) => (
<Box
key={autoEmbeddingsConfiguration.id}
className="flex h-[64px] w-full cursor-pointer items-center justify-between space-x-4 border-b-1 px-4 py-2 transition-colors"
sx={{
[`&:hover`]: {
backgroundColor: 'action.hover',
},
}}
>
<Box
onClick={() =>
viewAutoEmbeddingsConfiguration(autoEmbeddingsConfiguration)
}
className="flex w-full flex-row justify-between"
sx={{
backgroundColor: 'transparent',
}}
>
<div className="flex flex-1 flex-row items-center space-x-4">
<EmbeddingsIcon className="h-5 w-5" />
<div className="flex flex-col">
<Text variant="h4" className="font-semibold">
{autoEmbeddingsConfiguration?.name ?? 'unset'}
</Text>
<Tooltip title={autoEmbeddingsConfiguration.updatedAt}>
<span className="hidden cursor-pointer text-sm text-slate-500 xs+:flex">
Updated{' '}
{formatDistanceToNow(
new Date(autoEmbeddingsConfiguration.updatedAt),
)}{' '}
ago
</span>
</Tooltip>
</div>
</div>
</Box>
<Dropdown.Root>
<Dropdown.Trigger
asChild
hideChevron
onClick={(event) => event.stopPropagation()}
>
<IconButton
variant="borderless"
color="secondary"
aria-label="More options"
onClick={(event) => event.stopPropagation()}
>
<DotsHorizontalIcon />
</IconButton>
</Dropdown.Trigger>
<Dropdown.Content
menu
PaperProps={{ className: 'w-auto' }}
anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
transformOrigin={{ vertical: 'top', horizontal: 'right' }}
>
<Dropdown.Item
onClick={() =>
viewAutoEmbeddingsConfiguration(autoEmbeddingsConfiguration)
}
className="z-50 grid grid-flow-col items-center gap-2 p-2 text-sm+ font-medium"
>
<UserIcon className="h-4 w-4" />
<Text className="font-medium">
View {autoEmbeddingsConfiguration?.name}
</Text>
</Dropdown.Item>
<Divider component="li" />
<Dropdown.Item
className="grid grid-flow-col items-center gap-2 p-2 text-sm+ font-medium"
sx={{ color: 'error.main' }}
onClick={() =>
deleteAutoEmbeddingsConfiguration(autoEmbeddingsConfiguration)
}
>
<TrashIcon className="h-4 w-4" />
<Text className="font-medium" color="error">
Delete {autoEmbeddingsConfiguration?.name}
</Text>
</Dropdown.Item>
</Dropdown.Content>
</Dropdown.Root>
</Box>
))}
</Box>
);
}

View File

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

View File

@@ -0,0 +1,100 @@
import { Box } from '@/components/ui/v2/Box';
import { Button } from '@/components/ui/v2/Button';
import { Checkbox } from '@/components/ui/v2/Checkbox';
import { Text } from '@/components/ui/v2/Text';
import { useAdminApolloClient } from '@/features/projects/common/hooks/useAdminApolloClient';
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { useDeleteAssistantMutation } from '@/utils/__generated__/graphite.graphql';
import { type Assistant } from 'pages/[workspaceSlug]/[appSlug]/ai/assistants';
import { useState } from 'react';
import { twMerge } from 'tailwind-merge';
export interface DeleteAssistantModalProps {
assistant: Assistant;
onDelete?: () => Promise<any>;
close: () => void;
}
export default function DeleteAssistantModal({
assistant,
onDelete,
close,
}: DeleteAssistantModalProps) {
const [remove, setRemove] = useState(false);
const [loadingRemove, setLoadingRemove] = useState(false);
const { adminClient } = useAdminApolloClient();
const [deleteAssistantMutation] = useDeleteAssistantMutation({
client: adminClient,
});
const deleteAssistant = async () => {
await deleteAssistantMutation({
variables: {
id: assistant.assistantID,
},
});
await onDelete?.();
close();
};
async function handleClick() {
setLoadingRemove(true);
await execPromiseWithErrorToast(deleteAssistant, {
loadingMessage: 'Deleting the assistant...',
successMessage: 'The Assistant has been deleted successfully.',
errorMessage:
'An error occurred while deleting the Assistant. Please try again.',
});
}
return (
<Box className={twMerge('w-full rounded-lg p-6 text-left')}>
<div className="grid grid-flow-row gap-1">
<Text variant="h3" component="h2">
Delete Assistant {assistant?.name}
</Text>
<Text variant="subtitle2">
Are you sure you want to delete this Assistant?
</Text>
<Text
variant="subtitle2"
className="font-bold"
sx={{ color: (theme) => `${theme.palette.error.main} !important` }}
>
This cannot be undone.
</Text>
<Box className="my-4">
<Checkbox
id="accept-1"
label={`I'm sure I want to delete ${assistant?.name}`}
className="py-2"
checked={remove}
onChange={(_event, checked) => setRemove(checked)}
aria-label="Confirm Delete Assistant"
/>
</Box>
<div className="grid grid-flow-row gap-2">
<Button
color="error"
onClick={handleClick}
disabled={!remove}
loading={loadingRemove}
>
Delete Assistant
</Button>
<Button variant="outlined" color="secondary" onClick={close}>
Cancel
</Button>
</div>
</div>
</Box>
);
}

View File

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

View File

@@ -0,0 +1,125 @@
import { Box } from '@/components/ui/v2/Box';
import { Button } from '@/components/ui/v2/Button';
import { Checkbox } from '@/components/ui/v2/Checkbox';
import { Text } from '@/components/ui/v2/Text';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
import { getHasuraAdminSecret } from '@/utils/env';
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { useDeleteGraphiteAutoEmbeddingsConfigurationMutation } from '@/utils/__generated__/graphite.graphql';
import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client';
import { type AutoEmbeddingsConfiguration } from 'pages/[workspaceSlug]/[appSlug]/ai/auto-embeddings';
import { useState } from 'react';
import { twMerge } from 'tailwind-merge';
export interface DeleteAutoEmbeddingsModalProps {
autoEmbeddingsConfiguration: AutoEmbeddingsConfiguration;
onDelete?: () => Promise<any>;
close: () => void;
}
export default function DeleteAutoEmbeddingsModal({
autoEmbeddingsConfiguration,
onDelete,
close,
}: DeleteAutoEmbeddingsModalProps) {
const [remove, setRemove] = useState(false);
const [loadingRemove, setLoadingRemove] = useState(false);
const { currentProject } = useCurrentWorkspaceAndProject();
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 [deleteAutoEmbeddingsConfiguration] =
useDeleteGraphiteAutoEmbeddingsConfigurationMutation({
client,
});
const deleteAutoEmbeddingsConfig = async () => {
await deleteAutoEmbeddingsConfiguration({
variables: {
id: autoEmbeddingsConfiguration.id,
},
});
await onDelete?.();
close();
};
async function handleClick() {
setLoadingRemove(true);
await execPromiseWithErrorToast(deleteAutoEmbeddingsConfig, {
loadingMessage: 'Deleting Auto-Embeddings Configuration...',
successMessage:
'The Auto-Embeddings Configuration has been deleted successfully.',
errorMessage:
'An error occurred while deleting the Auto-Embeddings Configuration. Please try again.',
});
}
return (
<Box className={twMerge('w-full rounded-lg p-6 text-left')}>
<div className="grid grid-flow-row gap-1">
<Text variant="h3" component="h2">
Delete Auto-Embeddings Configuration{' '}
{autoEmbeddingsConfiguration?.name}
</Text>
<Text variant="subtitle2">
Are you sure you want to delete this Auto-Embeddings Configuration?
</Text>
<Text
variant="subtitle2"
className="font-bold"
sx={{ color: (theme) => `${theme.palette.error.main} !important` }}
>
This cannot be undone.
</Text>
<Box className="my-4">
<Checkbox
id="accept-1"
label={`I'm sure I want to delete ${autoEmbeddingsConfiguration?.name}`}
className="py-2"
checked={remove}
onChange={(_event, checked) => setRemove(checked)}
aria-label="Confirm Delete Auto-Embeddings Configuration"
/>
</Box>
<div className="grid grid-flow-row gap-2">
<Button
color="error"
onClick={handleClick}
disabled={!remove}
loading={loadingRemove}
>
Delete Auto-Embeddings Configuration
</Button>
<Button variant="outlined" color="secondary" onClick={close}>
Cancel
</Button>
</div>
</div>
</Box>
);
}

View File

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

View File

@@ -0,0 +1,235 @@
import { UpgradeToProBanner } from '@/components/common/UpgradeToProBanner';
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
import { Alert } from '@/components/ui/v2/Alert';
import { Box } from '@/components/ui/v2/Box';
import { ErrorToast } from '@/components/ui/v2/ErrorToast';
import { IconButton } from '@/components/ui/v2/IconButton';
import { ArrowUpIcon } from '@/components/ui/v2/icons/ArrowUpIcon';
import { Input } from '@/components/ui/v2/Input';
import { Link } from '@/components/ui/v2/Link';
import { Text } from '@/components/ui/v2/Text';
import { MessagesList } from '@/features/ai/DevAssistant/components/MessagesList';
import {
messagesState,
projectMessagesState,
sessionIDState,
} from '@/features/ai/DevAssistant/state';
import { useAdminApolloClient } from '@/features/projects/common/hooks/useAdminApolloClient';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
import { useIsGraphiteEnabled } from '@/features/projects/common/hooks/useIsGraphiteEnabled';
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
import {
useSendDevMessageMutation,
useStartDevSessionMutation,
type SendDevMessageMutation,
} from '@/utils/__generated__/graphite.graphql';
import { useState } from 'react';
import { toast } from 'react-hot-toast';
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
const MAX_THREAD_LENGTH = 50;
export type Message = Omit<
SendDevMessageMutation['graphite']['sendDevMessage']['messages'][0],
'__typename'
>;
export default function DevAssistant() {
const isPlatform = useIsPlatform();
const { currentProject, currentWorkspace } = useCurrentWorkspaceAndProject();
const [loading, setLoading] = useState(false);
const [userInput, setUserInput] = useState('');
const setMessages = useSetRecoilState(messagesState);
const messages = useRecoilValue(projectMessagesState(currentProject.id));
const [storedSessionID, setStoredSessionID] = useRecoilState(sessionIDState);
const { adminClient } = useAdminApolloClient();
const [startDevSession] = useStartDevSessionMutation({ client: adminClient });
const [sendDevMessage] = useSendDevMessageMutation({ client: adminClient });
const { isGraphiteEnabled } = useIsGraphiteEnabled();
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
try {
setLoading(true);
setUserInput('');
let sessionID = storedSessionID;
const lastMessage = messages.slice(1).pop(); // The first message is a welcome message, so we exclude it
let hasBeenAnHourSinceLastMessage = false;
if (lastMessage) {
hasBeenAnHourSinceLastMessage =
new Date().getTime() - new Date(lastMessage.createdAt).getTime() >
60 * 60 * 1000;
}
const $messages = [
...messages,
{
id: String(new Date().getTime()),
message: userInput,
createdAt: null,
role: 'user',
projectId: currentProject.id,
},
];
setMessages($messages);
if (!sessionID || hasBeenAnHourSinceLastMessage) {
const sessionRes = await startDevSession({ client: adminClient });
sessionID = sessionRes?.data?.graphite?.startDevSession?.sessionID;
setStoredSessionID(sessionID);
}
if (!sessionID) {
throw new Error('Failed to start a new session');
}
const {
data: {
graphite: { sendDevMessage: { messages: newMessages } = {} } = {},
} = {},
} = await sendDevMessage({
variables: {
message: userInput,
sessionId: sessionID || '',
prevMessageID: !hasBeenAnHourSinceLastMessage
? lastMessage?.id || ''
: '',
},
});
let thread = [
// remove the temp messages of the user input while we wait for the dev assistant to respond
...$messages.filter((item) => item.createdAt),
...newMessages
// remove empty messages
.filter((item) => item.message)
// add the currentProject.id to the new messages
.map((item) => ({ ...item, projectId: currentProject.id })),
];
if (thread.length > MAX_THREAD_LENGTH) {
thread = thread.slice(thread.length - MAX_THREAD_LENGTH); // keep the thread at a max length of MAX_THREAD_LENGTH
}
setMessages(thread);
} catch (error) {
toast.custom(
(t) => (
<ErrorToast
isVisible={t.visible}
errorMessage="Failed to send the message. Please try again later."
error={error}
close={() => toast.dismiss()}
/>
),
{
duration: Number.POSITIVE_INFINITY,
},
);
} finally {
setLoading(false);
}
};
const handleKeyPress = (event: React.KeyboardEvent<HTMLInputElement>) => {
if (event.key === 'Enter' && !event.shiftKey) {
event.preventDefault();
const form = event.currentTarget.closest('form');
if (form) {
form.dispatchEvent(
new Event('submit', { bubbles: true, cancelable: true }),
);
}
}
};
if (isPlatform && currentProject?.plan?.isFree) {
return (
<Box className="p-4">
<UpgradeToProBanner
title="Upgrade to Nhost Pro."
description={
<Text>
Graphite is an addon to the Pro plan. To unlock it, please upgrade
to Pro first.
</Text>
}
/>
</Box>
);
}
if (
(isPlatform &&
!currentProject?.plan?.isFree &&
!currentProject.config?.ai) ||
!isGraphiteEnabled
) {
return (
<Box className="p-4">
<Alert className="grid w-full grid-flow-col place-content-between items-center gap-2">
<Text className="grid grid-flow-row justify-items-start gap-0.5">
<Text component="span">
To enable graphite, configure the service first in{' '}
<Link
href={`/${currentWorkspace.slug}/${currentProject.slug}/settings/ai`}
target="_blank"
rel="noopener noreferrer"
underline="hover"
>
AI Settings
</Link>
.
</Text>
</Text>
</Alert>
</Box>
);
}
return (
<div className="flex h-full flex-col overflow-auto">
<MessagesList loading={loading} />
<form onSubmit={handleSubmit}>
<Box className="relative flex w-full flex-row justify-between p-2">
<Input
value={userInput}
onChange={(event) => {
const { value } = event.target;
setUserInput(value);
}}
onKeyPress={handleKeyPress}
placeholder="Ask graphite anything!"
className="w-full"
required
slotProps={{
input: { className: 'w-full rounded-none border-none' },
}}
multiline
maxRows={7}
/>
<IconButton
disabled={!userInput || loading}
color="primary"
aria-label="Send"
type="submit"
className="absolute right-2 h-10 w-12 self-end rounded-xl"
>
{loading ? <ActivityIndicator /> : <ArrowUpIcon />}
</IconButton>
</Box>
</form>
</div>
);
}

View File

@@ -0,0 +1,28 @@
import { Box } from '@/components/ui/v2/Box';
import { GraphiteIcon } from '@/components/ui/v2/icons/GraphiteIcon';
import { Text } from '@/components/ui/v2/Text';
export default function LoadingAssistantMessage() {
return (
<Box className="flex flex-col space-y-4 border-t p-4">
<div className="flex items-center space-x-2">
<GraphiteIcon />
<Text className="font-bold">Assistant</Text>
</div>
<div className="flex space-x-1">
<Box
className="h-1.5 w-1.5 animate-blinking rounded-full"
sx={{ backgroundColor: 'grey.600' }}
/>
<Box
className="h-1.5 w-1.5 animate-blinking rounded-full animate-delay-150"
sx={{ backgroundColor: 'grey.600' }}
/>
<Box
className="h-1.5 w-1.5 animate-blinking rounded-full animate-delay-300"
sx={{ backgroundColor: 'grey.600' }}
/>
</div>
</Box>
);
}

View File

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

View File

@@ -0,0 +1,98 @@
import { Avatar } from '@/components/ui/v2/Avatar';
import { Box } from '@/components/ui/v2/Box';
import { IconButton } from '@/components/ui/v2/IconButton';
import { CopyIcon } from '@/components/ui/v2/icons/CopyIcon';
import { GraphiteIcon } from '@/components/ui/v2/icons/GraphiteIcon';
import { Text } from '@/components/ui/v2/Text';
import { type Message } from '@/features/ai/DevAssistant';
import { copy } from '@/utils/copy';
import { useTheme } from '@mui/material';
import { useUserData } from '@nhost/nextjs';
import { onlyText } from 'react-children-utilities';
import Markdown, { type ExtraProps } from 'react-markdown';
import rehypeHighlight from 'rehype-highlight';
import remarkGFM from 'remark-gfm';
import { twMerge } from 'tailwind-merge';
import { type ClassAttributes, type HTMLAttributes } from 'react';
function PreComponent(
props: ClassAttributes<HTMLElement> &
HTMLAttributes<HTMLElement> &
ExtraProps,
) {
const { children } = props;
return (
<div className="relative group">
<pre>{children}</pre>
<IconButton
sx={{
minWidth: 0,
padding: 0.5,
backgroundColor: 'grey.100',
}}
color="warning"
variant="contained"
className="absolute hidden top-2 right-2 group-hover:flex"
onClick={(e) => {
e.stopPropagation();
copy(onlyText(children), 'Snippet');
}}
>
<CopyIcon className="w-5 h-5" />
</IconButton>
</div>
);
}
export default function MessageBox({ message }: { message: Message }) {
const theme = useTheme();
const user = useUserData();
const isUserMessage = message.role === 'user';
return (
<Box
className="flex flex-col p-4 space-y-4 border-t first:border-t-0"
sx={{
backgroundColor: isUserMessage && 'background.default',
}}
>
<div className="flex items-center space-x-2">
{message.role === 'assistant' ? (
<>
<GraphiteIcon />
<Text className="font-bold">Assistant</Text>
</>
) : (
<>
<Avatar
className="rounded-full h-7 w-7"
alt={user?.displayName}
src={user?.avatarUrl}
>
{user?.displayName || 'local'}
</Avatar>
<Text className="font-bold">
{user?.displayName || 'local'} (You)
</Text>
</>
)}
</div>
<Markdown
className={twMerge(
'prose',
theme.palette.mode === 'dark' && 'prose-invert',
)}
rehypePlugins={[rehypeHighlight]}
remarkPlugins={[remarkGFM]}
components={{
pre: PreComponent,
}}
>
{message.message}
</Markdown>
</Box>
);
}

View File

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

View File

@@ -0,0 +1,36 @@
import { Box } from '@/components/ui/v2/Box';
import { LoadingAssistantMessage } from '@/features/ai/DevAssistant/components/LoadingAssistantMessage';
import { MessageBox } from '@/features/ai/DevAssistant/components/MessageBox';
import { projectMessagesState } from '@/features/ai/DevAssistant/state';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
import { memo, useEffect, useRef } from 'react';
import { useRecoilValue } from 'recoil';
interface MessagesListProps {
loading: boolean;
}
function MessagesList({ loading }: MessagesListProps) {
const bottomElement = useRef(null);
const { currentProject } = useCurrentWorkspaceAndProject();
const messages = useRecoilValue(projectMessagesState(currentProject.id));
const scrollToBottom = () =>
bottomElement?.current?.scrollIntoView({ behavior: 'instant' });
useEffect(() => {
scrollToBottom();
}, [messages, loading]);
return (
<Box className="flex grow flex-col overflow-auto border-y">
{messages.map((message) => (
<MessageBox key={message.id} message={message} />
))}
{loading && <LoadingAssistantMessage />}
<div ref={bottomElement} />
</Box>
);
}
export default memo(MessagesList);

View File

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

View File

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

View File

@@ -0,0 +1,5 @@
export * from './messages';
export { default as messagesState } from './messages';
// eslint-disable-next-line import/no-cycle
export { default as projectMessagesState } from './projectMessages';
export { default as sessionIDState } from './session';

View File

@@ -0,0 +1,23 @@
import { type Message } from '@/features/ai/DevAssistant';
import { persistAtom } from '@/utils/recoil';
import { atom } from 'recoil';
export interface ProjectMessage extends Message {
projectId?: string;
}
const messagesState = atom<ProjectMessage[]>({
key: 'messages',
default: [
{
id: '0',
message:
"Hi, I'm your personal Nhost AI assistant. I'm here to help answer questions, assist with tasks, provide information, or just have a conversation about GraphQL!",
role: 'assistant',
createdAt: new Date().toISOString(),
},
],
effects: [persistAtom],
});
export default messagesState;

View File

@@ -0,0 +1,20 @@
import messagesState, {
type ProjectMessage,
} from '@/features/ai/DevAssistant/state/messages';
import { selectorFamily } from 'recoil';
const projectMessagesState = selectorFamily<ProjectMessage[], string>({
key: 'projectMessages',
get:
(projectId) =>
({ get }) => {
const messages = get(messagesState);
return messages.filter(
(message) =>
message.projectId === projectId || message.projectId === undefined,
);
},
});
export default projectMessagesState;

View File

@@ -0,0 +1,10 @@
import { persistAtom } from '@/utils/recoil';
import { atom } from 'recoil';
const sessionIDState = atom<string>({
key: 'sessionID',
default: '',
effects: [persistAtom],
});
export default sessionIDState;

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