Compare commits
34 Commits
@nhost/rea
...
@nhost/rea
| 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 />
|
<hr />
|
||||||
</div>
|
</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
|
- Open-Source
|
||||||
- Developer Productivity
|
- Developer Productivity
|
||||||
@@ -234,6 +234,13 @@ Here are some ways of contributing to making Nhost better:
|
|||||||
<sub><b>Mustafa Hanif</b></sub>
|
<sub><b>Mustafa Hanif</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</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">
|
<td align="center">
|
||||||
<a href="https://github.com/Savinvadim1312">
|
<a href="https://github.com/Savinvadim1312">
|
||||||
<img src="https://avatars.githubusercontent.com/u/16936043?v=4" width="100;" alt="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 />
|
<br />
|
||||||
<sub><b>Amir Ahmic</b></sub>
|
<sub><b>Amir Ahmic</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td></tr>
|
||||||
|
<tr>
|
||||||
<td align="center">
|
<td align="center">
|
||||||
<a href="https://github.com/akd-io">
|
<a href="https://github.com/akd-io">
|
||||||
<img src="https://avatars.githubusercontent.com/u/30059155?v=4" width="100;" alt="akd-io"/>
|
<img src="https://avatars.githubusercontent.com/u/30059155?v=4" width="100;" alt="akd-io"/>
|
||||||
<br />
|
<br />
|
||||||
<sub><b>Anders Kjær Damgaard</b></sub>
|
<sub><b>Anders Kjær Damgaard</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td></tr>
|
</td>
|
||||||
<tr>
|
|
||||||
<td align="center">
|
<td align="center">
|
||||||
<a href="https://github.com/rustyb">
|
<a href="https://github.com/rustyb">
|
||||||
<img src="https://avatars.githubusercontent.com/u/53086?v=4" width="100;" alt="rustyb"/>
|
<img src="https://avatars.githubusercontent.com/u/53086?v=4" width="100;" alt="rustyb"/>
|
||||||
@@ -290,21 +297,14 @@ Here are some ways of contributing to making Nhost better:
|
|||||||
<br />
|
<br />
|
||||||
<sub><b>Hoang Do</b></sub>
|
<sub><b>Hoang Do</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td></tr>
|
||||||
|
<tr>
|
||||||
<td align="center">
|
<td align="center">
|
||||||
<a href="https://github.com/ghoshnirmalya">
|
<a href="https://github.com/ghoshnirmalya">
|
||||||
<img src="https://avatars.githubusercontent.com/u/6391763?v=4" width="100;" alt="ghoshnirmalya"/>
|
<img src="https://avatars.githubusercontent.com/u/6391763?v=4" width="100;" alt="ghoshnirmalya"/>
|
||||||
<br />
|
<br />
|
||||||
<sub><b>Nirmalya Ghosh</b></sub>
|
<sub><b>Nirmalya Ghosh</b></sub>
|
||||||
</a>
|
</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>
|
||||||
<td align="center">
|
<td align="center">
|
||||||
<a href="https://github.com/quentin-decre">
|
<a href="https://github.com/quentin-decre">
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
title: 'Set permissions'
|
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.
|
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:
|
auth:
|
||||||
access_control:
|
access_control:
|
||||||
email:
|
email:
|
||||||
allowed_email_domains: ""
|
allowed_email_domains: ''
|
||||||
allowed_emails: ""
|
allowed_emails: ''
|
||||||
blocked_email_domains: ""
|
blocked_email_domains: ''
|
||||||
blocked_emails: ""
|
blocked_emails: ''
|
||||||
url:
|
allowed_redirect_urls: ''
|
||||||
allowed_redirect_urls: ""
|
|
||||||
anonymous_users_enabled: false
|
anonymous_users_enabled: false
|
||||||
client_url: http://localhost:3000
|
client_url: http://localhost:3000
|
||||||
disable_new_users: false
|
disable_new_users: false
|
||||||
@@ -28,11 +27,11 @@ auth:
|
|||||||
passwordless:
|
passwordless:
|
||||||
enabled: false
|
enabled: false
|
||||||
signin_email_verified_required: true
|
signin_email_verified_required: true
|
||||||
template_fetch_url: ""
|
template_fetch_url: ''
|
||||||
gravatar:
|
gravatar:
|
||||||
default: ""
|
default: ''
|
||||||
enabled: true
|
enabled: true
|
||||||
rating: ""
|
rating: ''
|
||||||
locale:
|
locale:
|
||||||
allowed: en
|
allowed: en
|
||||||
default: en
|
default: en
|
||||||
@@ -41,65 +40,65 @@ auth:
|
|||||||
min_length: 3
|
min_length: 3
|
||||||
provider:
|
provider:
|
||||||
apple:
|
apple:
|
||||||
client_id: ""
|
client_id: ''
|
||||||
enabled: false
|
enabled: false
|
||||||
key_id: ""
|
key_id: ''
|
||||||
private_key: ""
|
private_key: ''
|
||||||
scope: name,email
|
scope: name,email
|
||||||
team_id: ""
|
team_id: ''
|
||||||
bitbucket:
|
bitbucket:
|
||||||
client_id: ""
|
client_id: ''
|
||||||
client_secret: ""
|
client_secret: ''
|
||||||
enabled: false
|
enabled: false
|
||||||
facebook:
|
facebook:
|
||||||
client_id: ""
|
client_id: ''
|
||||||
client_secret: ""
|
client_secret: ''
|
||||||
enabled: false
|
enabled: false
|
||||||
scope: email,photos,displayName
|
scope: email,photos,displayName
|
||||||
github:
|
github:
|
||||||
client_id: ""
|
client_id: ''
|
||||||
client_secret: ""
|
client_secret: ''
|
||||||
enabled: false
|
enabled: false
|
||||||
scope: user:email
|
scope: user:email
|
||||||
token_url: ""
|
token_url: ''
|
||||||
user_profile_url: ""
|
user_profile_url: ''
|
||||||
gitlab:
|
gitlab:
|
||||||
base_url: ""
|
base_url: ''
|
||||||
client_id: ""
|
client_id: ''
|
||||||
client_secret: ""
|
client_secret: ''
|
||||||
enabled: false
|
enabled: false
|
||||||
scope: read_user
|
scope: read_user
|
||||||
google:
|
google:
|
||||||
client_id: ""
|
client_id: ''
|
||||||
client_secret: ""
|
client_secret: ''
|
||||||
enabled: false
|
enabled: false
|
||||||
scope: email,profile
|
scope: email,profile
|
||||||
linkedin:
|
linkedin:
|
||||||
client_id: ""
|
client_id: ''
|
||||||
client_secret: ""
|
client_secret: ''
|
||||||
enabled: false
|
enabled: false
|
||||||
scope: r_emailaddress,r_liteprofile
|
scope: r_emailaddress,r_liteprofile
|
||||||
spotify:
|
spotify:
|
||||||
client_id: ""
|
client_id: ''
|
||||||
client_secret: ""
|
client_secret: ''
|
||||||
enabled: false
|
enabled: false
|
||||||
scope: user-read-email,user-read-private
|
scope: user-read-email,user-read-private
|
||||||
strava:
|
strava:
|
||||||
client_id: ""
|
client_id: ''
|
||||||
client_secret: ""
|
client_secret: ''
|
||||||
enabled: false
|
enabled: false
|
||||||
twilio:
|
twilio:
|
||||||
account_sid: ""
|
account_sid: ''
|
||||||
auth_token: ""
|
auth_token: ''
|
||||||
enabled: false
|
enabled: false
|
||||||
messaging_service_id: ""
|
messaging_service_id: ''
|
||||||
twitter:
|
twitter:
|
||||||
consumer_key: ""
|
consumer_key: ''
|
||||||
consumer_secret: ""
|
consumer_secret: ''
|
||||||
enabled: false
|
enabled: false
|
||||||
windows_live:
|
windows_live:
|
||||||
client_id: ""
|
client_id: ''
|
||||||
client_secret: ""
|
client_secret: ''
|
||||||
enabled: false
|
enabled: false
|
||||||
scope: wl.basic,wl.emails,wl.contacts_emails
|
scope: wl.basic,wl.emails,wl.contacts_emails
|
||||||
sms:
|
sms:
|
||||||
@@ -108,13 +107,13 @@ auth:
|
|||||||
enabled: false
|
enabled: false
|
||||||
provider:
|
provider:
|
||||||
twilio:
|
twilio:
|
||||||
account_sid: ""
|
account_sid: ''
|
||||||
auth_token: ""
|
auth_token: ''
|
||||||
from: ""
|
from: ''
|
||||||
messaging_service_id: ""
|
messaging_service_id: ''
|
||||||
smtp:
|
smtp:
|
||||||
host: nhost_mailhog
|
host: nhost_mailhog
|
||||||
method: ""
|
method: ''
|
||||||
pass: password
|
pass: password
|
||||||
port: 1765
|
port: 1765
|
||||||
secure: false
|
secure: false
|
||||||
|
|||||||
@@ -2,14 +2,32 @@
|
|||||||
|
|
||||||
This demo is a work in progress, further improvements are to come
|
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
|
```sh
|
||||||
cd examples/nextjs
|
cd examples/nextjs
|
||||||
yarn
|
pnpm install
|
||||||
yarn dev
|
```
|
||||||
|
|
||||||
|
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:
|
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`
|
- 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:
|
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: ''
|
allowed_emails: ''
|
||||||
blocked_email_domains: ''
|
blocked_email_domains: ''
|
||||||
blocked_emails: ''
|
blocked_emails: ''
|
||||||
url:
|
allowed_redirect_urls: ''
|
||||||
allowed_redirect_urls: ''
|
|
||||||
anonymous_users_enabled: false
|
anonymous_users_enabled: false
|
||||||
client_url: http://localhost:3000
|
client_url: http://localhost:3000
|
||||||
disable_new_users: false
|
disable_new_users: false
|
||||||
|
|||||||
@@ -11,4 +11,4 @@
|
|||||||
max_connections: 50
|
max_connections: 50
|
||||||
retries: 20
|
retries: 20
|
||||||
use_prepared_statements: true
|
use_prepared_statements: true
|
||||||
tables: "!include default/tables/tables.yaml"
|
tables: '!include default/tables/tables.yaml'
|
||||||
|
|||||||
@@ -16,10 +16,10 @@ configuration:
|
|||||||
update: updateAuthProviders
|
update: updateAuthProviders
|
||||||
update_by_pk: updateAuthProvider
|
update_by_pk: updateAuthProvider
|
||||||
array_relationships:
|
array_relationships:
|
||||||
- name: userProviders
|
- name: userProviders
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
column: provider_id
|
column: provider_id
|
||||||
table:
|
table:
|
||||||
name: user_providers
|
name: user_providers
|
||||||
schema: auth
|
schema: auth
|
||||||
|
|||||||
@@ -19,6 +19,6 @@ configuration:
|
|||||||
update: updateAuthRefreshTokens
|
update: updateAuthRefreshTokens
|
||||||
update_by_pk: updateAuthRefreshToken
|
update_by_pk: updateAuthRefreshToken
|
||||||
object_relationships:
|
object_relationships:
|
||||||
- name: user
|
- name: user
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on: user_id
|
foreign_key_constraint_on: user_id
|
||||||
|
|||||||
@@ -16,17 +16,17 @@ configuration:
|
|||||||
update: updateAuthRoles
|
update: updateAuthRoles
|
||||||
update_by_pk: updateAuthRole
|
update_by_pk: updateAuthRole
|
||||||
array_relationships:
|
array_relationships:
|
||||||
- name: userRoles
|
- name: userRoles
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
column: role
|
column: role
|
||||||
table:
|
table:
|
||||||
name: user_roles
|
name: user_roles
|
||||||
schema: auth
|
schema: auth
|
||||||
- name: usersByDefaultRole
|
- name: usersByDefaultRole
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
column: default_role
|
column: default_role
|
||||||
table:
|
table:
|
||||||
name: users
|
name: users
|
||||||
schema: auth
|
schema: auth
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ configuration:
|
|||||||
update: updateAuthUserProviders
|
update: updateAuthUserProviders
|
||||||
update_by_pk: updateAuthUserProvider
|
update_by_pk: updateAuthUserProvider
|
||||||
object_relationships:
|
object_relationships:
|
||||||
- name: provider
|
- name: provider
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on: provider_id
|
foreign_key_constraint_on: provider_id
|
||||||
- name: user
|
- name: user
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on: user_id
|
foreign_key_constraint_on: user_id
|
||||||
|
|||||||
@@ -19,9 +19,9 @@ configuration:
|
|||||||
update: updateAuthUserRoles
|
update: updateAuthUserRoles
|
||||||
update_by_pk: updateAuthUserRole
|
update_by_pk: updateAuthUserRole
|
||||||
object_relationships:
|
object_relationships:
|
||||||
- name: roleByRole
|
- name: roleByRole
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on: role
|
foreign_key_constraint_on: role
|
||||||
- name: user
|
- name: user
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on: user_id
|
foreign_key_constraint_on: user_id
|
||||||
|
|||||||
@@ -38,28 +38,28 @@ configuration:
|
|||||||
update: updateUsers
|
update: updateUsers
|
||||||
update_by_pk: updateUser
|
update_by_pk: updateUser
|
||||||
object_relationships:
|
object_relationships:
|
||||||
- name: defaultRoleByRole
|
- name: defaultRoleByRole
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on: default_role
|
foreign_key_constraint_on: default_role
|
||||||
array_relationships:
|
array_relationships:
|
||||||
- name: refreshTokens
|
- name: refreshTokens
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
column: user_id
|
column: user_id
|
||||||
table:
|
table:
|
||||||
name: refresh_tokens
|
name: refresh_tokens
|
||||||
schema: auth
|
schema: auth
|
||||||
- name: roles
|
- name: roles
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
column: user_id
|
column: user_id
|
||||||
table:
|
table:
|
||||||
name: user_roles
|
name: user_roles
|
||||||
schema: auth
|
schema: auth
|
||||||
- name: userProviders
|
- name: userProviders
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
column: user_id
|
column: user_id
|
||||||
table:
|
table:
|
||||||
name: user_providers
|
name: user_providers
|
||||||
schema: auth
|
schema: auth
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ table:
|
|||||||
name: books
|
name: books
|
||||||
schema: public
|
schema: public
|
||||||
select_permissions:
|
select_permissions:
|
||||||
- permission:
|
- permission:
|
||||||
columns:
|
columns:
|
||||||
- id
|
- id
|
||||||
- title
|
- title
|
||||||
filter: {}
|
filter: {}
|
||||||
role: user
|
role: user
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ table:
|
|||||||
name: test
|
name: test
|
||||||
schema: public
|
schema: public
|
||||||
select_permissions:
|
select_permissions:
|
||||||
- permission:
|
- permission:
|
||||||
columns:
|
columns:
|
||||||
- bidon
|
- bidon
|
||||||
- id
|
- id
|
||||||
filter: {}
|
filter: {}
|
||||||
role: user
|
role: user
|
||||||
|
|||||||
@@ -23,10 +23,10 @@ configuration:
|
|||||||
update: updateBuckets
|
update: updateBuckets
|
||||||
update_by_pk: updateBucket
|
update_by_pk: updateBucket
|
||||||
array_relationships:
|
array_relationships:
|
||||||
- name: files
|
- name: files
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
column: bucket_id
|
column: bucket_id
|
||||||
table:
|
table:
|
||||||
name: files
|
name: files
|
||||||
schema: storage
|
schema: storage
|
||||||
|
|||||||
@@ -25,6 +25,6 @@ configuration:
|
|||||||
update: updateFiles
|
update: updateFiles
|
||||||
update_by_pk: updateFile
|
update_by_pk: updateFile
|
||||||
object_relationships:
|
object_relationships:
|
||||||
- name: bucket
|
- name: bucket
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on: bucket_id
|
foreign_key_constraint_on: bucket_id
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
- "!include auth_provider_requests.yaml"
|
- '!include auth_provider_requests.yaml'
|
||||||
- "!include auth_providers.yaml"
|
- '!include auth_providers.yaml'
|
||||||
- "!include auth_refresh_tokens.yaml"
|
- '!include auth_refresh_tokens.yaml'
|
||||||
- "!include auth_roles.yaml"
|
- '!include auth_roles.yaml'
|
||||||
- "!include auth_user_providers.yaml"
|
- '!include auth_user_providers.yaml'
|
||||||
- "!include auth_user_roles.yaml"
|
- '!include auth_user_roles.yaml'
|
||||||
- "!include auth_users.yaml"
|
- '!include auth_users.yaml'
|
||||||
- "!include public_books.yaml"
|
- '!include public_books.yaml'
|
||||||
- "!include storage_buckets.yaml"
|
- '!include storage_buckets.yaml'
|
||||||
- "!include storage_files.yaml"
|
- '!include storage_files.yaml'
|
||||||
|
|||||||
@@ -6,13 +6,23 @@
|
|||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start",
|
"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": {
|
"dependencies": {
|
||||||
"@apollo/client": "^3.5.10",
|
"@apollo/client": "^3.5.10",
|
||||||
"@nhost/nextjs": "^1.0.10",
|
"@nhost/apollo": "workspace:*",
|
||||||
"@nhost/react": "^0.5.0",
|
"@nhost/core": "workspace:*",
|
||||||
"@nhost/react-apollo": "^4.0.10",
|
"@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",
|
"graphql": "^16.3.0",
|
||||||
"next": "12.1.0",
|
"next": "12.1.0",
|
||||||
"react": "17.0.2",
|
"react": "17.0.2",
|
||||||
@@ -22,9 +32,10 @@
|
|||||||
"@types/node": "17.0.23",
|
"@types/node": "17.0.23",
|
||||||
"@types/react": "17.0.43",
|
"@types/react": "17.0.43",
|
||||||
"@xstate/inspect": "^0.6.2",
|
"@xstate/inspect": "^0.6.2",
|
||||||
"eslint": "8.8.0",
|
|
||||||
"eslint-config-next": "12.0.10",
|
"eslint-config-next": "12.0.10",
|
||||||
|
"next-transpile-modules": "^9.0.0",
|
||||||
"typescript": "4.5.5",
|
"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 })
|
const nhost = new NhostClient({ backendUrl: BACKEND_URL })
|
||||||
|
|
||||||
function MyApp({ Component, pageProps }: AppProps) {
|
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 (
|
return (
|
||||||
<NhostNextProvider nhost={nhost} initial={pageProps.nhostSession}>
|
<NhostNextProvider nhost={nhost} initial={pageProps.nhostSession}>
|
||||||
<NhostApolloProvider nhost={nhost}>
|
<NhostApolloProvider nhost={nhost}>
|
||||||
<div className="App">
|
<div className="App">
|
||||||
<Header />
|
<Header />
|
||||||
<Component {...pageProps} />
|
<AnyComponent {...pageProps} />
|
||||||
</div>
|
</div>
|
||||||
</NhostApolloProvider>
|
</NhostApolloProvider>
|
||||||
</NhostNextProvider>
|
</NhostNextProvider>
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es5",
|
"target": "es5",
|
||||||
"lib": [
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
"dom",
|
|
||||||
"dom.iterable",
|
|
||||||
"esnext"
|
|
||||||
],
|
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"strict": false,
|
"strict": false,
|
||||||
@@ -19,11 +15,6 @@
|
|||||||
"jsx": "preserve",
|
"jsx": "preserve",
|
||||||
"incremental": true
|
"incremental": true
|
||||||
},
|
},
|
||||||
"include": [
|
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
||||||
"next-env.d.ts",
|
"exclude": ["node_modules"]
|
||||||
"**/*.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
|
## Get started
|
||||||
|
|
||||||
1. Install dependencies
|
1. Clone the repository
|
||||||
|
|
||||||
```
|
```sh
|
||||||
npm install
|
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
|
nhost dev
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Terminal 2: Start React App
|
4. Terminal 2: Start React App
|
||||||
|
|
||||||
```
|
```sh
|
||||||
npm run start
|
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
|
> 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 = {
|
module.exports = {
|
||||||
client: {
|
client: {
|
||||||
service: {
|
service: {
|
||||||
name: "backend",
|
name: 'backend',
|
||||||
url: "http://localhost:1337/v1/graphql",
|
url: 'http://localhost:1337/v1/graphql',
|
||||||
headers: {
|
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:
|
headers:
|
||||||
x-hasura-admin-secret: nhost-admin-secret
|
x-hasura-admin-secret: nhost-admin-secret
|
||||||
documents:
|
documents:
|
||||||
- "src/**/*.graphql"
|
- 'src/**/*.graphql'
|
||||||
- "src/**/*.gql"
|
- 'src/**/*.gql'
|
||||||
generates:
|
generates:
|
||||||
src/utils/__generated__/graphql.ts:
|
src/utils/__generated__/graphql.ts:
|
||||||
plugins:
|
plugins:
|
||||||
- "typescript"
|
- 'typescript'
|
||||||
- "typescript-operations"
|
- 'typescript-operations'
|
||||||
- "typescript-react-apollo"
|
- 'typescript-react-apollo'
|
||||||
config:
|
config:
|
||||||
withRefetchFn: true
|
withRefetchFn: true
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { NhostClient } from '@nhost/nhost-js'
|
import { NhostClient } from '@nhost/nhost-js'
|
||||||
|
|
||||||
const nhost = new NhostClient({
|
const nhost = new NhostClient({
|
||||||
backendUrl: process.env.NHOST_BACKEND_URL!
|
backendUrl: process.env.NHOST_BACKEND_URL!
|
||||||
})
|
})
|
||||||
|
|
||||||
export { nhost }
|
export { nhost }
|
||||||
|
|||||||
@@ -2,104 +2,104 @@ import { Request, Response } from 'express'
|
|||||||
import { nhost } from '../../_utils/nhost'
|
import { nhost } from '../../_utils/nhost'
|
||||||
|
|
||||||
const handler = async (req: Request, res: Response) => {
|
const handler = async (req: Request, res: Response) => {
|
||||||
if (req.headers['nhsot-webhook-secret'] !== process.env.NHSOT_WEBHOOK_SECRET) {
|
if (req.headers['nhsot-webhook-secret'] !== process.env.NHSOT_WEBHOOK_SECRET) {
|
||||||
return res.status(401).send('Unauthorized')
|
return res.status(401).send('Unauthorized')
|
||||||
}
|
}
|
||||||
|
|
||||||
// User who just signed up
|
// User who just signed up
|
||||||
const user = req.body.event.data.new
|
const user = req.body.event.data.new
|
||||||
|
|
||||||
// Get the user's email domain
|
// Get the user's email domain
|
||||||
const emailDomain = user.email.split('@')[1]
|
const emailDomain = user.email.split('@')[1]
|
||||||
|
|
||||||
// Check if a company with the user's email domain already exists.
|
// Check if a company with the user's email domain already exists.
|
||||||
const GET_COMPANY_WITH_EMAIL_DOMAIN = `
|
const GET_COMPANY_WITH_EMAIL_DOMAIN = `
|
||||||
query getCompanyWithEmailDomain($emailDomain: String!) {
|
query getCompanyWithEmailDomain($emailDomain: String!) {
|
||||||
companies(where: { emailDomain: { _eq: $emailDomain } }) {
|
companies(where: { emailDomain: { _eq: $emailDomain } }) {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
const { data, error } = await nhost.graphql.request(
|
const { data, error } = await nhost.graphql.request(
|
||||||
GET_COMPANY_WITH_EMAIL_DOMAIN,
|
GET_COMPANY_WITH_EMAIL_DOMAIN,
|
||||||
{
|
{
|
||||||
emailDomain
|
emailDomain
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
'x-hasura-admin-secret': process.env.NHOST_ADMIN_SECRET
|
'x-hasura-admin-secret': process.env.NHOST_ADMIN_SECRET
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
)
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
return res.status(500).send(error)
|
return res.status(500).send(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
const { companies } = data as any
|
const { companies } = data as any
|
||||||
|
|
||||||
let companyId
|
let companyId
|
||||||
if (companies.length === 1) {
|
if (companies.length === 1) {
|
||||||
// if a company already exists, use that company's id
|
// if a company already exists, use that company's id
|
||||||
companyId = companies[0].id
|
companyId = companies[0].id
|
||||||
} else {
|
} else {
|
||||||
// else, create a new company for the newly created user with the same email domain as the user
|
// else, create a new company for the newly created user with the same email domain as the user
|
||||||
const CREATE_NEW_COMPANY = `
|
const CREATE_NEW_COMPANY = `
|
||||||
mutation insertCompany($emailDomain: String!) {
|
mutation insertCompany($emailDomain: String!) {
|
||||||
insertCompany(object: { name: $emailDomain, emailDomain: $emailDomain }) {
|
insertCompany(object: { name: $emailDomain, emailDomain: $emailDomain }) {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
const { data, error } = await nhost.graphql.request(
|
const { data, error } = await nhost.graphql.request(
|
||||||
CREATE_NEW_COMPANY,
|
CREATE_NEW_COMPANY,
|
||||||
{
|
{
|
||||||
emailDomain
|
emailDomain
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
'x-hasura-admin-secret': process.env.NHOST_ADMIN_SECRET
|
'x-hasura-admin-secret': process.env.NHOST_ADMIN_SECRET
|
||||||
}
|
}
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
return res.status(500).send(error)
|
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
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.
|
companyId = insertCompany.id
|
||||||
// Now let's add the user to the company.
|
}
|
||||||
|
|
||||||
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!) {
|
mutation addUserToCompany($userId: uuid!, $companyId: uuid!) {
|
||||||
insertCompanyUser(object: {userId: $userId, companyId: $companyId}) {
|
insertCompanyUser(object: {userId: $userId, companyId: $companyId}) {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
const { error: addUserToCompanyError } = await nhost.graphql.request(
|
const { error: addUserToCompanyError } = await nhost.graphql.request(
|
||||||
ADD_USER_TO_COMPANY,
|
ADD_USER_TO_COMPANY,
|
||||||
{
|
{
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
companyId
|
companyId
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
'x-hasura-admin-secret': process.env.NHOST_ADMIN_SECRET
|
'x-hasura-admin-secret': process.env.NHOST_ADMIN_SECRET
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
)
|
||||||
|
|
||||||
if (addUserToCompanyError) {
|
if (addUserToCompanyError) {
|
||||||
return res.status(500).send(error)
|
return res.status(500).send(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
res.status(200).send(`OK`)
|
res.status(200).send(`OK`)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default handler
|
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:
|
auth:
|
||||||
access_control:
|
access_control:
|
||||||
email:
|
email:
|
||||||
allowed_email_domains: ""
|
allowed_email_domains: ''
|
||||||
allowed_emails: ""
|
allowed_emails: ''
|
||||||
blocked_email_domains: ""
|
blocked_email_domains: ''
|
||||||
blocked_emails: ""
|
blocked_emails: ''
|
||||||
url:
|
allowed_redirect_urls: ''
|
||||||
allowed_redirect_urls: ""
|
|
||||||
anonymous_users_enabled: false
|
anonymous_users_enabled: false
|
||||||
client_url: http://localhost:3000
|
client_url: http://localhost:3000
|
||||||
disable_new_users: false
|
disable_new_users: false
|
||||||
@@ -19,12 +18,12 @@ auth:
|
|||||||
enabled: false
|
enabled: false
|
||||||
passwordless:
|
passwordless:
|
||||||
enabled: false
|
enabled: false
|
||||||
template_fetch_url: ""
|
template_fetch_url: ''
|
||||||
signin_email_verified_required: false
|
signin_email_verified_required: false
|
||||||
gravatar:
|
gravatar:
|
||||||
default: ""
|
default: ''
|
||||||
enabled: true
|
enabled: true
|
||||||
rating: ""
|
rating: ''
|
||||||
locale:
|
locale:
|
||||||
allowed: en
|
allowed: en
|
||||||
default: en
|
default: en
|
||||||
@@ -33,65 +32,65 @@ auth:
|
|||||||
min_length: 3
|
min_length: 3
|
||||||
provider:
|
provider:
|
||||||
apple:
|
apple:
|
||||||
client_id: ""
|
client_id: ''
|
||||||
enabled: false
|
enabled: false
|
||||||
key_id: ""
|
key_id: ''
|
||||||
private_key: ""
|
private_key: ''
|
||||||
scope: name,email
|
scope: name,email
|
||||||
team_id: ""
|
team_id: ''
|
||||||
bitbucket:
|
bitbucket:
|
||||||
client_id: ""
|
client_id: ''
|
||||||
client_secret: ""
|
client_secret: ''
|
||||||
enabled: false
|
enabled: false
|
||||||
facebook:
|
facebook:
|
||||||
client_id: ""
|
client_id: ''
|
||||||
client_secret: ""
|
client_secret: ''
|
||||||
enabled: false
|
enabled: false
|
||||||
scope: email,photos,displayName
|
scope: email,photos,displayName
|
||||||
github:
|
github:
|
||||||
client_id: ""
|
client_id: ''
|
||||||
client_secret: ""
|
client_secret: ''
|
||||||
enabled: false
|
enabled: false
|
||||||
scope: user:email
|
scope: user:email
|
||||||
token_url: ""
|
token_url: ''
|
||||||
user_profile_url: ""
|
user_profile_url: ''
|
||||||
gitlab:
|
gitlab:
|
||||||
base_url: ""
|
base_url: ''
|
||||||
client_id: ""
|
client_id: ''
|
||||||
client_secret: ""
|
client_secret: ''
|
||||||
enabled: false
|
enabled: false
|
||||||
scope: read_user
|
scope: read_user
|
||||||
google:
|
google:
|
||||||
client_id: ""
|
client_id: ''
|
||||||
client_secret: ""
|
client_secret: ''
|
||||||
enabled: false
|
enabled: false
|
||||||
scope: email,profile
|
scope: email,profile
|
||||||
linkedin:
|
linkedin:
|
||||||
client_id: ""
|
client_id: ''
|
||||||
client_secret: ""
|
client_secret: ''
|
||||||
enabled: false
|
enabled: false
|
||||||
scope: r_emailaddress,r_liteprofile
|
scope: r_emailaddress,r_liteprofile
|
||||||
spotify:
|
spotify:
|
||||||
client_id: ""
|
client_id: ''
|
||||||
client_secret: ""
|
client_secret: ''
|
||||||
enabled: false
|
enabled: false
|
||||||
scope: user-read-email,user-read-private
|
scope: user-read-email,user-read-private
|
||||||
strava:
|
strava:
|
||||||
client_id: ""
|
client_id: ''
|
||||||
client_secret: ""
|
client_secret: ''
|
||||||
enabled: false
|
enabled: false
|
||||||
twilio:
|
twilio:
|
||||||
account_sid: ""
|
account_sid: ''
|
||||||
auth_token: ""
|
auth_token: ''
|
||||||
enabled: false
|
enabled: false
|
||||||
messaging_service_id: ""
|
messaging_service_id: ''
|
||||||
twitter:
|
twitter:
|
||||||
consumer_key: ""
|
consumer_key: ''
|
||||||
consumer_secret: ""
|
consumer_secret: ''
|
||||||
enabled: false
|
enabled: false
|
||||||
windows_live:
|
windows_live:
|
||||||
client_id: ""
|
client_id: ''
|
||||||
client_secret: ""
|
client_secret: ''
|
||||||
enabled: false
|
enabled: false
|
||||||
scope: wl.basic,wl.emails,wl.contacts_emails
|
scope: wl.basic,wl.emails,wl.contacts_emails
|
||||||
sms:
|
sms:
|
||||||
@@ -100,13 +99,13 @@ auth:
|
|||||||
enabled: false
|
enabled: false
|
||||||
provider:
|
provider:
|
||||||
twilio:
|
twilio:
|
||||||
account_sid: ""
|
account_sid: ''
|
||||||
auth_token: ""
|
auth_token: ''
|
||||||
from: ""
|
from: ''
|
||||||
messaging_service_id: ""
|
messaging_service_id: ''
|
||||||
smtp:
|
smtp:
|
||||||
host: nhost_mailhog
|
host: nhost_mailhog
|
||||||
method: ""
|
method: ''
|
||||||
pass: password
|
pass: password
|
||||||
port: 1586
|
port: 1586
|
||||||
secure: false
|
secure: false
|
||||||
|
|||||||
@@ -7,9 +7,7 @@
|
|||||||
<h2>Verify Email</h2>
|
<h2>Verify Email</h2>
|
||||||
<p>Use this link to verify your email:</p>
|
<p>Use this link to verify your email:</p>
|
||||||
<p>
|
<p>
|
||||||
<a
|
<a href="${serverUrl}/verify?&ticket=${ticket}&type=emailVerify&redirectTo=${redirectTo}">
|
||||||
href="${serverUrl}/verify?&ticket=${ticket}&type=emailVerify&redirectTo=${redirectTo}"
|
|
||||||
>
|
|
||||||
Verify Email
|
Verify Email
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -7,9 +7,7 @@
|
|||||||
<h2>Reset Password</h2>
|
<h2>Reset Password</h2>
|
||||||
<p>Use this link to reset your password:</p>
|
<p>Use this link to reset your password:</p>
|
||||||
<p>
|
<p>
|
||||||
<a
|
<a href="${serverUrl}/verify?&ticket=${ticket}&type=passwordReset&redirectTo=${redirectTo}">
|
||||||
href="${serverUrl}/verify?&ticket=${ticket}&type=passwordReset&redirectTo=${redirectTo}"
|
|
||||||
>
|
|
||||||
Reset password
|
Reset password
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
type Mutation {
|
type Mutation {
|
||||||
actionName(
|
actionName(arg1: SampleInput!): SampleOutput
|
||||||
arg1: SampleInput!
|
|
||||||
): SampleOutput
|
|
||||||
}
|
}
|
||||||
|
|
||||||
input SampleInput {
|
input SampleInput {
|
||||||
@@ -12,4 +10,3 @@ input SampleInput {
|
|||||||
type SampleOutput {
|
type SampleOutput {
|
||||||
accessToken: String!
|
accessToken: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
actions:
|
actions:
|
||||||
- name: actionName
|
- name: actionName
|
||||||
definition:
|
definition:
|
||||||
kind: synchronous
|
kind: synchronous
|
||||||
handler: http://host.docker.internal:3000
|
handler: http://host.docker.internal:3000
|
||||||
permissions:
|
permissions:
|
||||||
- role: user
|
- role: user
|
||||||
custom_types:
|
custom_types:
|
||||||
enums: []
|
enums: []
|
||||||
input_objects:
|
input_objects:
|
||||||
- name: SampleInput
|
- name: SampleInput
|
||||||
objects:
|
objects:
|
||||||
- name: SampleOutput
|
- name: SampleOutput
|
||||||
scalars: []
|
scalars: []
|
||||||
|
|||||||
@@ -11,4 +11,4 @@
|
|||||||
max_connections: 50
|
max_connections: 50
|
||||||
retries: 20
|
retries: 20
|
||||||
use_prepared_statements: true
|
use_prepared_statements: true
|
||||||
tables: "!include default/tables/tables.yaml"
|
tables: '!include default/tables/tables.yaml'
|
||||||
|
|||||||
@@ -16,10 +16,10 @@ configuration:
|
|||||||
update: updateAuthProviders
|
update: updateAuthProviders
|
||||||
update_by_pk: updateAuthProvider
|
update_by_pk: updateAuthProvider
|
||||||
array_relationships:
|
array_relationships:
|
||||||
- name: userProviders
|
- name: userProviders
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
column: provider_id
|
column: provider_id
|
||||||
table:
|
table:
|
||||||
name: user_providers
|
name: user_providers
|
||||||
schema: auth
|
schema: auth
|
||||||
|
|||||||
@@ -19,6 +19,6 @@ configuration:
|
|||||||
update: updateAuthRefreshTokens
|
update: updateAuthRefreshTokens
|
||||||
update_by_pk: updateAuthRefreshToken
|
update_by_pk: updateAuthRefreshToken
|
||||||
object_relationships:
|
object_relationships:
|
||||||
- name: user
|
- name: user
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on: user_id
|
foreign_key_constraint_on: user_id
|
||||||
|
|||||||
@@ -16,17 +16,17 @@ configuration:
|
|||||||
update: updateAuthRoles
|
update: updateAuthRoles
|
||||||
update_by_pk: updateAuthRole
|
update_by_pk: updateAuthRole
|
||||||
array_relationships:
|
array_relationships:
|
||||||
- name: userRoles
|
- name: userRoles
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
column: role
|
column: role
|
||||||
table:
|
table:
|
||||||
name: user_roles
|
name: user_roles
|
||||||
schema: auth
|
schema: auth
|
||||||
- name: usersByDefaultRole
|
- name: usersByDefaultRole
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
column: default_role
|
column: default_role
|
||||||
table:
|
table:
|
||||||
name: users
|
name: users
|
||||||
schema: auth
|
schema: auth
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ configuration:
|
|||||||
update: updateAuthUserProviders
|
update: updateAuthUserProviders
|
||||||
update_by_pk: updateAuthUserProvider
|
update_by_pk: updateAuthUserProvider
|
||||||
object_relationships:
|
object_relationships:
|
||||||
- name: provider
|
- name: provider
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on: provider_id
|
foreign_key_constraint_on: provider_id
|
||||||
- name: user
|
- name: user
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on: user_id
|
foreign_key_constraint_on: user_id
|
||||||
|
|||||||
@@ -19,9 +19,9 @@ configuration:
|
|||||||
update: updateAuthUserRoles
|
update: updateAuthUserRoles
|
||||||
update_by_pk: updateAuthUserRole
|
update_by_pk: updateAuthUserRole
|
||||||
object_relationships:
|
object_relationships:
|
||||||
- name: roleByRole
|
- name: roleByRole
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on: role
|
foreign_key_constraint_on: role
|
||||||
- name: user
|
- name: user
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on: user_id
|
foreign_key_constraint_on: user_id
|
||||||
|
|||||||
@@ -38,79 +38,79 @@ configuration:
|
|||||||
update: updateUsers
|
update: updateUsers
|
||||||
update_by_pk: updateUser
|
update_by_pk: updateUser
|
||||||
object_relationships:
|
object_relationships:
|
||||||
- name: companyUser
|
- name: companyUser
|
||||||
using:
|
using:
|
||||||
manual_configuration:
|
manual_configuration:
|
||||||
column_mapping:
|
column_mapping:
|
||||||
id: user_id
|
id: user_id
|
||||||
insertion_order: null
|
insertion_order: null
|
||||||
remote_table:
|
remote_table:
|
||||||
name: company_users
|
name: company_users
|
||||||
schema: public
|
schema: public
|
||||||
- name: defaultRoleByRole
|
- name: defaultRoleByRole
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on: default_role
|
foreign_key_constraint_on: default_role
|
||||||
array_relationships:
|
array_relationships:
|
||||||
- name: customer_comments
|
- name: customer_comments
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
column: user_id
|
column: user_id
|
||||||
table:
|
table:
|
||||||
name: customer_comments
|
name: customer_comments
|
||||||
schema: public
|
schema: public
|
||||||
- name: customers
|
- name: customers
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
column: user_id
|
column: user_id
|
||||||
table:
|
table:
|
||||||
name: customers
|
name: customers
|
||||||
schema: public
|
schema: public
|
||||||
- name: refreshTokens
|
- name: refreshTokens
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
column: user_id
|
column: user_id
|
||||||
table:
|
table:
|
||||||
name: refresh_tokens
|
name: refresh_tokens
|
||||||
schema: auth
|
schema: auth
|
||||||
- name: roles
|
- name: roles
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
column: user_id
|
column: user_id
|
||||||
table:
|
table:
|
||||||
name: user_roles
|
name: user_roles
|
||||||
schema: auth
|
schema: auth
|
||||||
- name: userProviders
|
- name: userProviders
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
column: user_id
|
column: user_id
|
||||||
table:
|
table:
|
||||||
name: user_providers
|
name: user_providers
|
||||||
schema: auth
|
schema: auth
|
||||||
select_permissions:
|
select_permissions:
|
||||||
- permission:
|
- permission:
|
||||||
columns:
|
columns:
|
||||||
- avatar_url
|
- avatar_url
|
||||||
- display_name
|
- display_name
|
||||||
- email
|
- email
|
||||||
- id
|
- id
|
||||||
filter:
|
filter:
|
||||||
companyUser:
|
companyUser:
|
||||||
company:
|
company:
|
||||||
companyUsers:
|
companyUsers:
|
||||||
user_id:
|
user_id:
|
||||||
_eq: X-Hasura-User-Id
|
_eq: X-Hasura-User-Id
|
||||||
role: user
|
role: user
|
||||||
event_triggers:
|
event_triggers:
|
||||||
- definition:
|
- definition:
|
||||||
enable_manual: false
|
enable_manual: false
|
||||||
insert:
|
insert:
|
||||||
columns: "*"
|
columns: '*'
|
||||||
headers:
|
headers:
|
||||||
- name: nhost-webhook-secret
|
- name: nhost-webhook-secret
|
||||||
value_from_env: NHOST_WEBHOOK_SECRET
|
value_from_env: NHOST_WEBHOOK_SECRET
|
||||||
name: users-insert-create-company-connection
|
name: users-insert-create-company-connection
|
||||||
retry_conf:
|
retry_conf:
|
||||||
interval_sec: 10
|
interval_sec: 10
|
||||||
num_retries: 0
|
num_retries: 0
|
||||||
timeout_sec: 60
|
timeout_sec: 60
|
||||||
webhook: "{{NHOST_BACKEND_URL}}/v1/functions/users/insert/create-company-connection"
|
webhook: '{{NHOST_BACKEND_URL}}/v1/functions/users/insert/create-company-connection'
|
||||||
|
|||||||
@@ -18,29 +18,29 @@ configuration:
|
|||||||
update: updateCompanies
|
update: updateCompanies
|
||||||
update_by_pk: updateCompany
|
update_by_pk: updateCompany
|
||||||
array_relationships:
|
array_relationships:
|
||||||
- name: companyUsers
|
- name: companyUsers
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
column: company_id
|
column: company_id
|
||||||
table:
|
table:
|
||||||
name: company_users
|
name: company_users
|
||||||
schema: public
|
schema: public
|
||||||
- name: customers
|
- name: customers
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
column: company_id
|
column: company_id
|
||||||
table:
|
table:
|
||||||
name: customers
|
name: customers
|
||||||
schema: public
|
schema: public
|
||||||
select_permissions:
|
select_permissions:
|
||||||
- permission:
|
- permission:
|
||||||
columns:
|
columns:
|
||||||
- id
|
- id
|
||||||
- created_at
|
- created_at
|
||||||
- updated_at
|
- updated_at
|
||||||
- name
|
- name
|
||||||
filter:
|
filter:
|
||||||
companyUsers:
|
companyUsers:
|
||||||
user_id:
|
user_id:
|
||||||
_eq: X-Hasura-User-Id
|
_eq: X-Hasura-User-Id
|
||||||
role: user
|
role: user
|
||||||
|
|||||||
@@ -20,23 +20,23 @@ configuration:
|
|||||||
update: updateCompanyUsers
|
update: updateCompanyUsers
|
||||||
update_by_pk: updateCompanyUser
|
update_by_pk: updateCompanyUser
|
||||||
object_relationships:
|
object_relationships:
|
||||||
- name: company
|
- name: company
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on: company_id
|
foreign_key_constraint_on: company_id
|
||||||
- name: user
|
- name: user
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on: user_id
|
foreign_key_constraint_on: user_id
|
||||||
select_permissions:
|
select_permissions:
|
||||||
- permission:
|
- permission:
|
||||||
columns:
|
columns:
|
||||||
- id
|
- id
|
||||||
- created_at
|
- created_at
|
||||||
- updated_at
|
- updated_at
|
||||||
- company_id
|
- company_id
|
||||||
- user_id
|
- user_id
|
||||||
filter:
|
filter:
|
||||||
company:
|
company:
|
||||||
companyUsers:
|
companyUsers:
|
||||||
user_id:
|
user_id:
|
||||||
_eq: X-Hasura-User-Id
|
_eq: X-Hasura-User-Id
|
||||||
role: user
|
role: user
|
||||||
|
|||||||
@@ -19,65 +19,65 @@ configuration:
|
|||||||
update: updateCustomerComments
|
update: updateCustomerComments
|
||||||
update_by_pk: updateCustomerComment
|
update_by_pk: updateCustomerComment
|
||||||
object_relationships:
|
object_relationships:
|
||||||
- name: customer
|
- name: customer
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on: customer_id
|
foreign_key_constraint_on: customer_id
|
||||||
- name: file
|
- name: file
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on: file_id
|
foreign_key_constraint_on: file_id
|
||||||
- name: user
|
- name: user
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on: user_id
|
foreign_key_constraint_on: user_id
|
||||||
insert_permissions:
|
insert_permissions:
|
||||||
- permission:
|
- permission:
|
||||||
backend_only: false
|
backend_only: false
|
||||||
check:
|
check:
|
||||||
customer:
|
customer:
|
||||||
company:
|
company:
|
||||||
companyUsers:
|
companyUsers:
|
||||||
user_id:
|
user_id:
|
||||||
_eq: X-Hasura-User-Id
|
_eq: X-Hasura-User-Id
|
||||||
columns:
|
columns:
|
||||||
- customer_id
|
- customer_id
|
||||||
- file_id
|
- file_id
|
||||||
- text
|
- text
|
||||||
set:
|
set:
|
||||||
user_id: x-hasura-user-id
|
user_id: x-hasura-user-id
|
||||||
role: user
|
role: user
|
||||||
select_permissions:
|
select_permissions:
|
||||||
- permission:
|
- permission:
|
||||||
columns:
|
columns:
|
||||||
- created_at
|
- created_at
|
||||||
- customer_id
|
- customer_id
|
||||||
- file_id
|
- file_id
|
||||||
- id
|
- id
|
||||||
- text
|
- text
|
||||||
- updated_at
|
- updated_at
|
||||||
- user_id
|
- user_id
|
||||||
filter:
|
filter:
|
||||||
customer:
|
customer:
|
||||||
company:
|
company:
|
||||||
companyUsers:
|
companyUsers:
|
||||||
user_id:
|
user_id:
|
||||||
_eq: X-Hasura-User-Id
|
_eq: X-Hasura-User-Id
|
||||||
role: user
|
role: user
|
||||||
update_permissions:
|
update_permissions:
|
||||||
- permission:
|
- permission:
|
||||||
check: null
|
check: null
|
||||||
columns: []
|
columns: []
|
||||||
filter:
|
filter:
|
||||||
customer:
|
customer:
|
||||||
company:
|
company:
|
||||||
companyUsers:
|
companyUsers:
|
||||||
user_id:
|
user_id:
|
||||||
_eq: X-Hasura-User-Id
|
_eq: X-Hasura-User-Id
|
||||||
role: user
|
role: user
|
||||||
delete_permissions:
|
delete_permissions:
|
||||||
- permission:
|
- permission:
|
||||||
filter:
|
filter:
|
||||||
customer:
|
customer:
|
||||||
company:
|
company:
|
||||||
companyUsers:
|
companyUsers:
|
||||||
user_id:
|
user_id:
|
||||||
_eq: X-Hasura-User-Id
|
_eq: X-Hasura-User-Id
|
||||||
role: user
|
role: user
|
||||||
|
|||||||
@@ -20,48 +20,48 @@ configuration:
|
|||||||
update: updateCustomers
|
update: updateCustomers
|
||||||
update_by_pk: updateCustomer
|
update_by_pk: updateCustomer
|
||||||
object_relationships:
|
object_relationships:
|
||||||
- name: company
|
- name: company
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on: company_id
|
foreign_key_constraint_on: company_id
|
||||||
- name: user
|
- name: user
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on: user_id
|
foreign_key_constraint_on: user_id
|
||||||
array_relationships:
|
array_relationships:
|
||||||
- name: customerComments
|
- name: customerComments
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
column: customer_id
|
column: customer_id
|
||||||
table:
|
table:
|
||||||
name: customer_comments
|
name: customer_comments
|
||||||
schema: public
|
schema: public
|
||||||
insert_permissions:
|
insert_permissions:
|
||||||
- permission:
|
- permission:
|
||||||
backend_only: false
|
backend_only: false
|
||||||
check:
|
check:
|
||||||
company:
|
company:
|
||||||
companyUsers:
|
companyUsers:
|
||||||
user_id:
|
user_id:
|
||||||
_eq: X-Hasura-User-Id
|
_eq: X-Hasura-User-Id
|
||||||
columns:
|
columns:
|
||||||
- address_line_1
|
- address_line_1
|
||||||
- company_id
|
- company_id
|
||||||
- name
|
- name
|
||||||
set:
|
set:
|
||||||
user_id: x-hasura-user-id
|
user_id: x-hasura-user-id
|
||||||
role: user
|
role: user
|
||||||
select_permissions:
|
select_permissions:
|
||||||
- permission:
|
- permission:
|
||||||
columns:
|
columns:
|
||||||
- id
|
- id
|
||||||
- created_at
|
- created_at
|
||||||
- updated_at
|
- updated_at
|
||||||
- name
|
- name
|
||||||
- address_line_1
|
- address_line_1
|
||||||
- company_id
|
- company_id
|
||||||
- user_id
|
- user_id
|
||||||
filter:
|
filter:
|
||||||
company:
|
company:
|
||||||
companyUsers:
|
companyUsers:
|
||||||
user_id:
|
user_id:
|
||||||
_eq: X-Hasura-User-Id
|
_eq: X-Hasura-User-Id
|
||||||
role: user
|
role: user
|
||||||
|
|||||||
@@ -23,10 +23,10 @@ configuration:
|
|||||||
update: updateBuckets
|
update: updateBuckets
|
||||||
update_by_pk: updateBucket
|
update_by_pk: updateBucket
|
||||||
array_relationships:
|
array_relationships:
|
||||||
- name: files
|
- name: files
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
column: bucket_id
|
column: bucket_id
|
||||||
table:
|
table:
|
||||||
name: files
|
name: files
|
||||||
schema: storage
|
schema: storage
|
||||||
|
|||||||
@@ -25,51 +25,51 @@ configuration:
|
|||||||
update: updateFiles
|
update: updateFiles
|
||||||
update_by_pk: updateFile
|
update_by_pk: updateFile
|
||||||
object_relationships:
|
object_relationships:
|
||||||
- name: bucket
|
- name: bucket
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on: bucket_id
|
foreign_key_constraint_on: bucket_id
|
||||||
array_relationships:
|
array_relationships:
|
||||||
- name: customerCommentFiles
|
- name: customerCommentFiles
|
||||||
using:
|
using:
|
||||||
manual_configuration:
|
manual_configuration:
|
||||||
column_mapping:
|
column_mapping:
|
||||||
id: file_id
|
id: file_id
|
||||||
insertion_order: null
|
insertion_order: null
|
||||||
remote_table:
|
remote_table:
|
||||||
name: customer_comments
|
name: customer_comments
|
||||||
schema: public
|
schema: public
|
||||||
insert_permissions:
|
insert_permissions:
|
||||||
- permission:
|
- permission:
|
||||||
backend_only: false
|
backend_only: false
|
||||||
check:
|
check:
|
||||||
_or:
|
_or:
|
||||||
- bucket_id:
|
- bucket_id:
|
||||||
_eq: customerComments
|
_eq: customerComments
|
||||||
columns:
|
columns:
|
||||||
- bucket_id
|
- bucket_id
|
||||||
- id
|
- id
|
||||||
- mime_type
|
- mime_type
|
||||||
- name
|
- name
|
||||||
role: user
|
role: user
|
||||||
select_permissions:
|
select_permissions:
|
||||||
- permission:
|
- permission:
|
||||||
columns:
|
columns:
|
||||||
- id
|
- id
|
||||||
- created_at
|
- created_at
|
||||||
- updated_at
|
- updated_at
|
||||||
- bucket_id
|
- bucket_id
|
||||||
- name
|
- name
|
||||||
- size
|
- size
|
||||||
- mime_type
|
- mime_type
|
||||||
- etag
|
- etag
|
||||||
- is_uploaded
|
- is_uploaded
|
||||||
- uploaded_by_user_id
|
- uploaded_by_user_id
|
||||||
filter:
|
filter:
|
||||||
_or:
|
_or:
|
||||||
- customerCommentFiles:
|
- customerCommentFiles:
|
||||||
customer:
|
customer:
|
||||||
company:
|
company:
|
||||||
companyUsers:
|
companyUsers:
|
||||||
user_id:
|
user_id:
|
||||||
_eq: X-Hasura-User-Id
|
_eq: X-Hasura-User-Id
|
||||||
role: user
|
role: user
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
- "!include auth_provider_requests.yaml"
|
- '!include auth_provider_requests.yaml'
|
||||||
- "!include auth_providers.yaml"
|
- '!include auth_providers.yaml'
|
||||||
- "!include auth_refresh_tokens.yaml"
|
- '!include auth_refresh_tokens.yaml'
|
||||||
- "!include auth_roles.yaml"
|
- '!include auth_roles.yaml'
|
||||||
- "!include auth_user_providers.yaml"
|
- '!include auth_user_providers.yaml'
|
||||||
- "!include auth_user_roles.yaml"
|
- '!include auth_user_roles.yaml'
|
||||||
- "!include auth_users.yaml"
|
- '!include auth_users.yaml'
|
||||||
- "!include public_companies.yaml"
|
- '!include public_companies.yaml'
|
||||||
- "!include public_company_users.yaml"
|
- '!include public_company_users.yaml'
|
||||||
- "!include public_customer_comments.yaml"
|
- '!include public_customer_comments.yaml'
|
||||||
- "!include public_customers.yaml"
|
- '!include public_customers.yaml'
|
||||||
- "!include storage_buckets.yaml"
|
- '!include storage_buckets.yaml'
|
||||||
- "!include storage_files.yaml"
|
- '!include storage_files.yaml'
|
||||||
|
|||||||
@@ -3,38 +3,34 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@apollo/client": "^3.4.16",
|
"@apollo/client": "^3.5.10",
|
||||||
"@headlessui/react": "^1.4.2",
|
"@headlessui/react": "^1.5.0",
|
||||||
"@heroicons/react": "^1.0.5",
|
"@heroicons/react": "^1.0.6",
|
||||||
"@nhost/nhost-js": "^1.0.0",
|
"@nhost/nhost-js": "workspace:*",
|
||||||
"@nhost/react": "^0.3.0",
|
"@nhost/react": "workspace:*",
|
||||||
"@nhost/react-apollo": "^4.0.0",
|
"@nhost/react-apollo": "workspace:*",
|
||||||
"@tailwindcss/forms": "^0.3.4",
|
"@tailwindcss/forms": "^0.5.0",
|
||||||
"@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",
|
|
||||||
"classnames": "^2.3.1",
|
"classnames": "^2.3.1",
|
||||||
"date-fns": "^2.28.0",
|
"date-fns": "^2.28.0",
|
||||||
"graphql": "^15.8.0",
|
"graphql": "15.7.2",
|
||||||
"graphql-tag": "^2.12.6",
|
"graphql-tag": "^2.12.6",
|
||||||
"pretty-bytes": "^5.6.0",
|
"pretty-bytes": "^5.6.0",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-router-dom": "^6.0.2",
|
"react-router-dom": "^6.3.0",
|
||||||
"react-scripts": "^5.0.0",
|
"tailwindcss": "^3.0.24"
|
||||||
"typescript": "^4.1.2",
|
|
||||||
"web-vitals": "^1.0.1"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "react-scripts start",
|
"dev": "vite",
|
||||||
"build": "react-scripts build",
|
"build": "vite build",
|
||||||
"test": "react-scripts test",
|
"preview": "vite preview",
|
||||||
"eject": "react-scripts eject",
|
"codegen": "graphql-codegen --config codegen.yaml --errors-only",
|
||||||
"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": {
|
"eslintConfig": {
|
||||||
"extends": [
|
"extends": [
|
||||||
@@ -55,15 +51,21 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@graphql-codegen/cli": "^2.2.1",
|
"@graphql-codegen/cli": "^2.6.2",
|
||||||
"@graphql-codegen/introspection": "^2.1.0",
|
"@graphql-codegen/introspection": "^2.1.1",
|
||||||
"@graphql-codegen/typescript": "^2.2.4",
|
"@graphql-codegen/typescript": "^2.4.8",
|
||||||
"@graphql-codegen/typescript-operations": "^2.1.8",
|
"@graphql-codegen/typescript-operations": "^2.3.5",
|
||||||
"@graphql-codegen/typescript-react-apollo": "^3.1.6",
|
"@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",
|
"@types/express": "^4.17.13",
|
||||||
"autoprefixer": "^9.8.8",
|
"@vitejs/plugin-react": "^1.3.1",
|
||||||
"express": "^4.17.1",
|
"autoprefixer": "^10.4.4",
|
||||||
"postcss": "^7.0.39",
|
"express": "^4.17.3",
|
||||||
"tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.2.17"
|
"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 { NhostReactProvider } from '@nhost/react'
|
||||||
import { NhostApolloProvider } from '@nhost/react-apollo'
|
import { NhostApolloProvider } from '@nhost/react-apollo'
|
||||||
import { nhost } from './utils/nhost'
|
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 { Layout } from './components/ui/Layout'
|
||||||
import { Customers } from './components/Customers'
|
import { Customers } from './components/Customers'
|
||||||
import { Dashboard } from './components/Dashboard'
|
import { Dashboard } from './components/Dashboard'
|
||||||
|
|||||||
@@ -3,91 +3,85 @@ import { Dialog, Transition } from '@headlessui/react'
|
|||||||
import { nhost } from '../utils/nhost'
|
import { nhost } from '../utils/nhost'
|
||||||
|
|
||||||
export function ChangePasswordModal() {
|
export function ChangePasswordModal() {
|
||||||
const [open, setOpen] = useState(true)
|
const [open, setOpen] = useState(true)
|
||||||
const [newPassword, setNewPassword] = useState('')
|
const [newPassword, setNewPassword] = useState('')
|
||||||
|
|
||||||
const handleSubmit = async (e: React.SyntheticEvent<HTMLFormElement>) => {
|
const handleSubmit = async (e: React.SyntheticEvent<HTMLFormElement>) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
const { error } = await nhost.auth.changePassword({ newPassword })
|
const { error } = await nhost.auth.changePassword({ newPassword })
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
return alert(error.message)
|
return alert(error.message)
|
||||||
}
|
}
|
||||||
|
|
||||||
setOpen(false)
|
setOpen(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Transition.Root show={open} as={Fragment}>
|
<Transition.Root show={open} as={Fragment}>
|
||||||
<Dialog as="div" className="fixed z-10 inset-0 overflow-y-auto" onClose={setOpen}>
|
<Dialog as="div" className="fixed inset-0 z-10 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">
|
<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
|
<Transition.Child
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
enter="ease-out duration-300"
|
enter="ease-out duration-300"
|
||||||
enterFrom="opacity-0"
|
enterFrom="opacity-0"
|
||||||
enterTo="opacity-100"
|
enterTo="opacity-100"
|
||||||
leave="ease-in duration-200"
|
leave="ease-in duration-200"
|
||||||
leaveFrom="opacity-100"
|
leaveFrom="opacity-100"
|
||||||
leaveTo="opacity-0"
|
leaveTo="opacity-0"
|
||||||
>
|
>
|
||||||
<Dialog.Overlay className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" />
|
<Dialog.Overlay className="fixed inset-0 transition-opacity bg-gray-500 bg-opacity-75" />
|
||||||
</Transition.Child>
|
</Transition.Child>
|
||||||
|
|
||||||
{/* This element is to trick the browser into centering the modal contents. */}
|
{/* This element is to trick the browser into centering the modal contents. */}
|
||||||
<span
|
<span className="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">
|
||||||
className="hidden sm:inline-block sm:align-middle sm:h-screen"
|
​
|
||||||
aria-hidden="true"
|
</span>
|
||||||
>
|
<Transition.Child
|
||||||
​
|
as={Fragment}
|
||||||
</span>
|
enter="ease-out duration-300"
|
||||||
<Transition.Child
|
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||||
as={Fragment}
|
enterTo="opacity-100 translate-y-0 sm:scale-100"
|
||||||
enter="ease-out duration-300"
|
leave="ease-in duration-200"
|
||||||
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
||||||
enterTo="opacity-100 translate-y-0 sm:scale-100"
|
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||||
leave="ease-in duration-200"
|
>
|
||||||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
<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">
|
||||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
<form onSubmit={handleSubmit}>
|
||||||
>
|
<div>
|
||||||
<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">
|
<div className="mt-3 text-center sm:mt-5">
|
||||||
<form onSubmit={handleSubmit}>
|
<Dialog.Title as="h3" className="text-lg font-medium leading-6 text-gray-900">
|
||||||
<div>
|
Change Password
|
||||||
<div className="mt-3 text-center sm:mt-5">
|
</Dialog.Title>
|
||||||
<Dialog.Title
|
<div className="mt-2">
|
||||||
as="h3"
|
<input
|
||||||
className="text-lg leading-6 font-medium text-gray-900"
|
id="password"
|
||||||
>
|
name="password"
|
||||||
Change Password
|
type="password"
|
||||||
</Dialog.Title>
|
autoComplete="current-password"
|
||||||
<div className="mt-2">
|
required
|
||||||
<input
|
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"
|
||||||
id="password"
|
tabIndex={2}
|
||||||
name="password"
|
value={newPassword}
|
||||||
type="password"
|
onChange={(e) => setNewPassword(e.target.value)}
|
||||||
autoComplete="current-password"
|
/>
|
||||||
required
|
</div>
|
||||||
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>
|
|
||||||
</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>
|
</div>
|
||||||
</Dialog>
|
</Transition.Child>
|
||||||
</Transition.Root>
|
</div>
|
||||||
)
|
</Dialog>
|
||||||
|
</Transition.Root>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,47 +1,47 @@
|
|||||||
import { Main } from "./ui/Main";
|
import { Main } from './ui/Main'
|
||||||
import { Breadcrumbs } from "./ui/Breadcrumbs";
|
import { Breadcrumbs } from './ui/Breadcrumbs'
|
||||||
import { HeaderSection } from "./ui/HeaderSection";
|
import { HeaderSection } from './ui/HeaderSection'
|
||||||
import { PageHeader } from "./ui/PageHeader";
|
import { PageHeader } from './ui/PageHeader'
|
||||||
|
|
||||||
import { useParams } from "react-router";
|
import { useParams } from 'react-router-dom'
|
||||||
import { useCustomerQuery } from "../utils/__generated__/graphql";
|
import { useCustomerQuery } from '../utils/__generated__/graphql'
|
||||||
import { NavLink, Outlet } from "react-router-dom";
|
import { NavLink, Outlet } from 'react-router-dom'
|
||||||
import classNames from "classnames";
|
import classNames from 'classnames'
|
||||||
import { CustomerActivities } from "./CustomerActivities";
|
import { CustomerActivities } from './CustomerActivities'
|
||||||
import { CustomerAddComment } from "./CustomerAddComment";
|
import { CustomerAddComment } from './CustomerAddComment'
|
||||||
|
|
||||||
const tabs = [
|
const tabs = [
|
||||||
{ name: "Overview", href: "" },
|
{ name: 'Overview', href: '' },
|
||||||
{ name: "Orders", href: "orders" },
|
{ name: 'Orders', href: 'orders' },
|
||||||
{ name: "Files", href: "files" },
|
{ name: 'Files', href: 'files' }
|
||||||
];
|
]
|
||||||
|
|
||||||
export function Customer() {
|
export function Customer() {
|
||||||
const { customerId } = useParams();
|
const { customerId } = useParams()
|
||||||
|
|
||||||
const { data, loading } = useCustomerQuery({
|
const { data, loading } = useCustomerQuery({
|
||||||
variables: {
|
variables: {
|
||||||
customerId,
|
customerId
|
||||||
},
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return <div>Loading..</div>;
|
return <div>Loading..</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data || !data.customer) {
|
if (!data || !data.customer) {
|
||||||
return <div>No customer..</div>;
|
return <div>No customer..</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
const { customer } = data;
|
const { customer } = data
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Main>
|
<Main>
|
||||||
<Breadcrumbs
|
<Breadcrumbs
|
||||||
backLink={""}
|
backLink={''}
|
||||||
breadcrumbs={[
|
breadcrumbs={[
|
||||||
{ link: "/customers", text: "Customers" },
|
{ link: '/customers', text: 'Customers' },
|
||||||
{ link: `customers/${customerId}`, text: customer.name },
|
{ link: `customers/${customerId}`, text: customer.name }
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
<HeaderSection>
|
<HeaderSection>
|
||||||
@@ -57,7 +57,7 @@ export function Customer() {
|
|||||||
id="current-tab"
|
id="current-tab"
|
||||||
name="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"
|
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>1</option>
|
||||||
<option>2</option>
|
<option>2</option>
|
||||||
@@ -71,10 +71,10 @@ export function Customer() {
|
|||||||
className={({ isActive }) => {
|
className={({ isActive }) => {
|
||||||
return classNames(
|
return classNames(
|
||||||
isActive
|
isActive
|
||||||
? "border-blue-500 text-blue-600"
|
? 'border-blue-500 text-blue-600'
|
||||||
: "border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300",
|
: '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"
|
'whitespace-nowrap pb-4 px-1 border-b-2 font-medium text-sm'
|
||||||
);
|
)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{tab.name}
|
{tab.name}
|
||||||
@@ -95,5 +95,5 @@ export function Customer() {
|
|||||||
<CustomerAddComment />
|
<CustomerAddComment />
|
||||||
</div>
|
</div>
|
||||||
</Main>
|
</Main>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,35 +1,35 @@
|
|||||||
import { ChatAltIcon } from "@heroicons/react/solid";
|
import { ChatAltIcon } from '@heroicons/react/solid'
|
||||||
import { useGetCustomerCommentsSubscription } from "../utils/__generated__/graphql";
|
import { useGetCustomerCommentsSubscription } from '../utils/__generated__/graphql'
|
||||||
import { useParams } from "react-router";
|
import { useParams } from 'react-router-dom'
|
||||||
import { nhost } from "../utils/nhost";
|
import { nhost } from '../utils/nhost'
|
||||||
import { PhotographIcon } from "@heroicons/react/outline";
|
import { PhotographIcon } from '@heroicons/react/outline'
|
||||||
import prettyBytes from "pretty-bytes";
|
import prettyBytes from 'pretty-bytes'
|
||||||
import { formatDistanceToNow, parseISO } from "date-fns";
|
import { formatDistanceToNow, parseISO } from 'date-fns'
|
||||||
|
|
||||||
export function CustomerActivities() {
|
export function CustomerActivities() {
|
||||||
const { customerId } = useParams();
|
const { customerId } = useParams<{ customerId: string }>()
|
||||||
|
|
||||||
const { data, loading } = useGetCustomerCommentsSubscription({
|
const { data, loading } = useGetCustomerCommentsSubscription({
|
||||||
variables: {
|
variables: {
|
||||||
where: {
|
where: {
|
||||||
customerId: {
|
customerId: {
|
||||||
_eq: customerId,
|
_eq: customerId
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
console.log({ data });
|
console.log({ data })
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return <div>Loading...</div>;
|
return <div>Loading...</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data || !data.customerComments) {
|
if (!data || !data.customerComments) {
|
||||||
return <div>no comments</div>;
|
return <div>no comments</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
const { customerComments } = data;
|
const { customerComments } = data
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flow-root">
|
<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">
|
<span className="absolute -bottom-0.5 -right-1 bg-white rounded-tl px-0.5 py-px">
|
||||||
<ChatAltIcon
|
<ChatAltIcon className="w-5 h-5 text-gray-400" aria-hidden="true" />
|
||||||
className="w-5 h-5 text-gray-400"
|
|
||||||
aria-hidden="true"
|
|
||||||
/>
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1 min-w-0">
|
<div className="flex-1 min-w-0">
|
||||||
@@ -69,7 +66,7 @@ export function CustomerActivities() {
|
|||||||
</div>
|
</div>
|
||||||
<p className="mt-0.5 text-sm text-gray-500">
|
<p className="mt-0.5 text-sm text-gray-500">
|
||||||
{formatDistanceToNow(parseISO(comment.createdAt), {
|
{formatDistanceToNow(parseISO(comment.createdAt), {
|
||||||
addSuffix: true,
|
addSuffix: true
|
||||||
})}
|
})}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -80,24 +77,22 @@ export function CustomerActivities() {
|
|||||||
<div
|
<div
|
||||||
className="flex items-center mt-3 text-sm text-gray-700 cursor-pointer"
|
className="flex items-center mt-3 text-sm text-gray-700 cursor-pointer"
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
const { presignedUrl, error } =
|
const { presignedUrl, error } = await nhost.storage.getPresignedUrl({
|
||||||
await nhost.storage.getPresignedUrl({
|
fileId: comment.file!.id
|
||||||
fileId: comment.file!.id,
|
})
|
||||||
});
|
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
return alert(error.message);
|
return alert(error.message)
|
||||||
}
|
}
|
||||||
|
|
||||||
window.open(presignedUrl?.url, "_blank");
|
window.open(presignedUrl?.url, '_blank')
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<PhotographIcon className="w-5 mr-1 text-gray-500" />
|
<PhotographIcon className="w-5 mr-1 text-gray-500" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{comment.file.name},{" "}
|
{comment.file.name}, {prettyBytes(comment.file.size as number)}
|
||||||
{prettyBytes(comment.file.size as number)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -106,9 +101,9 @@ export function CustomerActivities() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
);
|
)
|
||||||
})}
|
})}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +1,31 @@
|
|||||||
import { useState } from "react";
|
import { useState } from 'react'
|
||||||
import { useParams } from "react-router";
|
import { useParams } from 'react-router-dom'
|
||||||
import { nhost } from "../utils/nhost";
|
import { nhost } from '../utils/nhost'
|
||||||
import { useInsertCustomerCommentMutation } from "../utils/__generated__/graphql";
|
import { useInsertCustomerCommentMutation } from '../utils/__generated__/graphql'
|
||||||
|
|
||||||
export function CustomerAddComment() {
|
export function CustomerAddComment() {
|
||||||
const [text, setText] = useState("");
|
const [text, setText] = useState('')
|
||||||
const [file, setFile] = useState<null | File>(null);
|
const [file, setFile] = useState<null | File>(null)
|
||||||
|
|
||||||
const { customerId } = useParams();
|
const { customerId } = useParams<{ customerId: string }>()
|
||||||
const [insertCustomerComment, { loading }] =
|
const [insertCustomerComment, { loading }] = useInsertCustomerCommentMutation()
|
||||||
useInsertCustomerCommentMutation();
|
|
||||||
|
|
||||||
const handleSubmit = async (e: React.SyntheticEvent<HTMLFormElement>) => {
|
const handleSubmit = async (e: React.SyntheticEvent<HTMLFormElement>) => {
|
||||||
e.preventDefault();
|
e.preventDefault()
|
||||||
|
|
||||||
let fileMetadata;
|
let fileMetadata
|
||||||
if (file) {
|
if (file) {
|
||||||
const fileUploadRes = await nhost.storage.upload({
|
const fileUploadRes = await nhost.storage.upload({
|
||||||
file,
|
file,
|
||||||
bucketId: "customerComments",
|
bucketId: 'customerComments'
|
||||||
});
|
})
|
||||||
|
|
||||||
if (fileUploadRes.error) {
|
if (fileUploadRes.error) {
|
||||||
alert(`error: ${fileUploadRes.error}`);
|
alert(`error: ${fileUploadRes.error}`)
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fileMetadata = fileUploadRes.fileMetadata;
|
fileMetadata = fileUploadRes.fileMetadata
|
||||||
}
|
}
|
||||||
|
|
||||||
await insertCustomerComment({
|
await insertCustomerComment({
|
||||||
@@ -34,21 +33,18 @@ export function CustomerAddComment() {
|
|||||||
customerComment: {
|
customerComment: {
|
||||||
text,
|
text,
|
||||||
customerId,
|
customerId,
|
||||||
fileId: fileMetadata ? fileMetadata.id : null,
|
fileId: fileMetadata ? fileMetadata.id : null
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
setText("");
|
setText('')
|
||||||
};
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="max-w-lg mx-auto">
|
<div className="max-w-lg mx-auto">
|
||||||
<form onSubmit={handleSubmit}>
|
<form onSubmit={handleSubmit}>
|
||||||
<label
|
<label htmlFor="email" className="block text-sm font-medium text-gray-700">
|
||||||
htmlFor="email"
|
|
||||||
className="block text-sm font-medium text-gray-700"
|
|
||||||
>
|
|
||||||
Comment
|
Comment
|
||||||
</label>
|
</label>
|
||||||
<div className="mt-1">
|
<div className="mt-1">
|
||||||
@@ -57,7 +53,7 @@ export function CustomerAddComment() {
|
|||||||
name="about"
|
name="about"
|
||||||
rows={3}
|
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"
|
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}
|
value={text}
|
||||||
onChange={(e) => setText(e.target.value)}
|
onChange={(e) => setText(e.target.value)}
|
||||||
/>
|
/>
|
||||||
@@ -94,7 +90,7 @@ export function CustomerAddComment() {
|
|||||||
className="sr-only"
|
className="sr-only"
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
if (e.target.files && e.target.files.length > 0) {
|
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 ? (
|
{file ? (
|
||||||
<div>{file.name}</div>
|
<div>{file.name}</div>
|
||||||
) : (
|
) : (
|
||||||
<p className="text-xs text-gray-500">
|
<p className="text-xs text-gray-500">PNG, JPG, GIF up to 10MB</p>
|
||||||
PNG, JPG, GIF up to 10MB
|
|
||||||
</p>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -124,5 +118,5 @@ export function CustomerAddComment() {
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,15 @@
|
|||||||
import { Main } from "./ui/Main";
|
import { Main } from './ui/Main'
|
||||||
import { Breadcrumbs } from "./ui/Breadcrumbs";
|
import { Breadcrumbs } from './ui/Breadcrumbs'
|
||||||
import { HeaderSection } from "./ui/HeaderSection";
|
import { HeaderSection } from './ui/HeaderSection'
|
||||||
import { PageHeader } from "./ui/PageHeader";
|
import { PageHeader } from './ui/PageHeader'
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from 'react-router-dom'
|
||||||
import { useGetCustomersSubscription } from "../utils/__generated__/graphql";
|
import { useGetCustomersSubscription } from '../utils/__generated__/graphql'
|
||||||
import { ChevronLeftIcon, ChevronRightIcon } from "@heroicons/react/solid";
|
import { ChevronLeftIcon, ChevronRightIcon } from '@heroicons/react/solid'
|
||||||
|
|
||||||
export function Customers() {
|
export function Customers() {
|
||||||
return (
|
return (
|
||||||
<Main>
|
<Main>
|
||||||
<Breadcrumbs
|
<Breadcrumbs backLink={''} breadcrumbs={[{ link: '/customers', text: 'Customers' }]} />
|
||||||
backLink={""}
|
|
||||||
breadcrumbs={[{ link: "/customers", text: "Customers" }]}
|
|
||||||
/>
|
|
||||||
<HeaderSection>
|
<HeaderSection>
|
||||||
<PageHeader>Customers</PageHeader>
|
<PageHeader>Customers</PageHeader>
|
||||||
<div className="flex flex-shrink-0 mt-4 md:mt-0 md:ml-4">
|
<div className="flex flex-shrink-0 mt-4 md:mt-0 md:ml-4">
|
||||||
@@ -31,11 +28,11 @@ export function Customers() {
|
|||||||
<CustomersList />
|
<CustomersList />
|
||||||
</div>
|
</div>
|
||||||
</Main>
|
</Main>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function CustomersList() {
|
function CustomersList() {
|
||||||
const { data } = useGetCustomersSubscription();
|
const { data } = useGetCustomersSubscription()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@@ -57,17 +54,14 @@ function CustomersList() {
|
|||||||
<tbody>
|
<tbody>
|
||||||
{data?.customers.map((customer, i) => {
|
{data?.customers.map((customer, i) => {
|
||||||
return (
|
return (
|
||||||
<tr
|
<tr key={customer.id} className={i % 2 === 0 ? 'bg-white' : 'bg-gray-50'}>
|
||||||
key={customer.id}
|
|
||||||
className={i % 2 === 0 ? "bg-white" : "bg-gray-50"}
|
|
||||||
>
|
|
||||||
<td className="text-sm font-medium text-gray-900 whitespace-nowrap">
|
<td className="text-sm font-medium text-gray-900 whitespace-nowrap">
|
||||||
<Link to={customer.id} className="block px-6 py-4">
|
<Link to={customer.id} className="block px-6 py-4">
|
||||||
{customer.name}
|
{customer.name}
|
||||||
</Link>
|
</Link>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
)
|
||||||
})}
|
})}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@@ -88,9 +82,9 @@ function CustomersList() {
|
|||||||
<div className="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between">
|
<div className="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm text-gray-700">
|
<p className="text-sm text-gray-700">
|
||||||
Showing <span className="font-medium">1</span> to{" "}
|
Showing <span className="font-medium">1</span> to{' '}
|
||||||
<span className="font-medium">10</span> of{" "}
|
<span className="font-medium">10</span> of <span className="font-medium">97</span>{' '}
|
||||||
<span className="font-medium">97</span> results
|
results
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -136,5 +130,5 @@ function CustomersList() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Main } from "./ui/Main";
|
import { Main } from './ui/Main'
|
||||||
|
|
||||||
export function Dashboard() {
|
export function Dashboard() {
|
||||||
return <Main>Dashboard</Main>;
|
return <Main>Dashboard</Main>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,67 +1,64 @@
|
|||||||
import { useState } from "react";
|
import { useState } from 'react'
|
||||||
import { Main } from "./ui/Main";
|
import { Main } from './ui/Main'
|
||||||
import { Breadcrumbs } from "./ui/Breadcrumbs";
|
import { Breadcrumbs } from './ui/Breadcrumbs'
|
||||||
import { HeaderSection } from "./ui/HeaderSection";
|
import { HeaderSection } from './ui/HeaderSection'
|
||||||
import { PageHeader } from "./ui/PageHeader";
|
import { PageHeader } from './ui/PageHeader'
|
||||||
import {
|
import { useGetCompanyWhereQuery, useInsertCustomerMutation } from '../utils/__generated__/graphql'
|
||||||
useGetCompanyWhereQuery,
|
import { nhost } from '../utils/nhost'
|
||||||
useInsertCustomerMutation,
|
import { useNavigate } from 'react-router-dom'
|
||||||
} from "../utils/__generated__/graphql";
|
|
||||||
import { nhost } from "../utils/nhost";
|
|
||||||
import { useNavigate } from "react-router";
|
|
||||||
|
|
||||||
export function NewCustomer() {
|
export function NewCustomer() {
|
||||||
const [name, setName] = useState("");
|
const [name, setName] = useState('')
|
||||||
const [email, setEmail] = useState("");
|
const [email, setEmail] = useState('')
|
||||||
const [addressLine1, setAddressLine1] = useState("");
|
const [addressLine1, setAddressLine1] = useState('')
|
||||||
|
|
||||||
const user = nhost.auth.getUser();
|
const user = nhost.auth.getUser()
|
||||||
let navigate = useNavigate();
|
let navigate = useNavigate()
|
||||||
|
|
||||||
const { data } = useGetCompanyWhereQuery({
|
const { data } = useGetCompanyWhereQuery({
|
||||||
variables: {
|
variables: {
|
||||||
where: {
|
where: {
|
||||||
companyUsers: {
|
companyUsers: {
|
||||||
userId: {
|
userId: {
|
||||||
_eq: user?.id,
|
_eq: user?.id
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
const [insertCustomer, { loading }] = useInsertCustomerMutation();
|
const [insertCustomer, { loading }] = useInsertCustomerMutation()
|
||||||
|
|
||||||
const handleSubmit = async (e: React.SyntheticEvent<HTMLFormElement>) => {
|
const handleSubmit = async (e: React.SyntheticEvent<HTMLFormElement>) => {
|
||||||
e.preventDefault();
|
e.preventDefault()
|
||||||
|
|
||||||
console.log("handle submit");
|
console.log('handle submit')
|
||||||
|
|
||||||
let res;
|
let res
|
||||||
try {
|
try {
|
||||||
res = await insertCustomer({
|
res = await insertCustomer({
|
||||||
variables: {
|
variables: {
|
||||||
customer: {
|
customer: {
|
||||||
name,
|
name,
|
||||||
addressLine1,
|
addressLine1,
|
||||||
companyId: data?.companies[0].id,
|
companyId: data?.companies[0].id
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return alert(`error: ${error}`);
|
return alert(`error: ${error}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
navigate(`/customers/${res.data?.insertCustomer?.id}`);
|
navigate(`/customers/${res.data?.insertCustomer?.id}`)
|
||||||
};
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Main>
|
<Main>
|
||||||
<Breadcrumbs
|
<Breadcrumbs
|
||||||
backLink={""}
|
backLink={''}
|
||||||
breadcrumbs={[
|
breadcrumbs={[
|
||||||
{ link: "/customers", text: "Customers" },
|
{ link: '/customers', text: 'Customers' },
|
||||||
{ link: "/new-customer", text: "New Customer" },
|
{ link: '/new-customer', text: 'New Customer' }
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
<HeaderSection>
|
<HeaderSection>
|
||||||
@@ -73,10 +70,7 @@ export function NewCustomer() {
|
|||||||
<div className="pt-12">
|
<div className="pt-12">
|
||||||
<div className="grid grid-cols-1 mt-6 gap-y-6 gap-x-4 sm:grid-cols-6">
|
<div className="grid grid-cols-1 mt-6 gap-y-6 gap-x-4 sm:grid-cols-6">
|
||||||
<div className="sm:col-span-3">
|
<div className="sm:col-span-3">
|
||||||
<label
|
<label htmlFor="first-name" className="block text-sm font-medium text-gray-700">
|
||||||
htmlFor="first-name"
|
|
||||||
className="block text-sm font-medium text-gray-700"
|
|
||||||
>
|
|
||||||
Name
|
Name
|
||||||
</label>
|
</label>
|
||||||
<div className="mt-1">
|
<div className="mt-1">
|
||||||
@@ -93,10 +87,7 @@ export function NewCustomer() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="sm:col-span-3">
|
<div className="sm:col-span-3">
|
||||||
<label
|
<label htmlFor="email" className="block text-sm font-medium text-gray-700">
|
||||||
htmlFor="email"
|
|
||||||
className="block text-sm font-medium text-gray-700"
|
|
||||||
>
|
|
||||||
Email address
|
Email address
|
||||||
</label>
|
</label>
|
||||||
<div className="mt-1">
|
<div className="mt-1">
|
||||||
@@ -113,10 +104,7 @@ export function NewCustomer() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="sm:col-span-6">
|
<div className="sm:col-span-6">
|
||||||
<label
|
<label htmlFor="street-address" className="block text-sm font-medium text-gray-700">
|
||||||
htmlFor="street-address"
|
|
||||||
className="block text-sm font-medium text-gray-700"
|
|
||||||
>
|
|
||||||
Street address
|
Street address
|
||||||
</label>
|
</label>
|
||||||
<div className="mt-1">
|
<div className="mt-1">
|
||||||
@@ -147,5 +135,5 @@ export function NewCustomer() {
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</Main>
|
</Main>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useNhostAuth } from '@nhost/react'
|
import { useNhostAuth } from '@nhost/react'
|
||||||
import React from '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 }) {
|
export function RequireAuth({ children }: { children: JSX.Element }) {
|
||||||
const { isAuthenticated, isLoading } = useNhostAuth()
|
const { isAuthenticated, isLoading } = useNhostAuth()
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useNhostAuth } from '@nhost/react'
|
import { useNhostAuth } from '@nhost/react'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { useNavigate } from 'react-router'
|
import { useNavigate } from 'react-router-dom'
|
||||||
import { nhost } from '../utils/nhost'
|
import { nhost } from '../utils/nhost'
|
||||||
|
|
||||||
export function ResetPassword() {
|
export function ResetPassword() {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useNhostAuth } from '@nhost/react'
|
import { useNhostAuth } from '@nhost/react'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { useNavigate } from 'react-router'
|
import { useNavigate } from 'react-router-dom'
|
||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom'
|
||||||
import { nhost } from '../utils/nhost'
|
import { nhost } from '../utils/nhost'
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useNhostAuth } from '@nhost/react'
|
import { useNhostAuth } from '@nhost/react'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { useNavigate } from 'react-router'
|
import { useNavigate } from 'react-router-dom'
|
||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom'
|
||||||
import { nhost } from '../utils/nhost'
|
import { nhost } from '../utils/nhost'
|
||||||
|
|
||||||
@@ -93,7 +93,7 @@ export function SignUp() {
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="text-center py-4">
|
<div className="py-4 text-center">
|
||||||
Already have an account?{' '}
|
Already have an account?{' '}
|
||||||
<Link to="/sign-in" className="text-blue-600 hover:text-blue-500">
|
<Link to="/sign-in" className="text-blue-600 hover:text-blue-500">
|
||||||
Sign In
|
Sign In
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
import { ChevronLeftIcon, ChevronRightIcon } from "@heroicons/react/solid";
|
import { ChevronLeftIcon, ChevronRightIcon } from '@heroicons/react/solid'
|
||||||
import classNames from "classnames";
|
import classNames from 'classnames'
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from 'react-router-dom'
|
||||||
|
|
||||||
type BreadcrumbsProps = {
|
type BreadcrumbsProps = {
|
||||||
backLink: string;
|
backLink: string
|
||||||
breadcrumbs: Breadcrumb[];
|
breadcrumbs: Breadcrumb[]
|
||||||
};
|
}
|
||||||
|
|
||||||
type Breadcrumb = {
|
type Breadcrumb = {
|
||||||
link: string;
|
link: string
|
||||||
text: string;
|
text: string
|
||||||
};
|
}
|
||||||
|
|
||||||
export function Breadcrumbs(props: BreadcrumbsProps) {
|
export function Breadcrumbs(props: BreadcrumbsProps) {
|
||||||
const { backLink, breadcrumbs } = props;
|
const { backLink, breadcrumbs } = props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@@ -32,13 +32,10 @@ export function Breadcrumbs(props: BreadcrumbsProps) {
|
|||||||
<nav className="hidden sm:flex" aria-label="Breadcrumb">
|
<nav className="hidden sm:flex" aria-label="Breadcrumb">
|
||||||
<ol className="flex items-center space-x-4">
|
<ol className="flex items-center space-x-4">
|
||||||
{breadcrumbs.map((breadcrumb, i) => {
|
{breadcrumbs.map((breadcrumb, i) => {
|
||||||
const isFirstItem = i === 0;
|
const isFirstItem = i === 0
|
||||||
const classes = classNames(
|
const classes = classNames('text-sm font-medium text-gray-500 hover:text-gray-700', {
|
||||||
"text-sm font-medium text-gray-500 hover:text-gray-700",
|
'ml-4': !isFirstItem
|
||||||
{
|
})
|
||||||
"ml-4": !isFirstItem,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li key={i}>
|
<li key={i}>
|
||||||
@@ -54,10 +51,10 @@ export function Breadcrumbs(props: BreadcrumbsProps) {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
);
|
)
|
||||||
})}
|
})}
|
||||||
</ol>
|
</ol>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
import React from "react";
|
import React from 'react'
|
||||||
|
|
||||||
export function HeaderSection({ children }: { children: React.ReactNode }) {
|
export function HeaderSection({ children }: { children: React.ReactNode }) {
|
||||||
return (
|
return <div className="mt-2 md:flex md:items-center md:justify-between">{children}</div>
|
||||||
<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 }) {
|
export function Main({ children }: { children: React.ReactNode }) {
|
||||||
return (
|
return <div className="px-4 mx-auto max-w-7xl sm:px-6 lg:px-8">{children}</div>
|
||||||
<div className="max-w-7xl mx-auto px-4 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 }) {
|
export function PageHeader({ children }: { children: React.ReactNode }) {
|
||||||
return (
|
return (
|
||||||
@@ -7,5 +7,5 @@ export function PageHeader({ children }: { children: React.ReactNode }) {
|
|||||||
{children}
|
{children}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</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(
|
mutation insertCustomerComment($customerComment: customerComments_insert_input!) {
|
||||||
$customerComment: customerComments_insert_input!
|
|
||||||
) {
|
|
||||||
insertCustomerComment(object: $customerComment) {
|
insertCustomerComment(object: $customerComment) {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu',
|
||||||
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
|
'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
|
||||||
sans-serif;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
code {
|
code {
|
||||||
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
|
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
|
||||||
monospace;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@tailwind base;
|
@tailwind base;
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import React from "react";
|
import React from 'react'
|
||||||
import ReactDOM from "react-dom";
|
import ReactDOM from 'react-dom'
|
||||||
import "./index.css";
|
import './index.css'
|
||||||
import App from "./App";
|
import App from './App'
|
||||||
import reportWebVitals from "./reportWebVitals";
|
import { BrowserRouter } from 'react-router-dom'
|
||||||
import { BrowserRouter } from "react-router-dom";
|
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
@@ -11,10 +10,5 @@ ReactDOM.render(
|
|||||||
<App />
|
<App />
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
</React.StrictMode>,
|
</React.StrictMode>,
|
||||||
document.getElementById("root")
|
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();
|
|
||||||
|
|||||||
@@ -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:
|
// allows you to do things like:
|
||||||
// expect(element).toHaveTextContent(/react/i)
|
// expect(element).toHaveTextContent(/react/i)
|
||||||
// learn more: https://github.com/testing-library/jest-dom
|
// 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'
|
import { NhostClient } from '@nhost/react'
|
||||||
|
|
||||||
const nhost = new NhostClient({
|
const nhost = new NhostClient({
|
||||||
backendUrl: process.env.REACT_APP_BACKEND_URL!
|
backendUrl: import.meta.env.VITE_NHOST_URL || 'http://localhost:1337'
|
||||||
})
|
})
|
||||||
|
|
||||||
export { nhost }
|
export { nhost }
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
purge: ["./src/**/*.{js,jsx,ts,tsx}", "./public/index.html"],
|
content: ['./src/**/*.{js,jsx,ts,tsx}', './index.html'],
|
||||||
darkMode: false, // or 'media' or 'class'
|
darkMode: 'media',
|
||||||
theme: {
|
theme: {
|
||||||
extend: {},
|
extend: {}
|
||||||
},
|
},
|
||||||
variants: {
|
variants: {
|
||||||
extend: {},
|
extend: {}
|
||||||
},
|
},
|
||||||
plugins: [require("@tailwindcss/forms")],
|
plugins: [require('@tailwindcss/forms')]
|
||||||
};
|
}
|
||||||
|
|||||||
@@ -1,20 +1,9 @@
|
|||||||
{
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es6",
|
"outDir": "dist",
|
||||||
"lib": ["dom", "dom.iterable", "esnext"],
|
"composite": true,
|
||||||
"allowJs": true,
|
"module": "esnext"
|
||||||
"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"
|
|
||||||
},
|
},
|
||||||
"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
|
# React-Apollo example
|
||||||
|
|
||||||
Once in the example's directory, run the two following commands in parallel:
|
## Get started
|
||||||
|
|
||||||
|
1. Clone the repository
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
# Start the Nhost CLI in the background
|
git clone https://github.com/nhost/nhost
|
||||||
nhost -d
|
cd nhost
|
||||||
|
```
|
||||||
# Start this project
|
|
||||||
yarn run dev
|
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:
|
environment:
|
||||||
hasura_graphql_enable_remote_schema_permissions: false
|
hasura_graphql_enable_remote_schema_permissions: false
|
||||||
auth:
|
auth:
|
||||||
version: 0.4.2
|
version: 0.6.3
|
||||||
auth:
|
auth:
|
||||||
access_control:
|
access_control:
|
||||||
email:
|
email:
|
||||||
@@ -15,8 +15,7 @@ auth:
|
|||||||
allowed_emails: ''
|
allowed_emails: ''
|
||||||
blocked_email_domains: ''
|
blocked_email_domains: ''
|
||||||
blocked_emails: ''
|
blocked_emails: ''
|
||||||
url:
|
allowed_redirect_urls: ''
|
||||||
allowed_redirect_urls: ''
|
|
||||||
anonymous_users_enabled: false
|
anonymous_users_enabled: false
|
||||||
client_url: http://localhost:3000
|
client_url: http://localhost:3000
|
||||||
disable_new_users: false
|
disable_new_users: false
|
||||||
|
|||||||
@@ -1,18 +1,14 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
</head>
|
||||||
|
|
||||||
<head>
|
<body>
|
||||||
<meta charset="utf-8" />
|
<h2>Confirm Email Change</h2>
|
||||||
</head>
|
<p>Use this link to confirm changing email:</p>
|
||||||
|
<p>
|
||||||
<body>
|
<a href="${link}"> Change email </a>
|
||||||
<h2>Confirm Email Change</h2>
|
</p>
|
||||||
<p>Use this link to confirm changing email:</p>
|
</body>
|
||||||
<p>
|
</html>
|
||||||
<a href="${link}">
|
|
||||||
Change email
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
|
|||||||
@@ -1,18 +1,14 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
</head>
|
||||||
|
|
||||||
<head>
|
<body>
|
||||||
<meta charset="utf-8" />
|
<h2>Verify Email</h2>
|
||||||
</head>
|
<p>Use this link to verify your email:</p>
|
||||||
|
<p>
|
||||||
<body>
|
<a href="${link}"> Verify Email </a>
|
||||||
<h2>Verify Email</h2>
|
</p>
|
||||||
<p>Use this link to verify your email:</p>
|
</body>
|
||||||
<p>
|
</html>
|
||||||
<a href="${link}">
|
|
||||||
Verify Email
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
|
|||||||
@@ -1,18 +1,14 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
</head>
|
||||||
|
|
||||||
<head>
|
<body>
|
||||||
<meta charset="utf-8" />
|
<h2>Reset Password</h2>
|
||||||
</head>
|
<p>Use this link to reset your password:</p>
|
||||||
|
<p>
|
||||||
<body>
|
<a href="${link}"> Reset password </a>
|
||||||
<h2>Reset Password</h2>
|
</p>
|
||||||
<p>Use this link to reset your password:</p>
|
</body>
|
||||||
<p>
|
</html>
|
||||||
<a href="${link}">
|
|
||||||
Reset password
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
|
|||||||
@@ -1,18 +1,14 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
</head>
|
||||||
|
|
||||||
<head>
|
<body>
|
||||||
<meta charset="utf-8" />
|
<h2>Magic Link</h2>
|
||||||
</head>
|
<p>Use this link to securely sign in:</p>
|
||||||
|
<p>
|
||||||
<body>
|
<a href="${link}"> Sign In </a>
|
||||||
<h2>Magic Link</h2>
|
</p>
|
||||||
<p>Use this link to securely sign in:</p>
|
</body>
|
||||||
<p>
|
</html>
|
||||||
<a href="${link}">
|
|
||||||
Sign In
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
|
|||||||
@@ -1,18 +1,14 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
</head>
|
||||||
|
|
||||||
<head>
|
<body>
|
||||||
<meta charset="utf-8" />
|
<h2>Confirmer changement de courriel</h2>
|
||||||
</head>
|
<p>Utilisez ce lien pour confirmer le changement de courriel:</p>
|
||||||
|
<p>
|
||||||
<body>
|
<a href="${link}"> Changer courriel </a>
|
||||||
<h2>Confirmer changement de courriel</h2>
|
</p>
|
||||||
<p>Utilisez ce lien pour confirmer le changement de courriel:</p>
|
</body>
|
||||||
<p>
|
</html>
|
||||||
<a href="${link}">
|
|
||||||
Changer courriel
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
|
|||||||
@@ -1,18 +1,14 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
</head>
|
||||||
|
|
||||||
<head>
|
<body>
|
||||||
<meta charset="utf-8" />
|
<h2>Vérifiez votre courriel</h2>
|
||||||
</head>
|
<p>Utilisez ce lien pour vérifier votre courriel:</p>
|
||||||
|
<p>
|
||||||
<body>
|
<a href="${link}"> Vérifier courriel </a>
|
||||||
<h2>Vérifiez votre courriel</h2>
|
</p>
|
||||||
<p>Utilisez ce lien pour vérifier votre courriel:</p>
|
</body>
|
||||||
<p>
|
</html>
|
||||||
<a href="${link}">
|
|
||||||
Vérifier courriel
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
|
|||||||
@@ -1,18 +1,14 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
</head>
|
||||||
|
|
||||||
<head>
|
<body>
|
||||||
<meta charset="utf-8" />
|
<h2>Réinitializer votre mot de passe</h2>
|
||||||
</head>
|
<p>Utilisez ce lien pour réinitializer votre mot de passe:</p>
|
||||||
|
<p>
|
||||||
<body>
|
<a href="${link}"> Réinitializer mot de passe </a>
|
||||||
<h2>Réinitializer votre mot de passe</h2>
|
</p>
|
||||||
<p>Utilisez ce lien pour réinitializer votre mot de passe:</p>
|
</body>
|
||||||
<p>
|
</html>
|
||||||
<a href="${link}">
|
|
||||||
Réinitializer mot de passe
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
|
|||||||
@@ -1,18 +1,14 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
</head>
|
||||||
|
|
||||||
<head>
|
<body>
|
||||||
<meta charset="utf-8" />
|
<h2>Lien magique</h2>
|
||||||
</head>
|
<p>Utilisez ce lien pour vous connecter de façon sécuritaire:</p>
|
||||||
|
<p>
|
||||||
<body>
|
<a href="${link}"> Connexion </a>
|
||||||
<h2>Lien magique</h2>
|
</p>
|
||||||
<p>Utilisez ce lien pour vous connecter de façon sécuritaire:</p>
|
</body>
|
||||||
<p>
|
</html>
|
||||||
<a href="${link}">
|
|
||||||
Connexion
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
|
|||||||
@@ -11,4 +11,4 @@
|
|||||||
max_connections: 50
|
max_connections: 50
|
||||||
retries: 20
|
retries: 20
|
||||||
use_prepared_statements: true
|
use_prepared_statements: true
|
||||||
tables: "!include default/tables/tables.yaml"
|
tables: '!include default/tables/tables.yaml'
|
||||||
|
|||||||
@@ -15,10 +15,10 @@ configuration:
|
|||||||
update: updateAuthProviders
|
update: updateAuthProviders
|
||||||
update_by_pk: updateAuthProvider
|
update_by_pk: updateAuthProvider
|
||||||
array_relationships:
|
array_relationships:
|
||||||
- name: userProviders
|
- name: userProviders
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
column: provider_id
|
column: provider_id
|
||||||
table:
|
table:
|
||||||
name: user_providers
|
name: user_providers
|
||||||
schema: auth
|
schema: auth
|
||||||
|
|||||||
@@ -19,6 +19,6 @@ configuration:
|
|||||||
update: updateAuthRefreshTokens
|
update: updateAuthRefreshTokens
|
||||||
update_by_pk: updateAuthRefreshToken
|
update_by_pk: updateAuthRefreshToken
|
||||||
object_relationships:
|
object_relationships:
|
||||||
- name: user
|
- name: user
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on: user_id
|
foreign_key_constraint_on: user_id
|
||||||
|
|||||||
@@ -15,17 +15,17 @@ configuration:
|
|||||||
update: updateAuthRoles
|
update: updateAuthRoles
|
||||||
update_by_pk: updateAuthRole
|
update_by_pk: updateAuthRole
|
||||||
array_relationships:
|
array_relationships:
|
||||||
- name: userRoles
|
- name: userRoles
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
column: role
|
column: role
|
||||||
table:
|
table:
|
||||||
name: user_roles
|
name: user_roles
|
||||||
schema: auth
|
schema: auth
|
||||||
- name: usersByDefaultRole
|
- name: usersByDefaultRole
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
column: default_role
|
column: default_role
|
||||||
table:
|
table:
|
||||||
name: users
|
name: users
|
||||||
schema: auth
|
schema: auth
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ configuration:
|
|||||||
update: updateAuthUserProviders
|
update: updateAuthUserProviders
|
||||||
update_by_pk: updateAuthUserProvider
|
update_by_pk: updateAuthUserProvider
|
||||||
object_relationships:
|
object_relationships:
|
||||||
- name: provider
|
- name: provider
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on: provider_id
|
foreign_key_constraint_on: provider_id
|
||||||
- name: user
|
- name: user
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on: user_id
|
foreign_key_constraint_on: user_id
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ configuration:
|
|||||||
update: updateAuthUserRoles
|
update: updateAuthUserRoles
|
||||||
update_by_pk: updateAuthUserRole
|
update_by_pk: updateAuthUserRole
|
||||||
object_relationships:
|
object_relationships:
|
||||||
- name: roleByRole
|
- name: roleByRole
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on: role
|
foreign_key_constraint_on: role
|
||||||
- name: user
|
- name: user
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on: user_id
|
foreign_key_constraint_on: user_id
|
||||||
|
|||||||
@@ -33,28 +33,28 @@ configuration:
|
|||||||
update: updateUsers
|
update: updateUsers
|
||||||
update_by_pk: updateUser
|
update_by_pk: updateUser
|
||||||
object_relationships:
|
object_relationships:
|
||||||
- name: defaultRoleByRole
|
- name: defaultRoleByRole
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on: default_role
|
foreign_key_constraint_on: default_role
|
||||||
array_relationships:
|
array_relationships:
|
||||||
- name: refreshTokens
|
- name: refreshTokens
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
column: user_id
|
column: user_id
|
||||||
table:
|
table:
|
||||||
name: refresh_tokens
|
name: refresh_tokens
|
||||||
schema: auth
|
schema: auth
|
||||||
- name: roles
|
- name: roles
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
column: user_id
|
column: user_id
|
||||||
table:
|
table:
|
||||||
name: user_roles
|
name: user_roles
|
||||||
schema: auth
|
schema: auth
|
||||||
- name: userProviders
|
- name: userProviders
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
column: user_id
|
column: user_id
|
||||||
table:
|
table:
|
||||||
name: user_providers
|
name: user_providers
|
||||||
schema: auth
|
schema: auth
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ table:
|
|||||||
name: books
|
name: books
|
||||||
schema: public
|
schema: public
|
||||||
select_permissions:
|
select_permissions:
|
||||||
- permission:
|
- permission:
|
||||||
columns:
|
columns:
|
||||||
- id
|
- id
|
||||||
- title
|
- title
|
||||||
filter: {}
|
filter: {}
|
||||||
role: user
|
role: user
|
||||||
|
|||||||
@@ -23,10 +23,10 @@ configuration:
|
|||||||
update: updateBuckets
|
update: updateBuckets
|
||||||
update_by_pk: updateBucket
|
update_by_pk: updateBucket
|
||||||
array_relationships:
|
array_relationships:
|
||||||
- name: files
|
- name: files
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
column: bucket_id
|
column: bucket_id
|
||||||
table:
|
table:
|
||||||
name: files
|
name: files
|
||||||
schema: storage
|
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