Compare commits

...

81 Commits

Author SHA1 Message Date
Pilou
a402fc17de Merge pull request #1192 from nhost/changeset-release/main
chore: update versions
2022-11-24 17:21:07 +01:00
github-actions[bot]
de0a125e98 chore: update versions 2022-11-24 09:38:59 +00:00
Pilou
ea1ad29031 Merge pull request #1200 from nhost/plmercereau-patch-storage-tag
Update docker-compose.yaml
2022-11-24 10:37:25 +01:00
Szilárd Dóró
3da40e5712 Merge pull request #1205 from nhost/fix/dashboard-meta
fix(dashboard): update terminology
2022-11-24 10:35:48 +01:00
Szilárd Dóró
b9087a4add fix(dashboard): console / dashboard terminology 2022-11-24 09:54:44 +01:00
Szilárd Dóró
1b7a6d0252 fix(dashboard): update terminology 2022-11-24 09:23:08 +01:00
Szilárd Dóró
1417d3e794 Merge pull request #1203 from nhost/contributors-readme-action-FFIU1CawPP
contributors readme action update
2022-11-24 08:55:41 +01:00
github-actions[bot]
e187923858 contrib-readme-action has updated readme 2022-11-24 07:52:33 +00:00
Johan Eliasson
8a60ed4074 Merge pull request #1199 from nhost/functions-more-examples
examples(serverless-functions): smtp + async/await
2022-11-24 08:52:19 +01:00
Pilou
d7d11a44a7 Update docker-compose.yaml
There's no latest tag on storage
2022-11-23 22:04:40 +01:00
Johan Eliasson
062e4691cd added examples 2022-11-23 21:53:25 +01:00
Pilou
a95d49fa2c Merge pull request #1197 from nhost/docs/custom-claims-singleton-array
docs: custom claims and singleton arrays
2022-11-23 19:06:34 +01:00
Johan Eliasson
d14fc96899 Merge pull request #1036 from ejkkan/feat/add-charges-to-stripe-package
feat(stripe-graphql-js): add charges, payment intents and connected accounts
2022-11-23 19:03:37 +01:00
Johan Eliasson
93db718254 Create blue-ghosts-accept.md 2022-11-23 19:03:12 +01:00
Pierre-Louis Mercereau
c367bd58b9 docs: custom claims and singleton arrays 2022-11-23 19:01:29 +01:00
Pilou
0bfed4d9e1 Merge pull request #1196 from nhost/plmercereau-patch-1
Update docker-compose.yaml
2022-11-23 18:43:36 +01:00
Pilou
1f3aecd379 Merge pull request #1193 from nhost/chore/bump-service-versions
ci: 🎡 bump services versions and trigger CI
2022-11-23 18:43:20 +01:00
Pilou
42306ea3bb Update docker-compose.yaml 2022-11-23 18:19:41 +01:00
Pilou
1b12a175f6 Update docker-compose.yaml 2022-11-23 18:18:06 +01:00
Szilárd Dóró
32060aaea0 Merge pull request #1195 from nhost/chore/dashboard-version
chore(dashboard): add changeset
2022-11-23 16:00:18 +01:00
Szilárd Dóró
f94cace5f2 Merge pull request #1194 from nhost/feat/dashboard-vercel-deployment
feat(dashboard): add Vercel deployment
2022-11-23 15:22:09 +01:00
Szilárd Dóró
5de965d9a5 chore(dashboard): add changeset 2022-11-23 15:15:08 +01:00
Szilárd Dóró
e10b3adc11 chore(changesets): incorporate Vercel deployment into publish process 2022-11-23 15:08:21 +01:00
Szilárd Dóró
457db76b06 Merge pull request #1191 from nhost/fix/sign-in-methods-order
fix(dashboard): alphabetic ordering of providers
2022-11-23 15:04:26 +01:00
Szilárd Dóró
1e952a026e chore(changesets): update publish step's name 2022-11-23 15:01:55 +01:00
Szilárd Dóró
2f4c040789 feat(dashboard): add Vercel deployment 2022-11-23 14:33:00 +01:00
Pierre-Louis Mercereau
74648752b4 ci: use correct hasura version 2022-11-23 13:12:32 +01:00
Szilárd Dóró
09d218a3fe fix(dashboard): sign-in method phrasing 2022-11-23 13:12:24 +01:00
Szilárd Dóró
2e8938dbb0 fix(dashboard): add missing Twilio icon 2022-11-23 13:00:12 +01:00
Pierre-Louis Mercereau
ec60d03536 ci: 🎡 bump services versions and trigger CI 2022-11-23 12:57:04 +01:00
Johan Eliasson
2f3767552f Merge pull request #1189 from nhost/docs-workos
docs(workos): WorkOS Docs
2022-11-23 12:14:57 +01:00
Szilárd Dóró
bc401c0dd2 fix(dashboard): alphabetic ordering of providers
- fixes #1188
- fix checkbox font size on the Settings page
2022-11-23 12:12:39 +01:00
Pilou
2907ecb7ff Merge pull request #1179 from nhost/changeset-release/main
chore: update versions
2022-11-23 11:24:55 +01:00
Pierre-Louis Mercereau
05d7f5207f chore: no major bump of peer dependencies 2022-11-23 11:22:55 +01:00
github-actions[bot]
07a053ee80 chore: update versions 2022-11-23 09:58:39 +00:00
Pilou
61e4414a8f Merge pull request #1190 from nhost/changeset-react-components
react components changeset added
2022-11-23 10:55:04 +01:00
Johan Eliasson
4601d84e0e changeset added 2022-11-23 10:29:19 +01:00
Johan Eliasson
ca012d790c Create tidy-teachers-flow.md 2022-11-23 10:27:23 +01:00
Johan Eliasson
aeda14ef53 docs link 2022-11-23 10:25:18 +01:00
Johan Eliasson
3fa5e2005a updates 2022-11-23 10:23:40 +01:00
Johan Eliasson
4dd2e99159 Merge pull request #1187 from nhost/docs-git-8g712asd
docs(git): git docs updates
2022-11-23 08:27:17 +01:00
Johan Eliasson
282c6c6d24 git docs update 2022-11-23 08:16:55 +01:00
Johan Eliasson
beadd84adb moving files 2022-11-23 07:52:57 +01:00
Johan Eliasson
f8f55d2b99 Merge branch 'main' into feat/add-charges-to-stripe-package 2022-11-23 07:49:17 +01:00
Johan Eliasson
03a98d4f3a config updates 2022-11-23 07:36:31 +01:00
Johan Eliasson
8ed8e04ab6 merge 2022-11-23 07:31:37 +01:00
Erik Magnusson
587efd4551 re-applied isAdmin checks for connected account field types 2022-11-23 08:15:44 +02:00
Johan Eliasson
c78227b085 Merge pull request #1185 from nhost/docs/node-16
docs: update developer's guide
2022-11-23 07:06:10 +01:00
Pierre-Louis Mercereau
d87e520307 docs: lessons learned from Sheena and Chris 2022-11-22 21:44:48 +01:00
Pilou
bbed04e4da Merge pull request #1158 from nhost/fix/use-user-roles
fix: 🐛 make `useUserRoles` reactive
2022-11-22 21:35:06 +01:00
Pilou
273afc9740 Merge pull request #1184 from nhost/contributors-readme-action-h-P6q9XKTD
contributors readme action update
2022-11-22 21:32:07 +01:00
github-actions[bot]
f4083aa4b3 contrib-readme-action has updated readme 2022-11-22 20:12:23 +00:00
Pilou
ddd2641726 Merge pull request #1183 from massless/min-version-node
Update minimum version of node
2022-11-22 21:12:04 +01:00
Chris Wetherell
4658aeb31e Update minimum version of node 2022-11-22 12:08:47 -08:00
Johan Eliasson
cc8e5fe4a9 Merge pull request #1180 from nhost/react-components-iy8gasd9
React Auth components: SignedIn and SignedOut
2022-11-22 19:54:19 +01:00
Szilárd Dóró
85c897c717 chore(docs): update source code references 2022-11-22 18:32:48 +01:00
Szilárd Dóró
c99e5552e6 chore(react): simplify component signature 2022-11-22 18:31:39 +01:00
Szilárd Dóró
97a2520ea1 feat(docgen): add support for components 2022-11-22 18:24:23 +01:00
Johan Eliasson
964af2912b inline docs 2022-11-22 17:04:39 +01:00
Johan Eliasson
afea682a8c merge 2022-11-22 14:09:38 +01:00
Pierre-Louis Mercereau
fefa2baa2e refactor: readability 2022-11-22 13:28:09 +01:00
Pilou
f09b3cfd24 Merge pull request #1178 from nhost/ci/freeze-pnpm-version
ci: set explicit pnpm version in the dashboard dockerfile
2022-11-22 13:20:35 +01:00
Pilou
dd3b2c41f1 Merge pull request #1171 from nhost/chore/vue-file-upload-changeset
chore: add changeset to vue, and correct inline documentation
2022-11-22 13:20:21 +01:00
Szilárd Dóró
aaced20f31 Merge pull request #1173 from nhost/fix/dashboard-provider-redirect-url
fix(dashboard): correct redirect URL input opacity
2022-11-22 13:15:35 +01:00
Pierre-Louis Mercereau
3e91c19e13 ci: set explicit pnpm version in the dashboard dockerfile 2022-11-22 13:11:00 +01:00
Johan Eliasson
d4fd4ec3e9 signedin and signedout 2022-11-22 10:48:24 +01:00
Szilárd Dóró
89bd37bc28 chore(dashboard): add changeset 2022-11-22 10:20:52 +01:00
Szilárd Dóró
0df73a41c9 fix(dashboard): redirect URL opacity 2022-11-22 10:20:09 +01:00
Pierre-Louis Mercereau
f6d2042adb chore: add changeset to vue, and correct inline documentation 2022-11-22 09:34:47 +01:00
Pierre-Louis Mercereau
843087cb11 fix: 🐛 make useUserRoles reactive 2022-11-21 15:58:55 +01:00
Erik Magnusson
7055ffc37a Merge branch 'feat/add-charges-to-stripe-package' of https://github.com/ejkkan/nhost into feat/add-charges-to-stripe-package 2022-10-20 20:57:56 +02:00
Erik Magnusson
c68ce6d480 removed isAdmin checks for connected accounts related schema fields 2022-10-20 20:57:01 +02:00
Erik Magnusson
98a149c8bf Update packages/stripe-graphql-js/src/schema/charge.ts
Co-authored-by: Johan Eliasson <johan@eliasson.me>
2022-10-18 08:48:58 +02:00
Erik Magnusson
ceb558975e Update packages/stripe-graphql-js/src/schema/charge.ts
Co-authored-by: Johan Eliasson <johan@eliasson.me>
2022-10-18 08:48:46 +02:00
Erik Magnusson
7a87321a7e fixd imports and linting 2022-10-14 21:21:25 +02:00
Erik Magnusson
9349766c0a corrected spelling 2022-10-14 21:19:23 +02:00
Erik Magnusson
31655191a3 added connected accounts 2022-10-14 21:05:57 +02:00
Erik Magnusson
e3b91efa84 feat/added charges 2022-10-14 20:13:35 +02:00
Erik Magnusson
cfe736776a feat/added charges 2022-10-14 20:03:19 +02:00
Erik Magnusson
481bf237cc updated naming convention to camel casing 2022-10-14 10:11:02 +02:00
Erik Magnusson
33ce9bf1b9 added payment intents type for customer and invoice objects 2022-10-04 18:10:02 +02:00
101 changed files with 1433 additions and 369 deletions

View File

@@ -18,6 +18,7 @@ env:
jobs: jobs:
version: version:
name: Version
runs-on: ubuntu-latest runs-on: ubuntu-latest
outputs: outputs:
hasChangesets: ${{ steps.changesets.outputs.hasChangesets }} hasChangesets: ${{ steps.changesets.outputs.hasChangesets }}
@@ -61,6 +62,7 @@ jobs:
secrets: inherit secrets: inherit
publish: publish:
name: Publish
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: needs:
- test - test
@@ -110,6 +112,8 @@ jobs:
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
push: true push: true
- name: Trigger a Vercel deployment
run: curl -X POST -d {} https://api.vercel.com/v1/integrations/deploy/${{ secrets.DASHBOARD_VERCEL_PROJECT_ID }}/${{ secrets.DASHBOARD_VERCEL_WEBHOOK_ID }}
- name: Create GitHub Release - name: Create GitHub Release
uses: taiki-e/create-gh-release-action@v1 uses: taiki-e/create-gh-release-action@v1
with: with:

View File

@@ -2,6 +2,8 @@
## Requirements ## Requirements
- This repository works with **Node 16**
- We use [pnpm](https://pnpm.io/) as a package manager to speed up development and builds, and as a basis for our monorepo. You need to make sure it's installed on your machine. There are [several ways to install it](https://pnpm.io/installation), but the easiest way is with `npm`: - We use [pnpm](https://pnpm.io/) as a package manager to speed up development and builds, and as a basis for our monorepo. You need to make sure it's installed on your machine. There are [several ways to install it](https://pnpm.io/installation), but the easiest way is with `npm`:
```sh ```sh
@@ -97,6 +99,12 @@ You can take a look at the changeset documentation: [How to add a changeset](htt
You'll notice that `git commit` takes a few seconds to run. We set a commit hook that scans the changes in the code, automatically generates documentation from the inline [TSDoc](https://tsdoc.org/) annotations, and adds these generated documentation files to the commit. They automatically update the [reference documentation](https://docs.nhost.io/reference). You'll notice that `git commit` takes a few seconds to run. We set a commit hook that scans the changes in the code, automatically generates documentation from the inline [TSDoc](https://tsdoc.org/) annotations, and adds these generated documentation files to the commit. They automatically update the [reference documentation](https://docs.nhost.io/reference).
The document generation script that is run in the pre-commit hook requires to be built first. You may need to run the following command before the commit:
```sh
pnpm run build
```
<!-- ## Good practices <!-- ## Good practices
- lint - lint
- prettier - prettier

View File

@@ -179,14 +179,21 @@ Here are some ways of contributing to making Nhost better:
<sub><b>Grégory D'Angelo</b></sub> <sub><b>Grégory D'Angelo</b></sub>
</a> </a>
</td> </td>
<td align="center">
<a href="https://github.com/ejkkan">
<img src="https://avatars.githubusercontent.com/u/32518962?v=4" width="100;" alt="ejkkan"/>
<br />
<sub><b>Erik Magnusson</b></sub>
</a>
</td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/guicurcio"> <a href="https://github.com/guicurcio">
<img src="https://avatars.githubusercontent.com/u/20285232?v=4" width="100;" alt="guicurcio"/> <img src="https://avatars.githubusercontent.com/u/20285232?v=4" width="100;" alt="guicurcio"/>
<br /> <br />
<sub><b>Guido Curcio</b></sub> <sub><b>Guido Curcio</b></sub>
</a> </a>
</td></tr> </td>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/subatuba21"> <a href="https://github.com/subatuba21">
<img src="https://avatars.githubusercontent.com/u/34824571?v=4" width="100;" alt="subatuba21"/> <img src="https://avatars.githubusercontent.com/u/34824571?v=4" width="100;" alt="subatuba21"/>
@@ -221,15 +228,15 @@ Here are some ways of contributing to making Nhost better:
<br /> <br />
<sub><b>Christopher Möller</b></sub> <sub><b>Christopher Möller</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/GavanWilhite"> <a href="https://github.com/GavanWilhite">
<img src="https://avatars.githubusercontent.com/u/2085119?v=4" width="100;" alt="GavanWilhite"/> <img src="https://avatars.githubusercontent.com/u/2085119?v=4" width="100;" alt="GavanWilhite"/>
<br /> <br />
<sub><b>Gavan Wilhite</b></sub> <sub><b>Gavan Wilhite</b></sub>
</a> </a>
</td></tr> </td>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/FuzzyReason"> <a href="https://github.com/FuzzyReason">
<img src="https://avatars.githubusercontent.com/u/62517920?v=4" width="100;" alt="FuzzyReason"/> <img src="https://avatars.githubusercontent.com/u/62517920?v=4" width="100;" alt="FuzzyReason"/>
@@ -237,13 +244,6 @@ Here are some ways of contributing to making Nhost better:
<sub><b>Vadim Smirnov</b></sub> <sub><b>Vadim Smirnov</b></sub>
</a> </a>
</td> </td>
<td align="center">
<a href="https://github.com/ejkkan">
<img src="https://avatars.githubusercontent.com/u/32518962?v=4" width="100;" alt="ejkkan"/>
<br />
<sub><b>Erik Magnusson</b></sub>
</a>
</td>
<td align="center"> <td align="center">
<a href="https://github.com/macmac49"> <a href="https://github.com/macmac49">
<img src="https://avatars.githubusercontent.com/u/831190?v=4" width="100;" alt="macmac49"/> <img src="https://avatars.githubusercontent.com/u/831190?v=4" width="100;" alt="macmac49"/>
@@ -380,6 +380,13 @@ Here are some ways of contributing to making Nhost better:
<sub><b>Chris</b></sub> <sub><b>Chris</b></sub>
</a> </a>
</td> </td>
<td align="center">
<a href="https://github.com/massless">
<img src="https://avatars.githubusercontent.com/u/44389?v=4" width="100;" alt="massless"/>
<br />
<sub><b>Chris Wetherell</b></sub>
</a>
</td>
<td align="center"> <td align="center">
<a href="https://github.com/rustyb"> <a href="https://github.com/rustyb">
<img src="https://avatars.githubusercontent.com/u/53086?v=4" width="100;" alt="rustyb"/> <img src="https://avatars.githubusercontent.com/u/53086?v=4" width="100;" alt="rustyb"/>
@@ -393,15 +400,15 @@ Here are some ways of contributing to making Nhost better:
<br /> <br />
<sub><b>Dago</b></sub> <sub><b>Dago</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/dminkovsky"> <a href="https://github.com/dminkovsky">
<img src="https://avatars.githubusercontent.com/u/218725?v=4" width="100;" alt="dminkovsky"/> <img src="https://avatars.githubusercontent.com/u/218725?v=4" width="100;" alt="dminkovsky"/>
<br /> <br />
<sub><b>Dmitry Minkovsky</b></sub> <sub><b>Dmitry Minkovsky</b></sub>
</a> </a>
</td></tr> </td>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/dohomi"> <a href="https://github.com/dohomi">
<img src="https://avatars.githubusercontent.com/u/489221?v=4" width="100;" alt="dohomi"/> <img src="https://avatars.githubusercontent.com/u/489221?v=4" width="100;" alt="dohomi"/>
@@ -436,15 +443,15 @@ Here are some ways of contributing to making Nhost better:
<br /> <br />
<sub><b>Ikko Ashimine</b></sub> <sub><b>Ikko Ashimine</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/jladuval"> <a href="https://github.com/jladuval">
<img src="https://avatars.githubusercontent.com/u/1935359?v=4" width="100;" alt="jladuval"/> <img src="https://avatars.githubusercontent.com/u/1935359?v=4" width="100;" alt="jladuval"/>
<br /> <br />
<sub><b>Jacob Duval</b></sub> <sub><b>Jacob Duval</b></sub>
</a> </a>
</td></tr> </td>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/leothorp"> <a href="https://github.com/leothorp">
<img src="https://avatars.githubusercontent.com/u/12928449?v=4" width="100;" alt="leothorp"/> <img src="https://avatars.githubusercontent.com/u/12928449?v=4" width="100;" alt="leothorp"/>
@@ -479,15 +486,15 @@ Here are some ways of contributing to making Nhost better:
<br /> <br />
<sub><b>Nirmalya Ghosh</b></sub> <sub><b>Nirmalya Ghosh</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/quentin-decre"> <a href="https://github.com/quentin-decre">
<img src="https://avatars.githubusercontent.com/u/1137511?v=4" width="100;" alt="quentin-decre"/> <img src="https://avatars.githubusercontent.com/u/1137511?v=4" width="100;" alt="quentin-decre"/>
<br /> <br />
<sub><b>Quentin Decré</b></sub> <sub><b>Quentin Decré</b></sub>
</a> </a>
</td></tr> </td>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/altschuler"> <a href="https://github.com/altschuler">
<img src="https://avatars.githubusercontent.com/u/956928?v=4" width="100;" alt="altschuler"/> <img src="https://avatars.githubusercontent.com/u/956928?v=4" width="100;" alt="altschuler"/>
@@ -522,15 +529,15 @@ Here are some ways of contributing to making Nhost better:
<br /> <br />
<sub><b>Zach Burnaby</b></sub> <sub><b>Zach Burnaby</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/komninoschat"> <a href="https://github.com/komninoschat">
<img src="https://avatars.githubusercontent.com/u/29049104?v=4" width="100;" alt="komninoschat"/> <img src="https://avatars.githubusercontent.com/u/29049104?v=4" width="100;" alt="komninoschat"/>
<br /> <br />
<sub><b>Komninos</b></sub> <sub><b>Komninos</b></sub>
</a> </a>
</td></tr> </td>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/meesvandongen"> <a href="https://github.com/meesvandongen">
<img src="https://avatars.githubusercontent.com/u/35409045?v=4" width="100;" alt="meesvandongen"/> <img src="https://avatars.githubusercontent.com/u/35409045?v=4" width="100;" alt="meesvandongen"/>

View File

@@ -1,5 +1,24 @@
# @nhost/dashboard # @nhost/dashboard
## 0.4.3
### Patch Changes
- 5de965d9: fix(dashboard): alphabetic ordering of providers
- b9087a4a: fix(dashboard): console -> dashboard terminology
- ca012d79: docs(workos): WorkOS Docs
## 0.4.2
### Patch Changes
- 89bd37bc: fix(dashboard): correct redirect URL input opacity
- Updated dependencies [4601d84e]
- Updated dependencies [843087cb]
- @nhost/react@0.15.0
- @nhost/nextjs@1.9.0
- @nhost/react-apollo@4.9.0
## 0.4.1 ## 0.4.1
### Patch Changes ### Patch Changes

View File

@@ -22,7 +22,7 @@ ENV NEXT_PUBLIC_NHOST_MIGRATIONS_URL http://localhost:9693
ENV NEXT_PUBLIC_NHOST_HASURA_URL http://localhost:9695 ENV NEXT_PUBLIC_NHOST_HASURA_URL http://localhost:9695
ENV NEXT_PUBLIC_ENV dev ENV NEXT_PUBLIC_ENV dev
RUN yarn global add pnpm RUN yarn global add pnpm@7.17.0
COPY .gitignore .gitignore COPY .gitignore .gitignore
COPY --from=pruner /app/out/json/ . COPY --from=pruner /app/out/json/ .
COPY --from=pruner /app/out/pnpm-*.yaml . COPY --from=pruner /app/out/pnpm-*.yaml .

View File

@@ -1,6 +1,6 @@
{ {
"name": "@nhost/dashboard", "name": "@nhost/dashboard",
"version": "0.4.1", "version": "0.4.3",
"private": true, "private": true,
"scripts": { "scripts": {
"preinstall": "npx only-allow pnpm", "preinstall": "npx only-allow pnpm",
@@ -35,10 +35,10 @@
"@mui/system": "^5.10.14", "@mui/system": "^5.10.14",
"@mui/x-date-pickers": "^5.0.8", "@mui/x-date-pickers": "^5.0.8",
"@nhost/core": "^0.9.3", "@nhost/core": "^0.9.3",
"@nhost/nextjs": "^1.8.3", "@nhost/nextjs": "^1.9.0",
"@nhost/nhost-js": "^1.6.1", "@nhost/nhost-js": "^1.6.1",
"@nhost/react": "^0.14.3", "@nhost/react": "^0.15.0",
"@nhost/react-apollo": "^4.8.3", "@nhost/react-apollo": "^4.9.0",
"@segment/snippet": "^4.15.3", "@segment/snippet": "^4.15.3",
"@tailwindcss/forms": "^0.5.3", "@tailwindcss/forms": "^0.5.3",
"@tanstack/react-query": "^4.16.1", "@tanstack/react-query": "^4.16.1",
@@ -169,4 +169,4 @@
"last 1 safari version" "last 1 safari version"
] ]
} }
} }

View File

@@ -0,0 +1 @@
<svg width="21" height="21" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M10.08 0c5.578 0 10.08 4.507 10.08 10.09 0 5.584-4.502 10.09-10.08 10.09A10.072 10.072 0 0 1 0 10.09C0 4.507 4.503 0 10.08 0Zm0 2.69a7.375 7.375 0 0 0-7.392 7.4c0 4.104 3.293 7.4 7.392 7.4 4.1 0 7.392-3.296 7.392-7.4 0-4.103-3.293-7.4-7.392-7.4Zm-2.486 7.804c1.142 0 2.083.942 2.083 2.085 0 1.144-.94 2.086-2.083 2.086a2.095 2.095 0 0 1-2.083-2.086c0-1.143.94-2.085 2.083-2.085Zm4.973 0c1.142 0 2.083.942 2.083 2.085 0 1.144-.94 2.086-2.083 2.086a2.095 2.095 0 0 1-2.084-2.086c0-1.143.941-2.085 2.084-2.085Zm0-4.978c1.142 0 2.083.942 2.083 2.085 0 1.144-.94 2.086-2.083 2.086A2.095 2.095 0 0 1 10.483 7.6c0-1.143.941-2.085 2.084-2.085Zm-4.973 0c1.142 0 2.083.942 2.083 2.085 0 1.144-.94 2.086-2.083 2.086A2.095 2.095 0 0 1 5.51 7.6c0-1.143.94-2.085 2.083-2.085Z" fill="#F22F46"/></svg>

After

Width:  |  Height:  |  Size: 869 B

View File

@@ -79,7 +79,7 @@ export default function AnonymousSignInSettings() {
<Form onSubmit={handlePasswordProtectionSettingsChange}> <Form onSubmit={handlePasswordProtectionSettingsChange}>
<SettingsContainer <SettingsContainer
title="Anonymous Users" title="Anonymous Users"
description="Allow users to sign-in anonymously." description="Allow users to sign in anonymously."
primaryActionButtonProps={{ primaryActionButtonProps={{
disabled: disabled:
form.formState.isSubmitting || form.formState.isSubmitting ||

View File

@@ -107,7 +107,7 @@ export default function AppleProviderSettings() {
<Form onSubmit={handleProviderUpdate}> <Form onSubmit={handleProviderUpdate}>
<SettingsContainer <SettingsContainer
title="Apple" title="Apple"
description="Allows users to sign in with Apple." description="Allow users to sign in with Apple."
primaryActionButtonProps={{ primaryActionButtonProps={{
disabled: !formState.isValid || !formState.isDirty, disabled: !formState.isValid || !formState.isDirty,
loading: formState.isSubmitting, loading: formState.isSubmitting,
@@ -168,7 +168,7 @@ export default function AppleProviderSettings() {
<Input <Input
name="redirectUrl" name="redirectUrl"
id="redirectUrl" id="redirectUrl"
placeholder={`${generateRemoteAppUrl( defaultValue={`${generateRemoteAppUrl(
currentApplication.subdomain, currentApplication.subdomain,
)}/v1/auth/signin/provider/apple/callback`} )}/v1/auth/signin/provider/apple/callback`}
className="col-span-2" className="col-span-2"

View File

@@ -88,7 +88,7 @@ export default function DiscordProviderSettings() {
<Form onSubmit={handleProviderUpdate}> <Form onSubmit={handleProviderUpdate}>
<SettingsContainer <SettingsContainer
title="Discord" title="Discord"
description="Allows users to sign in with Discord." description="Allow users to sign in with Discord."
primaryActionButtonProps={{ primaryActionButtonProps={{
disabled: !formState.isValid || !formState.isDirty, disabled: !formState.isValid || !formState.isDirty,
loading: formState.isSubmitting, loading: formState.isSubmitting,
@@ -112,7 +112,7 @@ export default function DiscordProviderSettings() {
fullWidth fullWidth
hideEmptyHelperText hideEmptyHelperText
label="Redirect URL" label="Redirect URL"
value={`${generateRemoteAppUrl( defaultValue={`${generateRemoteAppUrl(
currentApplication.subdomain, currentApplication.subdomain,
)}/v1/auth/signin/provider/discord/callback`} )}/v1/auth/signin/provider/discord/callback`}
disabled disabled

View File

@@ -23,7 +23,7 @@ export interface EmailAndPasswordFormValues {
authPasswordHibpEnabled: boolean; authPasswordHibpEnabled: boolean;
} }
export default function EmailSettings() { export default function EmailAndPasswordSettings() {
const { currentApplication } = useCurrentWorkspaceAndApplication(); const { currentApplication } = useCurrentWorkspaceAndApplication();
const [updateApp] = useUpdateAppMutation({ const [updateApp] = useUpdateAppMutation({
refetchQueries: [GetAppLoginDataDocument], refetchQueries: [GetAppLoginDataDocument],
@@ -61,7 +61,7 @@ export default function EmailSettings() {
const { formState } = form; const { formState } = form;
const handleEmailSettingsChange = async ( const handleEmailAndPasswordSettingsChange = async (
values: EmailAndPasswordFormValues, values: EmailAndPasswordFormValues,
) => { ) => {
const updateAppMutation = updateApp({ const updateAppMutation = updateApp({
@@ -90,10 +90,10 @@ export default function EmailSettings() {
return ( return (
<FormProvider {...form}> <FormProvider {...form}>
<Form onSubmit={handleEmailSettingsChange}> <Form onSubmit={handleEmailAndPasswordSettingsChange}>
<SettingsContainer <SettingsContainer
title="Email and Password" title="Email and Password"
description="Sign in users using email and password." description="Allow users to sign in with email and password."
docsLink="https://docs.nhost.io/authentication/sign-in-with-email-and-password" docsLink="https://docs.nhost.io/authentication/sign-in-with-email-and-password"
docsTitle="how to sign in users with email and password" docsTitle="how to sign in users with email and password"
className="grid grid-flow-row" className="grid grid-flow-row"
@@ -109,10 +109,8 @@ export default function EmailSettings() {
name="authEmailSigninEmailVerifiedRequired" name="authEmailSigninEmailVerifiedRequired"
id="authEmailSigninEmailVerifiedRequired" id="authEmailSigninEmailVerifiedRequired"
label={ label={
<span className="inline-grid grid-flow-row gap-y-[2px] text-[15px]"> <span className="inline-grid grid-flow-row gap-y-0.5 text-sm+">
<span className="text-[15px] font-medium"> <span className="font-medium">Require Verified Emails</span>
Require Verified Emails
</span>
<span className="font-normal text-greyscaleMedium"> <span className="font-normal text-greyscaleMedium">
Users must verify their email to be able to sign in. Users must verify their email to be able to sign in.
</span> </span>
@@ -124,11 +122,9 @@ export default function EmailSettings() {
name="authPasswordHibpEnabled" name="authPasswordHibpEnabled"
id="authPasswordHibpEnabled" id="authPasswordHibpEnabled"
label={ label={
<span className="inline-grid grid-flow-row gap-y-[2px] text-[15px]"> <span className="inline-grid grid-flow-row gap-y-0.5 text-sm+">
<span className="text-[15px] font-medium"> <span className="font-medium">Password Protection</span>
Password Protection <span className="font-normal text-greyscaleMedium">
</span>
<span className="text-[12px] font-normal text-greyscaleMedium">
Passwords must pass haveibeenpwned.com during sign-up. Passwords must pass haveibeenpwned.com during sign-up.
</span> </span>
</span> </span>

View File

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

View File

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

View File

@@ -88,7 +88,7 @@ export default function FacebookProviderSettings() {
<Form onSubmit={handleProviderUpdate}> <Form onSubmit={handleProviderUpdate}>
<SettingsContainer <SettingsContainer
title="Facebook" title="Facebook"
description="Allows users to sign in with Facebook." description="Allow users to sign in with Facebook."
primaryActionButtonProps={{ primaryActionButtonProps={{
disabled: !formState.isValid || !formState.isDirty, disabled: !formState.isValid || !formState.isDirty,
loading: formState.isSubmitting, loading: formState.isSubmitting,
@@ -112,7 +112,7 @@ export default function FacebookProviderSettings() {
fullWidth fullWidth
hideEmptyHelperText hideEmptyHelperText
label="Redirect URL" label="Redirect URL"
value={`${generateRemoteAppUrl( defaultValue={`${generateRemoteAppUrl(
currentApplication.subdomain, currentApplication.subdomain,
)}/v1/auth/signin/provider/facebook/callback`} )}/v1/auth/signin/provider/facebook/callback`}
disabled disabled

View File

@@ -88,7 +88,7 @@ export default function GitHubProviderSettings() {
<Form onSubmit={handleProviderUpdate}> <Form onSubmit={handleProviderUpdate}>
<SettingsContainer <SettingsContainer
title="GitHub" title="GitHub"
description="Allows users to sign in with GitHub." description="Allow users to sign in with GitHub."
primaryActionButtonProps={{ primaryActionButtonProps={{
disabled: !formState.isValid || !formState.isDirty, disabled: !formState.isValid || !formState.isDirty,
loading: formState.isSubmitting, loading: formState.isSubmitting,
@@ -112,7 +112,7 @@ export default function GitHubProviderSettings() {
fullWidth fullWidth
hideEmptyHelperText hideEmptyHelperText
label="Redirect URL" label="Redirect URL"
value={`${generateRemoteAppUrl( defaultValue={`${generateRemoteAppUrl(
currentApplication.subdomain, currentApplication.subdomain,
)}/v1/auth/signin/provider/github/callback`} )}/v1/auth/signin/provider/github/callback`}
disabled disabled

View File

@@ -88,7 +88,7 @@ export default function GoogleProviderSettings() {
<Form onSubmit={handleProviderUpdate}> <Form onSubmit={handleProviderUpdate}>
<SettingsContainer <SettingsContainer
title="Google" title="Google"
description="Allows users to sign in with Google." description="Allow users to sign in with Google."
primaryActionButtonProps={{ primaryActionButtonProps={{
disabled: !formState.isValid || !formState.isDirty, disabled: !formState.isValid || !formState.isDirty,
loading: formState.isSubmitting, loading: formState.isSubmitting,
@@ -112,7 +112,7 @@ export default function GoogleProviderSettings() {
fullWidth fullWidth
hideEmptyHelperText hideEmptyHelperText
label="Redirect URL" label="Redirect URL"
value={`${generateRemoteAppUrl( defaultValue={`${generateRemoteAppUrl(
currentApplication.subdomain, currentApplication.subdomain,
)}/v1/auth/signin/provider/google/callback`} )}/v1/auth/signin/provider/google/callback`}
disabled disabled

View File

@@ -88,7 +88,7 @@ export default function LinkedInProviderSettings() {
<Form onSubmit={handleProviderUpdate}> <Form onSubmit={handleProviderUpdate}>
<SettingsContainer <SettingsContainer
title="LinkedIn" title="LinkedIn"
description="Allows users to sign in with LinkedIn" description="Allow users to sign in with LinkedIn."
primaryActionButtonProps={{ primaryActionButtonProps={{
disabled: !formState.isValid || !formState.isDirty, disabled: !formState.isValid || !formState.isDirty,
loading: formState.isSubmitting, loading: formState.isSubmitting,
@@ -112,7 +112,7 @@ export default function LinkedInProviderSettings() {
fullWidth fullWidth
hideEmptyHelperText hideEmptyHelperText
label="Redirect URL" label="Redirect URL"
value={`${generateRemoteAppUrl( defaultValue={`${generateRemoteAppUrl(
currentApplication.subdomain, currentApplication.subdomain,
)}/v1/auth/signin/provider/linkedin/callback`} )}/v1/auth/signin/provider/linkedin/callback`}
disabled disabled

View File

@@ -80,7 +80,7 @@ export default function MagicLinkSettings() {
<Form onSubmit={handleMagicLinkSettingsUpdate}> <Form onSubmit={handleMagicLinkSettingsUpdate}>
<SettingsContainer <SettingsContainer
title="Magic Link" title="Magic Link"
description="Allow users to sign-in with a magic link." description="Allow users to sign in with a magic link."
primaryActionButtonProps={{ primaryActionButtonProps={{
disabled: !formState.isValid || !formState.isDirty, disabled: !formState.isValid || !formState.isDirty,
loading: formState.isSubmitting, loading: formState.isSubmitting,

View File

@@ -88,7 +88,7 @@ export default function SpotifyProviderSettings() {
<Form onSubmit={handleProviderUpdate}> <Form onSubmit={handleProviderUpdate}>
<SettingsContainer <SettingsContainer
title="Spotify" title="Spotify"
description="Allows users to sign in with Spotify." description="Allow users to sign in with Spotify."
primaryActionButtonProps={{ primaryActionButtonProps={{
disabled: !formState.isValid || !formState.isDirty, disabled: !formState.isValid || !formState.isDirty,
loading: formState.isSubmitting, loading: formState.isSubmitting,
@@ -112,7 +112,7 @@ export default function SpotifyProviderSettings() {
fullWidth fullWidth
hideEmptyHelperText hideEmptyHelperText
label="Redirect URL" label="Redirect URL"
value={`${generateRemoteAppUrl( defaultValue={`${generateRemoteAppUrl(
currentApplication.subdomain, currentApplication.subdomain,
)}/v1/auth/signin/provider/spotify/callback`} )}/v1/auth/signin/provider/spotify/callback`}
disabled disabled

View File

@@ -88,7 +88,7 @@ export default function TwitchProviderSettings() {
<Form onSubmit={handleProviderUpdate}> <Form onSubmit={handleProviderUpdate}>
<SettingsContainer <SettingsContainer
title="Twitch" title="Twitch"
description="Allows users to sign in with Twitch." description="Allow users to sign in with Twitch."
primaryActionButtonProps={{ primaryActionButtonProps={{
disabled: !formState.isValid || !formState.isDirty, disabled: !formState.isValid || !formState.isDirty,
loading: formState.isSubmitting, loading: formState.isSubmitting,
@@ -112,7 +112,7 @@ export default function TwitchProviderSettings() {
fullWidth fullWidth
hideEmptyHelperText hideEmptyHelperText
label="Redirect URL" label="Redirect URL"
value={`${generateRemoteAppUrl( defaultValue={`${generateRemoteAppUrl(
currentApplication.subdomain, currentApplication.subdomain,
)}/v1/auth/signin/provider/twitch/callback`} )}/v1/auth/signin/provider/twitch/callback`}
disabled disabled

View File

@@ -87,7 +87,7 @@ export default function TwitterProviderSettings() {
<Form onSubmit={handleProviderUpdate}> <Form onSubmit={handleProviderUpdate}>
<SettingsContainer <SettingsContainer
title="Twitter" title="Twitter"
description="Allows users to sign in with Twitter." description="Allow users to sign in with Twitter."
primaryActionButtonProps={{ primaryActionButtonProps={{
disabled: !formState.isValid || !formState.isDirty, disabled: !formState.isValid || !formState.isDirty,
loading: formState.isSubmitting, loading: formState.isSubmitting,
@@ -125,7 +125,7 @@ export default function TwitterProviderSettings() {
<Input <Input
name="redirectUrl" name="redirectUrl"
id="redirectUrl" id="redirectUrl"
placeholder={`${generateRemoteAppUrl( defaultValue={`${generateRemoteAppUrl(
currentApplication.subdomain, currentApplication.subdomain,
)}/v1/auth/signin/provider/twitter/callback`} )}/v1/auth/signin/provider/twitter/callback`}
className="col-span-2" className="col-span-2"
@@ -133,11 +133,6 @@ export default function TwitterProviderSettings() {
hideEmptyHelperText hideEmptyHelperText
label="Redirect URL" label="Redirect URL"
disabled disabled
slotProps={{
input: {
className: 'bg-opacity-5',
},
}}
endAdornment={ endAdornment={
<InputAdornment position="end" className="absolute right-2"> <InputAdornment position="end" className="absolute right-2">
<IconButton <IconButton

View File

@@ -81,7 +81,7 @@ export default function WebAuthnSettings() {
<Form onSubmit={handleWebAuthnSettingsUpdate}> <Form onSubmit={handleWebAuthnSettingsUpdate}>
<SettingsContainer <SettingsContainer
title="Security Keys" title="Security Keys"
description="Allow users to sign-in with security keys using WebAuthn." description="Allow users to sign in with security keys using WebAuthn."
primaryActionButtonProps={{ primaryActionButtonProps={{
disabled: !formState.isValid || !formState.isDirty, disabled: !formState.isValid || !formState.isDirty,
loading: formState.isSubmitting, loading: formState.isSubmitting,

View File

@@ -88,7 +88,7 @@ export default function WindowsLiveProviderSettings() {
<Form onSubmit={handleProviderUpdate}> <Form onSubmit={handleProviderUpdate}>
<SettingsContainer <SettingsContainer
title="Windows Live" title="Windows Live"
description="Allows users to sign in with Windows Live." description="Allow users to sign in with Windows Live."
primaryActionButtonProps={{ primaryActionButtonProps={{
disabled: !formState.isValid || !formState.isDirty, disabled: !formState.isValid || !formState.isDirty,
loading: formState.isSubmitting, loading: formState.isSubmitting,
@@ -111,7 +111,7 @@ export default function WindowsLiveProviderSettings() {
fullWidth fullWidth
hideEmptyHelperText hideEmptyHelperText
label="Redirect URL" label="Redirect URL"
value={`${generateRemoteAppUrl( defaultValue={`${generateRemoteAppUrl(
currentApplication.subdomain, currentApplication.subdomain,
)}/v1/auth/signin/provider/microsoft/callback`} )}/v1/auth/signin/provider/microsoft/callback`}
disabled disabled

View File

@@ -94,11 +94,13 @@ export default function WorkOsProviderSettings() {
<Form onSubmit={handleProviderUpdate}> <Form onSubmit={handleProviderUpdate}>
<SettingsContainer <SettingsContainer
title="WorkOS" title="WorkOS"
description="Allows users to sign in with WorkOS." description="Allow users to sign in with WorkOS."
primaryActionButtonProps={{ primaryActionButtonProps={{
disabled: !formState.isValid || !formState.isDirty, disabled: !formState.isValid || !formState.isDirty,
loading: formState.isSubmitting, loading: formState.isSubmitting,
}} }}
docsLink="https://docs.nhost.io/authentication/sign-in-with-workos"
docsTitle="how to sign in users with WorkOS"
icon="/logos/WorkOs.svg" icon="/logos/WorkOs.svg"
switchId="authWorkOsEnabled" switchId="authWorkOsEnabled"
showSwitch showSwitch
@@ -112,8 +114,8 @@ export default function WorkOsProviderSettings() {
{...register(`authWorkOsClientId`)} {...register(`authWorkOsClientId`)}
name="authWorkOsClientId" name="authWorkOsClientId"
id="authWorkOsClientId" id="authWorkOsClientId"
label="WorkOS Client ID" label="Client ID"
placeholder="WorkOS Client ID" placeholder="Enter your Client ID"
className="col-span-3" className="col-span-3"
fullWidth fullWidth
hideEmptyHelperText hideEmptyHelperText
@@ -122,28 +124,28 @@ export default function WorkOsProviderSettings() {
{...register('authWorkOsClientSecret')} {...register('authWorkOsClientSecret')}
name="authWorkOsClientSecret" name="authWorkOsClientSecret"
id="authWorkOsClientSecret" id="authWorkOsClientSecret"
label="WorkOS Client Secret" label="Client Secret"
placeholder="WorkOS Client Secret" placeholder="Enter your Client Secret"
className="col-span-3" className="col-span-3"
fullWidth fullWidth
hideEmptyHelperText hideEmptyHelperText
/> />
<Input
{...register('authWorkOsDefaultDomain')}
name="authWorkOsDefaultDomain"
id="authWorkOsDefaultDomain"
label="Default Domain"
placeholder="Default Domain"
className="col-span-2"
fullWidth
hideEmptyHelperText
/>
<Input <Input
{...register('authWorkOsDefaultOrganization')} {...register('authWorkOsDefaultOrganization')}
name="authWorkOsDefaultOrganization" name="authWorkOsDefaultOrganization"
id="authWorkOsDefaultOrganization" id="authWorkOsDefaultOrganization"
label="Default Organization" label="Default Organization ID (optional)"
placeholder="Default Organization" placeholder="Default Organization ID"
className="col-span-2"
fullWidth
hideEmptyHelperText
/>
<Input
{...register('authWorkOsDefaultDomain')}
name="authWorkOsDefaultDomain"
id="authWorkOsDefaultDomain"
label="Default Domain (optional)"
placeholder="Default Domain"
className="col-span-2" className="col-span-2"
fullWidth fullWidth
hideEmptyHelperText hideEmptyHelperText
@@ -152,7 +154,7 @@ export default function WorkOsProviderSettings() {
{...register('authWorkOsDefaultConnection')} {...register('authWorkOsDefaultConnection')}
name="authWorkOsDefaultConnection" name="authWorkOsDefaultConnection"
id="authWorkOsDefaultConnection" id="authWorkOsDefaultConnection"
label="Default Connection" label="Default Connection (optional)"
placeholder="Default Connection" placeholder="Default Connection"
className="col-span-2" className="col-span-2"
fullWidth fullWidth
@@ -161,7 +163,7 @@ export default function WorkOsProviderSettings() {
<Input <Input
name="redirectUrl" name="redirectUrl"
id="redirectUrl" id="redirectUrl"
placeholder={`${generateRemoteAppUrl( defaultValue={`${generateRemoteAppUrl(
currentApplication.subdomain, currentApplication.subdomain,
)}/v1/auth/signin/provider/workos/callback`} )}/v1/auth/signin/provider/workos/callback`}
className="col-span-6" className="col-span-6"
@@ -169,11 +171,6 @@ export default function WorkOsProviderSettings() {
hideEmptyHelperText hideEmptyHelperText
label="Redirect URL" label="Redirect URL"
disabled disabled
slotProps={{
input: {
className: 'bg-opacity-5',
},
}}
endAdornment={ endAdornment={
<InputAdornment position="end" className="absolute right-2"> <InputAdornment position="end" className="absolute right-2">
<IconButton <IconButton

View File

@@ -3,7 +3,7 @@ import SettingsLayout from '@/components/settings/SettingsLayout';
import AnonymousSignInSettings from '@/components/settings/signInMethods/AnonymousSignInSettings'; import AnonymousSignInSettings from '@/components/settings/signInMethods/AnonymousSignInSettings';
import AppleProviderSettings from '@/components/settings/signInMethods/AppleProviderSettings'; import AppleProviderSettings from '@/components/settings/signInMethods/AppleProviderSettings';
import DiscordProviderSettings from '@/components/settings/signInMethods/DiscordProviderSettings'; import DiscordProviderSettings from '@/components/settings/signInMethods/DiscordProviderSettings';
import EmailSettings from '@/components/settings/signInMethods/EmailSettings'; import EmailAndPasswordSettings from '@/components/settings/signInMethods/EmailAndPasswordSettings';
import FacebookProviderSettings from '@/components/settings/signInMethods/FacebookProviderSettings'; import FacebookProviderSettings from '@/components/settings/signInMethods/FacebookProviderSettings';
import GitHubProviderSettings from '@/components/settings/signInMethods/GitHubProviderSettings'; import GitHubProviderSettings from '@/components/settings/signInMethods/GitHubProviderSettings';
import GoogleProviderSettings from '@/components/settings/signInMethods/GoogleProviderSettings'; import GoogleProviderSettings from '@/components/settings/signInMethods/GoogleProviderSettings';
@@ -35,7 +35,7 @@ export default function SettingsSignInMethodsPage() {
return ( return (
<ActivityIndicator <ActivityIndicator
delay={1000} delay={1000}
label="Loading Sign-In Methods Settings..." label="Loading sign-in method settings..."
className="justify-center" className="justify-center"
/> />
); );
@@ -50,21 +50,21 @@ export default function SettingsSignInMethodsPage() {
className="max-w-5xl space-y-8 bg-fafafa" className="max-w-5xl space-y-8 bg-fafafa"
wrapperClassName="bg-fafafa" wrapperClassName="bg-fafafa"
> >
<EmailSettings /> <EmailAndPasswordSettings />
<MagicLinkSettings /> <MagicLinkSettings />
<WebAuthnSettings /> <WebAuthnSettings />
<AnonymousSignInSettings /> <AnonymousSignInSettings />
<SMSSettings /> <SMSSettings />
<GoogleProviderSettings />
<GitHubProviderSettings />
<LinkedInProviderSettings />
<AppleProviderSettings /> <AppleProviderSettings />
<WindowsLiveProviderSettings /> <DiscordProviderSettings />
<FacebookProviderSettings /> <FacebookProviderSettings />
<GitHubProviderSettings />
<GoogleProviderSettings />
<LinkedInProviderSettings />
<SpotifyProviderSettings /> <SpotifyProviderSettings />
<TwitchProviderSettings /> <TwitchProviderSettings />
<DiscordProviderSettings />
<TwitterProviderSettings /> <TwitterProviderSettings />
<WindowsLiveProviderSettings />
<WorkOsProviderSettings /> <WorkOsProviderSettings />
</Container> </Container>
); );
@@ -72,11 +72,7 @@ export default function SettingsSignInMethodsPage() {
SettingsSignInMethodsPage.getLayout = function getLayout(page: ReactElement) { SettingsSignInMethodsPage.getLayout = function getLayout(page: ReactElement) {
return ( return (
<SettingsLayout <SettingsLayout mainContainerProps={{ className: 'bg-fafafa' }}>
mainContainerProps={{
className: 'bg-fafafa',
}}
>
{page} {page}
</SettingsLayout> </SettingsLayout>
); );

View File

@@ -11,8 +11,8 @@ export default class MyDocument extends Document {
render() { render() {
const meta = { const meta = {
title: 'Nhost 2.0 | Console', title: 'Dashboard - Nhost',
description: 'Nhost Console 2.0', description: 'Nhost Dashboard',
image: '/assets/splash.png', image: '/assets/splash.png',
}; };

View File

@@ -26,5 +26,5 @@ export default function IndexPage() {
} }
IndexPage.getLayout = function getLayout(page: ReactElement) { IndexPage.getLayout = function getLayout(page: ReactElement) {
return <AuthenticatedLayout title="Console">{page}</AuthenticatedLayout>; return <AuthenticatedLayout title="Dashboard">{page}</AuthenticatedLayout>;
}; };

View File

@@ -1,5 +1,11 @@
# @nhost/docs # @nhost/docs
## 0.0.5
### Patch Changes
- ca012d79: docs(workos): WorkOS Docs
## 0.0.4 ## 0.0.4
### Patch Changes ### Patch Changes

View File

@@ -33,7 +33,7 @@ Follow this guide to sign in users with GitHub.
- Fill in Application Name. - Fill in Application Name.
- Fill in Homepage URL. - Fill in Homepage URL.
- Fill in **Authorization callback URL** with your OAuth Callbacke URL from Nhost. - Fill in **Authorization callback URL** with your OAuth Callback URL from Nhost.
## Configure Nhost ## Configure Nhost

View File

@@ -0,0 +1,67 @@
---
title: Sign In with WorkOS
sidebar_label: WorkOS
slug: /authentication/sign-in-with-workos
image: /img/og/sign-in-with-workos.png
---
Follow this guide to sign in users with WorkOS.
<p align="center">
<img
alt="WorkOS Sign In Preview"
src="/img/social-providers/workos-preview.svg"
width={480}
height={267}
/>
</p>
## Create WorkOS Account
- Go to [WorkOS's website](https://workos.com/).
- Click on **Sign In** in the top menu and create a WorkOS account.
## Get the Client ID
- In the WorkOS dashboard, click on **Configuration** in the left menu.
- Copy the **Client ID**, which starts with `project_`.
- Paste the **Client ID** in the **Client ID** field in the WorkOS settings in the Nhost Dashboard.
## Set correct Redirect URI
- In the WorkOS dashboard, click on **Configuration** in the left menu.
- Click on **Edit Redirect URIs** in the Redirect URIs section.
- Add the **Redirect URL** from the Nhost Dashboard to the list of Redirect URIs.
- Set the newly added redirect URI as the **Default Redirect URI**.
- Click on **Close**.
## Get the Client Secret
- In the WorkOS dashboard, click on **API Keys** in the left menu.
- Click on the eye icon next to the **Client Secret** to reveal it.
- Copy the **Client Secret**, which stars with `sk_`.
- Paste the **Client Secret** in the **Client Secret** field in the WorkOS settings in the Nhost Dashboard.
## Get Organization ID
- In the WorkOS dashboard, click on **Organizations** in the left menu.
- Click on **Create an Organization**.
- Fill in the organization details and click on **Create Organization**.
- Click on the newly created organization.
- Copy the **Organization ID**, which stars with `org_`.
- Paste the **Organization ID** in the **Organization ID** field in the WorkOS settings in the Nhost Dashboard.
- Click **Save** in the Nhost Dashboard to save all WorkOS settings.
The WorkOS configuration is now completed with Nhost.
See the [WorkOS documentation](https://workos.com/docs/) to learn more about how to configure WorkOS.
## Sign In Users
Use the [Nhost JavaScript client](/reference/javascript) to sign in users:
```js
nhost.auth.signIn({
provider: 'workos'
})
```

View File

@@ -88,6 +88,26 @@ custom_claims: '{"organisation-id":"user.profile.organisation.id"}'
JSON columns cannot be used in custom claims, with the exception of the `users.metadata` column. JSON columns cannot be used in custom claims, with the exception of the `users.metadata` column.
### Arrays
When the target value is expected to be an array, it is important to explicitly add a `[]` at the end of the expression. For instance: if `organisationIds` is expected to be an array, you must set the expression to `organisationIds[]`. It will otherwise return a litteral when the array is a singleton.
✅ Singleton array with `'{"organisation-ids":"organisationIds[]"}'`
```json
{
"x-hasura-organisation-ids": "{\"org-id-1\"}"
}
```
🛑 Singleton array with `'{"organisation-ids":"organisationIds"}'`
```json
{
"x-hasura-organisation-ids": "org-id-1"
}
```
## Roles ## Roles
Every GraphQL request is resolved based on a **single role**. Roles are added in the Hasura Console when selecting a table and clicking **Permisisons**. Every GraphQL request is resolved based on a **single role**. Roles are added in the Hasura Console when selecting a table and clicking **Permisisons**.

View File

@@ -12,13 +12,14 @@ Nhost allows you to automatically deploy your Nhost project when you do changes
Support GitLab, BitBucket, and other Git providers are on our roadmap. Support GitLab, BitBucket, and other Git providers are on our roadmap.
## How It Works ## Deployment
The following things are deployed: The following things are deployed:
- Database migrations - Database migrations
- Hasura metadata - Hasura metadata
- Serverless Functions - Serverless Functions
- Email Templates
:::caution :::caution
Settings in `nhost/config.yaml` are **not** deployed. That means you need to manually sync settings between local and remote environments between the CLI and Nhost Cloud. Settings in `nhost/config.yaml` are **not** deployed. That means you need to manually sync settings between local and remote environments between the CLI and Nhost Cloud.
@@ -40,20 +41,14 @@ Settings in `nhost/config.yaml` are **not** deployed. That means you need to man
## Deployment Branch ## Deployment Branch
Nhost only deploys your **deployment branch**. By default, your deployment branch matches the default branch set on GitHub (usually `main`). Nhost only deploys changes from the **Deployment Branch**. By default, your deployment branch matches the default branch (usually `main`).
You can change the deployment branch by clicking **Edit** next to the repository in your Nhost project's Overview. You can change the Deployment Branch on the **Git** page in the **Settings** section.
You can have multiple Nhost projects connected to the same GitHub repository and use different deployment branches (e.g., `main` and `staging`). It's possible to have multiple Nhost projects connected to the same Git repository and use different Deployment Branches (e.g., `main` and `staging`). Learn more about [multiple environments](/platform/multiple-environments).
<center>
<img src="/img/github-integration/deployment-branch.png" alt="drawing" width="50%" />
</center>
## Base Directory ## Base Directory
If your Nhost project is not at the root of your git repository (typically when using a monorepo), you can set a custom base directory. The base directory is where the `nhost` directory is located. In other words, the base directory is the **parent directory** of the `nhost` folder. If your Nhost project is not located at the root of your Git repository, which is typically the case when using a monorepo, it's possible to set a custom Base Directory. The Base Directory is where the `nhost/` directory is located. In other words, the Base Directory is the **parent directory** of the `nhost/` directory.
<center> You can change the Base Directory on the **Git** page in the **Settings** section.
<img src="/img/github-integration/base-directory.png" alt="drawing" width="50%" />
</center>

View File

@@ -0,0 +1,35 @@
---
# ⚠️ AUTO-GENERATED CONTENT. DO NOT EDIT THIS FILE DIRECTLY! ⚠️
title: <SignedIn />
sidebar_label: <SignedIn />
slug: /reference/nextjs/signed-in
description: Use `<SignedIn />` to control the rendering of components for users. Components inside `<SignedIn />` are only rendered if the user is authenticated.
custom_edit_url: https://github.com/nhost/nhost/edit/main/packages/react/src/components/SignedIn.tsx#L28
---
# `SignedIn()`
Use `<SignedIn />` to control the rendering of components for users. Components inside `<SignedIn />` are only rendered if the user is authenticated.
```tsx
import { NhostProvider, SignedOut } from '@nhost/react'
import { nhost } from '@/utils/nhost'
function Page() {
return (
<NhostProvider nhost={nhost}>
<SignedIn>
<h1>Only rendered if the user is authenticated</h1>
</SignedIn>
</NhostProvider>
)
}
```
## Parameters
---
**<span className="parameter-name">\_\_namedParameters</span>** <span className="optional-status">required</span> `{ children: ReactNode }`
---

View File

@@ -0,0 +1,35 @@
---
# ⚠️ AUTO-GENERATED CONTENT. DO NOT EDIT THIS FILE DIRECTLY! ⚠️
title: <SignedOut />
sidebar_label: <SignedOut />
slug: /reference/nextjs/signed-out
description: Use `<SignedOut />` to control the rendering of components for users. Components inside `<SignedOut />` are only rendered if the user is not authenticated.
custom_edit_url: https://github.com/nhost/nhost/edit/main/packages/react/src/components/SignedOut.tsx#L28
---
# `SignedOut()`
Use `<SignedOut />` to control the rendering of components for users. Components inside `<SignedOut />` are only rendered if the user is not authenticated.
```tsx
import { NhostProvider, SignedOut } from '@nhost/react'
import { nhost } from '@/utils/nhost'
function Page() {
return (
<NhostProvider nhost={nhost}>
<SignedOut>
<h1>Only rendered if the user is not authenticated</h1>
</SignedOut>
</NhostProvider>
)
}
```
## Parameters
---
**<span className="parameter-name">\_\_namedParameters</span>** <span className="optional-status">required</span> `{ children: ReactNode }`
---

View File

@@ -0,0 +1,35 @@
---
# ⚠️ AUTO-GENERATED CONTENT. DO NOT EDIT THIS FILE DIRECTLY! ⚠️
title: <SignedIn />
sidebar_label: <SignedIn />
slug: /reference/react/signed-in
description: Use `<SignedIn />` to control the rendering of components for users. Components inside `<SignedIn />` are only rendered if the user is authenticated.
custom_edit_url: https://github.com/nhost/nhost/edit/main/packages/react/src/components/SignedIn.tsx#L28
---
# `SignedIn()`
Use `<SignedIn />` to control the rendering of components for users. Components inside `<SignedIn />` are only rendered if the user is authenticated.
```tsx
import { NhostProvider, SignedOut } from '@nhost/react'
import { nhost } from '@/utils/nhost'
function Page() {
return (
<NhostProvider nhost={nhost}>
<SignedIn>
<h1>Only rendered if the user is authenticated</h1>
</SignedIn>
</NhostProvider>
)
}
```
## Parameters
---
**<span className="parameter-name">\_\_namedParameters</span>** <span className="optional-status">required</span> `{ children: ReactNode }`
---

View File

@@ -0,0 +1,35 @@
---
# ⚠️ AUTO-GENERATED CONTENT. DO NOT EDIT THIS FILE DIRECTLY! ⚠️
title: <SignedOut />
sidebar_label: <SignedOut />
slug: /reference/react/signed-out
description: Use `<SignedOut />` to control the rendering of components for users. Components inside `<SignedOut />` are only rendered if the user is not authenticated.
custom_edit_url: https://github.com/nhost/nhost/edit/main/packages/react/src/components/SignedOut.tsx#L28
---
# `SignedOut()`
Use `<SignedOut />` to control the rendering of components for users. Components inside `<SignedOut />` are only rendered if the user is not authenticated.
```tsx
import { NhostProvider, SignedOut } from '@nhost/react'
import { nhost } from '@/utils/nhost'
function Page() {
return (
<NhostProvider nhost={nhost}>
<SignedOut>
<h1>Only rendered if the user is not authenticated</h1>
</SignedOut>
</NhostProvider>
)
}
```
## Parameters
---
**<span className="parameter-name">\_\_namedParameters</span>** <span className="optional-status">required</span> `{ children: ReactNode }`
---

View File

@@ -0,0 +1,44 @@
---
# ⚠️ AUTO-GENERATED CONTENT. DO NOT EDIT THIS FILE DIRECTLY! ⚠️
title: useFileUploadItem()
sidebar_label: useFileUploadItem()
slug: /reference/vue/use-file-upload-item
description: Use the composable `useFileUploadItem` to control the file upload of a file in a multiple file upload.
custom_edit_url: https://github.com/nhost/nhost/edit/main/packages/vue/src/useFileUpload.ts#L61
---
# `useFileUploadItem()`
Use the composable `useFileUploadItem` to control the file upload of a file in a multiple file upload.
It has the same signature as `useFileUpload`.
```tsx
const Item = ({ itemRef }) => {
const { name, progress } = useFileUploadItem(itemRef)
return (
<li>
{name} {progress}
</li>
)
}
const List = () => {
const { list } = useMultipleFilesUpload()
return (
<ul>
{list.map((itemRef) => (
<Item key={item.id} itemRef={item} />
))}
</ul>
)
}
```
## Parameters
---
**<span className="parameter-name">ref</span>** <span className="optional-status">required</span> `ActorRefWithDeprecatedState<FileUploadContext, { type: "ADD", file: File, id: string, bucketId: string, name: string } | { type: "UPLOAD", url: string, file: File, id: string, bucketId: string, name: string, accessToken: string, adminSecret: string } | { type: "UPLOAD_PROGRESS", progress: number, loaded: number, additions: number } | { type: "UPLOAD_DONE", id: string, bucketId: string } | { type: "UPLOAD_ERROR", error: ErrorPayload } | { type: "CANCEL" } | { type: "DESTROY" }, { value: any, context: FileUploadContext }, ResolveTypegenMeta<Typegen0, { type: "ADD", file: File, id: string, bucketId: string, name: string } | { type: "UPLOAD", url: string, file: File, id: string, bucketId: string, name: string, accessToken: string, adminSecret: string } | { type: "UPLOAD_PROGRESS", progress: number, loaded: number, additions: number } | { type: "UPLOAD_DONE", id: string, bucketId: string } | { type: "UPLOAD_ERROR", error: ErrorPayload } | { type: "CANCEL" } | { type: "DESTROY" }, BaseActionObject, ServiceMap>>` | `Interpreter<FileUploadContext, any, { type: "ADD", file: File, id: string, bucketId: string, name: string } | { type: "UPLOAD", url: string, file: File, id: string, bucketId: string, name: string, accessToken: string, adminSecret: string } | { type: "UPLOAD_PROGRESS", progress: number, loaded: number, additions: number } | { type: "UPLOAD_DONE", id: string, bucketId: string } | { type: "UPLOAD_ERROR", error: ErrorPayload } | { type: "CANCEL" } | { type: "DESTROY" }, { value: any, context: FileUploadContext }, ResolveTypegenMeta<Typegen0, { type: "ADD", file: File, id: string, bucketId: string, name: string } | { type: "UPLOAD", url: string, file: File, id: string, bucketId: string, name: string, accessToken: string, adminSecret: string } | { type: "UPLOAD_PROGRESS", progress: number, loaded: number, additions: number } | { type: "UPLOAD_DONE", id: string, bucketId: string } | { type: "UPLOAD_ERROR", error: ErrorPayload } | { type: "CANCEL" } | { type: "DESTROY" }, BaseActionObject, ServiceMap>>`
---

View File

@@ -0,0 +1,33 @@
---
# ⚠️ AUTO-GENERATED CONTENT. DO NOT EDIT THIS FILE DIRECTLY! ⚠️
title: useFileUpload()
sidebar_label: useFileUpload()
slug: /reference/vue/use-file-upload
description: Use the composable `useFileUpload` to upload a file.
custom_edit_url: https://github.com/nhost/nhost/edit/main/packages/vue/src/useFileUpload.ts#L142
---
# `useFileUpload()`
Use the composable `useFileUpload` to upload a file.
```tsx
const {
add,
upload,
cancel,
isUploaded,
isUploading,
isError,
progress,
id,
bucketId,
name
} = useFileUpload()
const handleFormSubmit = async (e) => {
e.preventDefault()
await upload({ file })
}
```

View File

@@ -0,0 +1,10 @@
---
# ⚠️ AUTO-GENERATED CONTENT. DO NOT EDIT THIS FILE DIRECTLY! ⚠️
title: FileItemRef
sidebar_label: FileItemRef
description: No description provided.
displayed_sidebar: referenceSidebar
custom_edit_url: https://github.com/nhost/nhost/edit/main/packages/hasura-storage-js/src/machines/multiple-files-upload.ts#L7
---
# `FileItemRef`

View File

@@ -0,0 +1,80 @@
---
# ⚠️ AUTO-GENERATED CONTENT. DO NOT EDIT THIS FILE DIRECTLY! ⚠️
title: FileUploadComposableResult
sidebar_label: FileUploadComposableResult
description: No description provided.
displayed_sidebar: referenceSidebar
custom_edit_url: https://github.com/nhost/nhost/edit/main/packages/vue/src/useFileUpload.ts#L16
---
# `FileUploadComposableResult`
## Parameters
---
**<span className="parameter-name">isError</span>** <span className="optional-status">required</span> `boolean`
**`@returns`**
`true` if an error occurred
**`@depreacted`**
use `!isSuccess` or `!!error` instead
---
**<span className="parameter-name">error</span>** <span className="optional-status">required</span> `null` | `ErrorPayload`
Provides details about the error
---
**<span className="parameter-name">isUploading</span>** <span className="optional-status">required</span> `boolean`
Returns `true` when the file is being uploaded.
---
**<span className="parameter-name">progress</span>** <span className="optional-status">required</span> `null` | `number`
Returns the progress of the upload, from 0 to 100. Returns null if the upload has not started yet.
---
**<span className="parameter-name">isUploaded</span>** <span className="optional-status">required</span> `boolean`
Returns `true` when the file has been successfully uploaded.
---
**<span className="parameter-name">id</span>** <span className="optional-status">optional</span> `string`
Returns the id of the file.
---
**<span className="parameter-name">bucketId</span>** <span className="optional-status">optional</span> `string`
Returns the bucket id.
---
**<span className="parameter-name">name</span>** <span className="optional-status">optional</span> `string`
Returns the name of the file.
---
**<span className="parameter-name">add</span>** <span className="optional-status">required</span> `(params: StorageUploadFileParams) => void`
---
**<span className="parameter-name">upload</span>** <span className="optional-status">required</span> `(params: Partial<StorageUploadFileParams>) => Promise<UploadFileHandlerResult>`
---
**<span className="parameter-name">cancel</span>** <span className="optional-status">required</span> `() => void`
---

View File

@@ -1,6 +1,6 @@
{ {
"name": "@nhost/docs", "name": "@nhost/docs",
"version": "0.0.4", "version": "0.0.5",
"private": true, "private": true,
"scripts": { "scripts": {
"docusaurus": "docusaurus", "docusaurus": "docusaurus",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 55 KiB

View File

@@ -1,13 +1,13 @@
metadata_directory: metadata metadata_directory: metadata
services: services:
hasura: hasura:
image: hasura/graphql-engine:v2.10.1 image: hasura/graphql-engine:v2.15.2
environment: environment:
hasura_graphql_enable_remote_schema_permissions: false hasura_graphql_enable_remote_schema_permissions: false
auth: auth:
image: nhost/hasura-auth:0.15.0 image: nhost/hasura-auth:0.16.1
storage: storage:
image: nhost/hasura-storage:0.2.5 image: nhost/hasura-storage:0.3.0
auth: auth:
access_control: access_control:
email: email:

View File

@@ -1,13 +1,13 @@
metadata_directory: metadata metadata_directory: metadata
services: services:
hasura: hasura:
image: hasura/graphql-engine:v2.10.1 image: hasura/graphql-engine:v2.15.2
environment: environment:
hasura_graphql_enable_remote_schema_permissions: false hasura_graphql_enable_remote_schema_permissions: false
auth: auth:
image: nhost/hasura-auth:0.15.0 image: nhost/hasura-auth:0.16.1
storage: storage:
image: nhost/hasura-storage:0.2.5 image: nhost/hasura-storage:0.3.0
auth: auth:
access_control: access_control:
email: email:

View File

@@ -24,7 +24,7 @@ services:
ports: ports:
- '5432:5432' - '5432:5432'
graphql-engine: graphql-engine:
image: hasura/graphql-engine:v2.2.0 image: hasura/graphql-engine:v2.15.2
depends_on: depends_on:
- 'postgres' - 'postgres'
restart: always restart: always
@@ -72,7 +72,7 @@ services:
- "traefik.http.routers.auth.middlewares=strip-auth@docker" - "traefik.http.routers.auth.middlewares=strip-auth@docker"
- "traefik.http.routers.auth.entrypoints=web" - "traefik.http.routers.auth.entrypoints=web"
storage: storage:
image: nhost/hasura-storage:0.2.1 image: nhost/hasura-storage:0.3.1
depends_on: depends_on:
- postgres - postgres
- graphql-engine - graphql-engine

View File

@@ -1,13 +1,13 @@
metadata_directory: metadata metadata_directory: metadata
services: services:
hasura: hasura:
image: hasura/graphql-engine:v2.10.1 image: hasura/graphql-engine:v2.15.2
environment: environment:
hasura_graphql_enable_remote_schema_permissions: false hasura_graphql_enable_remote_schema_permissions: false
auth: auth:
image: nhost/hasura-auth:0.15.0 image: nhost/hasura-auth:0.16.1
storage: storage:
image: nhost/hasura-storage:0.2.5 image: nhost/hasura-storage:0.3.0
auth: auth:
access_control: access_control:
email: email:

View File

@@ -7,7 +7,7 @@
- ba785da1: Bump dependencies versions - ba785da1: Bump dependencies versions
- Updated dependencies [ba785da1] - Updated dependencies [ba785da1]
- Updated dependencies [6da44bf8] - Updated dependencies [6da44bf8]
- @nhost/nextjs@2.0.0 - @nhost/nextjs@1.9.0
- @nhost/react@0.14.0 - @nhost/react@0.14.0
- @nhost/react-apollo@5.0.0 - @nhost/react-apollo@5.0.0

View File

@@ -1,13 +1,13 @@
metadata_directory: metadata metadata_directory: metadata
services: services:
hasura: hasura:
image: hasura/graphql-engine:v2.10.1 image: hasura/graphql-engine:v2.15.2
environment: environment:
hasura_graphql_enable_remote_schema_permissions: false hasura_graphql_enable_remote_schema_permissions: false
auth: auth:
image: nhost/hasura-auth:0.15.0 image: nhost/hasura-auth:0.16.1
storage: storage:
image: nhost/hasura-storage:0.2.5 image: nhost/hasura-storage:0.3.0
auth: auth:
access_control: access_control:
email: email:

View File

@@ -1,13 +1,13 @@
metadata_directory: metadata metadata_directory: metadata
services: services:
hasura: hasura:
image: hasura/graphql-engine:v2.10.1 image: hasura/graphql-engine:v2.15.2
environment: environment:
hasura_graphql_enable_remote_schema_permissions: false hasura_graphql_enable_remote_schema_permissions: false
auth: auth:
image: nhost/hasura-auth:0.15.0 image: nhost/hasura-auth:0.16.1
storage: storage:
image: nhost/hasura-storage:0.2.5 image: nhost/hasura-storage:0.3.0
auth: auth:
access_control: access_control:
email: email:
@@ -15,7 +15,7 @@ auth:
allowed_emails: '' allowed_emails: ''
blocked_email_domains: '' blocked_email_domains: ''
blocked_emails: '' blocked_emails: ''
allowed_redirect_urls: 'http://127.0.0.1:3000' allowed_redirect_urls: http://127.0.0.1:3000
anonymous_users_enabled: true anonymous_users_enabled: true
client_url: http://localhost:3000 client_url: http://localhost:3000
disable_new_users: false disable_new_users: false

View File

@@ -3,7 +3,7 @@ services:
hasura: hasura:
environment: environment:
hasura_graphql_enable_remote_schema_permissions: false hasura_graphql_enable_remote_schema_permissions: false
image: hasura/graphql-engine:v2.10.1 image: hasura/graphql-engine:v2.15.2
minio: minio:
environment: environment:
minio_root_password: minioaccesskey123123 minio_root_password: minioaccesskey123123
@@ -13,9 +13,9 @@ services:
postgres_password: postgres postgres_password: postgres
postgres_user: postgres postgres_user: postgres
auth: auth:
image: nhost/hasura-auth:0.15.0 image: nhost/hasura-auth:0.16.1
storage: storage:
image: nhost/hasura-storage:0.2.5 image: nhost/hasura-storage:0.3.0
auth: auth:
webauthn: webauthn:
enabled: true enabled: true

View File

@@ -1,10 +1,11 @@
metadata_directory: metadata metadata_directory: metadata
services: services:
storage: storage:
image: nhost/hasura-storage:0.2.7 image: nhost/hasura-storage:0.3.0
hasura: hasura:
environment: environment:
hasura_graphql_enable_remote_schema_permissions: false hasura_graphql_enable_remote_schema_permissions: false
image: hasura/graphql-engine:v2.15.2
minio: minio:
environment: environment:
minio_root_password: minioaccesskey123123 minio_root_password: minioaccesskey123123
@@ -13,6 +14,8 @@ services:
environment: environment:
postgres_password: postgres postgres_password: postgres
postgres_user: postgres postgres_user: postgres
auth:
image: nhost/hasura-auth:0.16.1
auth: auth:
access_control: access_control:
email: email:

View File

@@ -3,6 +3,7 @@ services:
hasura: hasura:
environment: environment:
hasura_graphql_enable_remote_schema_permissions: false hasura_graphql_enable_remote_schema_permissions: false
image: hasura/graphql-engine:v2.15.2
minio: minio:
environment: environment:
minio_root_password: minioaccesskey123123 minio_root_password: minioaccesskey123123
@@ -11,15 +12,19 @@ services:
environment: environment:
postgres_password: postgres postgres_password: postgres
postgres_user: postgres postgres_user: postgres
auth:
image: nhost/hasura-auth:0.16.1
storage:
image: nhost/hasura-storage:0.3.0
auth: auth:
access_control: access_control:
email: email:
allowed_email_domains: "" allowed_email_domains: ''
allowed_emails: "" allowed_emails: ''
blocked_email_domains: "" blocked_email_domains: ''
blocked_emails: "" blocked_emails: ''
url: url:
allowed_redirect_urls: "" allowed_redirect_urls: ''
anonymous_users_enabled: false anonymous_users_enabled: false
client_url: http://localhost:3000 client_url: http://localhost:3000
disable_new_users: false disable_new_users: false
@@ -28,11 +33,11 @@ auth:
passwordless: passwordless:
enabled: false enabled: false
signin_email_verified_required: true signin_email_verified_required: true
template_fetch_url: "" template_fetch_url: ''
gravatar: gravatar:
default: "" default: ''
enabled: true enabled: true
rating: "" rating: ''
locale: locale:
allowed: en allowed: en
default: en default: en
@@ -41,65 +46,65 @@ auth:
min_length: 3 min_length: 3
provider: provider:
apple: apple:
client_id: "" client_id: ''
enabled: false enabled: false
key_id: "" key_id: ''
private_key: "" private_key: ''
scope: name,email scope: name,email
team_id: "" team_id: ''
bitbucket: bitbucket:
client_id: "" client_id: ''
client_secret: "" client_secret: ''
enabled: false enabled: false
facebook: facebook:
client_id: "" client_id: ''
client_secret: "" client_secret: ''
enabled: false enabled: false
scope: email,photos,displayName scope: email,photos,displayName
github: github:
client_id: "" client_id: ''
client_secret: "" client_secret: ''
enabled: false enabled: false
scope: user:email scope: user:email
token_url: "" token_url: ''
user_profile_url: "" user_profile_url: ''
gitlab: gitlab:
base_url: "" base_url: ''
client_id: "" client_id: ''
client_secret: "" client_secret: ''
enabled: false enabled: false
scope: read_user scope: read_user
google: google:
client_id: "" client_id: ''
client_secret: "" client_secret: ''
enabled: false enabled: false
scope: email,profile scope: email,profile
linkedin: linkedin:
client_id: "" client_id: ''
client_secret: "" client_secret: ''
enabled: false enabled: false
scope: r_emailaddress,r_liteprofile scope: r_emailaddress,r_liteprofile
spotify: spotify:
client_id: "" client_id: ''
client_secret: "" client_secret: ''
enabled: false enabled: false
scope: user-read-email,user-read-private scope: user-read-email,user-read-private
strava: strava:
client_id: "" client_id: ''
client_secret: "" client_secret: ''
enabled: false enabled: false
twilio: twilio:
account_sid: "" account_sid: ''
auth_token: "" auth_token: ''
enabled: false enabled: false
messaging_service_id: "" messaging_service_id: ''
twitter: twitter:
consumer_key: "" consumer_key: ''
consumer_secret: "" consumer_secret: ''
enabled: false enabled: false
windows_live: windows_live:
client_id: "" client_id: ''
client_secret: "" client_secret: ''
enabled: false enabled: false
scope: wl.basic,wl.emails,wl.contacts_emails scope: wl.basic,wl.emails,wl.contacts_emails
sms: sms:
@@ -108,13 +113,13 @@ auth:
enabled: false enabled: false
provider: provider:
twilio: twilio:
account_sid: "" account_sid: ''
auth_token: "" auth_token: ''
from: "" from: ''
messaging_service_id: "" messaging_service_id: ''
smtp: smtp:
host: mailhog host: mailhog
method: "" method: ''
pass: password pass: password
port: 1025 port: 1025
secure: false secure: false

View File

@@ -0,0 +1,9 @@
# @nhost-examples/serverless-functions
## 0.0.2
### Patch Changes
- 93db7182: feat(stripe-graphql-js): add charges, payment intents and connected accounts
- Updated dependencies [93db7182]
- @nhost/stripe-graphql-js@0.0.6

View File

@@ -0,0 +1,25 @@
/*
- How to use async/await.
Test:
curl http://localhost:1337/v1/functions/async-await
*/
import fetch from 'cross-fetch'
import { Request, Response } from 'express'
// using async in the function signature
export default async (req: Request, res: Response) => {
// using await
const result = await fetch('//api.github.com/repos/nhost/nhost')
if (result.status >= 400) {
throw new Error('Bad response from server')
}
const repo = await result.json()
res.json(repo)
}

View File

@@ -0,0 +1,44 @@
/*
- How to send an email via SMTP.
Test:
curl http://localhost:1337/v1/functions/send-email
*/
import { Request, Response } from 'express'
import nodemailer from 'nodemailer'
export default async (req: Request, res: Response) => {
// Only needed if you don't have a real mail account for testing
let testAccount = await nodemailer.createTestAccount()
// create reusable transporter object using the default SMTP transport
let transporter = nodemailer.createTransport({
host: 'smtp.ethereal.email',
port: 587,
secure: false, // true for 465, false for other ports
auth: {
user: testAccount.user, // generated ethereal user
pass: testAccount.pass // generated ethereal password
}
})
// send mail with defined transport object
let info = await transporter.sendMail({
from: '"Fred Foo 👻" <foo@example.com>', // sender address
to: 'bar@example.com, baz@example.com', // list of receivers
subject: 'Hello ✔', // Subject line
text: 'Hello world?', // plain text body
html: '<b>Hello world?</b>' // html body
})
console.log('Message sent: %s', info.messageId)
// Message sent: <b658f8ca-6296-ccf4-8306-87d57a0b4321@example.com>
// Preview only available when sending through an Ethereal account
console.log('Preview URL: %s', nodemailer.getTestMessageUrl(info))
res.json('Message sent')
}

View File

@@ -3,6 +3,7 @@ services:
hasura: hasura:
environment: environment:
hasura_graphql_enable_remote_schema_permissions: false hasura_graphql_enable_remote_schema_permissions: false
image: hasura/graphql-engine:v2.15.2
minio: minio:
environment: environment:
minio_root_password: minioaccesskey123123 minio_root_password: minioaccesskey123123
@@ -11,15 +12,19 @@ services:
environment: environment:
postgres_password: postgres postgres_password: postgres
postgres_user: postgres postgres_user: postgres
auth:
image: nhost/hasura-auth:0.16.1
storage:
image: nhost/hasura-storage:0.3.0
auth: auth:
access_control: access_control:
email: email:
allowed_email_domains: "" allowed_email_domains: ''
allowed_emails: "" allowed_emails: ''
blocked_email_domains: "" blocked_email_domains: ''
blocked_emails: "" blocked_emails: ''
url: url:
allowed_redirect_urls: "" allowed_redirect_urls: ''
anonymous_users_enabled: false anonymous_users_enabled: false
client_url: http://localhost:3000 client_url: http://localhost:3000
disable_new_users: false disable_new_users: false
@@ -28,11 +33,11 @@ auth:
passwordless: passwordless:
enabled: false enabled: false
signin_email_verified_required: true signin_email_verified_required: true
template_fetch_url: "" template_fetch_url: ''
gravatar: gravatar:
default: "" default: ''
enabled: true enabled: true
rating: "" rating: ''
locale: locale:
allowed: en allowed: en
default: en default: en
@@ -41,65 +46,65 @@ auth:
min_length: 3 min_length: 3
provider: provider:
apple: apple:
client_id: "" client_id: ''
enabled: false enabled: false
key_id: "" key_id: ''
private_key: "" private_key: ''
scope: name,email scope: name,email
team_id: "" team_id: ''
bitbucket: bitbucket:
client_id: "" client_id: ''
client_secret: "" client_secret: ''
enabled: false enabled: false
facebook: facebook:
client_id: "" client_id: ''
client_secret: "" client_secret: ''
enabled: false enabled: false
scope: email,photos,displayName scope: email,photos,displayName
github: github:
client_id: "" client_id: ''
client_secret: "" client_secret: ''
enabled: false enabled: false
scope: user:email scope: user:email
token_url: "" token_url: ''
user_profile_url: "" user_profile_url: ''
gitlab: gitlab:
base_url: "" base_url: ''
client_id: "" client_id: ''
client_secret: "" client_secret: ''
enabled: false enabled: false
scope: read_user scope: read_user
google: google:
client_id: "" client_id: ''
client_secret: "" client_secret: ''
enabled: false enabled: false
scope: email,profile scope: email,profile
linkedin: linkedin:
client_id: "" client_id: ''
client_secret: "" client_secret: ''
enabled: false enabled: false
scope: r_emailaddress,r_liteprofile scope: r_emailaddress,r_liteprofile
spotify: spotify:
client_id: "" client_id: ''
client_secret: "" client_secret: ''
enabled: false enabled: false
scope: user-read-email,user-read-private scope: user-read-email,user-read-private
strava: strava:
client_id: "" client_id: ''
client_secret: "" client_secret: ''
enabled: false enabled: false
twilio: twilio:
account_sid: "" account_sid: ''
auth_token: "" auth_token: ''
enabled: false enabled: false
messaging_service_id: "" messaging_service_id: ''
twitter: twitter:
consumer_key: "" consumer_key: ''
consumer_secret: "" consumer_secret: ''
enabled: false enabled: false
windows_live: windows_live:
client_id: "" client_id: ''
client_secret: "" client_secret: ''
enabled: false enabled: false
scope: wl.basic,wl.emails,wl.contacts_emails scope: wl.basic,wl.emails,wl.contacts_emails
sms: sms:
@@ -108,13 +113,13 @@ auth:
enabled: false enabled: false
provider: provider:
twilio: twilio:
account_sid: "" account_sid: ''
auth_token: "" auth_token: ''
from: "" from: ''
messaging_service_id: "" messaging_service_id: ''
smtp: smtp:
host: mailhog host: mailhog
method: "" method: ''
pass: password pass: password
port: 1025 port: 1025
secure: false secure: false

View File

@@ -1,15 +1,17 @@
{ {
"name": "@nhost-examples/serverless-functions", "name": "@nhost-examples/serverless-functions",
"private": true, "private": true,
"version": "0.0.1", "version": "0.0.2",
"devDependencies": { "devDependencies": {
"@types/express": "^4.17.13" "@types/express": "^4.17.13"
}, },
"dependencies": { "dependencies": {
"@graphql-yoga/node": "^2.13.13", "@graphql-yoga/node": "^2.13.13",
"@nhost/stripe-graphql-js": "^0.0.5", "@nhost/stripe-graphql-js": "^0.0.6",
"@pothos/core": "^3.21.0", "@pothos/core": "^3.21.0",
"cross-fetch": "^3.1.5",
"graphql": "15.7.2", "graphql": "15.7.2",
"nodemailer": "^6.8.0",
"slugify": "^1.6.5" "slugify": "^1.6.5"
} }
} }

View File

@@ -1,13 +1,13 @@
metadata_directory: metadata metadata_directory: metadata
services: services:
hasura: hasura:
image: hasura/graphql-engine:v2.10.1 image: hasura/graphql-engine:v2.15.2
environment: environment:
hasura_graphql_enable_remote_schema_permissions: false hasura_graphql_enable_remote_schema_permissions: false
auth: auth:
image: nhost/hasura-auth:0.15.0 image: nhost/hasura-auth:0.16.1
storage: storage:
image: nhost/hasura-storage:0.2.5 image: nhost/hasura-storage:0.3.0
auth: auth:
access_control: access_control:
email: email:

View File

@@ -1,5 +1,11 @@
# @nhost/stripe-graphql-js # @nhost/stripe-graphql-js
## 0.0.6
### Patch Changes
- 93db7182: feat(stripe-graphql-js): add charges, payment intents and connected accounts
## 0.0.5 ## 0.0.5
### Patch Changes ### Patch Changes

View File

@@ -197,6 +197,14 @@ Start the development server:
pnpm dev pnpm dev
``` ```
Include the correct admin secret header for admin access
```js
{
"x-hasura-admin-secret":"<secret value matching your NHOST_ADMIN_SECRET environment variable>"
}
```
The GraphQL Server will reload every time the code changes. The GraphQL Server will reload every time the code changes.
Open GraphiQL: Open GraphiQL:

View File

@@ -1,6 +1,6 @@
{ {
"name": "@nhost/stripe-graphql-js", "name": "@nhost/stripe-graphql-js",
"version": "0.0.5", "version": "0.0.6",
"description": "Stripe GraphQL API", "description": "Stripe GraphQL API",
"license": "MIT", "license": "MIT",
"keywords": [ "keywords": [

View File

@@ -3,7 +3,13 @@ import Stripe from 'stripe'
import SchemaBuilder from '@pothos/core' import SchemaBuilder from '@pothos/core'
import { Context, StripeInvoice, StripePaymentMethod, StripeSubscription } from './types' import {
Context,
StripeCharge,
StripeInvoice,
StripePaymentIntent,
StripePaymentMethod,
StripeSubscription} from './types'
// TODO: Make sure we either use Type or Types (e.g. StripePaymentMethodTypes or StripePaymentMethodType ) everywhere // TODO: Make sure we either use Type or Types (e.g. StripePaymentMethodTypes or StripePaymentMethodType ) everywhere
@@ -93,6 +99,18 @@ const builder = new SchemaBuilder<{
// BILLING PORTAL // BILLING PORTAL
StripeBillingPortalSession: Stripe.BillingPortal.Session StripeBillingPortalSession: Stripe.BillingPortal.Session
// PAYMENT INTENT
StripePaymentIntent: StripePaymentIntent
StripePaymentIntents: Stripe.ApiList<StripePaymentIntent>
// CHARGES
StripeCharge: StripeCharge
StripeCharges: Stripe.ApiList<StripeCharge>
// CONNECTED ACCOUNTS
StripeConnectedAccount: Stripe.Account
StripeConnectedAccounts: Stripe.ApiList<Stripe.Account>
} }
Context: Context Context: Context
}>({}) }>({})

View File

@@ -0,0 +1,82 @@
import Stripe from 'stripe'
import { builder } from '../builder'
import { StripeInvoice } from '../types'
import { stripe } from '../utils'
builder.objectType('StripeCharge', {
description: 'Stripe charge object',
fields: (t) => ({
id: t.exposeString('id'),
customer: t.exposeString('customer'),
amount: t.exposeInt('amount'),
amountCaptured: t.exposeInt('amount_captured'),
amountRefunded: t.exposeInt('amount_refunded'),
applicationFeeAmount: t.exposeInt('application_fee_amount', { nullable: true }),
calculatedStatementDescriptor: t.exposeString('calculated_statement_descriptor', {
nullable: true
}),
billingDetails: t.expose('billing_details', { type: 'JSON', nullable: true }),
captured: t.exposeBoolean('captured'),
created: t.exposeInt('created', {
nullable: true
}),
currency: t.exposeString('currency'),
description: t.exposeString('description', { nullable: true }),
disputed: t.exposeBoolean('disputed'),
failureCode: t.exposeString('failure_code', { nullable: true }),
invoice: t.field({
type: 'StripeInvoice',
nullable: true,
resolve: async (charge) => {
const { invoice } = charge
if (!invoice) {
return null
}
const invoiceData = await stripe.invoices.retrieve(invoice as string)
return invoiceData as Stripe.Response<StripeInvoice>
}
}),
application: t.field({
type: 'StripeConnectedAccount',
nullable: true,
resolve: async (charge) => {
const { application } = charge
if (!application) return null
const connectedAccount = await stripe.accounts.retrieve(application as string)
return connectedAccount
}
}),
livemode: t.exposeBoolean('livemode'),
metadata: t.expose('metadata', { nullable: true, type: 'JSON' }),
outcome: t.expose('outcome', { nullable: true, type: 'JSON' }),
fraudDetails: t.expose('fraud_details', { nullable: true, type: 'JSON' }),
paid: t.exposeBoolean('paid'),
receiptEmail: t.exposeString('receipt_email', { nullable: true }),
receiptNumber: t.exposeString('receipt_number', { nullable: true }),
receiptUrl: t.exposeString('receipt_url', { nullable: true }),
refunded: t.exposeBoolean('refunded'),
shipping: t.expose('shipping', { nullable: true, type: 'JSON' }),
statementDescriptor: t.exposeString('statement_descriptor', { nullable: true }),
statementDescriptorSuffix: t.exposeString('statement_descriptor_suffix', { nullable: true }),
status: t.exposeString('status'),
transferData: t.expose('transfer_data', { nullable: true, type: 'JSON' }),
transferGroup: t.exposeString('transfer_group', { nullable: true }),
refunds: t.expose('refunds', { nullable: true, type: 'JSON' }),
paymentMethodDetails: t.expose('payment_method_details', { nullable: true, type: 'JSON' }),
paymentIntent: t.exposeString('payment_intent', { nullable: true }),
paymentMethod: t.exposeString('payment_method', { nullable: true })
// todo: add missing fields
// application_fee
// balance_transaction
// on_behalf_of
// failure_balance_transaction
// source_transfer
})
})

View File

@@ -0,0 +1,14 @@
import { builder } from '../builder'
builder.objectType('StripeCharges', {
description: 'List of Stripe charge objects',
fields: (t) => ({
object: t.exposeString('object'),
url: t.exposeString('url'),
hasMore: t.exposeBoolean('has_more'),
data: t.expose('data', {
type: ['StripeCharge'],
nullable: false
})
})
})

View File

@@ -0,0 +1,28 @@
import { builder } from '../builder'
builder.objectType('StripeConnectedAccount', {
description: 'Stripe charge object',
fields: (t) => ({
id: t.exposeString('id'),
object: t.exposeString('object'),
country: t.exposeString('country', { nullable: true }),
businessType: t.exposeString('business_type', { nullable: true }),
capabilities: t.expose('capabilities', { type: 'JSON' }),
company: t.expose('company', { type: 'JSON' }),
email: t.exposeString('email', { nullable: true }),
individual: t.expose('individual', { type: 'JSON' }),
metadata: t.expose('metadata', { type: 'JSON' }),
requirements: t.expose('requirements', { type: 'JSON' }),
tosAcceptance: t.expose('tos_acceptance', { type: 'JSON' }),
businessProfile: t.expose('business_profile', { type: 'JSON' }),
chargesEnabled: t.exposeBoolean('charges_enabled'),
controller: t.expose('controller', { nullable: true, type: 'JSON' }),
created: t.exposeInt('created', { nullable: true }),
defaultCurrency: t.exposeString('default_currency', { nullable: true }),
detailsSubmitted: t.exposeBoolean('details_submitted'),
externalAccounts: t.expose('external_accounts', { type: 'JSON' }),
futureRequirements: t.expose('future_requirements', { type: 'JSON' }),
payoutsEnabled: t.exposeBoolean('payouts_enabled'),
settings: t.expose('settings', { type: 'JSON' })
})
})

View File

@@ -0,0 +1,14 @@
import { builder } from '../builder'
builder.objectType('StripeConnectedAccounts', {
description: 'List of Stripe Connected Account objects',
fields: (t) => ({
object: t.exposeString('object'),
url: t.exposeString('url'),
hasMore: t.exposeBoolean('has_more'),
data: t.expose('data', {
type: ['StripeConnectedAccount'],
nullable: false
})
})
})

View File

@@ -1,7 +1,12 @@
import Stripe from 'stripe' import Stripe from 'stripe'
import { builder } from '../builder' import { builder } from '../builder'
import { StripeInvoice, StripePaymentMethod, StripeSubscription } from '../types' import {
StripeCharge,
StripeInvoice,
StripePaymentIntent,
StripePaymentMethod,
StripeSubscription} from '../types'
import { stripe } from '../utils' import { stripe } from '../utils'
import { StripePaymentMethodTypes } from './payment-methods' import { StripePaymentMethodTypes } from './payment-methods'
@@ -110,6 +115,16 @@ builder.objectType('StripeCustomer', {
return invoices as Stripe.Response<Stripe.ApiList<StripeInvoice>> return invoices as Stripe.Response<Stripe.ApiList<StripeInvoice>>
} }
}), }),
paymentIntents: t.field({
type: 'StripePaymentIntents',
nullable: false,
resolve: async (customer) => {
const paymentIntents = await stripe.paymentIntents.list({
customer: customer.id
})
return paymentIntents as Stripe.Response<Stripe.ApiList<StripePaymentIntent>>
}
}),
paymentMethods: t.field({ paymentMethods: t.field({
type: 'StripePaymentMethods', type: 'StripePaymentMethods',
args: { args: {
@@ -138,6 +153,16 @@ builder.objectType('StripeCustomer', {
}) })
return paymentMethods as Stripe.Response<Stripe.ApiList<StripePaymentMethod>> return paymentMethods as Stripe.Response<Stripe.ApiList<StripePaymentMethod>>
} }
}),
charges: t.field({
type: 'StripeCharges',
nullable: false,
resolve: async (customer) => {
const charges = await stripe.charges.list({
customer: customer.id
})
return charges as Stripe.Response<Stripe.ApiList<StripeCharge>>
}
}) })
}) })
}) })

View File

@@ -42,6 +42,12 @@ import './product'
import './tax-rate' import './tax-rate'
import './test-clock' import './test-clock'
import './billing-portal-session' import './billing-portal-session'
import './payment-intent'
import './payment-intents'
import './charges'
import './charge'
import './connectedAccount'
import './connectedAccounts'
import { builder } from '../builder' import { builder } from '../builder'

View File

@@ -32,7 +32,18 @@ builder.objectType('StripeInvoice', {
amountRemaining: t.exposeInt('amount_remaining', { amountRemaining: t.exposeInt('amount_remaining', {
description: `The difference between amount_due and amount_paid, in %s.` description: `The difference between amount_due and amount_paid, in %s.`
}), }),
// todo: application application: t.field({
type: 'StripeConnectedAccount',
nullable: true,
resolve: async (invoice) => {
const { application } = invoice
if (!application) return null
const connectedAccount = await stripe.accounts.retrieve(application as string)
return connectedAccount
}
}),
applicationFeeAmount: t.exposeInt('application_fee_amount', { applicationFeeAmount: t.exposeInt('application_fee_amount', {
description: `The fee in %s that will be applied to the invoice and transferred to the application owner's Stripe account when the invoice is paid.`, description: `The fee in %s that will be applied to the invoice and transferred to the application owner's Stripe account when the invoice is paid.`,
nullable: true nullable: true

View File

@@ -0,0 +1,75 @@
import Stripe from 'stripe'
import { builder } from '../builder'
import { StripeInvoice } from '../types'
import { stripe } from '../utils'
builder.objectType('StripePaymentIntent', {
description: 'Payment intents',
fields: (t) => ({
id: t.exposeString('id'),
object: t.exposeString('object'),
amount: t.exposeInt('amount'),
currency: t.exposeString('currency'),
description: t.exposeString('description', {
nullable: true
}),
metadata: t.expose('metadata', {
type: 'JSON',
nullable: true
}),
paymentMethodTypes: t.exposeStringList('payment_method_types'),
statementDescriptor: t.exposeString('statement_descriptor', {
nullable: true
}),
statementDescriptorSuffix: t.exposeString('statement_descriptor_suffix', {
nullable: true
}),
receiptEmail: t.exposeString('receipt_email', {
nullable: true
}),
customer: t.exposeString('customer'),
amountCapturable: t.exposeInt('amount_capturable'),
amountDetails: t.expose('amount_details', {
nullable: true,
type: 'JSON'
}),
amountReceived: t.exposeInt('amount_received'),
applicationFeeAmount: t.exposeInt('application_fee_amount', {
nullable: true
}),
canceledAt: t.exposeInt('canceled_at', {
nullable: true
}),
transferGroup: t.exposeString('transfer_group', {
nullable: true
}),
cancellationReason: t.exposeString('cancellation_reason', {
nullable: true
}),
created: t.exposeInt('created', {
nullable: true
}),
status: t.exposeString('status'),
invoice: t.field({
type: 'StripeInvoice',
nullable: true,
resolve: async (paymentIntent) => {
const { invoice } = paymentIntent
if (!invoice) {
return null
}
const invoiceData = await stripe.invoices.retrieve(invoice as string)
return invoiceData as Stripe.Response<StripeInvoice>
}
})
// todo: missing fields
// capture_method
// add charges
// application
})
})

View File

@@ -0,0 +1,13 @@
import { builder } from '../builder'
builder.objectType('StripePaymentIntents', {
fields: (t) => ({
object: t.exposeString('object'),
url: t.exposeString('url'),
hasMore: t.exposeBoolean('has_more'),
data: t.expose('data', {
type: ['StripePaymentIntent'],
nullable: false
})
})
})

View File

@@ -7,6 +7,35 @@ import { stripe } from '../utils'
builder.objectType('Stripe', { builder.objectType('Stripe', {
fields: (t) => ({ fields: (t) => ({
connectedAccounts: t.field({
type: 'StripeConnectedAccounts',
resolve: async (_parent, _, context) => {
const { isAdmin } = context
if (!isAdmin) throw new GraphQLYogaError('Not allowed')
const connectedAccounts = await stripe.accounts.list()
return connectedAccounts
}
}),
connectedAccount: t.field({
type: 'StripeConnectedAccount',
args: {
id: t.arg.string({
required: true
})
},
resolve: async (_parent, { id }, context) => {
const { isAdmin } = context
if (!isAdmin) throw new GraphQLYogaError('Not allowed')
const connectedAccount = await stripe.accounts.retrieve(id)
return connectedAccount
}
}),
customer: t.field({ customer: t.field({
type: 'StripeCustomer', type: 'StripeCustomer',
args: { args: {

View File

@@ -31,6 +31,16 @@ export type StripeInvoice = Stripe.Invoice & {
id: string id: string
customer: string customer: string
default_payment_method: StripePaymentMethod | null default_payment_method: StripePaymentMethod | null
payment_intent: any
}
export type StripePaymentIntent = Stripe.PaymentIntent & {
customer: string
}
export type StripeCharge = Stripe.Charge & {
customer: string
payment_intent: string | null
} }
export type UserHasuraClaims = { export type UserHasuraClaims = {

View File

@@ -1,4 +1,4 @@
# Docker image versions used in the cloud # Docker image versions used in the cloud
hasura: v2.10.1 hasura: v2.15.2
auth: 0.15.0 auth: 0.16.1
storage: 0.2.5 storage: 0.3.0

View File

@@ -88,7 +88,7 @@
}, },
"packageManager": "pnpm@7.17.0", "packageManager": "pnpm@7.17.0",
"engines": { "engines": {
"node": ">=14 <17", "node": ">=16 <17",
"pnpm": ">=7.17.0" "pnpm": ">=7.17.0"
}, },
"eslintConfig": { "eslintConfig": {

View File

@@ -8,7 +8,9 @@ test('should categorize elements of groups in a Map', () => {
{ title: 'Classes', kind: 0, children: [1, 2, 3] }, { title: 'Classes', kind: 0, children: [1, 2, 3] },
{ title: 'Properties', kind: 0, children: [4, 5, 6, 7] }, { title: 'Properties', kind: 0, children: [4, 5, 6, 7] },
{ title: 'Type aliases', kind: 0, children: [8, 9] }, { title: 'Type aliases', kind: 0, children: [8, 9] },
{ title: 'Functions', kind: 0, children: [10] } { title: 'Functions', kind: 0, children: [10] },
{ title: 'Components', kind: 0, children: [11, 12, 13] },
{ title: 'References', kind: 0, children: [14, 15] }
]) ])
).toEqual( ).toEqual(
new Map([ new Map([
@@ -21,7 +23,12 @@ test('should categorize elements of groups in a Map', () => {
[7, 'Property'], [7, 'Property'],
[8, 'Type alias'], [8, 'Type alias'],
[9, 'Type alias'], [9, 'Type alias'],
[10, 'Function'] [10, 'Function'],
[11, 'Component'],
[12, 'Component'],
[13, 'Component'],
[14, 'Reference'],
[15, 'Reference']
]) ])
) )
}) })
@@ -57,3 +64,46 @@ test('should set content type to "undefined" if value does not exist in dictiona
]) ])
) )
}) })
test('should not treat the same text with different letter casing differently', () => {
expect(
getModuleContentMap([
{ title: 'Type aliases', kind: 0, children: [1, 2, 3] },
{ title: 'Type Aliases', kind: 0, children: [4] },
{ title: 'TYPE ALIASES', kind: 0, children: [5, 6] }
])
).toEqual(
new Map([
[1, 'Type alias'],
[2, 'Type alias'],
[3, 'Type alias'],
[4, 'Type alias'],
[5, 'Type alias'],
[6, 'Type alias']
])
)
})
test('should update the type of a child if it has a special category (not "Other")', () => {
expect(
getModuleContentMap([
{
title: 'Functions',
kind: 0,
children: [1, 2, 3],
categories: [
{ title: 'Components', children: [3] },
{ title: 'Other', children: [1] }
]
},
{ title: 'Type Aliases', kind: 0, children: [4] }
])
).toEqual(
new Map([
[1, 'Function'],
[2, 'Function'],
[3, 'Component'],
[4, 'Type alias']
])
)
})

View File

@@ -4,17 +4,19 @@ import { Group } from '../types'
* Used to convert plural names coming from TypeDoc to singular names. * Used to convert plural names coming from TypeDoc to singular names.
*/ */
const pluralSingularDictionary = new Map([ const pluralSingularDictionary = new Map([
['Classes', 'Class'], ['classes', 'Class'],
['Properties', 'Property'], ['properties', 'Property'],
['Methods', 'Method'], ['methods', 'Method'],
['Functions', 'Function'], ['functions', 'Function'],
['Type aliases', 'Type alias'], ['type aliases', 'Type alias'],
['Interfaces', 'Interface'], ['interfaces', 'Interface'],
['Modules', 'Module'], ['modules', 'Module'],
['Methods', 'Method'], ['methods', 'Method'],
['Variables', 'Variable'], ['variables', 'Variable'],
['Accessors', 'Accessor'], ['accessors', 'Accessor'],
['Constructors', 'Constructor'] ['constructors', 'Constructor'],
['components', 'Component'],
['references', 'Reference']
]) ])
/** /**
@@ -28,13 +30,27 @@ export function getModuleContentMap(
groups: Array<Group>, groups: Array<Group>,
originalMap: Map<number, string> = new Map() originalMap: Map<number, string> = new Map()
): Map<number, string> { ): Map<number, string> {
return groups.reduce((contentMap, { title, children }) => { return groups.reduce((contentMap, { title, children, categories }) => {
const singularTitle = pluralSingularDictionary.get(title) const singularTitle = pluralSingularDictionary.get(title.toLowerCase())
children.forEach((child) => { children.forEach((child) => {
contentMap.set(child, singularTitle || 'undefined') contentMap.set(child, singularTitle || 'undefined')
}) })
if (categories) {
categories.forEach(({ title: categoryTitle, children: categoryChildren }) => {
if (categoryTitle === 'Other') {
return
}
const singularTitle = pluralSingularDictionary.get(categoryTitle.toLowerCase())
categoryChildren.forEach((categoryChild) => {
contentMap.set(categoryChild, singularTitle || 'undefined')
})
})
}
return contentMap return contentMap
}, originalMap) }, originalMap)
} }

View File

@@ -16,7 +16,7 @@ import { Signature } from '../types'
* @returns Prettified function page template * @returns Prettified function page template
*/ */
export const FunctionTemplate = ( export const FunctionTemplate = (
{ name, comment, signatures, sources }: Signature, { id, name, comment, signatures, sources }: Signature,
originalDocument?: Array<Signature>, originalDocument?: Array<Signature>,
slug?: string, slug?: string,
functionFragmentOptions?: FunctionFragmentOptions functionFragmentOptions?: FunctionFragmentOptions
@@ -25,13 +25,14 @@ export const FunctionTemplate = (
const allChildrenDeprecated = signatures?.every((signature) => const allChildrenDeprecated = signatures?.every((signature) =>
signature.comment?.tags?.some(({ tag }) => tag === 'deprecated') signature.comment?.tags?.some(({ tag }) => tag === 'deprecated')
) )
const { baseEditUrl } = snapshot(appState) const { baseEditUrl, contentReferences } = snapshot(appState)
const isComponent = contentReferences.get(id) === 'Component'
const source = sources?.[0] const source = sources?.[0]
const header = `--- const header = `---
# ⚠️ AUTO-GENERATED CONTENT. DO NOT EDIT THIS FILE DIRECTLY! ⚠️ # ⚠️ AUTO-GENERATED CONTENT. DO NOT EDIT THIS FILE DIRECTLY! ⚠️
title: ${name}() title: ${isComponent ? `<${name} />` : `${name}()`}
sidebar_label: ${alias || name}() sidebar_label: ${isComponent ? `<${alias || name} />` : `${alias || name}()`}
${slug ? `slug: ${slug}` : ``} ${slug ? `slug: ${slug}` : ``}
${allChildrenDeprecated ? 'sidebar_class_name: deprecated' : ''} ${allChildrenDeprecated ? 'sidebar_class_name: deprecated' : ''}
${ ${

View File

@@ -29,6 +29,7 @@ export type Group = {
title: string title: string
kind: number kind: number
children: Array<number> children: Array<number>
categories?: Array<{ title: string; children: Array<number> }>
} }
export type Source = { export type Source = {

View File

@@ -1,13 +1,13 @@
metadata_directory: metadata metadata_directory: metadata
services: services:
hasura: hasura:
image: hasura/graphql-engine:v2.10.1 image: hasura/graphql-engine:v2.15.2
environment: environment:
hasura_graphql_enable_remote_schema_permissions: false hasura_graphql_enable_remote_schema_permissions: false
auth: auth:
image: nhost/hasura-auth:0.15.0 image: nhost/hasura-auth:0.16.1
storage: storage:
image: nhost/hasura-storage:0.2.5 image: nhost/hasura-storage:0.3.0
auth: auth:
access_control: access_control:
email: email:

View File

@@ -1,13 +1,13 @@
metadata_directory: metadata metadata_directory: metadata
services: services:
hasura: hasura:
image: hasura/graphql-engine:v2.10.1 image: hasura/graphql-engine:v2.15.2
environment: environment:
hasura_graphql_enable_remote_schema_permissions: false hasura_graphql_enable_remote_schema_permissions: false
auth: auth:
image: nhost/hasura-auth:0.15.0 image: nhost/hasura-auth:0.16.1
storage: storage:
image: nhost/hasura-storage:0.2.5 image: nhost/hasura-storage:0.3.0
auth: auth:
access_control: access_control:
email: email:

View File

@@ -1,5 +1,13 @@
# @nhost/nextjs # @nhost/nextjs
## 1.9.0
### Patch Changes
- Updated dependencies [4601d84e]
- Updated dependencies [843087cb]
- @nhost/react@0.15.0
## 1.8.3 ## 1.8.3
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@nhost/nextjs", "name": "@nhost/nextjs",
"version": "1.8.3", "version": "1.9.0",
"description": "Nhost NextJS library", "description": "Nhost NextJS library",
"license": "MIT", "license": "MIT",
"keywords": [ "keywords": [

View File

@@ -1,13 +1,13 @@
metadata_directory: metadata metadata_directory: metadata
services: services:
hasura: hasura:
image: hasura/graphql-engine:v2.10.1 image: hasura/graphql-engine:v2.15.2
environment: environment:
hasura_graphql_enable_remote_schema_permissions: false hasura_graphql_enable_remote_schema_permissions: false
auth: auth:
image: nhost/hasura-auth:0.15.0 image: nhost/hasura-auth:0.16.1
storage: storage:
image: nhost/hasura-storage:0.2.5 image: nhost/hasura-storage:0.3.0
auth: auth:
access_control: access_control:
email: email:

View File

@@ -1,5 +1,13 @@
# @nhost/react-apollo # @nhost/react-apollo
## 4.9.0
### Patch Changes
- Updated dependencies [4601d84e]
- Updated dependencies [843087cb]
- @nhost/react@0.15.0
## 4.8.3 ## 4.8.3
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@nhost/react-apollo", "name": "@nhost/react-apollo",
"version": "4.8.3", "version": "4.9.0",
"description": "Nhost React Apollo client", "description": "Nhost React Apollo client",
"license": "MIT", "license": "MIT",
"keywords": [ "keywords": [

View File

@@ -1,5 +1,15 @@
# @nhost/react # @nhost/react
## 0.15.0
### Minor Changes
- 4601d84e: Adding `<SignedIn />` and `<SignedOut />` components.
### Patch Changes
- 843087cb: Make `useUserRoles` reactive
## 0.14.3 ## 0.14.3
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@nhost/react", "name": "@nhost/react",
"version": "0.14.3", "version": "0.15.0",
"description": "Nhost React library", "description": "Nhost React library",
"license": "MIT", "license": "MIT",
"keywords": [ "keywords": [

View File

@@ -0,0 +1,36 @@
import { PropsWithChildren } from 'react'
import { useAuthenticationStatus } from '../useAuthenticationStatus'
/**
* Use `<SignedIn />` to control the rendering of components for users. Components inside `<SignedIn />` are only rendered if the user is authenticated.
*
* @example
* ```tsx
* import { NhostProvider, SignedOut } from "@nhost/react";
* import { nhost } from '@/utils/nhost';
*
* function Page() {
* return (
* <NhostProvider nhost={nhost}>
* <SignedIn>
* <h1>Only rendered if the user is authenticated</h1>
* </SignedIn>
* </NhostProvider>
* )
* }
* ```
*
* @docs https://docs.nhost.io/reference/react/signed-in
* @category Components
*/
export function SignedIn({ children }: PropsWithChildren<unknown>) {
const { isAuthenticated } = useAuthenticationStatus()
if (!isAuthenticated) {
return null
}
return <>{children}</>
}

View File

@@ -0,0 +1,36 @@
import { PropsWithChildren } from 'react'
import { useAuthenticationStatus } from '../useAuthenticationStatus'
/**
* Use `<SignedOut />` to control the rendering of components for users. Components inside `<SignedOut />` are only rendered if the user is not authenticated.
*
* @example
* ```tsx
* import { NhostProvider, SignedOut } from "@nhost/react";
* import { nhost } from '@/utils/nhost';
*
* function Page() {
* return (
* <NhostProvider nhost={nhost}>
* <SignedOut>
* <h1>Only rendered if the user is not authenticated</h1>
* </SignedOut>
* </NhostProvider>
* )
* }
* ```
*
* @docs https://docs.nhost.io/reference/react/signed-out
* @category Components
*/
export function SignedOut({ children }: PropsWithChildren<unknown>) {
const { isAuthenticated } = useAuthenticationStatus()
if (isAuthenticated) {
return null
}
return <>{children}</>
}

View File

@@ -0,0 +1,2 @@
export * from './SignedIn'
export * from './SignedOut'

View File

@@ -1,4 +1,5 @@
export * from './client' export * from './client'
export * from './components'
export * from './provider' export * from './provider'
export * from './useAccessToken' export * from './useAccessToken'
export * from './useAddSecurityKey' export * from './useAddSecurityKey'

View File

@@ -14,9 +14,10 @@ import { useAuthInterpreter } from './useAuthInterpreter'
*/ */
export const useUserRoles = () => { export const useUserRoles = () => {
const service = useAuthInterpreter() const service = useAuthInterpreter()
return useSelector( return useSelector(service, (state) => {
service, if (!state.matches('authentication.signedIn')) {
(state) => state.context.user?.roles || [], return []
(a, b) => a.every((i) => b.includes(i) && b.every((i) => a.includes(i))) }
) return state.context.user?.roles || []
})
} }

View File

@@ -1,5 +1,15 @@
# @nhost/vue # @nhost/vue
## 0.6.0
### Minor Changes
- f6d2042a: `useFileUpload` composable to upload a file useFileUpload composable
### Patch Changes
- 843087cb: Make `useUserRoles` reactive
## 0.5.3 ## 0.5.3
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@nhost/vue", "name": "@nhost/vue",
"version": "0.5.3", "version": "0.6.0",
"description": "Nhost Vue library", "description": "Nhost Vue library",
"license": "MIT", "license": "MIT",
"keywords": [ "keywords": [

View File

@@ -1,44 +1,44 @@
import { InterpreterFrom } from 'xstate' import { InterpreterFrom } from 'xstate'
import { import {
createFileUploadMachine, createFileUploadMachine,
FileItemRef, FileItemRef,
FileUploadMachine, FileUploadMachine,
FileUploadState, FileUploadState,
StorageUploadFileParams, StorageUploadFileParams,
UploadFileHandlerResult, UploadFileHandlerResult,
uploadFilePromise uploadFilePromise
} from '@nhost/hasura-storage-js' } from '@nhost/hasura-storage-js'
import { useInterpret, useSelector } from '@xstate/vue' import { useInterpret, useSelector } from '@xstate/vue'
import { useNhostClient } from './useNhostClient' import { useNhostClient } from './useNhostClient'
export interface FileUploadHookResult extends FileUploadState { export interface FileUploadComposableResult extends FileUploadState {
/** /**
* Add the file without uploading it. * Add the file without uploading it.
*/ */
add: (params: StorageUploadFileParams) => void add: (params: StorageUploadFileParams) => void
/** /**
* Upload the file given as a parameter, or that has been previously added. * Upload the file given as a parameter, or that has been previously added.
*/ */
upload: (params: Partial<StorageUploadFileParams>) => Promise<UploadFileHandlerResult> upload: (params: Partial<StorageUploadFileParams>) => Promise<UploadFileHandlerResult>
/** /**
* Cancel the ongoing upload. * Cancel the ongoing upload.
*/ */
cancel: () => void cancel: () => void
/** /**
* @internal - used by the MultipleFilesUpload component to notice the file should be removed from the list. * @internal - used by the MultipleFilesUpload component to notice the file should be removed from the list.
*/ */
destroy: () => void destroy: () => void
} }
export type { FileItemRef } export type { FileItemRef }
/** /**
* Use the hook `useFileUploadItem` to control the file upload of a file in a multiple file upload. * Use the composable `useFileUploadItem` to control the file upload of a file in a multiple file upload.
* *
* It has the same signature as `useFileUpload`. * It has the same signature as `useFileUpload`.
* *
@@ -59,61 +59,61 @@ export type { FileItemRef }
* ``` * ```
*/ */
export const useFileUploadItem = ( export const useFileUploadItem = (
ref: FileItemRef | InterpreterFrom<FileUploadMachine> ref: FileItemRef | InterpreterFrom<FileUploadMachine>
): FileUploadHookResult => { ): FileUploadComposableResult => {
const { nhost } = useNhostClient() const { nhost } = useNhostClient()
const add = (params: StorageUploadFileParams) => { const add = (params: StorageUploadFileParams) => {
ref.send({ ref.send({
type: 'ADD', type: 'ADD',
file: params.file, file: params.file,
bucketId: params.bucketId || bucketId bucketId: params.bucketId || bucketId
}) })
} }
const upload = (params: Partial<StorageUploadFileParams>) => const upload = (params: Partial<StorageUploadFileParams>) =>
uploadFilePromise(nhost, ref, { uploadFilePromise(nhost, ref, {
file: params.file, file: params.file,
bucketId: params.bucketId || bucketId, bucketId: params.bucketId || bucketId,
id, id,
name name
}) })
const cancel = () => { const cancel = () => {
ref.send('CANCEL') ref.send('CANCEL')
} }
const destroy = () => { const destroy = () => {
ref.send('DESTROY') ref.send('DESTROY')
} }
const isUploading = useSelector(ref, (state) => state.matches('uploading')).value const isUploading = useSelector(ref, (state) => state.matches('uploading')).value
const isUploaded = useSelector(ref, (state) => state.matches('uploaded')).value const isUploaded = useSelector(ref, (state) => state.matches('uploaded')).value
const isError = useSelector(ref, (state) => state.matches('error')).value const isError = useSelector(ref, (state) => state.matches('error')).value
const error = useSelector(ref, (state) => state.context.error || null).value const error = useSelector(ref, (state) => state.context.error || null).value
const progress = useSelector(ref, (state) => state.context.progress).value const progress = useSelector(ref, (state) => state.context.progress).value
const id = useSelector(ref, (state) => state.context.id).value const id = useSelector(ref, (state) => state.context.id).value
const bucketId = useSelector(ref, (state) => state.context.bucketId).value const bucketId = useSelector(ref, (state) => state.context.bucketId).value
const name = useSelector(ref, (state) => state.context.file?.name).value const name = useSelector(ref, (state) => state.context.file?.name).value
return { return {
add, add,
upload, upload,
cancel, cancel,
destroy, destroy,
isUploaded, isUploaded,
isUploading, isUploading,
isError, isError,
error, error,
progress, progress,
id, id,
bucketId, bucketId,
name name
} }
} }
/** /**
* Use the hook `useFileUpload` to upload a file. * Use the composable `useFileUpload` to upload a file.
* *
* @example * @example
* ```tsx * ```tsx
@@ -139,8 +139,8 @@ export const useFileUploadItem = (
* *
* @docs https://docs.nhost.io/reference/vue/use-file-upload * @docs https://docs.nhost.io/reference/vue/use-file-upload
*/ */
export const useFileUpload = (): FileUploadHookResult => { export const useFileUpload = (): FileUploadComposableResult => {
const service = useInterpret(createFileUploadMachine) const service = useInterpret(createFileUploadMachine)
return useFileUploadItem(service) return useFileUploadItem(service)
} }

View File

@@ -14,9 +14,10 @@ import { useAuthInterpreter } from './useAuthInterpreter'
*/ */
export const useUserRoles = () => { export const useUserRoles = () => {
const service = useAuthInterpreter() const service = useAuthInterpreter()
return useSelector( return useSelector(service.value, (state) => {
service.value, if (!state.matches('authentication.signedIn')) {
(state) => state.context.user?.roles || [], return []
(a, b) => a.every((i) => b.includes(i) && b.every((i) => a.includes(i))) }
) return state.context.user?.roles || []
})
} }

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