Compare commits

..

60 Commits

Author SHA1 Message Date
Szilárd Dóró
3601de3f85 Merge pull request #1208 from nhost/changeset-release/main
chore: update versions
2022-11-24 20:20:45 +01:00
github-actions[bot]
ac9404610b chore: update versions 2022-11-24 19:09:19 +00:00
Szilárd Dóró
63570db57c Merge pull request #1207 from nhost/contributors-readme-action-MBHUTcRQyD
contributors readme action update
2022-11-24 20:08:33 +01:00
github-actions[bot]
538ed78f5a contrib-readme-action has updated readme 2022-11-24 19:07:02 +00:00
Szilárd Dóró
b1a31ecb00 Merge pull request #1181 from nhost/fix/dashboard-custom-local-ports
feat(dashboard): make backend port configurable
2022-11-24 20:06:44 +01:00
Siarhei Lipchyk
bac8ace434 Add support for custom ports via placeholders 2022-11-24 19:03:02 +01:00
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
Szilárd Dóró
2145243b19 chore(dashboard): update environment variables 2022-11-23 10:56:47 +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
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
Szilárd Dóró
a48dd5bf74 chore(dashboard): add changeset 2022-11-22 14:32:53 +01:00
Szilárd Dóró
ef53df5cb3 feat(dashboard): make backend port configurable
- additionally: improve the way Hasura service ports are. configured through environment variables
2022-11-22 14:32:13 +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
85 changed files with 1056 additions and 420 deletions

View File

@@ -18,6 +18,7 @@ env:
jobs:
version:
name: Version
runs-on: ubuntu-latest
outputs:
hasChangesets: ${{ steps.changesets.outputs.hasChangesets }}
@@ -61,6 +62,7 @@ jobs:
secrets: inherit
publish:
name: Publish
runs-on: ubuntu-latest
needs:
- test
@@ -110,6 +112,8 @@ jobs:
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
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
uses: taiki-e/create-gh-release-action@v1
with:

View File

@@ -179,14 +179,21 @@ Here are some ways of contributing to making Nhost better:
<sub><b>Grégory D'Angelo</b></sub>
</a>
</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">
<a href="https://github.com/guicurcio">
<img src="https://avatars.githubusercontent.com/u/20285232?v=4" width="100;" alt="guicurcio"/>
<br />
<sub><b>Guido Curcio</b></sub>
</a>
</td></tr>
<tr>
</td>
<td align="center">
<a href="https://github.com/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 />
<sub><b>Christopher Möller</b></sub>
</a>
</td>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/GavanWilhite">
<img src="https://avatars.githubusercontent.com/u/2085119?v=4" width="100;" alt="GavanWilhite"/>
<br />
<sub><b>Gavan Wilhite</b></sub>
</a>
</td></tr>
<tr>
</td>
<td align="center">
<a href="https://github.com/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>
</a>
</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">
<a href="https://github.com/macmac49">
<img src="https://avatars.githubusercontent.com/u/831190?v=4" width="100;" alt="macmac49"/>
@@ -495,6 +495,13 @@ Here are some ways of contributing to making Nhost better:
<sub><b>Quentin Decré</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/elephant3">
<img src="https://avatars.githubusercontent.com/u/48279149?v=4" width="100;" alt="elephant3"/>
<br />
<sub><b>Siarhei Lipchyk</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/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 />
<sub><b>Vadim</b></sub>
</a>
</td>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/TheRedLancer">
<img src="https://avatars.githubusercontent.com/u/58493767?v=4" width="100;" alt="TheRedLancer"/>
<br />
<sub><b>Zach Burnaby</b></sub>
</a>
</td></tr>
<tr>
</td>
<td align="center">
<a href="https://github.com/komninoschat">
<img src="https://avatars.githubusercontent.com/u/29049104?v=4" width="100;" alt="komninoschat"/>

View File

@@ -1,5 +1,19 @@
# @nhost/dashboard
## 0.5.0
### Minor Changes
- a48dd5bf: feat(dashboard): make backend port configurable
## 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

View File

@@ -1,4 +1,3 @@
FROM node:16-alpine AS pruner
RUN apk add --no-cache libc6-compat
RUN apk update
@@ -17,10 +16,13 @@ RUN apk update
WORKDIR /app
ENV NEXT_TELEMETRY_DISABLED 1
ENV NEXT_PUBLIC_NHOST_PLATFORM false
ENV NEXT_PUBLIC_NHOST_MIGRATIONS_URL http://localhost:9693
ENV NEXT_PUBLIC_NHOST_HASURA_URL http://localhost:9695
ENV NEXT_PUBLIC_ENV dev
ENV NEXT_PUBLIC_NHOST_PLATFORM false
# placeholders for ports, will be replaced on runtime by entrypoint script
ENV NEXT_PUBLIC_NHOST_MIGRATIONS_PORT __NEXT_PUBLIC_NHOST_MIGRATIONS_PORT__
ENV NEXT_PUBLIC_NHOST_HASURA_PORT __NEXT_PUBLIC_NHOST_HASURA_PORT__
ENV NEXT_PUBLIC_NHOST_LOCAL_BACKEND_PORT __NEXT_PUBLIC_NHOST_LOCAL_BACKEND_PORT__
RUN yarn global add pnpm@7.17.0
COPY .gitignore .gitignore
@@ -40,11 +42,14 @@ RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
USER nextjs
COPY --from=builder /app/dashboard/next.config.js .
COPY --from=builder /app/dashboard/package.json .
COPY --from=builder /app/dashboard/public ./dashboard/public
COPY --chown=nextjs:nodejs dashboard/docker-entrypoint.sh .
COPY --from=builder --chown=nextjs:nodejs /app/dashboard/next.config.js .
COPY --from=builder --chown=nextjs:nodejs /app/dashboard/package.json .
COPY --from=builder --chown=nextjs:nodejs /app/dashboard/public ./dashboard/public
COPY --from=builder --chown=nextjs:nodejs /app/dashboard/.next/standalone/app ./
COPY --from=builder --chown=nextjs:nodejs /app/dashboard/.next/static ./dashboard/.next/static
CMD node dashboard/server.js
ENTRYPOINT ["./docker-entrypoint.sh"]
CMD ["node", "dashboard/server.js"]

View File

@@ -30,31 +30,27 @@ First, you need to run the following command to start your backend locally:
cd <your_nhost_project> && nhost dev
```
Two environment variables are required to connect the Nhost Dashboard to your local backend:
You can connect the Nhost Dashboard to your locally running backend by setting the following environment variables in `.env.development.local`:
- `NEXT_PUBLIC_NHOST_PLATFORM` should be set to `false`, because otherwise the Nhost Dashboard will try to connect to the Nhost platform.
- `NEXT_PUBLIC_NHOST_MIGRATIONS_URL` should be set to `http://localhost:9693` unless Hasura is configured to run on a different port. This is the URL of Hasura's migrations endpoint.
Example:
```
```bash
NEXT_PUBLIC_ENV=dev
NEXT_PUBLIC_NHOST_PLATFORM=false
NEXT_PUBLIC_NHOST_MIGRATIONS_URL=http://localhost:9693
```
### Full list of environment variables
| Name | Description |
| ------------------------------------ | ------------------------------------------------------------------------------------------------ |
| `NEXT_PUBLIC_NHOST_PLATFORM` | This should be set to `false` to connect the Nhost Dashboard to a locally running Nhost backend. |
| `NEXT_PUBLIC_NHOST_MIGRATIONS_URL` | URL of Hasura's migrations endpoint. Used only if local development is enabled. |
| `NEXT_PUBLIC_NHOST_HASURA_URL` | URL of the Hasura Console. Used only when `NEXT_PUBLIC_ENV` is `dev`. |
| `NEXT_PUBLIC_ENV` | `dev`, `staging` or `prod`. Should be set to `dev` in most cases. |
| `NEXT_PUBLIC_NHOST_BACKEND_URL` | Backend URL. Not necessary for local development. |
| `NEXT_PUBLIC_STRIPE_PK` | Stripe public key. Not necessary for local development. |
| `NEXT_PUBLIC_GITHUB_APP_INSTALL_URL` | URL of the GitHub application. Not necessary for local development. |
| `NEXT_PUBLIC_ANALYTICS_WRITE_KEY` | Analytics key. Not necessary for local development. |
| `NEXT_PUBLIC_NHOST_BRAGI_WEBSOCKET` | URL of the Bragi websocket. Not necessary for local development. |
| Name | Description |
| ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| `NEXT_PUBLIC_ENV` | `dev`, `staging` or `prod`. Should be set to `dev` in most cases. |
| `NEXT_PUBLIC_NHOST_PLATFORM` | This should be set to `false` to connect the Nhost Dashboard to a locally running Nhost backend. Setting this to `true` turns off local development. |
| `NEXT_PUBLIC_NHOST_LOCAL_MIGRATIONS_PORT` | Custom port that was passed to the CLI. Used only if local development is enabled. Default: `9693` |
| `NEXT_PUBLIC_NHOST_LOCAL_HASURA_PORT` | Custom port that was passed to the CLI. Used only if local development is enabled and `NEXT_PUBLIC_ENV` is `dev`. Default: `9695` |
| `NEXT_PUBLIC_NHOST_LOCAL_BACKEND_PORT` | Custom port that was passed to the CLI. Used only if local development is enabled. Default: `1337` |
| `NEXT_PUBLIC_NHOST_BACKEND_URL` | Backend URL. Not necessary for local development. |
| `NEXT_PUBLIC_STRIPE_PK` | Stripe public key. Not necessary for local development. |
| `NEXT_PUBLIC_GITHUB_APP_INSTALL_URL` | URL of the GitHub application. Not necessary for local development. |
| `NEXT_PUBLIC_ANALYTICS_WRITE_KEY` | Analytics key. Not necessary for local development. |
| `NEXT_PUBLIC_NHOST_BRAGI_WEBSOCKET` | URL of the Bragi websocket. Not necessary for local development. |
## ESLint Rules
@@ -67,6 +63,7 @@ NEXT_PUBLIC_NHOST_MIGRATIONS_URL=http://localhost:9693
| `import/extensions` | JS / TS files should be imported without file extensions. |
| `react/jsx-filename-extension` | JSX should only appear in `.jsx` and `.tsx` files. |
| `react/jsx-no-bind` | Further investigation must be made on the performance impact of functions directly passed as props to components. |
| `import/order` | Until we have a better auto-formatter, we disable this rule. |
| `import/no-extraneous-dependencies` | `devDependencies` should be excluded from the list of disallowed imports. |
| `curly` | By default it only enforces curly braces for multi-line blocks, but it should be enforced for single-line blocks as well. |
| `no-restricted-exports` | `export { default } from './module'` is used heavily in `@/ui/v2` which is a restricted export by default. |

15
dashboard/docker-entrypoint.sh Executable file
View File

@@ -0,0 +1,15 @@
#!/bin/sh
set -e
# read ports from env variables or use defaults
NEXT_PUBLIC_NHOST_MIGRATIONS_PORT="${NEXT_PUBLIC_NHOST_MIGRATIONS_PORT:=9693}"
NEXT_PUBLIC_NHOST_HASURA_PORT="${NEXT_PUBLIC_NHOST_HASURA_PORT:=9695}"
NEXT_PUBLIC_NHOST_LOCAL_BACKEND_PORT="${NEXT_PUBLIC_NHOST_LOCAL_BACKEND_PORT:=1337}"
# replace placeholders
find dashboard -type f -exec sed -i "s/__NEXT_PUBLIC_NHOST_MIGRATIONS_PORT__/${NEXT_PUBLIC_NHOST_MIGRATIONS_PORT}/g" {} +
find dashboard -type f -exec sed -i "s/__NEXT_PUBLIC_NHOST_HASURA_PORT__/${NEXT_PUBLIC_NHOST_HASURA_PORT}/g" {} +
find dashboard -type f -exec sed -i "s/__NEXT_PUBLIC_NHOST_LOCAL_BACKEND_PORT__/${NEXT_PUBLIC_NHOST_LOCAL_BACKEND_PORT}/g" {} +
exec "$@"

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/dashboard",
"version": "0.4.2",
"version": "0.5.0",
"private": true,
"scripts": {
"preinstall": "npx only-allow pnpm",

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

@@ -5,6 +5,7 @@ import Button from '@/ui/v2/Button';
import ArrowSquareOutIcon from '@/ui/v2/icons/ArrowSquareOutIcon';
import Link from '@/ui/v2/Link';
import Text from '@/ui/v2/Text';
import { LOCAL_HASURA_URL } from '@/utils/env';
import { generateRemoteAppUrl } from '@/utils/helpers';
import Image from 'next/image';
@@ -24,7 +25,7 @@ export function HasuraData({ close }: HasuraDataProps) {
const hasuraUrl =
process.env.NEXT_PUBLIC_ENV === 'dev'
? process.env.NEXT_PUBLIC_NHOST_HASURA_URL || 'http://localhost:9695'
? LOCAL_HASURA_URL
: generateRemoteAppUrl(currentApplication.subdomain);
return (

View File

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

View File

@@ -107,7 +107,7 @@ export default function AppleProviderSettings() {
<Form onSubmit={handleProviderUpdate}>
<SettingsContainer
title="Apple"
description="Allows users to sign in with Apple."
description="Allow users to sign in with Apple."
primaryActionButtonProps={{
disabled: !formState.isValid || !formState.isDirty,
loading: formState.isSubmitting,

View File

@@ -88,7 +88,7 @@ export default function DiscordProviderSettings() {
<Form onSubmit={handleProviderUpdate}>
<SettingsContainer
title="Discord"
description="Allows users to sign in with Discord."
description="Allow users to sign in with Discord."
primaryActionButtonProps={{
disabled: !formState.isValid || !formState.isDirty,
loading: formState.isSubmitting,

View File

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

View File

@@ -88,7 +88,7 @@ export default function GitHubProviderSettings() {
<Form onSubmit={handleProviderUpdate}>
<SettingsContainer
title="GitHub"
description="Allows users to sign in with GitHub."
description="Allow users to sign in with GitHub."
primaryActionButtonProps={{
disabled: !formState.isValid || !formState.isDirty,
loading: formState.isSubmitting,

View File

@@ -88,7 +88,7 @@ export default function GoogleProviderSettings() {
<Form onSubmit={handleProviderUpdate}>
<SettingsContainer
title="Google"
description="Allows users to sign in with Google."
description="Allow users to sign in with Google."
primaryActionButtonProps={{
disabled: !formState.isValid || !formState.isDirty,
loading: formState.isSubmitting,

View File

@@ -88,7 +88,7 @@ export default function LinkedInProviderSettings() {
<Form onSubmit={handleProviderUpdate}>
<SettingsContainer
title="LinkedIn"
description="Allows users to sign in with LinkedIn"
description="Allow users to sign in with LinkedIn."
primaryActionButtonProps={{
disabled: !formState.isValid || !formState.isDirty,
loading: formState.isSubmitting,

View File

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

View File

@@ -88,7 +88,7 @@ export default function SpotifyProviderSettings() {
<Form onSubmit={handleProviderUpdate}>
<SettingsContainer
title="Spotify"
description="Allows users to sign in with Spotify."
description="Allow users to sign in with Spotify."
primaryActionButtonProps={{
disabled: !formState.isValid || !formState.isDirty,
loading: formState.isSubmitting,

View File

@@ -88,7 +88,7 @@ export default function TwitchProviderSettings() {
<Form onSubmit={handleProviderUpdate}>
<SettingsContainer
title="Twitch"
description="Allows users to sign in with Twitch."
description="Allow users to sign in with Twitch."
primaryActionButtonProps={{
disabled: !formState.isValid || !formState.isDirty,
loading: formState.isSubmitting,

View File

@@ -87,7 +87,7 @@ export default function TwitterProviderSettings() {
<Form onSubmit={handleProviderUpdate}>
<SettingsContainer
title="Twitter"
description="Allows users to sign in with Twitter."
description="Allow users to sign in with Twitter."
primaryActionButtonProps={{
disabled: !formState.isValid || !formState.isDirty,
loading: formState.isSubmitting,

View File

@@ -81,7 +81,7 @@ export default function WebAuthnSettings() {
<Form onSubmit={handleWebAuthnSettingsUpdate}>
<SettingsContainer
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={{
disabled: !formState.isValid || !formState.isDirty,
loading: formState.isSubmitting,

View File

@@ -88,7 +88,7 @@ export default function WindowsLiveProviderSettings() {
<Form onSubmit={handleProviderUpdate}>
<SettingsContainer
title="Windows Live"
description="Allows users to sign in with Windows Live."
description="Allow users to sign in with Windows Live."
primaryActionButtonProps={{
disabled: !formState.isValid || !formState.isDirty,
loading: formState.isSubmitting,

View File

@@ -94,11 +94,13 @@ export default function WorkOsProviderSettings() {
<Form onSubmit={handleProviderUpdate}>
<SettingsContainer
title="WorkOS"
description="Allows users to sign in with WorkOS."
description="Allow users to sign in with WorkOS."
primaryActionButtonProps={{
disabled: !formState.isValid || !formState.isDirty,
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"
switchId="authWorkOsEnabled"
showSwitch
@@ -112,8 +114,8 @@ export default function WorkOsProviderSettings() {
{...register(`authWorkOsClientId`)}
name="authWorkOsClientId"
id="authWorkOsClientId"
label="WorkOS Client ID"
placeholder="WorkOS Client ID"
label="Client ID"
placeholder="Enter your Client ID"
className="col-span-3"
fullWidth
hideEmptyHelperText
@@ -122,28 +124,28 @@ export default function WorkOsProviderSettings() {
{...register('authWorkOsClientSecret')}
name="authWorkOsClientSecret"
id="authWorkOsClientSecret"
label="WorkOS Client Secret"
placeholder="WorkOS Client Secret"
label="Client Secret"
placeholder="Enter your Client Secret"
className="col-span-3"
fullWidth
hideEmptyHelperText
/>
<Input
{...register('authWorkOsDefaultDomain')}
name="authWorkOsDefaultDomain"
id="authWorkOsDefaultDomain"
label="Default Domain"
placeholder="Default Domain"
className="col-span-2"
fullWidth
hideEmptyHelperText
/>
<Input
{...register('authWorkOsDefaultOrganization')}
name="authWorkOsDefaultOrganization"
id="authWorkOsDefaultOrganization"
label="Default Organization"
placeholder="Default Organization"
label="Default Organization ID (optional)"
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"
fullWidth
hideEmptyHelperText
@@ -152,7 +154,7 @@ export default function WorkOsProviderSettings() {
{...register('authWorkOsDefaultConnection')}
name="authWorkOsDefaultConnection"
id="authWorkOsDefaultConnection"
label="Default Connection"
label="Default Connection (optional)"
placeholder="Default Connection"
className="col-span-2"
fullWidth

View File

@@ -7,6 +7,7 @@ import type {
} from '@/types/data-browser';
import { getPreparedHasuraQuery } from '@/utils/dataBrowser/hasuraQueryHelpers';
import normalizeQueryError from '@/utils/dataBrowser/normalizeQueryError';
import { LOCAL_MIGRATIONS_URL } from '@/utils/env';
import prepareCreateColumnQuery from './prepareCreateColumnQuery';
export interface CreateColumnMigrationVariables {
@@ -33,30 +34,27 @@ export default async function createColumnMigration({
column,
});
const response = await fetch(
`${process.env.NEXT_PUBLIC_NHOST_MIGRATIONS_URL}/apis/migrate`,
{
method: 'POST',
headers: {
'x-hasura-admin-secret': adminSecret,
},
body: JSON.stringify({
dataSource,
skip_execution: false,
name: `alter_table_${schema}_${table}_add_column_${column.name}`,
down: [
getPreparedHasuraQuery(
dataSource,
'ALTER TABLE %I.%I DROP COLUMN IF EXISTS %I',
schema,
table,
column.name,
),
],
up: args,
}),
const response = await fetch(`${LOCAL_MIGRATIONS_URL}/apis/migrate`, {
method: 'POST',
headers: {
'x-hasura-admin-secret': adminSecret,
},
);
body: JSON.stringify({
dataSource,
skip_execution: false,
name: `alter_table_${schema}_${table}_add_column_${column.name}`,
down: [
getPreparedHasuraQuery(
dataSource,
'ALTER TABLE %I.%I DROP COLUMN IF EXISTS %I',
schema,
table,
column.name,
),
],
up: args,
}),
});
const responseData: [AffectedRowsResult, QueryResult<string[]>] | QueryError =
await response.json();

View File

@@ -7,6 +7,7 @@ import type {
} from '@/types/data-browser';
import { getPreparedHasuraQuery } from '@/utils/dataBrowser/hasuraQueryHelpers';
import normalizeQueryError from '@/utils/dataBrowser/normalizeQueryError';
import { LOCAL_MIGRATIONS_URL } from '@/utils/env';
import prepareCreateTableQuery from './prepareCreateTableQuery';
export interface CreateTableMigrationVariables {
@@ -27,29 +28,26 @@ export default async function createTableMigration({
}: CreateTableMigrationOptions & CreateTableMigrationVariables) {
const args = prepareCreateTableQuery({ dataSource, schema, table });
const response = await fetch(
`${process.env.NEXT_PUBLIC_NHOST_MIGRATIONS_URL}/apis/migrate`,
{
method: 'POST',
headers: {
'x-hasura-admin-secret': adminSecret,
},
body: JSON.stringify({
dataSource,
skip_execution: false,
name: `create_table_${schema}_${table.name}`,
down: [
getPreparedHasuraQuery(
dataSource,
'DROP TABLE IF EXISTS %I.%I',
schema,
table.name,
),
],
up: args,
}),
const response = await fetch(`${LOCAL_MIGRATIONS_URL}/apis/migrate`, {
method: 'POST',
headers: {
'x-hasura-admin-secret': adminSecret,
},
);
body: JSON.stringify({
dataSource,
skip_execution: false,
name: `create_table_${schema}_${table.name}`,
down: [
getPreparedHasuraQuery(
dataSource,
'DROP TABLE IF EXISTS %I.%I',
schema,
table.name,
),
],
up: args,
}),
});
const responseData: [AffectedRowsResult, QueryResult<string[]>] | QueryError =
await response.json();

View File

@@ -8,6 +8,7 @@ import type {
} from '@/types/data-browser';
import { getPreparedHasuraQuery } from '@/utils/dataBrowser/hasuraQueryHelpers';
import normalizeQueryError from '@/utils/dataBrowser/normalizeQueryError';
import { LOCAL_MIGRATIONS_URL } from '@/utils/env';
export interface DeleteColumnMigrationVariables {
/**
@@ -45,30 +46,27 @@ export default async function deleteColumnMigration({
},
});
const response = await fetch(
`${process.env.NEXT_PUBLIC_NHOST_MIGRATIONS_URL}/apis/migrate`,
{
method: 'POST',
headers: {
'x-hasura-admin-secret': adminSecret,
},
body: JSON.stringify({
dataSource,
skip_execution: false,
name: `alter_table_${schema}_${table}_drop_column_${column.id}`,
down: recreateColumnArgs,
up: [
getPreparedHasuraQuery(
dataSource,
'ALTER TABLE %I.%I DROP COLUMN IF EXISTS %I CASCADE',
schema,
table,
column.id,
),
],
}),
const response = await fetch(`${LOCAL_MIGRATIONS_URL}/apis/migrate`, {
method: 'POST',
headers: {
'x-hasura-admin-secret': adminSecret,
},
);
body: JSON.stringify({
dataSource,
skip_execution: false,
name: `alter_table_${schema}_${table}_drop_column_${column.id}`,
down: recreateColumnArgs,
up: [
getPreparedHasuraQuery(
dataSource,
'ALTER TABLE %I.%I DROP COLUMN IF EXISTS %I CASCADE',
schema,
table,
column.id,
),
],
}),
});
const responseData: [AffectedRowsResult, QueryResult<string[]>] | QueryError =
await response.json();

View File

@@ -9,6 +9,7 @@ import {
getPreparedHasuraQuery,
} from '@/utils/dataBrowser/hasuraQueryHelpers';
import normalizeQueryError from '@/utils/dataBrowser/normalizeQueryError';
import { LOCAL_MIGRATIONS_URL } from '@/utils/env';
export interface DeleteTableMigrationVariables {
/**
@@ -39,32 +40,29 @@ export default async function deleteTable({
),
];
const response = await fetch(
`${process.env.NEXT_PUBLIC_NHOST_MIGRATIONS_URL}/apis/migrate`,
{
method: 'POST',
headers: {
'x-hasura-admin-secret': adminSecret,
},
body: JSON.stringify({
dataSource,
skip_execution: false,
name: `drop_table_${schema}_${table}`,
down: [
{
type: 'run_sql',
args: {
cascade: false,
read_only: false,
source: '',
sql: getEmptyDownMigrationMessage(deleteTableArgs),
},
},
],
up: deleteTableArgs,
}),
const response = await fetch(`${LOCAL_MIGRATIONS_URL}/apis/migrate`, {
method: 'POST',
headers: {
'x-hasura-admin-secret': adminSecret,
},
);
body: JSON.stringify({
dataSource,
skip_execution: false,
name: `drop_table_${schema}_${table}`,
down: [
{
type: 'run_sql',
args: {
cascade: false,
read_only: false,
source: '',
sql: getEmptyDownMigrationMessage(deleteTableArgs),
},
},
],
up: deleteTableArgs,
}),
});
const responseData: [AffectedRowsResult, QueryResult<string[]>] | QueryError =
await response.json();

View File

@@ -6,6 +6,7 @@ import type {
QueryResult,
} from '@/types/data-browser';
import normalizeQueryError from '@/utils/dataBrowser/normalizeQueryError';
import { LOCAL_MIGRATIONS_URL } from '@/utils/env';
import prepareTrackForeignKeyRelationsMetadata from './prepareTrackForeignKeyRelationsMetadata';
export interface TrackForeignKeyRelationsMigrationVariables {
@@ -45,23 +46,20 @@ export default async function trackForeignKeyRelationsMigration({
foreignKeyRelations,
});
const response = await fetch(
`${process.env.NEXT_PUBLIC_NHOST_MIGRATIONS_URL}/apis/migrate`,
{
method: 'POST',
headers: {
'x-hasura-admin-secret': adminSecret,
},
body: JSON.stringify({
dataSource,
skip_execution: false,
name: `track_foreign_key_relations_${schema}_${table}`,
down: [],
up: creatableRelationships,
}),
const response = await fetch(`${LOCAL_MIGRATIONS_URL}/apis/migrate`, {
method: 'POST',
headers: {
'x-hasura-admin-secret': adminSecret,
},
);
body: JSON.stringify({
dataSource,
skip_execution: false,
name: `track_foreign_key_relations_${schema}_${table}`,
down: [],
up: creatableRelationships,
}),
});
const responseData: [AffectedRowsResult, QueryResult<string[]>] | QueryError =
await response.json();

View File

@@ -6,6 +6,7 @@ import type {
QueryResult,
} from '@/types/data-browser';
import normalizeQueryError from '@/utils/dataBrowser/normalizeQueryError';
import { LOCAL_MIGRATIONS_URL } from '@/utils/env';
export interface TrackTableMigrationVariables {
/**
@@ -23,32 +24,29 @@ export default async function trackTableMigration({
adminSecret,
table,
}: TrackTableMigrationOptions & TrackTableMigrationVariables) {
const response = await fetch(
`${process.env.NEXT_PUBLIC_NHOST_MIGRATIONS_URL}/apis/migrate`,
{
method: 'POST',
headers: {
'x-hasura-admin-secret': adminSecret,
},
body: JSON.stringify({
dataSource,
skip_execution: false,
name: `add_existing_table_or_view_${schema}_${table.name}`,
down: [
{
type: 'pg_untrack_table',
args: { source: dataSource, table: { schema, name: table.name } },
},
],
up: [
{
args: { source: dataSource, table: { schema, name: table.name } },
type: 'pg_track_table',
},
],
}),
const response = await fetch(`${LOCAL_MIGRATIONS_URL}/apis/migrate`, {
method: 'POST',
headers: {
'x-hasura-admin-secret': adminSecret,
},
);
body: JSON.stringify({
dataSource,
skip_execution: false,
name: `add_existing_table_or_view_${schema}_${table.name}`,
down: [
{
type: 'pg_untrack_table',
args: { source: dataSource, table: { schema, name: table.name } },
},
],
up: [
{
args: { source: dataSource, table: { schema, name: table.name } },
type: 'pg_track_table',
},
],
}),
});
const responseData: [AffectedRowsResult, QueryResult<string[]>] | QueryError =
await response.json();

View File

@@ -7,6 +7,7 @@ import type {
} from '@/types/data-browser';
import { getEmptyDownMigrationMessage } from '@/utils/dataBrowser/hasuraQueryHelpers';
import normalizeQueryError from '@/utils/dataBrowser/normalizeQueryError';
import { LOCAL_MIGRATIONS_URL } from '@/utils/env';
import prepareUpdateColumnQuery from './prepareUpdateColumnQuery';
export interface UpdateColumnMigrationVariables {
@@ -65,22 +66,19 @@ export default async function updateColumnMigration({
];
}
const response = await fetch(
`${process.env.NEXT_PUBLIC_NHOST_MIGRATIONS_URL}/apis/migrate`,
{
method: 'POST',
headers: {
'x-hasura-admin-secret': adminSecret,
},
body: JSON.stringify({
dataSource,
skip_execution: false,
name: `alter_table_${schema}_${table}_alter_column_${originalColumn.name}`,
down: columnUpdateDownMigration,
up: columnUpdateUpMigration,
}),
const response = await fetch(`${LOCAL_MIGRATIONS_URL}/apis/migrate`, {
method: 'POST',
headers: {
'x-hasura-admin-secret': adminSecret,
},
);
body: JSON.stringify({
dataSource,
skip_execution: false,
name: `alter_table_${schema}_${table}_alter_column_${originalColumn.name}`,
down: columnUpdateDownMigration,
up: columnUpdateUpMigration,
}),
});
const responseData: [AffectedRowsResult, QueryResult<string[]>] | QueryError =
await response.json();

View File

@@ -10,6 +10,7 @@ import type {
} from '@/types/data-browser';
import { getEmptyDownMigrationMessage } from '@/utils/dataBrowser/hasuraQueryHelpers';
import normalizeQueryError from '@/utils/dataBrowser/normalizeQueryError';
import { LOCAL_MIGRATIONS_URL } from '@/utils/env';
import prepareUpdateTableQuery from './prepareUpdateTableQuery';
export interface UpdateTableMigrationVariables {
@@ -56,32 +57,29 @@ export default async function updateTableMigration({
return;
}
const response = await fetch(
`${process.env.NEXT_PUBLIC_NHOST_MIGRATIONS_URL}/apis/migrate`,
{
method: 'POST',
headers: {
'x-hasura-admin-secret': adminSecret,
},
body: JSON.stringify({
dataSource,
skip_execution: false,
name: `alter_table_${schema}_${originalTable.table_name}`,
down: [
{
type: 'run_sql',
args: {
cascade: false,
read_only: false,
source: '',
sql: getEmptyDownMigrationMessage(args),
},
},
],
up: args,
}),
const response = await fetch(`${LOCAL_MIGRATIONS_URL}/apis/migrate`, {
method: 'POST',
headers: {
'x-hasura-admin-secret': adminSecret,
},
);
body: JSON.stringify({
dataSource,
skip_execution: false,
name: `alter_table_${schema}_${originalTable.table_name}`,
down: [
{
type: 'run_sql',
args: {
cascade: false,
read_only: false,
source: '',
sql: getEmptyDownMigrationMessage(args),
},
},
],
up: args,
}),
});
const responseData: [AffectedRowsResult, QueryResult<string[]>] | QueryError =
await response.json();

View File

@@ -1,3 +1,4 @@
import { LOCAL_SUBDOMAIN } from '@/utils/env';
import { isDevOrStaging } from '@/utils/helpers';
import type { NhostClientConstructorParams } from '@nhost/nhost-js';
import { NhostClient } from '@nhost/nhost-js';
@@ -20,7 +21,7 @@ export function useAppClient(
if (process.env.NEXT_PUBLIC_ENV === 'dev') {
return new NhostClient({
subdomain: 'localhost:1337',
subdomain: LOCAL_SUBDOMAIN,
start: false,
...options,
});

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,36 @@
/**
* URL of Hasura's Migration API. This is only used when local development is
* enabled.
*/
export const LOCAL_MIGRATIONS_URL = `http://localhost:${
process.env.NEXT_PUBLIC_NHOST_LOCAL_MIGRATIONS_PORT || 9693
}`;
/**
* Port of the locally running backend.s
*/
export const LOCAL_BACKEND_PORT =
process.env.NEXT_PUBLIC_NHOST_LOCAL_BACKEND_PORT;
/**
* Local subdomain. This is only used when local development is enabled.
*/
export const LOCAL_SUBDOMAIN = LOCAL_BACKEND_PORT
? `localhost:${LOCAL_BACKEND_PORT}`
: 'localhost';
/**
* URL of Hasura Console. This is only used when running the Nhost Dashboard
* locally.
*/
export const LOCAL_HASURA_URL = `http://localhost:${
process.env.NEXT_PUBLIC_NHOST_LOCAL_HASURA_PORT || 9695
}`;
/**
* Backend URL for the locally running instance. This is only used when running
* the Nhost Dashboard locally.
*/
export const LOCAL_BACKEND_URL = `http://localhost:${
process.env.NEXT_PUBLIC_NHOST_LOCAL_BACKEND_PORT || 1337
}`;

View File

@@ -6,6 +6,7 @@ import features from '@/data/features.json';
import { ApplicationStatus } from '@/types/application';
import type { NextRouter } from 'next/router';
import slugify from 'slugify';
import { LOCAL_BACKEND_URL } from './env';
import type { DeploymentRowFragment } from './__generated__/graphql';
export function getLastLiveDeployment(deployments: DeploymentRowFragment[]) {
@@ -57,11 +58,11 @@ export function getCurrentEnvironment(): Environment {
export function generateRemoteAppUrl(subdomain: string): string {
if (process.env.NEXT_PUBLIC_NHOST_PLATFORM !== 'true') {
return 'http://localhost:1337';
return LOCAL_BACKEND_URL;
}
if (process.env.NEXT_PUBLIC_ENV === 'dev') {
return process.env.NEXT_PUBLIC_NHOST_BACKEND_URL || 'http://localhost:1337';
return process.env.NEXT_PUBLIC_NHOST_BACKEND_URL || LOCAL_BACKEND_URL;
}
if (process.env.NEXT_PUBLIC_ENV === 'staging') {

View File

@@ -1,8 +1,9 @@
import { NhostClient } from '@nhost/nextjs';
import { LOCAL_SUBDOMAIN } from './env';
const nhost = new NhostClient({
backendUrl: process.env.NEXT_PUBLIC_NHOST_BACKEND_URL as string,
});
export const nhost =
process.env.NEXT_PUBLIC_NHOST_PLATFORM === 'true'
? new NhostClient({ backendUrl: process.env.NEXT_PUBLIC_NHOST_BACKEND_URL })
: new NhostClient({ subdomain: LOCAL_SUBDOMAIN });
export { nhost };
export default nhost;

View File

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

View File

@@ -33,7 +33,7 @@ Follow this guide to sign in users with GitHub.
- Fill in Application Name.
- 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

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.
### 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
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

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

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
services:
hasura:
image: hasura/graphql-engine:v2.10.1
image: hasura/graphql-engine:v2.15.2
environment:
hasura_graphql_enable_remote_schema_permissions: false
auth:
image: nhost/hasura-auth:0.15.0
image: nhost/hasura-auth:0.16.1
storage:
image: nhost/hasura-storage:0.2.5
image: nhost/hasura-storage:0.3.0
auth:
access_control:
email:

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,15 +1,17 @@
{
"name": "@nhost-examples/serverless-functions",
"private": true,
"version": "0.0.1",
"version": "0.0.2",
"devDependencies": {
"@types/express": "^4.17.13"
},
"dependencies": {
"@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",
"cross-fetch": "^3.1.5",
"graphql": "15.7.2",
"nodemailer": "^6.8.0",
"slugify": "^1.6.5"
}
}

View File

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

View File

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

View File

@@ -197,6 +197,14 @@ Start the development server:
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.
Open GraphiQL:

View File

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

View File

@@ -3,7 +3,13 @@ import Stripe from 'stripe'
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
@@ -93,6 +99,18 @@ const builder = new SchemaBuilder<{
// BILLING PORTAL
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
}>({})

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 { builder } from '../builder'
import { StripeInvoice, StripePaymentMethod, StripeSubscription } from '../types'
import {
StripeCharge,
StripeInvoice,
StripePaymentIntent,
StripePaymentMethod,
StripeSubscription} from '../types'
import { stripe } from '../utils'
import { StripePaymentMethodTypes } from './payment-methods'
@@ -110,6 +115,16 @@ builder.objectType('StripeCustomer', {
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({
type: 'StripePaymentMethods',
args: {
@@ -138,6 +153,16 @@ builder.objectType('StripeCustomer', {
})
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 './test-clock'
import './billing-portal-session'
import './payment-intent'
import './payment-intents'
import './charges'
import './charge'
import './connectedAccount'
import './connectedAccounts'
import { builder } from '../builder'

View File

@@ -32,7 +32,18 @@ builder.objectType('StripeInvoice', {
amountRemaining: t.exposeInt('amount_remaining', {
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', {
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

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', {
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({
type: 'StripeCustomer',
args: {

View File

@@ -31,6 +31,16 @@ export type StripeInvoice = Stripe.Invoice & {
id: string
customer: string
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 = {

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,7 @@
import { NhostClientConstructorParams } from './types'
const LOCALHOST_REGEX = /^((?<protocol>http[s]?):\/\/)?(?<host>localhost)(:(?<port>\d+))?$/
// a port can be a number or a placeholder string with leading and trailing double underscores, f.e. "8080" or "__PLACEHOLDER_NAME__"
const LOCALHOST_REGEX = /^((?<protocol>http[s]?):\/\/)?(?<host>localhost)(:(?<port>(\d+|__\w+__)))?$/
/**
* `backendUrl` should now be used only when self-hosting

View File

@@ -62,5 +62,21 @@ describe('urlFromParams', () => {
expect(url).toBe('http://localhost:2001/v1/auth')
})
})
describe('"localhost" with a placeholder for custom port', () => {
it('should use the specified placeholder and return "http://localhost:__FOO_BAR__/v1/auth"', async () => {
const url = urlFromSubdomain({ subdomain: 'localhost:__FOO_BAR__' }, 'auth')
expect(url).toBe('http://localhost:__FOO_BAR__/v1/auth')
})
})
describe('"localhost" with invalid custom port', () => {
it('should throw an error"', async () => {
expect(() => {
urlFromSubdomain({ subdomain: 'localhost:_invalid_FOO_BAR__' }, 'auth')
}).toThrow()
})
})
})
})

11
pnpm-lock.yaml generated
View File

@@ -638,16 +638,20 @@ importers:
examples/serverless-functions:
specifiers:
'@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
'@types/express': ^4.17.13
cross-fetch: ^3.1.5
graphql: 15.7.2
nodemailer: ^6.8.0
slugify: ^1.6.5
dependencies:
'@graphql-yoga/node': 2.13.13_graphql@15.7.2
'@nhost/stripe-graphql-js': link:../../integrations/stripe-graphql-js
'@pothos/core': 3.21.0_graphql@15.7.2
cross-fetch: 3.1.5
graphql: 15.7.2
nodemailer: 6.8.0
slugify: 1.6.5
devDependencies:
'@types/express': 4.17.13
@@ -24109,6 +24113,11 @@ packages:
/node-releases/2.0.6:
resolution: {integrity: sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==}
/nodemailer/6.8.0:
resolution: {integrity: sha512-EjYvSmHzekz6VNkNd12aUqAco+bOkRe3Of5jVhltqKhEsjw/y0PYPJfp83+s9Wzh1dspYAkUW/YNQ350NATbSQ==}
engines: {node: '>=6.0.0'}
dev: false
/normalize-package-data/2.5.0:
resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==}
dependencies: