Compare commits
34 Commits
@nhost/rea
...
@nhost/cor
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bebf9e1f2b | ||
|
|
2413c10283 | ||
|
|
0f7fbdab97 | ||
|
|
14e5fd63a6 | ||
|
|
2446913836 | ||
|
|
1f88a9f47a | ||
|
|
261e37cda4 | ||
|
|
5ee395ea8e | ||
|
|
828633ffc9 | ||
|
|
7b7527a5e6 | ||
|
|
620566fa4d | ||
|
|
4ce8b88d27 | ||
|
|
28d25e46de | ||
|
|
e0cfcafead | ||
|
|
12bc30daa3 | ||
|
|
7b5f00d10e | ||
|
|
58e1485c13 | ||
|
|
a64f1c4396 | ||
|
|
75a1428114 | ||
|
|
d82d830849 | ||
|
|
2def59fc6c | ||
|
|
64ceb2c6bf | ||
|
|
3ee007620c | ||
|
|
b9cf8172a0 | ||
|
|
32edfb4a9f | ||
|
|
848db9b672 | ||
|
|
3766921bcc | ||
|
|
5546052b2c | ||
|
|
c569b56d3d | ||
|
|
52ffa84adb | ||
|
|
b5ae438a8e | ||
|
|
fae05f7af2 | ||
|
|
380d7fc8ce | ||
|
|
94132bbc7f |
26
README.md
26
README.md
@@ -20,7 +20,7 @@
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
**Nhost is a open-source GraphQL backend,** built with the following things in mind:
|
||||
**Nhost is an open-source GraphQL backend,** built with the following things in mind:
|
||||
|
||||
- Open-Source
|
||||
- Developer Productivity
|
||||
@@ -234,6 +234,13 @@ Here are some ways of contributing to making Nhost better:
|
||||
<sub><b>Mustafa Hanif</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/timpratim">
|
||||
<img src="https://avatars.githubusercontent.com/u/32492961?v=4" width="100;" alt="timpratim"/>
|
||||
<br />
|
||||
<sub><b>Pratim</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/Savinvadim1312">
|
||||
<img src="https://avatars.githubusercontent.com/u/16936043?v=4" width="100;" alt="Savinvadim1312"/>
|
||||
@@ -247,15 +254,15 @@ Here are some ways of contributing to making Nhost better:
|
||||
<br />
|
||||
<sub><b>Amir Ahmic</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<a href="https://github.com/akd-io">
|
||||
<img src="https://avatars.githubusercontent.com/u/30059155?v=4" width="100;" alt="akd-io"/>
|
||||
<br />
|
||||
<sub><b>Anders Kjær Damgaard</b></sub>
|
||||
</a>
|
||||
</td></tr>
|
||||
<tr>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/rustyb">
|
||||
<img src="https://avatars.githubusercontent.com/u/53086?v=4" width="100;" alt="rustyb"/>
|
||||
@@ -290,21 +297,14 @@ Here are some ways of contributing to making Nhost better:
|
||||
<br />
|
||||
<sub><b>Hoang Do</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<a href="https://github.com/ghoshnirmalya">
|
||||
<img src="https://avatars.githubusercontent.com/u/6391763?v=4" width="100;" alt="ghoshnirmalya"/>
|
||||
<br />
|
||||
<sub><b>Nirmalya Ghosh</b></sub>
|
||||
</a>
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<a href="https://github.com/timpratim">
|
||||
<img src="https://avatars.githubusercontent.com/u/32492961?v=4" width="100;" alt="timpratim"/>
|
||||
<br />
|
||||
<sub><b>Pratim</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/quentin-decre">
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: 'Set permissions'
|
||||
---
|
||||
|
||||
In the previous section, you could fetch the todos because the **admin** role is enabled by default when using Hasura Console. When building your applications, you want to define permissions using **roles** that your users can assume when making requests.
|
||||
While using the Hasura Console, you could fetch the todos because the **admin** role is enabled by default but when building your applications with a client, you want to define permissions using **roles** that your users can assume when making requests.
|
||||
|
||||
Hasura supports role-based access control. You create rules for each role, table, and operation (select, insert, update and delete) that can check dynamic session variables, like user ID.
|
||||
|
||||
|
||||
@@ -14,12 +14,11 @@ services:
|
||||
auth:
|
||||
access_control:
|
||||
email:
|
||||
allowed_email_domains: ""
|
||||
allowed_emails: ""
|
||||
blocked_email_domains: ""
|
||||
blocked_emails: ""
|
||||
url:
|
||||
allowed_redirect_urls: ""
|
||||
allowed_email_domains: ''
|
||||
allowed_emails: ''
|
||||
blocked_email_domains: ''
|
||||
blocked_emails: ''
|
||||
allowed_redirect_urls: ''
|
||||
anonymous_users_enabled: false
|
||||
client_url: http://localhost:3000
|
||||
disable_new_users: false
|
||||
@@ -28,11 +27,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 +40,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 +107,13 @@ auth:
|
||||
enabled: false
|
||||
provider:
|
||||
twilio:
|
||||
account_sid: ""
|
||||
auth_token: ""
|
||||
from: ""
|
||||
messaging_service_id: ""
|
||||
account_sid: ''
|
||||
auth_token: ''
|
||||
from: ''
|
||||
messaging_service_id: ''
|
||||
smtp:
|
||||
host: nhost_mailhog
|
||||
method: ""
|
||||
method: ''
|
||||
pass: password
|
||||
port: 1765
|
||||
secure: false
|
||||
|
||||
@@ -2,14 +2,32 @@
|
||||
|
||||
This demo is a work in progress, further improvements are to come
|
||||
|
||||
### Installation
|
||||
## Get started
|
||||
|
||||
First, clone this repo. Then run the commands:
|
||||
1. Clone the repository
|
||||
|
||||
```sh
|
||||
git clone https://github.com/nhost/nhost
|
||||
cd nhost
|
||||
```
|
||||
|
||||
2. Install dependencies
|
||||
|
||||
```sh
|
||||
cd examples/nextjs
|
||||
yarn
|
||||
yarn dev
|
||||
pnpm install
|
||||
```
|
||||
|
||||
3. Terminal 1: Start Nhost
|
||||
|
||||
```sh
|
||||
nhost dev
|
||||
```
|
||||
|
||||
4. Terminal 2: Start React App
|
||||
|
||||
```sh
|
||||
pnpm run dev
|
||||
```
|
||||
|
||||
If you want to use this demo with your own cloud instance:
|
||||
@@ -18,8 +36,3 @@ If you want to use this demo with your own cloud instance:
|
||||
- don't forget to change the client URL in the Nhost console so email verification will work: `Users -> Login Settings -> Client login URLs`: `http://localhost:4000`
|
||||
|
||||
If you want to use a local Nhost instance, start the CLI in parallel to Nextjs:
|
||||
|
||||
```sh
|
||||
# Inside examples/nextjs
|
||||
nhost -d
|
||||
```
|
||||
|
||||
13
examples/nextjs/next.config.js
Normal file
13
examples/nextjs/next.config.js
Normal file
@@ -0,0 +1,13 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {}
|
||||
|
||||
const pkg = require('./package.json')
|
||||
// * Only required to make it work with the monorepo. Is not required otherwise
|
||||
const withTM = require('next-transpile-modules')(
|
||||
// * All references to workspace packages are transpiled
|
||||
Object.entries(pkg.dependencies)
|
||||
.filter(([name, version]) => version.startsWith('workspace'))
|
||||
.map(([name]) => name)
|
||||
)
|
||||
|
||||
module.exports = withTM(nextConfig)
|
||||
@@ -15,8 +15,7 @@ auth:
|
||||
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
|
||||
|
||||
@@ -11,4 +11,4 @@
|
||||
max_connections: 50
|
||||
retries: 20
|
||||
use_prepared_statements: true
|
||||
tables: "!include default/tables/tables.yaml"
|
||||
tables: '!include default/tables/tables.yaml'
|
||||
|
||||
@@ -16,10 +16,10 @@ configuration:
|
||||
update: updateAuthProviders
|
||||
update_by_pk: updateAuthProvider
|
||||
array_relationships:
|
||||
- name: userProviders
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: provider_id
|
||||
table:
|
||||
name: user_providers
|
||||
schema: auth
|
||||
- name: userProviders
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: provider_id
|
||||
table:
|
||||
name: user_providers
|
||||
schema: auth
|
||||
|
||||
@@ -19,6 +19,6 @@ configuration:
|
||||
update: updateAuthRefreshTokens
|
||||
update_by_pk: updateAuthRefreshToken
|
||||
object_relationships:
|
||||
- name: user
|
||||
using:
|
||||
foreign_key_constraint_on: user_id
|
||||
- name: user
|
||||
using:
|
||||
foreign_key_constraint_on: user_id
|
||||
|
||||
@@ -16,17 +16,17 @@ configuration:
|
||||
update: updateAuthRoles
|
||||
update_by_pk: updateAuthRole
|
||||
array_relationships:
|
||||
- name: userRoles
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: role
|
||||
table:
|
||||
name: user_roles
|
||||
schema: auth
|
||||
- name: usersByDefaultRole
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: default_role
|
||||
table:
|
||||
name: users
|
||||
schema: auth
|
||||
- name: userRoles
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: role
|
||||
table:
|
||||
name: user_roles
|
||||
schema: auth
|
||||
- name: usersByDefaultRole
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: default_role
|
||||
table:
|
||||
name: users
|
||||
schema: auth
|
||||
|
||||
@@ -23,9 +23,9 @@ configuration:
|
||||
update: updateAuthUserProviders
|
||||
update_by_pk: updateAuthUserProvider
|
||||
object_relationships:
|
||||
- name: provider
|
||||
using:
|
||||
foreign_key_constraint_on: provider_id
|
||||
- name: user
|
||||
using:
|
||||
foreign_key_constraint_on: user_id
|
||||
- name: provider
|
||||
using:
|
||||
foreign_key_constraint_on: provider_id
|
||||
- name: user
|
||||
using:
|
||||
foreign_key_constraint_on: user_id
|
||||
|
||||
@@ -19,9 +19,9 @@ configuration:
|
||||
update: updateAuthUserRoles
|
||||
update_by_pk: updateAuthUserRole
|
||||
object_relationships:
|
||||
- name: roleByRole
|
||||
using:
|
||||
foreign_key_constraint_on: role
|
||||
- name: user
|
||||
using:
|
||||
foreign_key_constraint_on: user_id
|
||||
- name: roleByRole
|
||||
using:
|
||||
foreign_key_constraint_on: role
|
||||
- name: user
|
||||
using:
|
||||
foreign_key_constraint_on: user_id
|
||||
|
||||
@@ -38,28 +38,28 @@ configuration:
|
||||
update: updateUsers
|
||||
update_by_pk: updateUser
|
||||
object_relationships:
|
||||
- name: defaultRoleByRole
|
||||
using:
|
||||
foreign_key_constraint_on: default_role
|
||||
- name: defaultRoleByRole
|
||||
using:
|
||||
foreign_key_constraint_on: default_role
|
||||
array_relationships:
|
||||
- name: refreshTokens
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: user_id
|
||||
table:
|
||||
name: refresh_tokens
|
||||
schema: auth
|
||||
- name: roles
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: user_id
|
||||
table:
|
||||
name: user_roles
|
||||
schema: auth
|
||||
- name: userProviders
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: user_id
|
||||
table:
|
||||
name: user_providers
|
||||
schema: auth
|
||||
- name: refreshTokens
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: user_id
|
||||
table:
|
||||
name: refresh_tokens
|
||||
schema: auth
|
||||
- name: roles
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: user_id
|
||||
table:
|
||||
name: user_roles
|
||||
schema: auth
|
||||
- name: userProviders
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: user_id
|
||||
table:
|
||||
name: user_providers
|
||||
schema: auth
|
||||
|
||||
@@ -2,9 +2,9 @@ table:
|
||||
name: books
|
||||
schema: public
|
||||
select_permissions:
|
||||
- permission:
|
||||
columns:
|
||||
- id
|
||||
- title
|
||||
filter: {}
|
||||
role: user
|
||||
- permission:
|
||||
columns:
|
||||
- id
|
||||
- title
|
||||
filter: {}
|
||||
role: user
|
||||
|
||||
@@ -2,9 +2,9 @@ table:
|
||||
name: test
|
||||
schema: public
|
||||
select_permissions:
|
||||
- permission:
|
||||
columns:
|
||||
- bidon
|
||||
- id
|
||||
filter: {}
|
||||
role: user
|
||||
- permission:
|
||||
columns:
|
||||
- bidon
|
||||
- id
|
||||
filter: {}
|
||||
role: user
|
||||
|
||||
@@ -23,10 +23,10 @@ configuration:
|
||||
update: updateBuckets
|
||||
update_by_pk: updateBucket
|
||||
array_relationships:
|
||||
- name: files
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: bucket_id
|
||||
table:
|
||||
name: files
|
||||
schema: storage
|
||||
- name: files
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: bucket_id
|
||||
table:
|
||||
name: files
|
||||
schema: storage
|
||||
|
||||
@@ -25,6 +25,6 @@ configuration:
|
||||
update: updateFiles
|
||||
update_by_pk: updateFile
|
||||
object_relationships:
|
||||
- name: bucket
|
||||
using:
|
||||
foreign_key_constraint_on: bucket_id
|
||||
- name: bucket
|
||||
using:
|
||||
foreign_key_constraint_on: bucket_id
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
- "!include auth_provider_requests.yaml"
|
||||
- "!include auth_providers.yaml"
|
||||
- "!include auth_refresh_tokens.yaml"
|
||||
- "!include auth_roles.yaml"
|
||||
- "!include auth_user_providers.yaml"
|
||||
- "!include auth_user_roles.yaml"
|
||||
- "!include auth_users.yaml"
|
||||
- "!include public_books.yaml"
|
||||
- "!include storage_buckets.yaml"
|
||||
- "!include storage_files.yaml"
|
||||
- '!include auth_provider_requests.yaml'
|
||||
- '!include auth_providers.yaml'
|
||||
- '!include auth_refresh_tokens.yaml'
|
||||
- '!include auth_roles.yaml'
|
||||
- '!include auth_user_providers.yaml'
|
||||
- '!include auth_user_roles.yaml'
|
||||
- '!include auth_users.yaml'
|
||||
- '!include public_books.yaml'
|
||||
- '!include storage_buckets.yaml'
|
||||
- '!include storage_files.yaml'
|
||||
|
||||
@@ -6,13 +6,23 @@
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
"prettier": "prettier --check .",
|
||||
"prettier:fix": "prettier --write .",
|
||||
"lint": "eslint . --ext .ts,.tsx",
|
||||
"lint:fix": "eslint . --ext .ts,.tsx --fix",
|
||||
"verify": "run-p prettier lint",
|
||||
"verify:fix": "run-p prettier:fix lint:fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.5.10",
|
||||
"@nhost/nextjs": "^1.0.10",
|
||||
"@nhost/react": "^0.5.0",
|
||||
"@nhost/react-apollo": "^4.0.10",
|
||||
"@nhost/apollo": "workspace:*",
|
||||
"@nhost/core": "workspace:*",
|
||||
"@nhost/nextjs": "workspace:*",
|
||||
"@nhost/react": "workspace:*",
|
||||
"@nhost/react-apollo": "workspace:*",
|
||||
"@nhost/nhost-js": "workspace:*",
|
||||
"@nhost/hasura-auth-js": "workspace:*",
|
||||
"@nhost/hasura-storage-js": "workspace:*",
|
||||
"graphql": "^16.3.0",
|
||||
"next": "12.1.0",
|
||||
"react": "17.0.2",
|
||||
@@ -22,9 +32,10 @@
|
||||
"@types/node": "17.0.23",
|
||||
"@types/react": "17.0.43",
|
||||
"@xstate/inspect": "^0.6.2",
|
||||
"eslint": "8.8.0",
|
||||
"eslint-config-next": "12.0.10",
|
||||
"next-transpile-modules": "^9.0.0",
|
||||
"typescript": "4.5.5",
|
||||
"ws": "^8.5.0"
|
||||
"ws": "^8.5.0",
|
||||
"xstate": "^4.30.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,12 +19,14 @@ if (typeof window !== 'undefined' && process.env.NEXT_PUBLIC_DEBUG) {
|
||||
const nhost = new NhostClient({ backendUrl: BACKEND_URL })
|
||||
|
||||
function MyApp({ Component, pageProps }: AppProps) {
|
||||
// * Monorepo-related. See: https://stackoverflow.com/questions/71843247/react-nextjs-type-error-component-cannot-be-used-as-a-jsx-component
|
||||
const AnyComponent = Component as any
|
||||
return (
|
||||
<NhostNextProvider nhost={nhost} initial={pageProps.nhostSession}>
|
||||
<NhostApolloProvider nhost={nhost}>
|
||||
<div className="App">
|
||||
<Header />
|
||||
<Component {...pageProps} />
|
||||
<AnyComponent {...pageProps} />
|
||||
</div>
|
||||
</NhostApolloProvider>
|
||||
</NhostNextProvider>
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": false,
|
||||
@@ -19,11 +15,6 @@
|
||||
"jsx": "preserve",
|
||||
"incremental": true
|
||||
},
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx"],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1 +1 @@
|
||||
REACT_APP_BACKEND_URL=http://localhost:1337
|
||||
VITE_NHOST_URL=http://localhost:1337
|
||||
@@ -72,25 +72,33 @@ This example app has some work in progress:
|
||||
|
||||
## Get started
|
||||
|
||||
1. Install dependencies
|
||||
1. Clone the repository
|
||||
|
||||
```
|
||||
npm install
|
||||
```sh
|
||||
git clone https://github.com/nhost/nhost
|
||||
cd nhost
|
||||
```
|
||||
|
||||
2. Terminal 1: Start Nhost
|
||||
2. Install dependencies
|
||||
|
||||
```sh
|
||||
cd examples/react-apollo-crm
|
||||
pnpm install
|
||||
```
|
||||
|
||||
3. Terminal 1: Start Nhost
|
||||
|
||||
```sh
|
||||
nhost dev
|
||||
```
|
||||
|
||||
2. Terminal 2: Start React App
|
||||
4. Terminal 2: Start React App
|
||||
|
||||
```
|
||||
npm run start
|
||||
```sh
|
||||
pnpm run dev
|
||||
```
|
||||
|
||||
3. Terminal 3: Start GraphQL Codegens
|
||||
5. Terminal 3: Start GraphQL Codegens
|
||||
|
||||
> Make sure that the Nhost backend in step 2 has started and is available before you run this command
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
module.exports = {
|
||||
client: {
|
||||
service: {
|
||||
name: "backend",
|
||||
url: "http://localhost:1337/v1/graphql",
|
||||
name: 'backend',
|
||||
url: 'http://localhost:1337/v1/graphql',
|
||||
headers: {
|
||||
"x-hasura-admin-secret": "nhost-admin-secret",
|
||||
},
|
||||
'x-hasura-admin-secret': 'nhost-admin-secret'
|
||||
}
|
||||
},
|
||||
includes: ["src/**/*.graphql", "src/**/*.gql"],
|
||||
},
|
||||
};
|
||||
includes: ['src/**/*.graphql', 'src/**/*.gql']
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,13 +3,13 @@ schema: http://localhost:1337/v1/graphql
|
||||
headers:
|
||||
x-hasura-admin-secret: nhost-admin-secret
|
||||
documents:
|
||||
- "src/**/*.graphql"
|
||||
- "src/**/*.gql"
|
||||
- 'src/**/*.graphql'
|
||||
- 'src/**/*.gql'
|
||||
generates:
|
||||
src/utils/__generated__/graphql.ts:
|
||||
plugins:
|
||||
- "typescript"
|
||||
- "typescript-operations"
|
||||
- "typescript-react-apollo"
|
||||
- 'typescript'
|
||||
- 'typescript-operations'
|
||||
- 'typescript-react-apollo'
|
||||
config:
|
||||
withRefetchFn: true
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { NhostClient } from '@nhost/nhost-js'
|
||||
|
||||
const nhost = new NhostClient({
|
||||
backendUrl: process.env.NHOST_BACKEND_URL!
|
||||
backendUrl: process.env.NHOST_BACKEND_URL!
|
||||
})
|
||||
|
||||
export { nhost }
|
||||
|
||||
@@ -2,104 +2,104 @@ import { Request, Response } from 'express'
|
||||
import { nhost } from '../../_utils/nhost'
|
||||
|
||||
const handler = async (req: Request, res: Response) => {
|
||||
if (req.headers['nhsot-webhook-secret'] !== process.env.NHSOT_WEBHOOK_SECRET) {
|
||||
return res.status(401).send('Unauthorized')
|
||||
}
|
||||
if (req.headers['nhsot-webhook-secret'] !== process.env.NHSOT_WEBHOOK_SECRET) {
|
||||
return res.status(401).send('Unauthorized')
|
||||
}
|
||||
|
||||
// User who just signed up
|
||||
const user = req.body.event.data.new
|
||||
// User who just signed up
|
||||
const user = req.body.event.data.new
|
||||
|
||||
// Get the user's email domain
|
||||
const emailDomain = user.email.split('@')[1]
|
||||
// Get the user's email domain
|
||||
const emailDomain = user.email.split('@')[1]
|
||||
|
||||
// Check if a company with the user's email domain already exists.
|
||||
const GET_COMPANY_WITH_EMAIL_DOMAIN = `
|
||||
// Check if a company with the user's email domain already exists.
|
||||
const GET_COMPANY_WITH_EMAIL_DOMAIN = `
|
||||
query getCompanyWithEmailDomain($emailDomain: String!) {
|
||||
companies(where: { emailDomain: { _eq: $emailDomain } }) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`
|
||||
const { data, error } = await nhost.graphql.request(
|
||||
GET_COMPANY_WITH_EMAIL_DOMAIN,
|
||||
{
|
||||
emailDomain
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'x-hasura-admin-secret': process.env.NHOST_ADMIN_SECRET
|
||||
}
|
||||
const { data, error } = await nhost.graphql.request(
|
||||
GET_COMPANY_WITH_EMAIL_DOMAIN,
|
||||
{
|
||||
emailDomain
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'x-hasura-admin-secret': process.env.NHOST_ADMIN_SECRET
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
if (error) {
|
||||
return res.status(500).send(error)
|
||||
}
|
||||
if (error) {
|
||||
return res.status(500).send(error)
|
||||
}
|
||||
|
||||
const { companies } = data as any
|
||||
const { companies } = data as any
|
||||
|
||||
let companyId
|
||||
if (companies.length === 1) {
|
||||
// if a company already exists, use that company's id
|
||||
companyId = companies[0].id
|
||||
} else {
|
||||
// else, create a new company for the newly created user with the same email domain as the user
|
||||
const CREATE_NEW_COMPANY = `
|
||||
let companyId
|
||||
if (companies.length === 1) {
|
||||
// if a company already exists, use that company's id
|
||||
companyId = companies[0].id
|
||||
} else {
|
||||
// else, create a new company for the newly created user with the same email domain as the user
|
||||
const CREATE_NEW_COMPANY = `
|
||||
mutation insertCompany($emailDomain: String!) {
|
||||
insertCompany(object: { name: $emailDomain, emailDomain: $emailDomain }) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`
|
||||
const { data, error } = await nhost.graphql.request(
|
||||
CREATE_NEW_COMPANY,
|
||||
{
|
||||
emailDomain
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'x-hasura-admin-secret': process.env.NHOST_ADMIN_SECRET
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
if (error) {
|
||||
return res.status(500).send(error)
|
||||
const { data, error } = await nhost.graphql.request(
|
||||
CREATE_NEW_COMPANY,
|
||||
{
|
||||
emailDomain
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'x-hasura-admin-secret': process.env.NHOST_ADMIN_SECRET
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const { insertCompany } = data as any
|
||||
if (error) {
|
||||
return res.status(500).send(error)
|
||||
}
|
||||
|
||||
companyId = insertCompany.id
|
||||
}
|
||||
const { insertCompany } = data as any
|
||||
|
||||
// We now have the company id of an existing, or a newly created company.
|
||||
// Now let's add the user to the company.
|
||||
companyId = insertCompany.id
|
||||
}
|
||||
|
||||
const ADD_USER_TO_COMPANY = `
|
||||
// We now have the company id of an existing, or a newly created company.
|
||||
// Now let's add the user to the company.
|
||||
|
||||
const ADD_USER_TO_COMPANY = `
|
||||
mutation addUserToCompany($userId: uuid!, $companyId: uuid!) {
|
||||
insertCompanyUser(object: {userId: $userId, companyId: $companyId}) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`
|
||||
const { error: addUserToCompanyError } = await nhost.graphql.request(
|
||||
ADD_USER_TO_COMPANY,
|
||||
{
|
||||
userId: user.id,
|
||||
companyId
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'x-hasura-admin-secret': process.env.NHOST_ADMIN_SECRET
|
||||
}
|
||||
const { error: addUserToCompanyError } = await nhost.graphql.request(
|
||||
ADD_USER_TO_COMPANY,
|
||||
{
|
||||
userId: user.id,
|
||||
companyId
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'x-hasura-admin-secret': process.env.NHOST_ADMIN_SECRET
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
if (addUserToCompanyError) {
|
||||
return res.status(500).send(error)
|
||||
}
|
||||
if (addUserToCompanyError) {
|
||||
return res.status(500).send(error)
|
||||
}
|
||||
|
||||
res.status(200).send(`OK`)
|
||||
res.status(200).send(`OK`)
|
||||
}
|
||||
|
||||
export default handler
|
||||
|
||||
18
examples/react-apollo-crm/index.html
Normal file
18
examples/react-apollo-crm/index.html
Normal file
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta name="description" content="Web site created using create-react-app" />
|
||||
<link rel="apple-touch-icon" href="/logo192.png" />
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
<title>React App</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/index.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -6,12 +6,11 @@ services:
|
||||
auth:
|
||||
access_control:
|
||||
email:
|
||||
allowed_email_domains: ""
|
||||
allowed_emails: ""
|
||||
blocked_email_domains: ""
|
||||
blocked_emails: ""
|
||||
url:
|
||||
allowed_redirect_urls: ""
|
||||
allowed_email_domains: ''
|
||||
allowed_emails: ''
|
||||
blocked_email_domains: ''
|
||||
blocked_emails: ''
|
||||
allowed_redirect_urls: ''
|
||||
anonymous_users_enabled: false
|
||||
client_url: http://localhost:3000
|
||||
disable_new_users: false
|
||||
@@ -19,12 +18,12 @@ auth:
|
||||
enabled: false
|
||||
passwordless:
|
||||
enabled: false
|
||||
template_fetch_url: ""
|
||||
template_fetch_url: ''
|
||||
signin_email_verified_required: false
|
||||
gravatar:
|
||||
default: ""
|
||||
default: ''
|
||||
enabled: true
|
||||
rating: ""
|
||||
rating: ''
|
||||
locale:
|
||||
allowed: en
|
||||
default: en
|
||||
@@ -33,65 +32,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:
|
||||
@@ -100,13 +99,13 @@ auth:
|
||||
enabled: false
|
||||
provider:
|
||||
twilio:
|
||||
account_sid: ""
|
||||
auth_token: ""
|
||||
from: ""
|
||||
messaging_service_id: ""
|
||||
account_sid: ''
|
||||
auth_token: ''
|
||||
from: ''
|
||||
messaging_service_id: ''
|
||||
smtp:
|
||||
host: nhost_mailhog
|
||||
method: ""
|
||||
method: ''
|
||||
pass: password
|
||||
port: 1586
|
||||
secure: false
|
||||
|
||||
@@ -7,9 +7,7 @@
|
||||
<h2>Verify Email</h2>
|
||||
<p>Use this link to verify your email:</p>
|
||||
<p>
|
||||
<a
|
||||
href="${serverUrl}/verify?&ticket=${ticket}&type=emailVerify&redirectTo=${redirectTo}"
|
||||
>
|
||||
<a href="${serverUrl}/verify?&ticket=${ticket}&type=emailVerify&redirectTo=${redirectTo}">
|
||||
Verify Email
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@@ -7,9 +7,7 @@
|
||||
<h2>Reset Password</h2>
|
||||
<p>Use this link to reset your password:</p>
|
||||
<p>
|
||||
<a
|
||||
href="${serverUrl}/verify?&ticket=${ticket}&type=passwordReset&redirectTo=${redirectTo}"
|
||||
>
|
||||
<a href="${serverUrl}/verify?&ticket=${ticket}&type=passwordReset&redirectTo=${redirectTo}">
|
||||
Reset password
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
type Mutation {
|
||||
actionName(
|
||||
arg1: SampleInput!
|
||||
): SampleOutput
|
||||
actionName(arg1: SampleInput!): SampleOutput
|
||||
}
|
||||
|
||||
input SampleInput {
|
||||
@@ -12,4 +10,3 @@ input SampleInput {
|
||||
type SampleOutput {
|
||||
accessToken: String!
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
actions:
|
||||
- name: actionName
|
||||
definition:
|
||||
kind: synchronous
|
||||
handler: http://host.docker.internal:3000
|
||||
permissions:
|
||||
- role: user
|
||||
- name: actionName
|
||||
definition:
|
||||
kind: synchronous
|
||||
handler: http://host.docker.internal:3000
|
||||
permissions:
|
||||
- role: user
|
||||
custom_types:
|
||||
enums: []
|
||||
input_objects:
|
||||
- name: SampleInput
|
||||
- name: SampleInput
|
||||
objects:
|
||||
- name: SampleOutput
|
||||
- name: SampleOutput
|
||||
scalars: []
|
||||
|
||||
@@ -11,4 +11,4 @@
|
||||
max_connections: 50
|
||||
retries: 20
|
||||
use_prepared_statements: true
|
||||
tables: "!include default/tables/tables.yaml"
|
||||
tables: '!include default/tables/tables.yaml'
|
||||
|
||||
@@ -16,10 +16,10 @@ configuration:
|
||||
update: updateAuthProviders
|
||||
update_by_pk: updateAuthProvider
|
||||
array_relationships:
|
||||
- name: userProviders
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: provider_id
|
||||
table:
|
||||
name: user_providers
|
||||
schema: auth
|
||||
- name: userProviders
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: provider_id
|
||||
table:
|
||||
name: user_providers
|
||||
schema: auth
|
||||
|
||||
@@ -19,6 +19,6 @@ configuration:
|
||||
update: updateAuthRefreshTokens
|
||||
update_by_pk: updateAuthRefreshToken
|
||||
object_relationships:
|
||||
- name: user
|
||||
using:
|
||||
foreign_key_constraint_on: user_id
|
||||
- name: user
|
||||
using:
|
||||
foreign_key_constraint_on: user_id
|
||||
|
||||
@@ -16,17 +16,17 @@ configuration:
|
||||
update: updateAuthRoles
|
||||
update_by_pk: updateAuthRole
|
||||
array_relationships:
|
||||
- name: userRoles
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: role
|
||||
table:
|
||||
name: user_roles
|
||||
schema: auth
|
||||
- name: usersByDefaultRole
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: default_role
|
||||
table:
|
||||
name: users
|
||||
schema: auth
|
||||
- name: userRoles
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: role
|
||||
table:
|
||||
name: user_roles
|
||||
schema: auth
|
||||
- name: usersByDefaultRole
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: default_role
|
||||
table:
|
||||
name: users
|
||||
schema: auth
|
||||
|
||||
@@ -23,9 +23,9 @@ configuration:
|
||||
update: updateAuthUserProviders
|
||||
update_by_pk: updateAuthUserProvider
|
||||
object_relationships:
|
||||
- name: provider
|
||||
using:
|
||||
foreign_key_constraint_on: provider_id
|
||||
- name: user
|
||||
using:
|
||||
foreign_key_constraint_on: user_id
|
||||
- name: provider
|
||||
using:
|
||||
foreign_key_constraint_on: provider_id
|
||||
- name: user
|
||||
using:
|
||||
foreign_key_constraint_on: user_id
|
||||
|
||||
@@ -19,9 +19,9 @@ configuration:
|
||||
update: updateAuthUserRoles
|
||||
update_by_pk: updateAuthUserRole
|
||||
object_relationships:
|
||||
- name: roleByRole
|
||||
using:
|
||||
foreign_key_constraint_on: role
|
||||
- name: user
|
||||
using:
|
||||
foreign_key_constraint_on: user_id
|
||||
- name: roleByRole
|
||||
using:
|
||||
foreign_key_constraint_on: role
|
||||
- name: user
|
||||
using:
|
||||
foreign_key_constraint_on: user_id
|
||||
|
||||
@@ -38,79 +38,79 @@ configuration:
|
||||
update: updateUsers
|
||||
update_by_pk: updateUser
|
||||
object_relationships:
|
||||
- name: companyUser
|
||||
using:
|
||||
manual_configuration:
|
||||
column_mapping:
|
||||
id: user_id
|
||||
insertion_order: null
|
||||
remote_table:
|
||||
name: company_users
|
||||
schema: public
|
||||
- name: defaultRoleByRole
|
||||
using:
|
||||
foreign_key_constraint_on: default_role
|
||||
- name: companyUser
|
||||
using:
|
||||
manual_configuration:
|
||||
column_mapping:
|
||||
id: user_id
|
||||
insertion_order: null
|
||||
remote_table:
|
||||
name: company_users
|
||||
schema: public
|
||||
- name: defaultRoleByRole
|
||||
using:
|
||||
foreign_key_constraint_on: default_role
|
||||
array_relationships:
|
||||
- name: customer_comments
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: user_id
|
||||
table:
|
||||
name: customer_comments
|
||||
schema: public
|
||||
- name: customers
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: user_id
|
||||
table:
|
||||
name: customers
|
||||
schema: public
|
||||
- name: refreshTokens
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: user_id
|
||||
table:
|
||||
name: refresh_tokens
|
||||
schema: auth
|
||||
- name: roles
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: user_id
|
||||
table:
|
||||
name: user_roles
|
||||
schema: auth
|
||||
- name: userProviders
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: user_id
|
||||
table:
|
||||
name: user_providers
|
||||
schema: auth
|
||||
- name: customer_comments
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: user_id
|
||||
table:
|
||||
name: customer_comments
|
||||
schema: public
|
||||
- name: customers
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: user_id
|
||||
table:
|
||||
name: customers
|
||||
schema: public
|
||||
- name: refreshTokens
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: user_id
|
||||
table:
|
||||
name: refresh_tokens
|
||||
schema: auth
|
||||
- name: roles
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: user_id
|
||||
table:
|
||||
name: user_roles
|
||||
schema: auth
|
||||
- name: userProviders
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: user_id
|
||||
table:
|
||||
name: user_providers
|
||||
schema: auth
|
||||
select_permissions:
|
||||
- permission:
|
||||
columns:
|
||||
- avatar_url
|
||||
- display_name
|
||||
- email
|
||||
- id
|
||||
filter:
|
||||
companyUser:
|
||||
company:
|
||||
companyUsers:
|
||||
user_id:
|
||||
_eq: X-Hasura-User-Id
|
||||
role: user
|
||||
- permission:
|
||||
columns:
|
||||
- avatar_url
|
||||
- display_name
|
||||
- email
|
||||
- id
|
||||
filter:
|
||||
companyUser:
|
||||
company:
|
||||
companyUsers:
|
||||
user_id:
|
||||
_eq: X-Hasura-User-Id
|
||||
role: user
|
||||
event_triggers:
|
||||
- definition:
|
||||
enable_manual: false
|
||||
insert:
|
||||
columns: "*"
|
||||
headers:
|
||||
- name: nhost-webhook-secret
|
||||
value_from_env: NHOST_WEBHOOK_SECRET
|
||||
name: users-insert-create-company-connection
|
||||
retry_conf:
|
||||
interval_sec: 10
|
||||
num_retries: 0
|
||||
timeout_sec: 60
|
||||
webhook: "{{NHOST_BACKEND_URL}}/v1/functions/users/insert/create-company-connection"
|
||||
- definition:
|
||||
enable_manual: false
|
||||
insert:
|
||||
columns: '*'
|
||||
headers:
|
||||
- name: nhost-webhook-secret
|
||||
value_from_env: NHOST_WEBHOOK_SECRET
|
||||
name: users-insert-create-company-connection
|
||||
retry_conf:
|
||||
interval_sec: 10
|
||||
num_retries: 0
|
||||
timeout_sec: 60
|
||||
webhook: '{{NHOST_BACKEND_URL}}/v1/functions/users/insert/create-company-connection'
|
||||
|
||||
@@ -18,29 +18,29 @@ configuration:
|
||||
update: updateCompanies
|
||||
update_by_pk: updateCompany
|
||||
array_relationships:
|
||||
- name: companyUsers
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: company_id
|
||||
table:
|
||||
name: company_users
|
||||
schema: public
|
||||
- name: customers
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: company_id
|
||||
table:
|
||||
name: customers
|
||||
schema: public
|
||||
- name: companyUsers
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: company_id
|
||||
table:
|
||||
name: company_users
|
||||
schema: public
|
||||
- name: customers
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: company_id
|
||||
table:
|
||||
name: customers
|
||||
schema: public
|
||||
select_permissions:
|
||||
- permission:
|
||||
columns:
|
||||
- id
|
||||
- created_at
|
||||
- updated_at
|
||||
- name
|
||||
filter:
|
||||
companyUsers:
|
||||
user_id:
|
||||
_eq: X-Hasura-User-Id
|
||||
role: user
|
||||
- permission:
|
||||
columns:
|
||||
- id
|
||||
- created_at
|
||||
- updated_at
|
||||
- name
|
||||
filter:
|
||||
companyUsers:
|
||||
user_id:
|
||||
_eq: X-Hasura-User-Id
|
||||
role: user
|
||||
|
||||
@@ -20,23 +20,23 @@ configuration:
|
||||
update: updateCompanyUsers
|
||||
update_by_pk: updateCompanyUser
|
||||
object_relationships:
|
||||
- name: company
|
||||
using:
|
||||
foreign_key_constraint_on: company_id
|
||||
- name: user
|
||||
using:
|
||||
foreign_key_constraint_on: user_id
|
||||
- name: company
|
||||
using:
|
||||
foreign_key_constraint_on: company_id
|
||||
- name: user
|
||||
using:
|
||||
foreign_key_constraint_on: user_id
|
||||
select_permissions:
|
||||
- permission:
|
||||
columns:
|
||||
- id
|
||||
- created_at
|
||||
- updated_at
|
||||
- company_id
|
||||
- user_id
|
||||
filter:
|
||||
company:
|
||||
companyUsers:
|
||||
user_id:
|
||||
_eq: X-Hasura-User-Id
|
||||
role: user
|
||||
- permission:
|
||||
columns:
|
||||
- id
|
||||
- created_at
|
||||
- updated_at
|
||||
- company_id
|
||||
- user_id
|
||||
filter:
|
||||
company:
|
||||
companyUsers:
|
||||
user_id:
|
||||
_eq: X-Hasura-User-Id
|
||||
role: user
|
||||
|
||||
@@ -19,65 +19,65 @@ configuration:
|
||||
update: updateCustomerComments
|
||||
update_by_pk: updateCustomerComment
|
||||
object_relationships:
|
||||
- name: customer
|
||||
using:
|
||||
foreign_key_constraint_on: customer_id
|
||||
- name: file
|
||||
using:
|
||||
foreign_key_constraint_on: file_id
|
||||
- name: user
|
||||
using:
|
||||
foreign_key_constraint_on: user_id
|
||||
- name: customer
|
||||
using:
|
||||
foreign_key_constraint_on: customer_id
|
||||
- name: file
|
||||
using:
|
||||
foreign_key_constraint_on: file_id
|
||||
- name: user
|
||||
using:
|
||||
foreign_key_constraint_on: user_id
|
||||
insert_permissions:
|
||||
- permission:
|
||||
backend_only: false
|
||||
check:
|
||||
customer:
|
||||
company:
|
||||
companyUsers:
|
||||
user_id:
|
||||
_eq: X-Hasura-User-Id
|
||||
columns:
|
||||
- customer_id
|
||||
- file_id
|
||||
- text
|
||||
set:
|
||||
user_id: x-hasura-user-id
|
||||
role: user
|
||||
- permission:
|
||||
backend_only: false
|
||||
check:
|
||||
customer:
|
||||
company:
|
||||
companyUsers:
|
||||
user_id:
|
||||
_eq: X-Hasura-User-Id
|
||||
columns:
|
||||
- customer_id
|
||||
- file_id
|
||||
- text
|
||||
set:
|
||||
user_id: x-hasura-user-id
|
||||
role: user
|
||||
select_permissions:
|
||||
- permission:
|
||||
columns:
|
||||
- created_at
|
||||
- customer_id
|
||||
- file_id
|
||||
- id
|
||||
- text
|
||||
- updated_at
|
||||
- user_id
|
||||
filter:
|
||||
customer:
|
||||
company:
|
||||
companyUsers:
|
||||
user_id:
|
||||
_eq: X-Hasura-User-Id
|
||||
role: user
|
||||
- permission:
|
||||
columns:
|
||||
- created_at
|
||||
- customer_id
|
||||
- file_id
|
||||
- id
|
||||
- text
|
||||
- updated_at
|
||||
- user_id
|
||||
filter:
|
||||
customer:
|
||||
company:
|
||||
companyUsers:
|
||||
user_id:
|
||||
_eq: X-Hasura-User-Id
|
||||
role: user
|
||||
update_permissions:
|
||||
- permission:
|
||||
check: null
|
||||
columns: []
|
||||
filter:
|
||||
customer:
|
||||
company:
|
||||
companyUsers:
|
||||
user_id:
|
||||
_eq: X-Hasura-User-Id
|
||||
role: user
|
||||
- permission:
|
||||
check: null
|
||||
columns: []
|
||||
filter:
|
||||
customer:
|
||||
company:
|
||||
companyUsers:
|
||||
user_id:
|
||||
_eq: X-Hasura-User-Id
|
||||
role: user
|
||||
delete_permissions:
|
||||
- permission:
|
||||
filter:
|
||||
customer:
|
||||
company:
|
||||
companyUsers:
|
||||
user_id:
|
||||
_eq: X-Hasura-User-Id
|
||||
role: user
|
||||
- permission:
|
||||
filter:
|
||||
customer:
|
||||
company:
|
||||
companyUsers:
|
||||
user_id:
|
||||
_eq: X-Hasura-User-Id
|
||||
role: user
|
||||
|
||||
@@ -20,48 +20,48 @@ configuration:
|
||||
update: updateCustomers
|
||||
update_by_pk: updateCustomer
|
||||
object_relationships:
|
||||
- name: company
|
||||
using:
|
||||
foreign_key_constraint_on: company_id
|
||||
- name: user
|
||||
using:
|
||||
foreign_key_constraint_on: user_id
|
||||
- name: company
|
||||
using:
|
||||
foreign_key_constraint_on: company_id
|
||||
- name: user
|
||||
using:
|
||||
foreign_key_constraint_on: user_id
|
||||
array_relationships:
|
||||
- name: customerComments
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: customer_id
|
||||
table:
|
||||
name: customer_comments
|
||||
schema: public
|
||||
- name: customerComments
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: customer_id
|
||||
table:
|
||||
name: customer_comments
|
||||
schema: public
|
||||
insert_permissions:
|
||||
- permission:
|
||||
backend_only: false
|
||||
check:
|
||||
company:
|
||||
companyUsers:
|
||||
user_id:
|
||||
_eq: X-Hasura-User-Id
|
||||
columns:
|
||||
- address_line_1
|
||||
- company_id
|
||||
- name
|
||||
set:
|
||||
user_id: x-hasura-user-id
|
||||
role: user
|
||||
- permission:
|
||||
backend_only: false
|
||||
check:
|
||||
company:
|
||||
companyUsers:
|
||||
user_id:
|
||||
_eq: X-Hasura-User-Id
|
||||
columns:
|
||||
- address_line_1
|
||||
- company_id
|
||||
- name
|
||||
set:
|
||||
user_id: x-hasura-user-id
|
||||
role: user
|
||||
select_permissions:
|
||||
- permission:
|
||||
columns:
|
||||
- id
|
||||
- created_at
|
||||
- updated_at
|
||||
- name
|
||||
- address_line_1
|
||||
- company_id
|
||||
- user_id
|
||||
filter:
|
||||
company:
|
||||
companyUsers:
|
||||
user_id:
|
||||
_eq: X-Hasura-User-Id
|
||||
role: user
|
||||
- permission:
|
||||
columns:
|
||||
- id
|
||||
- created_at
|
||||
- updated_at
|
||||
- name
|
||||
- address_line_1
|
||||
- company_id
|
||||
- user_id
|
||||
filter:
|
||||
company:
|
||||
companyUsers:
|
||||
user_id:
|
||||
_eq: X-Hasura-User-Id
|
||||
role: user
|
||||
|
||||
@@ -23,10 +23,10 @@ configuration:
|
||||
update: updateBuckets
|
||||
update_by_pk: updateBucket
|
||||
array_relationships:
|
||||
- name: files
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: bucket_id
|
||||
table:
|
||||
name: files
|
||||
schema: storage
|
||||
- name: files
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: bucket_id
|
||||
table:
|
||||
name: files
|
||||
schema: storage
|
||||
|
||||
@@ -25,51 +25,51 @@ configuration:
|
||||
update: updateFiles
|
||||
update_by_pk: updateFile
|
||||
object_relationships:
|
||||
- name: bucket
|
||||
using:
|
||||
foreign_key_constraint_on: bucket_id
|
||||
- name: bucket
|
||||
using:
|
||||
foreign_key_constraint_on: bucket_id
|
||||
array_relationships:
|
||||
- name: customerCommentFiles
|
||||
using:
|
||||
manual_configuration:
|
||||
column_mapping:
|
||||
id: file_id
|
||||
insertion_order: null
|
||||
remote_table:
|
||||
name: customer_comments
|
||||
schema: public
|
||||
- name: customerCommentFiles
|
||||
using:
|
||||
manual_configuration:
|
||||
column_mapping:
|
||||
id: file_id
|
||||
insertion_order: null
|
||||
remote_table:
|
||||
name: customer_comments
|
||||
schema: public
|
||||
insert_permissions:
|
||||
- permission:
|
||||
backend_only: false
|
||||
check:
|
||||
_or:
|
||||
- bucket_id:
|
||||
_eq: customerComments
|
||||
columns:
|
||||
- bucket_id
|
||||
- id
|
||||
- mime_type
|
||||
- name
|
||||
role: user
|
||||
- permission:
|
||||
backend_only: false
|
||||
check:
|
||||
_or:
|
||||
- bucket_id:
|
||||
_eq: customerComments
|
||||
columns:
|
||||
- bucket_id
|
||||
- id
|
||||
- mime_type
|
||||
- name
|
||||
role: user
|
||||
select_permissions:
|
||||
- permission:
|
||||
columns:
|
||||
- id
|
||||
- created_at
|
||||
- updated_at
|
||||
- bucket_id
|
||||
- name
|
||||
- size
|
||||
- mime_type
|
||||
- etag
|
||||
- is_uploaded
|
||||
- uploaded_by_user_id
|
||||
filter:
|
||||
_or:
|
||||
- customerCommentFiles:
|
||||
customer:
|
||||
company:
|
||||
companyUsers:
|
||||
user_id:
|
||||
_eq: X-Hasura-User-Id
|
||||
role: user
|
||||
- permission:
|
||||
columns:
|
||||
- id
|
||||
- created_at
|
||||
- updated_at
|
||||
- bucket_id
|
||||
- name
|
||||
- size
|
||||
- mime_type
|
||||
- etag
|
||||
- is_uploaded
|
||||
- uploaded_by_user_id
|
||||
filter:
|
||||
_or:
|
||||
- customerCommentFiles:
|
||||
customer:
|
||||
company:
|
||||
companyUsers:
|
||||
user_id:
|
||||
_eq: X-Hasura-User-Id
|
||||
role: user
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
- "!include auth_provider_requests.yaml"
|
||||
- "!include auth_providers.yaml"
|
||||
- "!include auth_refresh_tokens.yaml"
|
||||
- "!include auth_roles.yaml"
|
||||
- "!include auth_user_providers.yaml"
|
||||
- "!include auth_user_roles.yaml"
|
||||
- "!include auth_users.yaml"
|
||||
- "!include public_companies.yaml"
|
||||
- "!include public_company_users.yaml"
|
||||
- "!include public_customer_comments.yaml"
|
||||
- "!include public_customers.yaml"
|
||||
- "!include storage_buckets.yaml"
|
||||
- "!include storage_files.yaml"
|
||||
- '!include auth_provider_requests.yaml'
|
||||
- '!include auth_providers.yaml'
|
||||
- '!include auth_refresh_tokens.yaml'
|
||||
- '!include auth_roles.yaml'
|
||||
- '!include auth_user_providers.yaml'
|
||||
- '!include auth_user_roles.yaml'
|
||||
- '!include auth_users.yaml'
|
||||
- '!include public_companies.yaml'
|
||||
- '!include public_company_users.yaml'
|
||||
- '!include public_customer_comments.yaml'
|
||||
- '!include public_customers.yaml'
|
||||
- '!include storage_buckets.yaml'
|
||||
- '!include storage_files.yaml'
|
||||
|
||||
@@ -3,38 +3,34 @@
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.4.16",
|
||||
"@headlessui/react": "^1.4.2",
|
||||
"@heroicons/react": "^1.0.5",
|
||||
"@nhost/nhost-js": "^1.0.0",
|
||||
"@nhost/react": "^0.3.0",
|
||||
"@nhost/react-apollo": "^4.0.0",
|
||||
"@tailwindcss/forms": "^0.3.4",
|
||||
"@testing-library/jest-dom": "^5.11.4",
|
||||
"@testing-library/react": "^11.1.0",
|
||||
"@testing-library/user-event": "^12.1.10",
|
||||
"@types/jest": "^26.0.15",
|
||||
"@types/node": "^12.0.0",
|
||||
"@types/react": "^17.0.0",
|
||||
"@types/react-dom": "^17.0.0",
|
||||
"@apollo/client": "^3.5.10",
|
||||
"@headlessui/react": "^1.5.0",
|
||||
"@heroicons/react": "^1.0.6",
|
||||
"@nhost/nhost-js": "workspace:*",
|
||||
"@nhost/react": "workspace:*",
|
||||
"@nhost/react-apollo": "workspace:*",
|
||||
"@tailwindcss/forms": "^0.5.0",
|
||||
"classnames": "^2.3.1",
|
||||
"date-fns": "^2.28.0",
|
||||
"graphql": "^15.8.0",
|
||||
"graphql": "15.7.2",
|
||||
"graphql-tag": "^2.12.6",
|
||||
"pretty-bytes": "^5.6.0",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-router-dom": "^6.0.2",
|
||||
"react-scripts": "^5.0.0",
|
||||
"typescript": "^4.1.2",
|
||||
"web-vitals": "^1.0.1"
|
||||
"react-router-dom": "^6.3.0",
|
||||
"tailwindcss": "^3.0.24"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject",
|
||||
"codegen": "graphql-codegen --config codegen.yaml --errors-only"
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"codegen": "graphql-codegen --config codegen.yaml --errors-only",
|
||||
"prettier": "prettier --check .",
|
||||
"prettier:fix": "prettier --write .",
|
||||
"lint": "eslint . --ext .ts,.tsx",
|
||||
"lint:fix": "eslint . --ext .ts,.tsx --fix",
|
||||
"verify": "run-p prettier lint",
|
||||
"verify:fix": "run-p prettier:fix lint:fix"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
@@ -55,15 +51,21 @@
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@graphql-codegen/cli": "^2.2.1",
|
||||
"@graphql-codegen/introspection": "^2.1.0",
|
||||
"@graphql-codegen/typescript": "^2.2.4",
|
||||
"@graphql-codegen/typescript-operations": "^2.1.8",
|
||||
"@graphql-codegen/typescript-react-apollo": "^3.1.6",
|
||||
"@graphql-codegen/cli": "^2.6.2",
|
||||
"@graphql-codegen/introspection": "^2.1.1",
|
||||
"@graphql-codegen/typescript": "^2.4.8",
|
||||
"@graphql-codegen/typescript-operations": "^2.3.5",
|
||||
"@graphql-codegen/typescript-react-apollo": "^3.2.11",
|
||||
"@types/jest": "^26.0.24",
|
||||
"@types/node": "^12.20.48",
|
||||
"@types/react": "^17.0.44",
|
||||
"@types/react-dom": "^17.0.15",
|
||||
"@types/express": "^4.17.13",
|
||||
"autoprefixer": "^9.8.8",
|
||||
"express": "^4.17.1",
|
||||
"postcss": "^7.0.39",
|
||||
"tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.2.17"
|
||||
"@vitejs/plugin-react": "^1.3.1",
|
||||
"autoprefixer": "^10.4.4",
|
||||
"express": "^4.17.3",
|
||||
"postcss": "^8.4.12",
|
||||
"typescript": "^4.6.3",
|
||||
"vite": "^2.9.5"
|
||||
}
|
||||
}
|
||||
|
||||
6
examples/react-apollo-crm/postcss.config.js
Normal file
6
examples/react-apollo-crm/postcss.config.js
Normal file
@@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {}
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Web site created using create-react-app"
|
||||
/>
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,6 +0,0 @@
|
||||
import React from 'react'
|
||||
import App from './App'
|
||||
|
||||
test('single noop test', () => {
|
||||
expect(true).toBeTruthy()
|
||||
})
|
||||
@@ -2,7 +2,7 @@ import './App.css'
|
||||
import { NhostReactProvider } from '@nhost/react'
|
||||
import { NhostApolloProvider } from '@nhost/react-apollo'
|
||||
import { nhost } from './utils/nhost'
|
||||
import { Route, Routes } from 'react-router'
|
||||
import { Route, Routes } from 'react-router-dom'
|
||||
import { Layout } from './components/ui/Layout'
|
||||
import { Customers } from './components/Customers'
|
||||
import { Dashboard } from './components/Dashboard'
|
||||
|
||||
@@ -3,91 +3,85 @@ import { Dialog, Transition } from '@headlessui/react'
|
||||
import { nhost } from '../utils/nhost'
|
||||
|
||||
export function ChangePasswordModal() {
|
||||
const [open, setOpen] = useState(true)
|
||||
const [newPassword, setNewPassword] = useState('')
|
||||
const [open, setOpen] = useState(true)
|
||||
const [newPassword, setNewPassword] = useState('')
|
||||
|
||||
const handleSubmit = async (e: React.SyntheticEvent<HTMLFormElement>) => {
|
||||
e.preventDefault()
|
||||
const handleSubmit = async (e: React.SyntheticEvent<HTMLFormElement>) => {
|
||||
e.preventDefault()
|
||||
|
||||
const { error } = await nhost.auth.changePassword({ newPassword })
|
||||
const { error } = await nhost.auth.changePassword({ newPassword })
|
||||
|
||||
if (error) {
|
||||
return alert(error.message)
|
||||
}
|
||||
if (error) {
|
||||
return alert(error.message)
|
||||
}
|
||||
|
||||
setOpen(false)
|
||||
}
|
||||
setOpen(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<Transition.Root show={open} as={Fragment}>
|
||||
<Dialog as="div" className="fixed z-10 inset-0 overflow-y-auto" onClose={setOpen}>
|
||||
<div className="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
|
||||
<Transition.Child
|
||||
as={Fragment}
|
||||
enter="ease-out duration-300"
|
||||
enterFrom="opacity-0"
|
||||
enterTo="opacity-100"
|
||||
leave="ease-in duration-200"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<Dialog.Overlay className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" />
|
||||
</Transition.Child>
|
||||
return (
|
||||
<Transition.Root show={open} as={Fragment}>
|
||||
<Dialog as="div" className="fixed inset-0 z-10 overflow-y-auto" onClose={setOpen}>
|
||||
<div className="flex items-end justify-center min-h-screen px-4 pt-4 pb-20 text-center sm:block sm:p-0">
|
||||
<Transition.Child
|
||||
as={Fragment}
|
||||
enter="ease-out duration-300"
|
||||
enterFrom="opacity-0"
|
||||
enterTo="opacity-100"
|
||||
leave="ease-in duration-200"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<Dialog.Overlay className="fixed inset-0 transition-opacity bg-gray-500 bg-opacity-75" />
|
||||
</Transition.Child>
|
||||
|
||||
{/* This element is to trick the browser into centering the modal contents. */}
|
||||
<span
|
||||
className="hidden sm:inline-block sm:align-middle sm:h-screen"
|
||||
aria-hidden="true"
|
||||
>
|
||||
​
|
||||
</span>
|
||||
<Transition.Child
|
||||
as={Fragment}
|
||||
enter="ease-out duration-300"
|
||||
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||
enterTo="opacity-100 translate-y-0 sm:scale-100"
|
||||
leave="ease-in duration-200"
|
||||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||
>
|
||||
<div className="inline-block align-bottom bg-white rounded-lg px-4 pt-5 pb-4 text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-sm sm:w-full sm:p-6">
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div>
|
||||
<div className="mt-3 text-center sm:mt-5">
|
||||
<Dialog.Title
|
||||
as="h3"
|
||||
className="text-lg leading-6 font-medium text-gray-900"
|
||||
>
|
||||
Change Password
|
||||
</Dialog.Title>
|
||||
<div className="mt-2">
|
||||
<input
|
||||
id="password"
|
||||
name="password"
|
||||
type="password"
|
||||
autoComplete="current-password"
|
||||
required
|
||||
className="block w-full px-3 py-2 placeholder-gray-400 border border-gray-300 rounded-md shadow-sm appearance-none focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm"
|
||||
tabIndex={2}
|
||||
value={newPassword}
|
||||
onChange={(e) => setNewPassword(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-5 sm:mt-6">
|
||||
<button
|
||||
type="submit"
|
||||
className="inline-flex justify-center w-full rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:text-sm"
|
||||
>
|
||||
Set new password
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
{/* This element is to trick the browser into centering the modal contents. */}
|
||||
<span className="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">
|
||||
​
|
||||
</span>
|
||||
<Transition.Child
|
||||
as={Fragment}
|
||||
enter="ease-out duration-300"
|
||||
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||
enterTo="opacity-100 translate-y-0 sm:scale-100"
|
||||
leave="ease-in duration-200"
|
||||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||
>
|
||||
<div className="inline-block px-4 pt-5 pb-4 overflow-hidden text-left align-bottom transition-all transform bg-white rounded-lg shadow-xl sm:my-8 sm:align-middle sm:max-w-sm sm:w-full sm:p-6">
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div>
|
||||
<div className="mt-3 text-center sm:mt-5">
|
||||
<Dialog.Title as="h3" className="text-lg font-medium leading-6 text-gray-900">
|
||||
Change Password
|
||||
</Dialog.Title>
|
||||
<div className="mt-2">
|
||||
<input
|
||||
id="password"
|
||||
name="password"
|
||||
type="password"
|
||||
autoComplete="current-password"
|
||||
required
|
||||
className="block w-full px-3 py-2 placeholder-gray-400 border border-gray-300 rounded-md shadow-sm appearance-none focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm"
|
||||
tabIndex={2}
|
||||
value={newPassword}
|
||||
onChange={(e) => setNewPassword(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Transition.Child>
|
||||
</div>
|
||||
<div className="mt-5 sm:mt-6">
|
||||
<button
|
||||
type="submit"
|
||||
className="inline-flex justify-center w-full px-4 py-2 text-base font-medium text-white bg-blue-600 border border-transparent rounded-md shadow-sm hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:text-sm"
|
||||
>
|
||||
Set new password
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</Dialog>
|
||||
</Transition.Root>
|
||||
)
|
||||
</Transition.Child>
|
||||
</div>
|
||||
</Dialog>
|
||||
</Transition.Root>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,47 +1,47 @@
|
||||
import { Main } from "./ui/Main";
|
||||
import { Breadcrumbs } from "./ui/Breadcrumbs";
|
||||
import { HeaderSection } from "./ui/HeaderSection";
|
||||
import { PageHeader } from "./ui/PageHeader";
|
||||
import { Main } from './ui/Main'
|
||||
import { Breadcrumbs } from './ui/Breadcrumbs'
|
||||
import { HeaderSection } from './ui/HeaderSection'
|
||||
import { PageHeader } from './ui/PageHeader'
|
||||
|
||||
import { useParams } from "react-router";
|
||||
import { useCustomerQuery } from "../utils/__generated__/graphql";
|
||||
import { NavLink, Outlet } from "react-router-dom";
|
||||
import classNames from "classnames";
|
||||
import { CustomerActivities } from "./CustomerActivities";
|
||||
import { CustomerAddComment } from "./CustomerAddComment";
|
||||
import { useParams } from 'react-router-dom'
|
||||
import { useCustomerQuery } from '../utils/__generated__/graphql'
|
||||
import { NavLink, Outlet } from 'react-router-dom'
|
||||
import classNames from 'classnames'
|
||||
import { CustomerActivities } from './CustomerActivities'
|
||||
import { CustomerAddComment } from './CustomerAddComment'
|
||||
|
||||
const tabs = [
|
||||
{ name: "Overview", href: "" },
|
||||
{ name: "Orders", href: "orders" },
|
||||
{ name: "Files", href: "files" },
|
||||
];
|
||||
{ name: 'Overview', href: '' },
|
||||
{ name: 'Orders', href: 'orders' },
|
||||
{ name: 'Files', href: 'files' }
|
||||
]
|
||||
|
||||
export function Customer() {
|
||||
const { customerId } = useParams();
|
||||
const { customerId } = useParams()
|
||||
|
||||
const { data, loading } = useCustomerQuery({
|
||||
variables: {
|
||||
customerId,
|
||||
},
|
||||
});
|
||||
customerId
|
||||
}
|
||||
})
|
||||
|
||||
if (loading) {
|
||||
return <div>Loading..</div>;
|
||||
return <div>Loading..</div>
|
||||
}
|
||||
|
||||
if (!data || !data.customer) {
|
||||
return <div>No customer..</div>;
|
||||
return <div>No customer..</div>
|
||||
}
|
||||
|
||||
const { customer } = data;
|
||||
const { customer } = data
|
||||
|
||||
return (
|
||||
<Main>
|
||||
<Breadcrumbs
|
||||
backLink={""}
|
||||
backLink={''}
|
||||
breadcrumbs={[
|
||||
{ link: "/customers", text: "Customers" },
|
||||
{ link: `customers/${customerId}`, text: customer.name },
|
||||
{ link: '/customers', text: 'Customers' },
|
||||
{ link: `customers/${customerId}`, text: customer.name }
|
||||
]}
|
||||
/>
|
||||
<HeaderSection>
|
||||
@@ -57,7 +57,7 @@ export function Customer() {
|
||||
id="current-tab"
|
||||
name="current-tab"
|
||||
className="block w-full py-2 pl-3 pr-10 text-base border-gray-300 rounded-md focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
||||
defaultValue={"ok"}
|
||||
defaultValue={'ok'}
|
||||
>
|
||||
<option>1</option>
|
||||
<option>2</option>
|
||||
@@ -71,10 +71,10 @@ export function Customer() {
|
||||
className={({ isActive }) => {
|
||||
return classNames(
|
||||
isActive
|
||||
? "border-blue-500 text-blue-600"
|
||||
: "border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300",
|
||||
"whitespace-nowrap pb-4 px-1 border-b-2 font-medium text-sm"
|
||||
);
|
||||
? 'border-blue-500 text-blue-600'
|
||||
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300',
|
||||
'whitespace-nowrap pb-4 px-1 border-b-2 font-medium text-sm'
|
||||
)
|
||||
}}
|
||||
>
|
||||
{tab.name}
|
||||
@@ -95,5 +95,5 @@ export function Customer() {
|
||||
<CustomerAddComment />
|
||||
</div>
|
||||
</Main>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
import { ChatAltIcon } from "@heroicons/react/solid";
|
||||
import { useGetCustomerCommentsSubscription } from "../utils/__generated__/graphql";
|
||||
import { useParams } from "react-router";
|
||||
import { nhost } from "../utils/nhost";
|
||||
import { PhotographIcon } from "@heroicons/react/outline";
|
||||
import prettyBytes from "pretty-bytes";
|
||||
import { formatDistanceToNow, parseISO } from "date-fns";
|
||||
import { ChatAltIcon } from '@heroicons/react/solid'
|
||||
import { useGetCustomerCommentsSubscription } from '../utils/__generated__/graphql'
|
||||
import { useParams } from 'react-router-dom'
|
||||
import { nhost } from '../utils/nhost'
|
||||
import { PhotographIcon } from '@heroicons/react/outline'
|
||||
import prettyBytes from 'pretty-bytes'
|
||||
import { formatDistanceToNow, parseISO } from 'date-fns'
|
||||
|
||||
export function CustomerActivities() {
|
||||
const { customerId } = useParams();
|
||||
const { customerId } = useParams<{ customerId: string }>()
|
||||
|
||||
const { data, loading } = useGetCustomerCommentsSubscription({
|
||||
variables: {
|
||||
where: {
|
||||
customerId: {
|
||||
_eq: customerId,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
_eq: customerId
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
console.log({ data });
|
||||
console.log({ data })
|
||||
|
||||
if (loading) {
|
||||
return <div>Loading...</div>;
|
||||
return <div>Loading...</div>
|
||||
}
|
||||
|
||||
if (!data || !data.customerComments) {
|
||||
return <div>no comments</div>;
|
||||
return <div>no comments</div>
|
||||
}
|
||||
|
||||
const { customerComments } = data;
|
||||
const { customerComments } = data
|
||||
|
||||
return (
|
||||
<div className="flow-root">
|
||||
@@ -54,10 +54,7 @@ export function CustomerActivities() {
|
||||
/>
|
||||
|
||||
<span className="absolute -bottom-0.5 -right-1 bg-white rounded-tl px-0.5 py-px">
|
||||
<ChatAltIcon
|
||||
className="w-5 h-5 text-gray-400"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<ChatAltIcon className="w-5 h-5 text-gray-400" aria-hidden="true" />
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
@@ -69,7 +66,7 @@ export function CustomerActivities() {
|
||||
</div>
|
||||
<p className="mt-0.5 text-sm text-gray-500">
|
||||
{formatDistanceToNow(parseISO(comment.createdAt), {
|
||||
addSuffix: true,
|
||||
addSuffix: true
|
||||
})}
|
||||
</p>
|
||||
</div>
|
||||
@@ -80,24 +77,22 @@ export function CustomerActivities() {
|
||||
<div
|
||||
className="flex items-center mt-3 text-sm text-gray-700 cursor-pointer"
|
||||
onClick={async () => {
|
||||
const { presignedUrl, error } =
|
||||
await nhost.storage.getPresignedUrl({
|
||||
fileId: comment.file!.id,
|
||||
});
|
||||
const { presignedUrl, error } = await nhost.storage.getPresignedUrl({
|
||||
fileId: comment.file!.id
|
||||
})
|
||||
|
||||
if (error) {
|
||||
return alert(error.message);
|
||||
return alert(error.message)
|
||||
}
|
||||
|
||||
window.open(presignedUrl?.url, "_blank");
|
||||
window.open(presignedUrl?.url, '_blank')
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
<PhotographIcon className="w-5 mr-1 text-gray-500" />
|
||||
</div>
|
||||
<div>
|
||||
{comment.file.name},{" "}
|
||||
{prettyBytes(comment.file.size as number)}
|
||||
{comment.file.name}, {prettyBytes(comment.file.size as number)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -106,9 +101,9 @@ export function CustomerActivities() {
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
);
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,32 +1,31 @@
|
||||
import { useState } from "react";
|
||||
import { useParams } from "react-router";
|
||||
import { nhost } from "../utils/nhost";
|
||||
import { useInsertCustomerCommentMutation } from "../utils/__generated__/graphql";
|
||||
import { useState } from 'react'
|
||||
import { useParams } from 'react-router-dom'
|
||||
import { nhost } from '../utils/nhost'
|
||||
import { useInsertCustomerCommentMutation } from '../utils/__generated__/graphql'
|
||||
|
||||
export function CustomerAddComment() {
|
||||
const [text, setText] = useState("");
|
||||
const [file, setFile] = useState<null | File>(null);
|
||||
const [text, setText] = useState('')
|
||||
const [file, setFile] = useState<null | File>(null)
|
||||
|
||||
const { customerId } = useParams();
|
||||
const [insertCustomerComment, { loading }] =
|
||||
useInsertCustomerCommentMutation();
|
||||
const { customerId } = useParams<{ customerId: string }>()
|
||||
const [insertCustomerComment, { loading }] = useInsertCustomerCommentMutation()
|
||||
|
||||
const handleSubmit = async (e: React.SyntheticEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
e.preventDefault()
|
||||
|
||||
let fileMetadata;
|
||||
let fileMetadata
|
||||
if (file) {
|
||||
const fileUploadRes = await nhost.storage.upload({
|
||||
file,
|
||||
bucketId: "customerComments",
|
||||
});
|
||||
bucketId: 'customerComments'
|
||||
})
|
||||
|
||||
if (fileUploadRes.error) {
|
||||
alert(`error: ${fileUploadRes.error}`);
|
||||
return;
|
||||
alert(`error: ${fileUploadRes.error}`)
|
||||
return
|
||||
}
|
||||
|
||||
fileMetadata = fileUploadRes.fileMetadata;
|
||||
fileMetadata = fileUploadRes.fileMetadata
|
||||
}
|
||||
|
||||
await insertCustomerComment({
|
||||
@@ -34,21 +33,18 @@ export function CustomerAddComment() {
|
||||
customerComment: {
|
||||
text,
|
||||
customerId,
|
||||
fileId: fileMetadata ? fileMetadata.id : null,
|
||||
},
|
||||
},
|
||||
});
|
||||
fileId: fileMetadata ? fileMetadata.id : null
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
setText("");
|
||||
};
|
||||
setText('')
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="max-w-lg mx-auto">
|
||||
<form onSubmit={handleSubmit}>
|
||||
<label
|
||||
htmlFor="email"
|
||||
className="block text-sm font-medium text-gray-700"
|
||||
>
|
||||
<label htmlFor="email" className="block text-sm font-medium text-gray-700">
|
||||
Comment
|
||||
</label>
|
||||
<div className="mt-1">
|
||||
@@ -57,7 +53,7 @@ export function CustomerAddComment() {
|
||||
name="about"
|
||||
rows={3}
|
||||
className="block w-full max-w-lg border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm"
|
||||
defaultValue={""}
|
||||
defaultValue={''}
|
||||
value={text}
|
||||
onChange={(e) => setText(e.target.value)}
|
||||
/>
|
||||
@@ -94,7 +90,7 @@ export function CustomerAddComment() {
|
||||
className="sr-only"
|
||||
onChange={(e) => {
|
||||
if (e.target.files && e.target.files.length > 0) {
|
||||
setFile(e.target.files[0]);
|
||||
setFile(e.target.files[0])
|
||||
}
|
||||
}}
|
||||
/>
|
||||
@@ -104,9 +100,7 @@ export function CustomerAddComment() {
|
||||
{file ? (
|
||||
<div>{file.name}</div>
|
||||
) : (
|
||||
<p className="text-xs text-gray-500">
|
||||
PNG, JPG, GIF up to 10MB
|
||||
</p>
|
||||
<p className="text-xs text-gray-500">PNG, JPG, GIF up to 10MB</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -124,5 +118,5 @@ export function CustomerAddComment() {
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
import { Main } from "./ui/Main";
|
||||
import { Breadcrumbs } from "./ui/Breadcrumbs";
|
||||
import { HeaderSection } from "./ui/HeaderSection";
|
||||
import { PageHeader } from "./ui/PageHeader";
|
||||
import { Link } from "react-router-dom";
|
||||
import { useGetCustomersSubscription } from "../utils/__generated__/graphql";
|
||||
import { ChevronLeftIcon, ChevronRightIcon } from "@heroicons/react/solid";
|
||||
import { Main } from './ui/Main'
|
||||
import { Breadcrumbs } from './ui/Breadcrumbs'
|
||||
import { HeaderSection } from './ui/HeaderSection'
|
||||
import { PageHeader } from './ui/PageHeader'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { useGetCustomersSubscription } from '../utils/__generated__/graphql'
|
||||
import { ChevronLeftIcon, ChevronRightIcon } from '@heroicons/react/solid'
|
||||
|
||||
export function Customers() {
|
||||
return (
|
||||
<Main>
|
||||
<Breadcrumbs
|
||||
backLink={""}
|
||||
breadcrumbs={[{ link: "/customers", text: "Customers" }]}
|
||||
/>
|
||||
<Breadcrumbs backLink={''} breadcrumbs={[{ link: '/customers', text: 'Customers' }]} />
|
||||
<HeaderSection>
|
||||
<PageHeader>Customers</PageHeader>
|
||||
<div className="flex flex-shrink-0 mt-4 md:mt-0 md:ml-4">
|
||||
@@ -31,11 +28,11 @@ export function Customers() {
|
||||
<CustomersList />
|
||||
</div>
|
||||
</Main>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
function CustomersList() {
|
||||
const { data } = useGetCustomersSubscription();
|
||||
const { data } = useGetCustomersSubscription()
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -57,17 +54,14 @@ function CustomersList() {
|
||||
<tbody>
|
||||
{data?.customers.map((customer, i) => {
|
||||
return (
|
||||
<tr
|
||||
key={customer.id}
|
||||
className={i % 2 === 0 ? "bg-white" : "bg-gray-50"}
|
||||
>
|
||||
<tr key={customer.id} className={i % 2 === 0 ? 'bg-white' : 'bg-gray-50'}>
|
||||
<td className="text-sm font-medium text-gray-900 whitespace-nowrap">
|
||||
<Link to={customer.id} className="block px-6 py-4">
|
||||
{customer.name}
|
||||
</Link>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
)
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -88,9 +82,9 @@ function CustomersList() {
|
||||
<div className="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between">
|
||||
<div>
|
||||
<p className="text-sm text-gray-700">
|
||||
Showing <span className="font-medium">1</span> to{" "}
|
||||
<span className="font-medium">10</span> of{" "}
|
||||
<span className="font-medium">97</span> results
|
||||
Showing <span className="font-medium">1</span> to{' '}
|
||||
<span className="font-medium">10</span> of <span className="font-medium">97</span>{' '}
|
||||
results
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
@@ -136,5 +130,5 @@ function CustomersList() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Main } from "./ui/Main";
|
||||
import { Main } from './ui/Main'
|
||||
|
||||
export function Dashboard() {
|
||||
return <Main>Dashboard</Main>;
|
||||
return <Main>Dashboard</Main>
|
||||
}
|
||||
|
||||
@@ -1,67 +1,64 @@
|
||||
import { useState } from "react";
|
||||
import { Main } from "./ui/Main";
|
||||
import { Breadcrumbs } from "./ui/Breadcrumbs";
|
||||
import { HeaderSection } from "./ui/HeaderSection";
|
||||
import { PageHeader } from "./ui/PageHeader";
|
||||
import {
|
||||
useGetCompanyWhereQuery,
|
||||
useInsertCustomerMutation,
|
||||
} from "../utils/__generated__/graphql";
|
||||
import { nhost } from "../utils/nhost";
|
||||
import { useNavigate } from "react-router";
|
||||
import { useState } from 'react'
|
||||
import { Main } from './ui/Main'
|
||||
import { Breadcrumbs } from './ui/Breadcrumbs'
|
||||
import { HeaderSection } from './ui/HeaderSection'
|
||||
import { PageHeader } from './ui/PageHeader'
|
||||
import { useGetCompanyWhereQuery, useInsertCustomerMutation } from '../utils/__generated__/graphql'
|
||||
import { nhost } from '../utils/nhost'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
|
||||
export function NewCustomer() {
|
||||
const [name, setName] = useState("");
|
||||
const [email, setEmail] = useState("");
|
||||
const [addressLine1, setAddressLine1] = useState("");
|
||||
const [name, setName] = useState('')
|
||||
const [email, setEmail] = useState('')
|
||||
const [addressLine1, setAddressLine1] = useState('')
|
||||
|
||||
const user = nhost.auth.getUser();
|
||||
let navigate = useNavigate();
|
||||
const user = nhost.auth.getUser()
|
||||
let navigate = useNavigate()
|
||||
|
||||
const { data } = useGetCompanyWhereQuery({
|
||||
variables: {
|
||||
where: {
|
||||
companyUsers: {
|
||||
userId: {
|
||||
_eq: user?.id,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
_eq: user?.id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const [insertCustomer, { loading }] = useInsertCustomerMutation();
|
||||
const [insertCustomer, { loading }] = useInsertCustomerMutation()
|
||||
|
||||
const handleSubmit = async (e: React.SyntheticEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
e.preventDefault()
|
||||
|
||||
console.log("handle submit");
|
||||
console.log('handle submit')
|
||||
|
||||
let res;
|
||||
let res
|
||||
try {
|
||||
res = await insertCustomer({
|
||||
variables: {
|
||||
customer: {
|
||||
name,
|
||||
addressLine1,
|
||||
companyId: data?.companies[0].id,
|
||||
},
|
||||
},
|
||||
});
|
||||
companyId: data?.companies[0].id
|
||||
}
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
return alert(`error: ${error}`);
|
||||
return alert(`error: ${error}`)
|
||||
}
|
||||
|
||||
navigate(`/customers/${res.data?.insertCustomer?.id}`);
|
||||
};
|
||||
navigate(`/customers/${res.data?.insertCustomer?.id}`)
|
||||
}
|
||||
|
||||
return (
|
||||
<Main>
|
||||
<Breadcrumbs
|
||||
backLink={""}
|
||||
backLink={''}
|
||||
breadcrumbs={[
|
||||
{ link: "/customers", text: "Customers" },
|
||||
{ link: "/new-customer", text: "New Customer" },
|
||||
{ link: '/customers', text: 'Customers' },
|
||||
{ link: '/new-customer', text: 'New Customer' }
|
||||
]}
|
||||
/>
|
||||
<HeaderSection>
|
||||
@@ -73,10 +70,7 @@ export function NewCustomer() {
|
||||
<div className="pt-12">
|
||||
<div className="grid grid-cols-1 mt-6 gap-y-6 gap-x-4 sm:grid-cols-6">
|
||||
<div className="sm:col-span-3">
|
||||
<label
|
||||
htmlFor="first-name"
|
||||
className="block text-sm font-medium text-gray-700"
|
||||
>
|
||||
<label htmlFor="first-name" className="block text-sm font-medium text-gray-700">
|
||||
Name
|
||||
</label>
|
||||
<div className="mt-1">
|
||||
@@ -93,10 +87,7 @@ export function NewCustomer() {
|
||||
</div>
|
||||
|
||||
<div className="sm:col-span-3">
|
||||
<label
|
||||
htmlFor="email"
|
||||
className="block text-sm font-medium text-gray-700"
|
||||
>
|
||||
<label htmlFor="email" className="block text-sm font-medium text-gray-700">
|
||||
Email address
|
||||
</label>
|
||||
<div className="mt-1">
|
||||
@@ -113,10 +104,7 @@ export function NewCustomer() {
|
||||
</div>
|
||||
|
||||
<div className="sm:col-span-6">
|
||||
<label
|
||||
htmlFor="street-address"
|
||||
className="block text-sm font-medium text-gray-700"
|
||||
>
|
||||
<label htmlFor="street-address" className="block text-sm font-medium text-gray-700">
|
||||
Street address
|
||||
</label>
|
||||
<div className="mt-1">
|
||||
@@ -147,5 +135,5 @@ export function NewCustomer() {
|
||||
</div>
|
||||
</form>
|
||||
</Main>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useNhostAuth } from '@nhost/react'
|
||||
import React from 'react'
|
||||
import { Navigate, useLocation } from 'react-router'
|
||||
import { Navigate, useLocation } from 'react-router-dom'
|
||||
|
||||
export function RequireAuth({ children }: { children: JSX.Element }) {
|
||||
const { isAuthenticated, isLoading } = useNhostAuth()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useNhostAuth } from '@nhost/react'
|
||||
import { useState } from 'react'
|
||||
import { useNavigate } from 'react-router'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { nhost } from '../utils/nhost'
|
||||
|
||||
export function ResetPassword() {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useNhostAuth } from '@nhost/react'
|
||||
import { useState } from 'react'
|
||||
import { useNavigate } from 'react-router'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { nhost } from '../utils/nhost'
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useNhostAuth } from '@nhost/react'
|
||||
import { useState } from 'react'
|
||||
import { useNavigate } from 'react-router'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { nhost } from '../utils/nhost'
|
||||
|
||||
@@ -93,7 +93,7 @@ export function SignUp() {
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div className="text-center py-4">
|
||||
<div className="py-4 text-center">
|
||||
Already have an account?{' '}
|
||||
<Link to="/sign-in" className="text-blue-600 hover:text-blue-500">
|
||||
Sign In
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import { ChevronLeftIcon, ChevronRightIcon } from "@heroicons/react/solid";
|
||||
import classNames from "classnames";
|
||||
import { Link } from "react-router-dom";
|
||||
import { ChevronLeftIcon, ChevronRightIcon } from '@heroicons/react/solid'
|
||||
import classNames from 'classnames'
|
||||
import { Link } from 'react-router-dom'
|
||||
|
||||
type BreadcrumbsProps = {
|
||||
backLink: string;
|
||||
breadcrumbs: Breadcrumb[];
|
||||
};
|
||||
backLink: string
|
||||
breadcrumbs: Breadcrumb[]
|
||||
}
|
||||
|
||||
type Breadcrumb = {
|
||||
link: string;
|
||||
text: string;
|
||||
};
|
||||
link: string
|
||||
text: string
|
||||
}
|
||||
|
||||
export function Breadcrumbs(props: BreadcrumbsProps) {
|
||||
const { backLink, breadcrumbs } = props;
|
||||
const { backLink, breadcrumbs } = props
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -32,13 +32,10 @@ export function Breadcrumbs(props: BreadcrumbsProps) {
|
||||
<nav className="hidden sm:flex" aria-label="Breadcrumb">
|
||||
<ol className="flex items-center space-x-4">
|
||||
{breadcrumbs.map((breadcrumb, i) => {
|
||||
const isFirstItem = i === 0;
|
||||
const classes = classNames(
|
||||
"text-sm font-medium text-gray-500 hover:text-gray-700",
|
||||
{
|
||||
"ml-4": !isFirstItem,
|
||||
}
|
||||
);
|
||||
const isFirstItem = i === 0
|
||||
const classes = classNames('text-sm font-medium text-gray-500 hover:text-gray-700', {
|
||||
'ml-4': !isFirstItem
|
||||
})
|
||||
|
||||
return (
|
||||
<li key={i}>
|
||||
@@ -54,10 +51,10 @@ export function Breadcrumbs(props: BreadcrumbsProps) {
|
||||
</Link>
|
||||
</div>
|
||||
</li>
|
||||
);
|
||||
)
|
||||
})}
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
import React from "react";
|
||||
import React from 'react'
|
||||
|
||||
export function HeaderSection({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<div className="mt-2 md:flex md:items-center md:justify-between">
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
return <div className="mt-2 md:flex md:items-center md:justify-between">{children}</div>
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import React from "react";
|
||||
import React from 'react'
|
||||
|
||||
export function Main({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">{children}</div>
|
||||
);
|
||||
return <div className="px-4 mx-auto max-w-7xl sm:px-6 lg:px-8">{children}</div>
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from "react";
|
||||
import React from 'react'
|
||||
|
||||
export function PageHeader({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
@@ -7,5 +7,5 @@ export function PageHeader({ children }: { children: React.ReactNode }) {
|
||||
{children}
|
||||
</h2>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
10
examples/react-apollo-crm/src/env.d.ts
vendored
Normal file
10
examples/react-apollo-crm/src/env.d.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
interface ImportMetaEnv {
|
||||
readonly VITE_NHOST_URL: string
|
||||
// more env variables...
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
mutation insertCustomerComment(
|
||||
$customerComment: customerComments_insert_input!
|
||||
) {
|
||||
mutation insertCustomerComment($customerComment: customerComments_insert_input!) {
|
||||
insertCustomerComment(object: $customerComment) {
|
||||
id
|
||||
}
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
|
||||
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
|
||||
sans-serif;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu',
|
||||
'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
|
||||
monospace;
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
|
||||
}
|
||||
|
||||
@tailwind base;
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import "./index.css";
|
||||
import App from "./App";
|
||||
import reportWebVitals from "./reportWebVitals";
|
||||
import { BrowserRouter } from "react-router-dom";
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import './index.css'
|
||||
import App from './App'
|
||||
import { BrowserRouter } from 'react-router-dom'
|
||||
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
@@ -11,10 +10,5 @@ ReactDOM.render(
|
||||
<App />
|
||||
</BrowserRouter>
|
||||
</React.StrictMode>,
|
||||
document.getElementById("root")
|
||||
);
|
||||
|
||||
// If you want to start measuring performance in your app, pass a function
|
||||
// to log results (for example: reportWebVitals(console.log))
|
||||
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
|
||||
reportWebVitals();
|
||||
document.getElementById('root')
|
||||
)
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
/// <reference types="react-scripts" />
|
||||
@@ -1,15 +0,0 @@
|
||||
import { ReportHandler } from 'web-vitals';
|
||||
|
||||
const reportWebVitals = (onPerfEntry?: ReportHandler) => {
|
||||
if (onPerfEntry && onPerfEntry instanceof Function) {
|
||||
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
||||
getCLS(onPerfEntry);
|
||||
getFID(onPerfEntry);
|
||||
getFCP(onPerfEntry);
|
||||
getLCP(onPerfEntry);
|
||||
getTTFB(onPerfEntry);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default reportWebVitals;
|
||||
@@ -2,4 +2,4 @@
|
||||
// allows you to do things like:
|
||||
// expect(element).toHaveTextContent(/react/i)
|
||||
// learn more: https://github.com/testing-library/jest-dom
|
||||
import '@testing-library/jest-dom';
|
||||
import '@testing-library/jest-dom'
|
||||
|
||||
5522
examples/react-apollo-crm/src/utils/__generated__/graphql.ts
generated
5522
examples/react-apollo-crm/src/utils/__generated__/graphql.ts
generated
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
import { NhostClient } from '@nhost/react'
|
||||
|
||||
const nhost = new NhostClient({
|
||||
backendUrl: process.env.REACT_APP_BACKEND_URL!
|
||||
backendUrl: import.meta.env.VITE_NHOST_URL || 'http://localhost:1337'
|
||||
})
|
||||
|
||||
export { nhost }
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
module.exports = {
|
||||
purge: ["./src/**/*.{js,jsx,ts,tsx}", "./public/index.html"],
|
||||
darkMode: false, // or 'media' or 'class'
|
||||
content: ['./src/**/*.{js,jsx,ts,tsx}', './index.html'],
|
||||
darkMode: 'media',
|
||||
theme: {
|
||||
extend: {},
|
||||
extend: {}
|
||||
},
|
||||
variants: {
|
||||
extend: {},
|
||||
extend: {}
|
||||
},
|
||||
plugins: [require("@tailwindcss/forms")],
|
||||
};
|
||||
plugins: [require('@tailwindcss/forms')]
|
||||
}
|
||||
|
||||
@@ -1,20 +1,9 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"target": "es6",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx"
|
||||
"outDir": "dist",
|
||||
"composite": true,
|
||||
"module": "esnext"
|
||||
},
|
||||
"include": ["src"]
|
||||
"include": ["src/**/*", "types/**/*", "../../types/**/*", "tests/**/*"]
|
||||
}
|
||||
|
||||
9
examples/react-apollo-crm/vite.config.js
Normal file
9
examples/react-apollo-crm/vite.config.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import tsconfigPaths from 'vite-tsconfig-paths'
|
||||
|
||||
import react from '@vitejs/plugin-react'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [tsconfigPaths(), react()]
|
||||
})
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,11 +1,29 @@
|
||||
# React-Apollo example
|
||||
|
||||
Once in the example's directory, run the two following commands in parallel:
|
||||
## Get started
|
||||
|
||||
1. Clone the repository
|
||||
|
||||
```sh
|
||||
# Start the Nhost CLI in the background
|
||||
nhost -d
|
||||
|
||||
# Start this project
|
||||
yarn run dev
|
||||
git clone https://github.com/nhost/nhost
|
||||
cd nhost
|
||||
```
|
||||
|
||||
2. Install dependencies
|
||||
|
||||
```sh
|
||||
cd examples/react-apollo
|
||||
pnpm install
|
||||
```
|
||||
|
||||
3. Terminal 1: Start Nhost
|
||||
|
||||
```sh
|
||||
nhost dev
|
||||
```
|
||||
|
||||
4. Terminal 2: Start React App
|
||||
|
||||
```sh
|
||||
pnpm run dev
|
||||
```
|
||||
|
||||
@@ -7,7 +7,7 @@ services:
|
||||
environment:
|
||||
hasura_graphql_enable_remote_schema_permissions: false
|
||||
auth:
|
||||
version: 0.4.2
|
||||
version: 0.6.3
|
||||
auth:
|
||||
access_control:
|
||||
email:
|
||||
@@ -15,8 +15,7 @@ auth:
|
||||
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
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Confirm Email Change</h2>
|
||||
<p>Use this link to confirm changing email:</p>
|
||||
<p>
|
||||
<a href="${link}">
|
||||
Change email
|
||||
</a>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
<body>
|
||||
<h2>Confirm Email Change</h2>
|
||||
<p>Use this link to confirm changing email:</p>
|
||||
<p>
|
||||
<a href="${link}"> Change email </a>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Verify Email</h2>
|
||||
<p>Use this link to verify your email:</p>
|
||||
<p>
|
||||
<a href="${link}">
|
||||
Verify Email
|
||||
</a>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
<body>
|
||||
<h2>Verify Email</h2>
|
||||
<p>Use this link to verify your email:</p>
|
||||
<p>
|
||||
<a href="${link}"> Verify Email </a>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Reset Password</h2>
|
||||
<p>Use this link to reset your password:</p>
|
||||
<p>
|
||||
<a href="${link}">
|
||||
Reset password
|
||||
</a>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
<body>
|
||||
<h2>Reset Password</h2>
|
||||
<p>Use this link to reset your password:</p>
|
||||
<p>
|
||||
<a href="${link}"> Reset password </a>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Magic Link</h2>
|
||||
<p>Use this link to securely sign in:</p>
|
||||
<p>
|
||||
<a href="${link}">
|
||||
Sign In
|
||||
</a>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
<body>
|
||||
<h2>Magic Link</h2>
|
||||
<p>Use this link to securely sign in:</p>
|
||||
<p>
|
||||
<a href="${link}"> Sign In </a>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Confirmer changement de courriel</h2>
|
||||
<p>Utilisez ce lien pour confirmer le changement de courriel:</p>
|
||||
<p>
|
||||
<a href="${link}">
|
||||
Changer courriel
|
||||
</a>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
<body>
|
||||
<h2>Confirmer changement de courriel</h2>
|
||||
<p>Utilisez ce lien pour confirmer le changement de courriel:</p>
|
||||
<p>
|
||||
<a href="${link}"> Changer courriel </a>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Vérifiez votre courriel</h2>
|
||||
<p>Utilisez ce lien pour vérifier votre courriel:</p>
|
||||
<p>
|
||||
<a href="${link}">
|
||||
Vérifier courriel
|
||||
</a>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
<body>
|
||||
<h2>Vérifiez votre courriel</h2>
|
||||
<p>Utilisez ce lien pour vérifier votre courriel:</p>
|
||||
<p>
|
||||
<a href="${link}"> Vérifier courriel </a>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Réinitializer votre mot de passe</h2>
|
||||
<p>Utilisez ce lien pour réinitializer votre mot de passe:</p>
|
||||
<p>
|
||||
<a href="${link}">
|
||||
Réinitializer mot de passe
|
||||
</a>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
<body>
|
||||
<h2>Réinitializer votre mot de passe</h2>
|
||||
<p>Utilisez ce lien pour réinitializer votre mot de passe:</p>
|
||||
<p>
|
||||
<a href="${link}"> Réinitializer mot de passe </a>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Lien magique</h2>
|
||||
<p>Utilisez ce lien pour vous connecter de façon sécuritaire:</p>
|
||||
<p>
|
||||
<a href="${link}">
|
||||
Connexion
|
||||
</a>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
<body>
|
||||
<h2>Lien magique</h2>
|
||||
<p>Utilisez ce lien pour vous connecter de façon sécuritaire:</p>
|
||||
<p>
|
||||
<a href="${link}"> Connexion </a>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -11,4 +11,4 @@
|
||||
max_connections: 50
|
||||
retries: 20
|
||||
use_prepared_statements: true
|
||||
tables: "!include default/tables/tables.yaml"
|
||||
tables: '!include default/tables/tables.yaml'
|
||||
|
||||
@@ -15,10 +15,10 @@ configuration:
|
||||
update: updateAuthProviders
|
||||
update_by_pk: updateAuthProvider
|
||||
array_relationships:
|
||||
- name: userProviders
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: provider_id
|
||||
table:
|
||||
name: user_providers
|
||||
schema: auth
|
||||
- name: userProviders
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: provider_id
|
||||
table:
|
||||
name: user_providers
|
||||
schema: auth
|
||||
|
||||
@@ -19,6 +19,6 @@ configuration:
|
||||
update: updateAuthRefreshTokens
|
||||
update_by_pk: updateAuthRefreshToken
|
||||
object_relationships:
|
||||
- name: user
|
||||
using:
|
||||
foreign_key_constraint_on: user_id
|
||||
- name: user
|
||||
using:
|
||||
foreign_key_constraint_on: user_id
|
||||
|
||||
@@ -15,17 +15,17 @@ configuration:
|
||||
update: updateAuthRoles
|
||||
update_by_pk: updateAuthRole
|
||||
array_relationships:
|
||||
- name: userRoles
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: role
|
||||
table:
|
||||
name: user_roles
|
||||
schema: auth
|
||||
- name: usersByDefaultRole
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: default_role
|
||||
table:
|
||||
name: users
|
||||
schema: auth
|
||||
- name: userRoles
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: role
|
||||
table:
|
||||
name: user_roles
|
||||
schema: auth
|
||||
- name: usersByDefaultRole
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: default_role
|
||||
table:
|
||||
name: users
|
||||
schema: auth
|
||||
|
||||
@@ -22,9 +22,9 @@ configuration:
|
||||
update: updateAuthUserProviders
|
||||
update_by_pk: updateAuthUserProvider
|
||||
object_relationships:
|
||||
- name: provider
|
||||
using:
|
||||
foreign_key_constraint_on: provider_id
|
||||
- name: user
|
||||
using:
|
||||
foreign_key_constraint_on: user_id
|
||||
- name: provider
|
||||
using:
|
||||
foreign_key_constraint_on: provider_id
|
||||
- name: user
|
||||
using:
|
||||
foreign_key_constraint_on: user_id
|
||||
|
||||
@@ -17,9 +17,9 @@ configuration:
|
||||
update: updateAuthUserRoles
|
||||
update_by_pk: updateAuthUserRole
|
||||
object_relationships:
|
||||
- name: roleByRole
|
||||
using:
|
||||
foreign_key_constraint_on: role
|
||||
- name: user
|
||||
using:
|
||||
foreign_key_constraint_on: user_id
|
||||
- name: roleByRole
|
||||
using:
|
||||
foreign_key_constraint_on: role
|
||||
- name: user
|
||||
using:
|
||||
foreign_key_constraint_on: user_id
|
||||
|
||||
@@ -33,28 +33,28 @@ configuration:
|
||||
update: updateUsers
|
||||
update_by_pk: updateUser
|
||||
object_relationships:
|
||||
- name: defaultRoleByRole
|
||||
using:
|
||||
foreign_key_constraint_on: default_role
|
||||
- name: defaultRoleByRole
|
||||
using:
|
||||
foreign_key_constraint_on: default_role
|
||||
array_relationships:
|
||||
- name: refreshTokens
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: user_id
|
||||
table:
|
||||
name: refresh_tokens
|
||||
schema: auth
|
||||
- name: roles
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: user_id
|
||||
table:
|
||||
name: user_roles
|
||||
schema: auth
|
||||
- name: userProviders
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: user_id
|
||||
table:
|
||||
name: user_providers
|
||||
schema: auth
|
||||
- name: refreshTokens
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: user_id
|
||||
table:
|
||||
name: refresh_tokens
|
||||
schema: auth
|
||||
- name: roles
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: user_id
|
||||
table:
|
||||
name: user_roles
|
||||
schema: auth
|
||||
- name: userProviders
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: user_id
|
||||
table:
|
||||
name: user_providers
|
||||
schema: auth
|
||||
|
||||
@@ -2,9 +2,9 @@ table:
|
||||
name: books
|
||||
schema: public
|
||||
select_permissions:
|
||||
- permission:
|
||||
columns:
|
||||
- id
|
||||
- title
|
||||
filter: {}
|
||||
role: user
|
||||
- permission:
|
||||
columns:
|
||||
- id
|
||||
- title
|
||||
filter: {}
|
||||
role: user
|
||||
|
||||
@@ -23,10 +23,10 @@ configuration:
|
||||
update: updateBuckets
|
||||
update_by_pk: updateBucket
|
||||
array_relationships:
|
||||
- name: files
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: bucket_id
|
||||
table:
|
||||
name: files
|
||||
schema: storage
|
||||
- name: files
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: bucket_id
|
||||
table:
|
||||
name: files
|
||||
schema: storage
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user