Compare commits

..

17 Commits

Author SHA1 Message Date
github-actions[bot]
4854df4559 chore: update versions (#3099)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @nhost/hasura-auth-js@2.9.0

### Minor Changes

- b944d05: feat: introduce `initWithSession` to initialize auth client
with an existing session

## @nhost/hasura-storage-js@2.6.0

### Minor Changes

- 4148964: fix: stack overflow on storage client getHeaders method call

## @nhost/nextjs@2.2.0

### Minor Changes

- 46fc520: chore: add support to next.js 15, update quickstart template
commands in docs
-   29d27e1: chore: update `next` to v14.2.22 to fix vulnerabilities

### Patch Changes

-   @nhost/react@3.8.1

## @nhost/apollo@8.0.2

### Patch Changes

-   @nhost/nhost-js@3.2.2

## @nhost/react-apollo@15.0.1

### Patch Changes

-   @nhost/apollo@8.0.2
-   @nhost/react@3.8.1

## @nhost/react-urql@12.0.1

### Patch Changes

-   @nhost/react@3.8.1

## @nhost/nhost-js@3.2.2

### Patch Changes

-   Updated dependencies [b944d05]
-   Updated dependencies [4148964]
    -   @nhost/hasura-auth-js@2.9.0
    -   @nhost/hasura-storage-js@2.6.0

## @nhost/react@3.8.1

### Patch Changes

-   @nhost/nhost-js@3.2.2

## @nhost/vue@2.8.1

### Patch Changes

-   @nhost/nhost-js@3.2.2

## @nhost/dashboard@2.13.0

### Minor Changes

- 21e90da: chore: remove restrictions on SMTP sender so My Name
[name@acme.com](mailto:name@acme.com) can be added
- 865dd93: fix: duplicate Run placeholders when there is an error in the
backend
- 6902a36: fix: can remove resources if postgres capacity is higher than
10
-   a535aa3: fix: fetch user roles locally in auth section
-   0c50816: fix: allow decimal numbers in database row insert
- aea6d18: chore: add warning when pausing a project about losing Run
services persistent volume data
- d3b4fc3: feat: allow to change postgres settings if project is paused
-   29d27e1: chore: update `next` to v14.2.22 to fix vulnerabilities
-   c9dca09: feat: add reset password form
-   b3bcacb: fix: paused project banner cannot read null project name

### Patch Changes

-   Updated dependencies [46fc520]
-   Updated dependencies [29d27e1]
    -   @nhost/nextjs@2.2.0
    -   @nhost/react-apollo@15.0.1

## @nhost/docs@2.25.0

### Minor Changes

- 46fc520: chore: add support to next.js 15, update quickstart template
commands in docs
-   cdf6776: fix: update links to create new project in dashboard

## @nhost-examples/nextjs@0.4.0

### Minor Changes

-   29d27e1: chore: update `next` to v14.2.22 to fix vulnerabilities

### Patch Changes

-   Updated dependencies [46fc520]
-   Updated dependencies [29d27e1]
    -   @nhost/nextjs@2.2.0
    -   @nhost/react@3.8.1
    -   @nhost/react-apollo@15.0.1

## @nhost-examples/nextjs-server-components@0.5.0

### Minor Changes

- b944d05: chore: simplify Nhost client initialization with session and
remove xstate dependency
-   29d27e1: chore: update `next` to v14.2.22 to fix vulnerabilities

### Patch Changes

-   @nhost/nhost-js@3.2.2

## @nhost-examples/cli@0.3.15

### Patch Changes

-   @nhost/nhost-js@3.2.2

## @nhost-examples/codegen-react-apollo@0.4.16

### Patch Changes

-   @nhost/react@3.8.1
-   @nhost/react-apollo@15.0.1

## @nhost-examples/codegen-react-query@0.4.16

### Patch Changes

-   @nhost/react@3.8.1

## @nhost-examples/codegen-react-urql@0.3.16

### Patch Changes

-   @nhost/react@3.8.1
-   @nhost/react-urql@12.0.1

## @nhost-examples/multi-tenant-one-to-many@2.2.16

### Patch Changes

-   @nhost/nhost-js@3.2.2

## @nhost-examples/node-storage@0.2.15

### Patch Changes

-   @nhost/nhost-js@3.2.2

## @nhost-examples/react-apollo@1.1.2

### Patch Changes

-   @nhost/react@3.8.1
-   @nhost/react-apollo@15.0.1

## @nhost-examples/react-gqty@1.2.16

### Patch Changes

-   @nhost/react@3.8.1

## @nhost-examples/react-native@0.1.1

### Patch Changes

-   @nhost/react@3.8.1
-   @nhost/react-apollo@15.0.1

## @nhost-examples/vue-apollo@0.7.2

### Patch Changes

-   @nhost/nhost-js@3.2.2
-   @nhost/apollo@8.0.2
-   @nhost/vue@2.8.1

## @nhost-examples/vue-quickstart@0.2.16

### Patch Changes

-   @nhost/apollo@8.0.2
-   @nhost/vue@2.8.1

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-08 13:47:10 +01:00
David BM
865dd93fbe fix (dashboard): duplicate Run placeholders when there is a backend error (#3114)
### **User description**
Resolves #2842


___

### **PR Type**
Bug fix, Enhancement


___

### **Description**
- Refactor Run service creation process

- Use single mutation for service config insertion

- Remove duplicate placeholder creation

- Update GraphQL schema and related types


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>ServiceForm.tsx</strong><dd><code>Refactor service
creation process in ServiceForm component</code></dd></summary>
<hr>


dashboard/src/features/orgs/projects/services/components/ServiceForm/ServiceForm.tsx

<li>Replace separate insertRunService and insertRunServiceConfig
mutations <br>with single insertRunServiceConfig<br> <li> Remove UUID
generation for new services<br> <li> Update error handling and form
submission logic<br> <li> Adjust image handling for private registries


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3114/files#diff-a02746694d45a84390d09b49a1b3eec85c25a8bd9a70b4834ee5af1ba82cb88e">+14/-34</a>&nbsp;
</td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>ServiceFormTypes.ts</strong><dd><code>Enhance image
field validation in ServiceFormTypes</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/features/orgs/projects/services/components/ServiceForm/ServiceFormTypes.ts

<li>Add trim() to image validation<br> <li> Enforce minimum length of 1
character for image field


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3114/files#diff-e9e0545b8c213ce04a08f9b04aedc81f96a031429e2ac9ac9e19d47982c112dc">+5/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>graphql.ts</strong><dd><code>Update GraphQL schema
types for Run service changes</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></summary>
<hr>

dashboard/src/utils/__generated__/graphql.ts

<li>Add InsertRunServiceConfigResponse type<br> <li> Update
Mutation_Root and related types<br> <li> Remove creatorUserId and
creator fields from Run_Service type<br> <li> Update Users type to
remove runServices field


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3114/files#diff-fbd5db84b560b1c91675004448c6c7fa0dcbfb28b9eb05d53b03e6cb7b83ebac">+16/-57</a>&nbsp;
</td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>insertRunService.graphql</strong><dd><code>Rename
insertRunService GraphQL mutation</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

dashboard/src/gql/services/insertRunService.graphql

- Rename mutation from insertRunService to InsertRunService


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3114/files#diff-a74b9bbdda4bce6f90fe8e8438397c61c2f044b5956e3da856f934b084ec3dc6">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td>
    <details>

<summary><strong>insertRunServiceConfig.graphql</strong><dd><code>Refactor
insertRunServiceConfig GraphQL mutation</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

dashboard/src/gql/services/insertRunServiceConfig.graphql

<li>Rename mutation to InsertRunServiceConfig<br> <li> Remove serviceID
parameter<br> <li> Update return type to include serviceID and config


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3114/files#diff-9f98ee0dd349db6404e3de3a3e487a4df6a4737acfd80ae8e5c0a8c6043ecb05">+6/-8</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></td></tr><tr><td><strong>Formatting</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>ReplicasFormSection.tsx</strong><dd><code>Minor styling
updates in ReplicasFormSection component</code>&nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>


dashboard/src/features/orgs/projects/services/components/ServiceForm/components/ReplicasFormSection/ReplicasFormSection.tsx

- Minor CSS class order adjustments
- Update InfoOutlinedIcon styling


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3114/files#diff-026fa3492e982d5c25430ea27282a81bbb372dcb7061274006d123d6f91a36f2">+3/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>curly-hotels-hang.md</strong><dd><code>Add changeset
for Run placeholders fix</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

.changeset/curly-hotels-hang.md

- Add changeset for fixing duplicate Run placeholders issue


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3114/files#diff-f2d1135a0f9ad0a75d2b50a42fb2c0ce1f17749af238f4acd06e5699f303d668">+5/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></td></tr></tr></tbody></table>

___

> 💡 **PR-Agent usage**: Comment `/help "your question"` on any pull
request to receive relevant information
2025-01-08 13:31:56 +01:00
David BM
0c50816717 fix (dashboard): allow decimal row insert (#3110)
### **User description**
Fixes #2923


___

### **PR Type**
Bug fix, Enhancement


___

### **Description**
- Allow decimal numbers in database row insert

- Separate integer and decimal cell components

- Update PostgreSQL type constants

- Refactor DataBrowserGrid component imports


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><details><summary>7
files</summary><table>
<tr>
<td><strong>DataBrowserGrid.tsx</strong><dd><code>Refactor imports and
add decimal cell support</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3110/files#diff-5910fd8730fbe65c60aa5f54031989a7868e944d5958f69535e5684b72ca1396">+22/-11</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>postgresqlConstants.ts</strong><dd><code>Separate integer
and decimal PostgreSQL types</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3110/files#diff-b497da90feca5bff94b0d38b69e519d171d43acc292098054d672a73a89b4717">+8/-5</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>DataGridDecimalCell.tsx</strong><dd><code>Add new
DataGridDecimalCell component</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3110/files#diff-9ad38d4c8a67f8daf6020b9782cb1d7a4933e2901b4937a597a2c19c2367d7d0">+108/-0</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>index.ts</strong><dd><code>Add index file for
DataGridDecimalCell</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3110/files#diff-796c86f4c7526c140e70830072876324b6809204eb0e59da9931f048bb00c3ed">+2/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>DataGridIntegerCell.tsx</strong><dd><code>Rename
DataGridNumericCell to DataGridIntegerCell</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3110/files#diff-9db68b16a44a34c57b847023c1dd2f74e486b0a028f84fcc0cc1f29e0ff38f0d">+3/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>index.ts</strong><dd><code>Add index file for
DataGridIntegerCell</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3110/files#diff-2354d98927d0c0bf7165211cbe9f478727bb889793716cfe39083c200d625c40">+2/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>index.ts</strong><dd><code>Remove DataGridNumericCell index
file</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3110/files#diff-0b88c218b31ef402892e055abae0b5a05b96ec1550881d69f0fd73bad93e159e">+0/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></details></td></tr><tr><td><strong>Bug
fix</strong></td><td><details><summary>1 files</summary><table>
<tr>
<td><strong>DatabaseRecordInputGroup.tsx</strong><dd><code>Remove step
property from input</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3110/files#diff-52b5499e9afc3c5e4929046b487de649d421dda3250a4131462ec710575abc12">+0/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

</table></details></td></tr><tr><td><strong>Documentation</strong></td><td><details><summary>1
files</summary><table>
<tr>
<td><strong>nice-mangos-act.md</strong><dd><code>Add changeset for
decimal number fix</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3110/files#diff-7207f060172dcdd7fd5c3c4078140fb57564714e1f95c96d428a22d9e7a3e670">+5/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></details></td></tr></tr></tbody></table>

___

> 💡 **PR-Agent usage**: Comment `/help "your question"` on any pull
request to receive relevant information
2025-01-07 22:18:04 +01:00
David BM
d3b4fc358e feat (dashboard): allow to change postgres settings if project is paused (#3106) 2025-01-07 18:09:12 +01:00
David BM
b3bcacb300 fix (dashboard): paused application cannot read null project name (#3117)
### **User description**
Fixes the occasional error `Cannot read properties of null (reading
'name') when you open a page inside a paused project

![image](https://github.com/user-attachments/assets/bfd57bf6-5679-48d3-ac8f-b69f6d72ee3d)


___

### **PR Type**
Bug fix


___

### **Description**
- Fix error when reading project name in paused application

- Update ApplicationPaused component to handle null project

- Add optional chaining to prevent null reference errors

- Improve error handling for paused projects in dashboard


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Bug
fix</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>ApplicationPaused.tsx</strong><dd><code>Add null checks
for project name in ApplicationPaused component</code></dd></summary>
<hr>


dashboard/src/features/orgs/projects/common/components/ApplicationPaused/ApplicationPaused.tsx

<li>Added optional chaining (<code>?.</code>) to
<code>project.name</code> references<br> <li> Updated modal title and
description to handle potential null project


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3117/files#diff-14afdf5ac20f058c26563a6992a3751f11cf173eec27206001262b5d1b3b979f">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>wise-chefs-drum.md</strong><dd><code>Add changeset for
paused project banner fix</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

.changeset/wise-chefs-drum.md

<li>Added changeset file for version bump and change description<br>
<li> Described fix for paused project banner issue


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3117/files#diff-dddc3d3dd31a1cb69106c6acad798c2201016cffb11cb8447e0696563838300c">+5/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></td></tr></tr></tbody></table>

___

> 💡 **PR-Agent usage**: Comment `/help "your question"` on any pull
request to receive relevant information
2025-01-07 15:51:47 +01:00
David Barroso
aa7ecdb38f chore: update pr-agent (#3121)
### **PR Type**
Enhancement


___

### **Description**
- Update PR Agent action to version 0.26


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>gen_ai_review.yaml</strong><dd><code>Upgrade PR Agent
action version</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

.github/workflows/gen_ai_review.yaml

- Updated PR Agent action from version 0.24 to 0.26


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3121/files#diff-d1e4c772e0acb5ce4891df2dd94ba58ffaf6393e8f75493ec7e10cbce1c4992c">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></td></tr></tr></tbody></table>

___

> 💡 **PR-Agent usage**: Comment `/help "your question"` on any pull
request to receive relevant information
2025-01-07 15:00:13 +01:00
David Barroso
20672c7a9b chore: update actions/cache to v4 (#3120)
### **PR Type**
Enhancement


___

### **Description**
- Update actions/cache from v3 to v4


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Dependencies</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>action.yaml</strong><dd><code>Update actions/cache
version</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></summary>
<hr>

.github/actions/install-dependencies/action.yaml

- Upgraded actions/cache from v3 to v4


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3120/files#diff-342d59190b4737ee45e2062eb625ada477bcea5b4a843b25900ad55d7982f200">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></td></tr></tr></tbody></table>

___

> 💡 **PR-Agent usage**: Comment `/help "your question"` on any pull
request to receive relevant information
2025-01-07 14:59:00 +01:00
David BM
29d27e19b4 chore: update dependencies with vulnerabilities, fix ci (#3118)
### **PR Type**
Enhancement, Bug fix


___

### **Description**
- Update Next.js to v14.2.22 for vulnerability fixes

- Upgrade @nhost/react and @nhost/react-apollo packages

- Update dependencies across multiple projects

- Add changeset for version bumps


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>smart-penguins-love.md</strong><dd><code>Add changeset
for Next.js and Nhost package updates</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></summary>
<hr>

.changeset/smart-penguins-love.md

<li>Add new changeset file for version bumps<br> <li> Specify minor
version updates for multiple packages<br> <li> Note Next.js update to
v14.2.22 for vulnerability fixes


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3118/files#diff-e7c2756594d0b5180066d581205200665f8f3f6104259550e080c3916dca065a">+8/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></td></tr><tr><td><strong>Dependencies</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>package.json</strong><dd><code>Upgrade Next.js to
v14.2.22 in dashboard</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></summary>
<hr>

dashboard/package.json

- Update `next` dependency from ^14.2.10 to ^14.2.22


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3118/files#diff-2d8d55c799cd71f1b35e831f075f8178ed1734c4820a2ad548b4dd24d6938d7c">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>package.json</strong><dd><code>Upgrade Next.js to
v14.2.22 in NextJS example</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

examples/nextjs/package.json

- Update `next` dependency from ^14.2.10 to ^14.2.22


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3118/files#diff-23044c563f1173db6464d127497c342c8f7f90722764a37749681bf455a515e0">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>package.json</strong><dd><code>Upgrade Next.js to
v14.2.22 in server components example</code>&nbsp; </dd></summary>
<hr>

examples/quickstarts/nextjs-server-components/package.json

- Update `next` dependency from ^14.2.10 to ^14.2.22


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3118/files#diff-04889f3402d5191034459febd340282af1c718175c3b0b14ff03fb2ab46cf9b3">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>package.json</strong><dd><code>Upgrade Next.js dev
dependency in NextJS package</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

packages/nextjs/package.json

- Update `next` devDependency from ^14.2.10 to ^14.2.22


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3118/files#diff-e5237f683dda3354b835c7c7c94b9759db2c743d4ba94d47d7f8b8e0b2bfb442">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>package.json</strong><dd><code>Upgrade Nhost React and
Apollo packages in CRA template</code>&nbsp; &nbsp; </dd></summary>
<hr>

templates/cra-template-nhost-react-apollo-template/template/package.json

<li>Update @nhost/react from ^3.5.4 to ^3.8.0<br> <li> Update
@nhost/react-apollo from ^12.0.4 to ^12.0.5


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3118/files#diff-27f71682a447c654ff4a94d33944ebb70e10d07a4279107c230bd8ec7dce7391">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></td></tr></tr></tbody></table>

___

> 💡 **PR-Agent usage**: Comment `/help "your question"` on any pull
request to receive relevant information
2025-01-07 14:17:32 +01:00
David BM
46fc520707 chore (nextjs): fix nextjs tutorial quickstart commands in docs, add support to next.js 15 (#3109)
### **User description**
Resolves #3103, resolves #3102


___

### **PR Type**
Enhancement, Bug fix


___

### **Description**
- Update Next.js quickstart and tutorial for version 14

- Add support for Next.js 15 and React 19

- Fix typos in documentation

- Update Nhost package versions in template


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>nextjs.mdx</strong><dd><code>Update Next.js quickstart
guide for version 14</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

docs/guides/quickstarts/nextjs.mdx

<li>Updated command to create Next.js 14 app instead of latest<br> <li>
Fixed typo: 'Navidate' to 'Navigate'


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3109/files#diff-d39f09ffc6c1ab86d648e6bf0e612463f51f5588a9f674e43454b86ce86bc174">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>vue.mdx</strong><dd><code>Fix typo in Vue quickstart
guide</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

docs/guides/quickstarts/vue.mdx

- Fixed typo: 'Navidate' to 'Navigate'


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3109/files#diff-1038d117c49e6af817cc5cb861d8e0af9df274612c9acbf1dc24bb7ee76aa6f4">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>nextjs.mdx</strong><dd><code>Update Next.js tutorial
for version 14</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></summary>
<hr>

docs/guides/tutorials/nextjs.mdx

- Updated command to create Next.js 14 app instead of latest


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3109/files#diff-f6388bd90e4e34be1cdfd7c81a5ce7bc21a51949553a29a16bdc32e6875aba6f">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></td></tr><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>package.json</strong><dd><code>Update Next.js and React
version support</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

packages/nextjs/package.json

<li>Added support for Next.js 15 and React 19 in peerDependencies<br>
<li> Updated devDependencies to Next.js 15 and React 19


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3109/files#diff-e5237f683dda3354b835c7c7c94b9759db2c743d4ba94d47d7f8b8e0b2bfb442">+7/-7</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></td></tr><tr><td><strong>Dependencies</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>package.json</strong><dd><code>Update Nhost package
versions in template</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

templates/cra-template-nhost-react-apollo-template/template/package.json

- Updated @nhost/react and @nhost/react-apollo versions


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3109/files#diff-27f71682a447c654ff4a94d33944ebb70e10d07a4279107c230bd8ec7dce7391">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></td></tr></tr></tbody></table>

___

> 💡 **PR-Agent usage**: Comment `/help "your question"` on any pull
request to receive relevant information
2025-01-02 17:24:01 +01:00
David BM
21e90da476 chore (dashboard): remove restrictions on SMTP sender so My Name <name@acme.com> can be added (#3111) 2025-01-02 11:38:48 +01:00
Hassan Ben Jobrane
b944d053d0 feat(hasura-auth-js): feat: addinitWithSession to initialize auth client with existing session (#3108)
### **User description**
resolves https://github.com/nhost/nhost/issues/2319


___

### **PR Type**
Enhancement


___

### **Description**
- Added new `initWithSession()` method to `@nhost/hasura-auth-js`
package, allowing initialization of auth client with an existing session
- Simplified Nhost client initialization in Next.js server components
example by using the new `initWithSession()` method
- Removed xstate dependency from Next.js server components example
- Updated changesets to document the new feature and changes in the
Next.js example
- Improved code organization and reduced complexity in the Next.js
example



___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>nhost.ts</strong><dd><code>Simplify Nhost client
initialization in Next.js</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

examples/quickstarts/nextjs-server-components/src/utils/nhost.ts

<li>Removed xstate dependency imports<br> <li> Replaced
<code>nhost.auth.client.start()</code> and <code>waitFor()</code> with
new <br><code>nhost.auth.initWithSession()</code> method<br> <li>
Simplified initialization of Nhost client with existing session


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3108/files#diff-e13ecdf248c9041902e5e8a79555ccefc225eb7df3d717cc1b61ce0d5da092db">+1/-7</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>hasura-auth-client.ts</strong><dd><code>Add
initWithSession method to HasuraAuthClient</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

packages/hasura-auth-js/src/hasura-auth-client.ts

<li>Added <code>NhostSession</code> import<br> <li> Implemented new
<code>initWithSession()</code> method in <code>HasuraAuthClient</code>
class<br> <li> Added JSDoc comments for the new method


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3108/files#diff-0dbc30932ed723b7fd458066893f29f2f77658436c84adf42613813ea042c992">+18/-0</a>&nbsp;
&nbsp; </td>

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>flat-apes-shake.md</strong><dd><code>Add changeset for
Next.js example updates</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

.changeset/flat-apes-shake.md

<li>Added changeset for Next.js server components example<br> <li>
Describes simplification of Nhost client initialization and removal of
<br>xstate dependency


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3108/files#diff-ee9361d5d0dad7378328ba9e63937d85fbe91156790a50764aaa285fab6b4db1">+5/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>long-guests-sparkle.md</strong><dd><code>Add changeset
for new initWithSession feature</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

.changeset/long-guests-sparkle.md

<li>Added changeset for @nhost/hasura-auth-js package<br> <li> Describes
the addition of <code>initWithSession</code> method


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3108/files#diff-e7c748ca311b610d130750f4d24256383ef064c1ee2f1a9981060fd274335a1c">+5/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></td></tr><tr><td><strong>Dependencies</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>package.json</strong><dd><code>Remove xstate dependency
from Next.js example</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

examples/quickstarts/nextjs-server-components/package.json

- Removed "xstate" dependency from the project


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3108/files#diff-04889f3402d5191034459febd340282af1c718175c3b0b14ff03fb2ab46cf9b3">+1/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></td></tr></tr></tbody></table>

___

> 💡 **PR-Agent usage**: Comment `/help "your question"` on any pull
request to receive relevant information
2024-12-31 12:58:10 +01:00
David BM
6902a36512 fix (dashboard): remove compute resources erases postgres capacity (#3107)
### **User description**
Fixes #3075


___

### **PR Type**
Bug fix, Enhancement


___

### **Description**
- Fixed a bug that prevented removing compute resources when PostgreSQL
capacity was higher than 10
- Refactored resource configuration handling to preserve non-compute
settings when disabling resources
- Updated GraphQL types and queries to include additional fields for
networking and storage configurations
- Implemented UI tweaks for better alignment and dark theme
compatibility in the resource settings form
- Added a changeset file to document the bug fix and minor version bump



___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>ResourcesForm.tsx</strong><dd><code>Refactor resource
configuration handling</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></summary>
<hr>


dashboard/src/features/orgs/projects/resources/settings/components/ResourcesForm/ResourcesForm.tsx

<li>Added <code>getFormattedConfig</code> function to handle resource
configuration<br> <li> Modified <code>handleSubmit</code> to use
<code>getFormattedConfig</code><br> <li> Updated initial resource
retrieval to include <code>rest</code> properties<br> <li> Implemented
logic to preserve non-compute resource settings when <br>disabling
resources


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3107/files#diff-0a7e99e6ee09c17eec103656a9aa088b379c7927a182098538b793488a1f9337">+118/-59</a></td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>graphql.ts</strong><dd><code>Update GraphQL types for
extended resource configurations</code></dd></summary>
<hr>

dashboard/src/utils/__generated__/graphql.ts

<li>Updated GraphQL types to include additional fields for resources<br>
<li> Added networking and storage-related fields to various resource
<br>configurations


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3107/files#diff-fbd5db84b560b1c91675004448c6c7fa0dcbfb28b9eb05d53b03e6cb7b83ebac">+16/-2</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>getResources.gql</strong><dd><code>Extend GraphQL query
for resource configurations</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/features/orgs/projects/resources/settings/gql/getResources.gql

<li>Updated GraphQL query to include additional fields for resources<br>
<li> Added networking and storage-related fields to the query


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3107/files#diff-45c2f030236a2836bd4ba61e46a20bc0b40f2ab08874c056c49b285a9c2c80eb">+14/-0</a>&nbsp;
&nbsp; </td>

</tr>
</table></td></tr><tr><td><strong>Formatting</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>ServiceResourcesFormFragment.tsx</strong><dd><code>UI
tweaks for resource settings form</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/features/orgs/projects/resources/settings/components/ServiceResourcesFormFragment/ServiceResourcesFormFragment.tsx

<li>Minor CSS class adjustments for better alignment<br> <li> Updated
icon color handling for dark theme compatibility


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3107/files#diff-9b9bf7e4f4e4dd34502e1b636c9f9aabbb20defe43595a79aa7e3f7d89750029">+6/-6</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>eighty-candles-tell.md</strong><dd><code>Add changeset
for bug fix</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

.changeset/eighty-candles-tell.md

- Added a changeset file to document the bug fix


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3107/files#diff-872c88455eb33ca58fddfd06a1cb56559dddfbdc4fd4aea7b44c2984ef9785a1">+5/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></td></tr></tr></tbody></table>

___

> 💡 **PR-Agent usage**: Comment `/help "your question"` on any pull
request to receive relevant information
2024-12-31 12:21:20 +01:00
David BM
aea6d186c2 chore (dashboard): warn run volumes losing data on project pause (#3104)
### **User description**
Resolves #3048


___

### **PR Type**
Enhancement


___

### **Description**
- Added a warning message when pausing a project with Run services that
have persistent volume data.
- The warning is displayed in an Alert component within the pause
confirmation dialog.
- Implemented logic to determine when to show the warning based on the
project's plan and Run services configuration.
- Updated the pause confirmation dialog to include more detailed
information and styling.
- Added a changeset file to document the minor version bump for this
feature.



___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>index.tsx</strong><dd><code>Add warning for Run service
data loss on project pause</code>&nbsp; &nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/pages/orgs/[orgSlug]/projects/[appSubdomain]/settings/index.tsx

<li>Added imports for new UI components (Alert, Link, Text)<br> <li>
Implemented <code>useRunServices</code> hook and
<code>showWarning</code> logic<br> <li> Enhanced the pause project
dialog with a warning about data loss for <br>Run services<br> <li>
Added conditional rendering of the warning alert


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3104/files#diff-b4185be97a505e25badcdefe31ea86fa9d69f72264c4bb35eae17fba936a3d47">+61/-3</a>&nbsp;
&nbsp; </td>

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>purple-trains-itch.md</strong><dd><code>Add changeset
for Run services warning feature</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

.changeset/purple-trains-itch.md

<li>Added a changeset file to document the minor version bump<br> <li>
Described the new feature of warning about data loss when pausing a
<br>project


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3104/files#diff-e810895b65f5a519690acf26c92d7f534ddab07a3baf619556674561d965b026">+5/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></td></tr></tr></tbody></table>

___

> 💡 **PR-Agent usage**: Comment `/help "your question"` on any pull
request to receive relevant information
2024-12-30 16:19:41 +01:00
David BM
a535aa3834 fix (dashboard): fetch user roles locally in auth section (#3096)
### **User description**
Fixes #2472


___

### **PR Type**
Bug fix


___

### **Description**
- Fixed issue with user roles not appearing locally in the Nhost
dashboard
- Implemented support for fetching user roles and locales using a local
Mimir client when not running on the Nhost platform
- Modified queries in EditUserForm and UsersBody components to use the
local client when appropriate
- Corrected image source paths for provider logos in both components
- Added a changeset file to document the minor version bump and fix
description
- Improved code formatting and consistency



___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>EditUserForm.tsx</strong><dd><code>Add local client
support for user roles and locales</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/features/orgs/projects/authentication/users/components/EditUserForm/EditUserForm.tsx

<li>Added <code>useIsPlatform</code> and
<code>useLocalMimirClient</code> hooks<br> <li> Modified
<code>useGetRolesPermissionsQuery</code> and
<code>useGetProjectLocalesQuery</code> to <br>use local Mimir client
when not on platform<br> <li> Fixed image source paths for provider
logos<br>


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3096/files#diff-6867937d55b269352d4e146ff21b36ca939f6a838ee70b1b29efa9eabad88c2e">+10/-4</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>UsersBody.tsx</strong><dd><code>Implement local client
for user roles in UsersBody</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/features/orgs/projects/authentication/users/components/UsersBody/UsersBody.tsx

<li>Added <code>useIsPlatform</code> and
<code>useLocalMimirClient</code> hooks<br> <li> Modified
<code>useGetRolesPermissionsQuery</code> to use local Mimir client when
<br>not on platform<br> <li> Fixed formatting for date display and image
source paths<br>


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3096/files#diff-33b33017f46d5cb8e4652c183619f3dc86c5377125ed3a612888739e0da22484">+12/-7</a>&nbsp;
&nbsp; </td>

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>forty-knives-check.md</strong><dd><code>Add changeset
for user roles fix</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

.changeset/forty-knives-check.md

<li>Added a changeset file to document the minor version bump and fix
<br>description<br>


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3096/files#diff-1eb27af3bf6c2c3562da23f6e52944ae10861d75351b5df022fdf0c50b1ca245">+5/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></td></tr></tr></tbody></table>

___

> 💡 **PR-Agent usage**: Comment `/help "your question"` on any pull
request to receive relevant information
2024-12-30 14:31:23 +01:00
Hassan Ben Jobrane
c9dca09478 feat(dashboard): add change password form (#3089)
### **User description**
resolves https://github.com/nhost/nhost/issues/3058


___

### **PR Type**
Enhancement, Bug fix


___

### **Description**
- Renamed the existing reset password page to `NewPasswordPage` and
updated its form handling.
- Added a new `ResetPasswordPage` with a form to change the password,
including validation and success/error handling.
- Updated the "Forgot password?" link in the sign-in page to direct
users to the new password page.



___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>new.tsx</strong><dd><code>Rename and update reset
password page</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

dashboard/src/pages/password/new.tsx

<li>Renamed <code>ResetPasswordPage</code> to
<code>NewPasswordPage</code>.<br> <li> Updated form type from
<code>ResetPasswordFormValues</code> to
<br><code>NewPasswordFormValues</code>.<br> <li> Changed layout title to
"Request Password Reset".<br>


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3089/files#diff-153045bbcb44ce952fbd9ee585c63109891973ab4d1ecc1e1b5edf8f981b1259">+8/-6</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>reset.tsx</strong><dd><code>Add new reset password page
with form</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></summary>
<hr>

dashboard/src/pages/password/reset.tsx

<li>Introduced a new <code>ResetPasswordPage</code> component.<br> <li>
Implemented form for changing password with validation.<br> <li> Added
navigation to sign-in page upon successful password change.<br>


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3089/files#diff-0b60d94b63e36ce54a4dafb098322e11b9a130defb0f48984f8b3e71461e8011">+144/-0</a>&nbsp;
</td>

</tr>
</table></td></tr><tr><td><strong>Bug fix</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>email.tsx</strong><dd><code>Update forgot password link
and formatting</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

dashboard/src/pages/signin/email.tsx

<li>Updated "Forgot password?" link to point to the new password
page.<br> <li> Minor formatting adjustments in the component.<br>


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3089/files#diff-b5d7db4460066bc114cb766771612d6f908bd6e440f40de98e4ac311a26b50cd">+4/-4</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></td></tr></tr></tbody></table>

___

> 💡 **PR-Agent usage**: Comment `/help "your question"` on any pull
request to receive relevant information
2024-12-30 12:51:38 +01:00
David BM
414896491f fix (hasura-storage-js): stack overflow on storage client getHeaders (#3100)
### **User description**
Fixes #2964


___

### **PR Type**
Bug fix


___

### **Description**
- Fixed a critical bug in the `HasuraStorageClient` class where the
`getHeaders` method was causing a stack overflow due to recursive
self-calling.
- Updated the `getHeaders` method to correctly call
`this.api.getHeaders()` instead of `this.getHeaders()`.
- Added a changeset file to document the bug fix and specify a minor
version bump for the '@nhost/hasura-storage-js' package.
- This fix resolves the issue reported in ticket #2964, where calling
`nhostClient.storage.getHeaders()` was leading to a stack overflow
error.



___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Bug
fix</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>hasura-storage-client.ts</strong><dd><code>Fix stack
overflow in storage client getHeaders method</code>&nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

packages/hasura-storage-js/src/hasura-storage-client.ts

<li>Fixed a recursive call in the <code>getHeaders</code> method that
was causing a <br>stack overflow<br> <li> Changed
<code>this.getHeaders()</code> to <code>this.api.getHeaders()</code><br>


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3100/files#diff-f994829d5b30e7a7d47629651e1a013110a71ed2c8cddced340fb3ac05603956">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>smooth-wombats-begin.md</strong><dd><code>Add changeset
for storage client bug fix</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></summary>
<hr>

.changeset/smooth-wombats-begin.md

<li>Added a changeset file to document the bug fix<br> <li> Specified a
minor version bump for '@nhost/hasura-storage-js' package<br>


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3100/files#diff-9174b11cea1aad4b7308eac7c7fc2d78a44e81b7040b38e542974549ef15b047">+5/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></td></tr></tr></tbody></table>

___

> 💡 **PR-Agent usage**: Comment `/help "your question"` on any pull
request to receive relevant information
2024-12-27 16:46:00 +01:00
David BM
cdf6776523 fix (docs): broken links to create new project in dashboard (#3098)
### **PR Type**
Bug fix, Documentation


___

### **Description**
- Fixed broken links to create a new project in the Nhost Dashboard
across multiple documentation files
- Updated the URL from `https://app.nhost.io/new` to
`https://app.nhost.io` in all affected files
- Modified quickstart guides for Next.js, React Native, React, and Vue
- Updated tutorial guides for Next.js, React, and Vue
- Added a changeset file to document the fix and specify the version
change for `@nhost/docs`



___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>wicked-colts-fetch.md</strong><dd><code>Add changeset
for documentation update</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

.changeset/wicked-colts-fetch.md

<li>Added a new changeset file for documenting the fix<br> <li>
Specified the package and version change<br> <li> Brief description of
the fix<br>


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3098/files#diff-fd20b463cfa62ac545411e62d62a7443334fbc24050651eec02a9a0fb21cc02c">+5/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></td></tr><tr><td><strong>Bug fix</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>nextjs.mdx</strong><dd><code>Update Nhost Dashboard
link in Next.js quickstart</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

docs/guides/quickstarts/nextjs.mdx

- Updated the link to create a new project in the Nhost Dashboard



</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3098/files#diff-d39f09ffc6c1ab86d648e6bf0e612463f51f5588a9f674e43454b86ce86bc174">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>react-native.mdx</strong><dd><code>Update Nhost
Dashboard link in React Native quickstart</code>&nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

docs/guides/quickstarts/react-native.mdx

- Updated the link to create a new project in the Nhost Dashboard



</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3098/files#diff-7f0904dabc13ea9bd8e8b39e5b870ed6926791172f22a1df922302dfc43dac9e">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>react.mdx</strong><dd><code>Update Nhost Dashboard link
in React quickstart</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

docs/guides/quickstarts/react.mdx

- Updated the link to create a new project in the Nhost Dashboard



</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3098/files#diff-b954a7a56bea978a7b33eedf5a250f4599f285bc0a8556a3c85e1a416bc89e61">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>vue.mdx</strong><dd><code>Update Nhost Dashboard link
in Vue quickstart</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

docs/guides/quickstarts/vue.mdx

- Updated the link to create a new project in the Nhost Dashboard



</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3098/files#diff-1038d117c49e6af817cc5cb861d8e0af9df274612c9acbf1dc24bb7ee76aa6f4">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>nextjs.mdx</strong><dd><code>Update Nhost Dashboard
link in Next.js tutorial</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

docs/guides/tutorials/nextjs.mdx

- Updated the link to create a new project in the Nhost Dashboard



</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3098/files#diff-f6388bd90e4e34be1cdfd7c81a5ce7bc21a51949553a29a16bdc32e6875aba6f">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>react.mdx</strong><dd><code>Update Nhost Dashboard link
in React tutorial</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

docs/guides/tutorials/react.mdx

- Updated the link to create a new project in the Nhost Dashboard



</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3098/files#diff-22eb5f72de09dd8d979ef3fb5ae8a321000db2b29defac5dd6459703972b7e9a">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>vue.mdx</strong><dd><code>Update Nhost Dashboard link
in Vue tutorial</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

docs/guides/tutorials/vue.mdx

- Updated the link to create a new project in the Nhost Dashboard



</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3098/files#diff-861872b2c9bf786c73e9ded726a1d4b27f57918cc351dc06ba2bfaf51fda6d09">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></td></tr></tr></tbody></table>

___

> 💡 **PR-Agent usage**: Comment `/help "your question"` on any pull
request to receive relevant information
2024-12-27 13:55:53 +01:00
97 changed files with 1192 additions and 877 deletions

View File

@@ -20,7 +20,7 @@ runs:
id: pnpm-cache-dir
shell: bash
run: echo "dir=$(pnpm store path)" >> $GITHUB_OUTPUT
- uses: actions/cache@v3
- uses: actions/cache@v4
id: pnpm-cache
with:
path: ${{ steps.pnpm-cache-dir.outputs.dir }}

View File

@@ -16,7 +16,7 @@ jobs:
steps:
- name: PR Agent action step
id: pragent
uses: Codium-ai/pr-agent@v0.24
uses: Codium-ai/pr-agent@v0.26
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
OPENAI_KEY: ${{ secrets.OPENAI_API_KEY }}

View File

@@ -1,5 +1,27 @@
# @nhost/dashboard
## 2.13.0
### Minor Changes
- 21e90da: chore: remove restrictions on SMTP sender so My Name <name@acme.com> can be added
- 865dd93: fix: duplicate Run placeholders when there is an error in the backend
- 6902a36: fix: can remove resources if postgres capacity is higher than 10
- a535aa3: fix: fetch user roles locally in auth section
- 0c50816: fix: allow decimal numbers in database row insert
- aea6d18: chore: add warning when pausing a project about losing Run services persistent volume data
- d3b4fc3: feat: allow to change postgres settings if project is paused
- 29d27e1: chore: update `next` to v14.2.22 to fix vulnerabilities
- c9dca09: feat: add reset password form
- b3bcacb: fix: paused project banner cannot read null project name
### Patch Changes
- Updated dependencies [46fc520]
- Updated dependencies [29d27e1]
- @nhost/nextjs@2.2.0
- @nhost/react-apollo@15.0.1
## 2.12.0
### Minor Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/dashboard",
"version": "2.12.0",
"version": "2.13.0",
"private": true,
"scripts": {
"preinstall": "npx only-allow pnpm",
@@ -84,7 +84,7 @@
"just-kebab-case": "^4.2.0",
"lodash.debounce": "^4.0.8",
"lucide-react": "^0.416.0",
"next": "^14.2.10",
"next": "^14.2.22",
"next-nprogress-bar": "^2.3.13",
"next-seo": "^6.5.0",
"next-themes": "^0.3.0",

View File

@@ -21,23 +21,22 @@ export default function UnauthenticatedLayout({
const router = useRouter();
const isPlatform = useIsPlatform();
const { isAuthenticated, isLoading } = useAuthenticationStatus();
const isOnResetPassword = router.route === '/password/reset';
useEffect(() => {
if (!isPlatform || (!isLoading && isAuthenticated)) {
router.push('/');
// we do not want to redirect if the user tries to reset their password
if (!isOnResetPassword) {
router.push('/');
}
}
}, [isLoading, isAuthenticated, router, isPlatform]);
}, [isLoading, isAuthenticated, router, isPlatform, isOnResetPassword]);
if (!isPlatform || isLoading || isAuthenticated) {
if ((!isPlatform || isLoading || isAuthenticated) && !isOnResetPassword) {
return (
<BaseLayout {...props}>
<LoadingScreen
sx={{ backgroundColor: (theme) => theme.palette.background.default }}
slotProps={{
activityIndicator: {
className: 'text-white',
},
}}
/>
</BaseLayout>
);
@@ -59,19 +58,19 @@ export default function UnauthenticatedLayout({
<RetryableErrorBoundary>
<Box
className="flex items-center min-h-screen"
className="flex min-h-screen items-center"
sx={{ backgroundColor: (theme) => theme.palette.common.black }}
>
<Container
rootClassName="bg-transparent h-full"
className="grid items-center w-full h-full gap-12 pt-8 pb-12 bg-transparent justify-items-center lg:grid-cols-2 lg:gap-4 lg:pb-0 lg:pt-0"
className="grid h-full w-full items-center justify-items-center gap-12 bg-transparent pb-12 pt-8 lg:grid-cols-2 lg:gap-4 lg:pb-0 lg:pt-0"
>
<div className="relative z-10 order-2 grid w-full max-w-[544px] grid-flow-row gap-12 lg:order-1">
{children}
</div>
<div className="relative z-0 order-1 flex h-full w-full items-center justify-center md:min-h-[150px] lg:order-2 lg:min-h-[none]">
<div className="absolute top-0 bottom-0 left-0 right-0 flex items-center justify-center w-full h-full max-w-xl mx-auto overflow-hidden opacity-70">
<div className="absolute bottom-0 left-0 right-0 top-0 mx-auto flex h-full w-full max-w-xl items-center justify-center overflow-hidden opacity-70">
<Image
priority
src="/assets/line-grid.svg"

View File

@@ -19,7 +19,7 @@ import { execPromiseWithErrorToast } from '@/features/orgs/utils/execPromiseWith
const validationSchema = yup
.object({
sender: yup.string().label('SMTP Sender').email().required(),
sender: yup.string().label('SMTP Sender').required(),
password: yup.string().label('Password').required(),
})
.required();

View File

@@ -30,7 +30,7 @@ const smtpValidationSchema = yup
user: yup.string().label('Username').required(),
password: yup.string().label('Password'),
method: yup.string().required(),
sender: yup.string().label('SMTP Sender').email().required(),
sender: yup.string().label('SMTP Sender').required(),
})
.required();

View File

@@ -16,18 +16,20 @@ import { Text } from '@/components/ui/v2/Text';
import { useRemoteApplicationGQLClient } from '@/features/orgs/hooks/useRemoteApplicationGQLClient';
import { EditUserPasswordForm } from '@/features/orgs/projects/authentication/users/components/EditUserPasswordForm';
import { getReadableProviderName } from '@/features/orgs/projects/authentication/users/utils/getReadableProviderName';
import { useIsPlatform } from '@/features/orgs/projects/common/hooks/useIsPlatform';
import { useLocalMimirClient } from '@/features/orgs/projects/hooks/useLocalMimirClient';
import { useProject } from '@/features/orgs/projects/hooks/useProject';
import { execPromiseWithErrorToast } from '@/features/orgs/utils/execPromiseWithErrorToast';
import { getUserRoles } from '@/features/projects/roles/settings/utils/getUserRoles';
import { type RemoteAppUser } from '@/pages/orgs/[orgSlug]/projects/[appSubdomain]/users';
import type { DialogFormProps } from '@/types/common';
import { copy } from '@/utils/copy';
import {
RemoteAppGetUsersDocument,
useGetProjectLocalesQuery,
useGetRolesPermissionsQuery,
useUpdateRemoteAppUserMutation,
} from '@/utils/__generated__/graphql';
import { copy } from '@/utils/copy';
import { yupResolver } from '@hookform/resolvers/yup';
import { useTheme } from '@mui/material';
import { format } from 'date-fns';
@@ -106,6 +108,8 @@ export default function EditUserForm({
onDeleteUser,
roles,
}: EditUserFormProps) {
const isPlatform = useIsPlatform();
const localMimirClient = useLocalMimirClient();
const theme = useTheme();
const { onDirtyStateChange, openDialog } = useDialog();
const { project } = useProject();
@@ -196,6 +200,7 @@ export default function EditUserForm({
const { data: dataRoles } = useGetRolesPermissionsQuery({
variables: { appId: project?.id },
...(!isPlatform ? { client: localMimirClient } : {}),
});
const allAvailableProjectRoles = getUserRoles(
@@ -206,6 +211,7 @@ export default function EditUserForm({
variables: {
appId: project?.id,
},
...(!isPlatform ? { client: localMimirClient } : {}),
});
const allowedLocales = data?.config?.auth?.user?.locale?.allowed || [];

View File

@@ -15,6 +15,8 @@ import { Text } from '@/components/ui/v2/Text';
import { useRemoteApplicationGQLClient } from '@/features/orgs/hooks/useRemoteApplicationGQLClient';
import type { EditUserFormValues } from '@/features/orgs/projects/authentication/users/components/EditUserForm';
import { getReadableProviderName } from '@/features/orgs/projects/authentication/users/utils/getReadableProviderName';
import { useIsPlatform } from '@/features/orgs/projects/common/hooks/useIsPlatform';
import { useLocalMimirClient } from '@/features/orgs/projects/hooks/useLocalMimirClient';
import { useProject } from '@/features/orgs/projects/hooks/useProject';
import { execPromiseWithErrorToast } from '@/features/orgs/utils/execPromiseWithErrorToast';
import { getUserRoles } from '@/features/projects/roles/settings/utils/getUserRoles';
@@ -61,6 +63,8 @@ export interface UsersBodyProps {
export default function UsersBody({ users, onSubmit }: UsersBodyProps) {
const theme = useTheme();
const isPlatform = useIsPlatform();
const localMimirClient = useLocalMimirClient();
const { openAlertDialog, openDrawer, closeDrawer } = useDialog();
const { project } = useProject();
const remoteProjectGQLClient = useRemoteApplicationGQLClient();
@@ -88,6 +92,7 @@ export default function UsersBody({ users, onSubmit }: UsersBodyProps) {
*/
const { data: dataRoles } = useGetRolesPermissionsQuery({
variables: { appId: project?.id },
...(!isPlatform ? { client: localMimirClient } : {}),
});
const { allowed: allowedRoles } = dataRoles?.config?.auth?.user?.roles || {};

View File

@@ -36,8 +36,8 @@ export default function ApplicationPaused() {
>
<RemoveApplicationModal
close={() => setShowDeletingModal(false)}
title={`Remove project ${project.name}?`}
description={`The project ${project.name} will be removed. All data will be lost and there will be no way to
title={`Remove project ${project?.name}?`}
description={`The project ${project?.name} will be removed. All data will be lost and there will be no way to
recover the app once it has been deleted.`}
className="z-50"
/>

View File

@@ -24,7 +24,7 @@ export default function useProjectRedirectWhenReady(
const { data, client, startPolling, ...rest } = useGetApplicationStateQuery({
...options,
variables: { ...options.variables, appId: project?.id },
skip: !project.id,
skip: !project?.id,
});
useEffect(() => {

View File

@@ -1,10 +1,4 @@
import { useDialog } from '@/components/common/DialogProvider';
import type { DataGridProps } from '@/components/dataGrid/DataGrid';
import { DataGrid } from '@/components/dataGrid/DataGrid';
import { DataGridBooleanCell } from '@/components/dataGrid/DataGridBooleanCell';
import { DataGridDateCell } from '@/components/dataGrid/DataGridDateCell';
import { DataGridNumericCell } from '@/components/dataGrid/DataGridNumericCell';
import { DataGridTextCell } from '@/components/dataGrid/DataGridTextCell';
import { FormActivityIndicator } from '@/components/form/FormActivityIndicator';
import { InlineCode } from '@/components/presentational/InlineCode';
import { KeyIcon } from '@/components/ui/v2/icons/KeyIcon';
@@ -23,11 +17,19 @@ import { normalizeDefaultValue } from '@/features/orgs/projects/database/dataGri
import {
POSTGRESQL_CHARACTER_TYPES,
POSTGRESQL_DATE_TIME_TYPES,
POSTGRESQL_DECIMAL_TYPES,
POSTGRESQL_INTEGER_TYPES,
POSTGRESQL_JSON_TYPES,
POSTGRESQL_NUMERIC_TYPES,
} from '@/features/orgs/projects/database/dataGrid/utils/postgresqlConstants';
import { isSchemaLocked } from '@/features/orgs/projects/database/dataGrid/utils/schemaHelpers';
import { useProject } from '@/features/orgs/projects/hooks/useProject';
import type { DataGridProps } from '@/features/orgs/projects/storage/dataGrid/components/DataGrid';
import { DataGrid } from '@/features/orgs/projects/storage/dataGrid/components/DataGrid';
import { DataGridBooleanCell } from '@/features/orgs/projects/storage/dataGrid/components/DataGridBooleanCell';
import { DataGridDateCell } from '@/features/orgs/projects/storage/dataGrid/components/DataGridDateCell';
import { DataGridDecimalCell } from '@/features/orgs/projects/storage/dataGrid/components/DataGridDecimalCell';
import { DataGridIntegerCell } from '@/features/orgs/projects/storage/dataGrid/components/DataGridIntegerCell';
import { DataGridTextCell } from '@/features/orgs/projects/storage/dataGrid/components/DataGridTextCell';
import { useQueryClient } from '@tanstack/react-query';
import dynamic from 'next/dynamic';
import { useRouter } from 'next/router';
@@ -68,10 +70,10 @@ export function createDataGridColumn(
const defaultColumnConfiguration = {
Header: () => (
<div className="grid items-center justify-start grid-flow-col gap-1 font-normal">
<div className="grid grid-flow-col items-center justify-start gap-1 font-normal">
{column.is_primary && <KeyIcon className="text-sm" />}
<span className="font-bold truncate" title={column.column_name}>
<span className="truncate font-bold" title={column.column_name}>
{column.column_name}
</span>
@@ -104,12 +106,21 @@ export function createDataGridColumn(
foreignKeyRelation: column.foreign_key_relation,
};
if (POSTGRESQL_NUMERIC_TYPES.includes(column.data_type)) {
if (POSTGRESQL_INTEGER_TYPES.includes(column.data_type)) {
return {
...defaultColumnConfiguration,
type: 'number',
width: 200,
Cell: DataGridNumericCell,
Cell: DataGridIntegerCell,
};
}
if (POSTGRESQL_DECIMAL_TYPES.includes(column.data_type)) {
return {
...defaultColumnConfiguration,
type: 'text',
width: 200,
Cell: DataGridDecimalCell,
};
}

View File

@@ -209,7 +209,6 @@ export default function DatabaseRecordInputGroup({
autoFocus={index === 0 && autoFocusFirstInput}
slotProps={{
label: commonLabelProps,
inputRoot: { step: 1 },
}}
/>
);

View File

@@ -19,20 +19,23 @@ export const POSTGRESQL_ERROR_CODES = {
*
* @docs https://www.postgresql.org/docs/current/datatype-numeric.html
*/
export const POSTGRESQL_NUMERIC_TYPES = [
export const POSTGRESQL_INTEGER_TYPES = [
'smallint',
'integer',
'bigint',
'decimal',
'numeric',
'real',
'double precision',
'smallserial',
'serial',
'bigserial',
'oid',
];
export const POSTGRESQL_DECIMAL_TYPES = [
'decimal',
'numeric',
'real',
'double precision',
];
/**
* Character data types in PostgreSQL.
*

View File

@@ -118,8 +118,8 @@ export default function DatabaseConnectionInfo() {
}
const postgresHost = generateAppServiceUrl(
project.subdomain,
project.region,
project?.subdomain,
project?.region,
'db',
).replace('https://', '');

View File

@@ -43,7 +43,8 @@ const validationSchema = Yup.object({
value: Yup.string().required('Major version is a required field'),
})
.label('Postgres major version')
.required(),
.required()
.test('not-zero', 'Invalid major version', (value) => value?.value !== '0'),
minorVersion: Yup.object({
label: Yup.string().required(),
value: Yup.string().required('Minor version is a required field'),
@@ -186,18 +187,29 @@ export default function DatabaseServiceVersionSettings() {
shouldPoll: true,
});
const showMigrateWarning =
Number(selectedMajor) > Number(currentPostgresMajor);
const { state } = useAppState();
const applicationUpdating =
state === ApplicationStatus.Updating ||
state === ApplicationStatus.Migrating;
const applicationLive = state === ApplicationStatus.Live;
const applicationPaused = state === ApplicationStatus.Paused;
const applicationPausing = state === ApplicationStatus.Pausing;
const showMigrateWarning =
!applicationPaused &&
!applicationPausing &&
Number(selectedMajor) > Number(currentPostgresMajor);
const applicationUnhealthy =
state !== ApplicationStatus.Live && !applicationUpdating;
!applicationLive &&
!applicationPaused &&
!applicationPausing &&
!applicationUpdating;
const isMajorVersionDirty = formState?.dirtyFields?.majorVersion;
const isMinorVersionDirty = formState?.dirtyFields?.minorVersion;
const isDirty = isMajorVersionDirty || isMinorVersionDirty;
const versionFieldsDisabled =
applicationUpdating || applicationUnhealthy || maintenanceActive;
const saveDisabled = versionFieldsDisabled || !isDirty;
@@ -208,7 +220,7 @@ export default function DatabaseServiceVersionSettings() {
const newVersion = `${formValues.majorVersion.value}.${formValues.minorVersion.value}`;
// Major version change
if (isMajorVersionDirty) {
if (isMajorVersionDirty && applicationLive) {
openDialog({
title: 'Update Postgres MAJOR version',
component: (
@@ -228,7 +240,7 @@ export default function DatabaseServiceVersionSettings() {
return;
}
// Minor version change
// Only minor version change or project is paused/pausing
const updateConfigPromise = updateConfig({
variables: {
appId: project.id,
@@ -338,7 +350,6 @@ export default function DatabaseServiceVersionSettings() {
return option.value;
}}
showCustomOption="auto"
isOptionEqualToValue={() => false}
filterOptions={(options, { inputValue }) => {
const inputValueLower = inputValue.toLowerCase();
const matched = [];
@@ -383,12 +394,13 @@ export default function DatabaseServiceVersionSettings() {
form.setValue('majorVersion', value);
}
}}
clearOnBlur
fullWidth
className="lg:col-span-1"
label="MAJOR"
options={availableMajorVersions}
error={!!formState.errors?.majorVersion?.value?.message}
helperText={formState.errors?.majorVersion?.value?.message}
error={!!formState.errors?.majorVersion?.message}
helperText={formState.errors?.majorVersion?.message}
customOptionLabel={(value) => `Use custom value: "${value}"`}
/>
<ControlledAutocomplete
@@ -424,12 +436,13 @@ export default function DatabaseServiceVersionSettings() {
return result;
}}
clearOnBlur
fullWidth
className="lg:col-span-2"
label="MINOR"
options={availableMinorVersions}
error={!!formState.errors?.minorVersion?.value?.message}
helperText={formState.errors?.minorVersion?.value?.message}
error={!!formState.errors?.minorVersion?.message}
helperText={formState.errors?.minorVersion?.message}
showCustomOption="auto"
customOptionLabel={(value) => `Use custom value: "${value}"`}
/>

View File

@@ -2,11 +2,13 @@ import { useUI } from '@/components/common/UIProvider';
import { Form } from '@/components/form/Form';
import { SettingsContainer } from '@/components/layout/SettingsContainer';
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
import { Alert } from '@/components/ui/v2/Alert';
import { Box } from '@/components/ui/v2/Box';
import { Input } from '@/components/ui/v2/Input';
import { InputAdornment } from '@/components/ui/v2/InputAdornment';
import { UpgradeNotification } from '@/features/orgs/projects/common/components/UpgradeNotification';
import { useAppState } from '@/features/orgs/projects/common/hooks/useAppState';
import { useIsPlatform } from '@/features/orgs/projects/common/hooks/useIsPlatform';
import { DatabaseStorageCapacityWarning } from '@/features/orgs/projects/database/settings/components/DatabaseStorageCapacityWarning';
import { useCurrentOrg } from '@/features/orgs/projects/hooks/useCurrentOrg';
import { useLocalMimirClient } from '@/features/orgs/projects/hooks/useLocalMimirClient';
import { useProject } from '@/features/orgs/projects/hooks/useProject';
@@ -15,18 +17,25 @@ import {
useGetPostgresSettingsQuery,
useUpdateConfigMutation,
} from '@/generated/graphql';
import { ApplicationStatus } from '@/types/application';
import { yupResolver } from '@hookform/resolvers/yup';
import { useEffect } from 'react';
import { useEffect, useMemo } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import * as Yup from 'yup';
const validationSchema = Yup.object({
capacity: Yup.number().required().min(10),
capacity: Yup.number()
.integer('Capacity must be an integer')
.typeError('You must specify a number')
.min(1, 'Capacity must be greater than 0')
.required('Capacity is required'),
});
export type AuthDomainFormValues = Yup.InferType<typeof validationSchema>;
export type DatabaseStorageCapacityFormValues = Yup.InferType<
typeof validationSchema
>;
export default function AuthDomain() {
export default function DatabaseStorageCapacity() {
const isPlatform = useIsPlatform();
const { org } = useCurrentOrg();
const { maintenanceActive } = useUI();
@@ -58,8 +67,32 @@ export default function AuthDomain() {
resolver: yupResolver(validationSchema),
});
const { formState, register, reset } = form;
const { state } = useAppState();
const applicationPause =
state === ApplicationStatus.Paused || state === ApplicationStatus.Pausing;
const { formState, register, reset, watch } = form;
const isDirty = Object.keys(formState.dirtyFields).length > 0;
const newCapacity = watch('capacity');
const decreasingSize = newCapacity < capacity;
const submitDisabled = useMemo(() => {
if (!isDirty) {
return true;
}
if (maintenanceActive) {
return true;
}
if (decreasingSize && !applicationPause) {
return true;
}
return false;
}, [isDirty, maintenanceActive, decreasingSize, applicationPause]);
useEffect(() => {
if (data && !loading) {
@@ -81,7 +114,7 @@ export default function AuthDomain() {
throw error;
}
async function handleSubmit(formValues: AuthDomainFormValues) {
async function handleSubmit(formValues: DatabaseStorageCapacityFormValues) {
await execPromiseWithErrorToast(
async () => {
await updateConfig({
@@ -120,7 +153,7 @@ export default function AuthDomain() {
description="Specify the storage capacity for your PostgreSQL database."
slotProps={{
submitButton: {
disabled: !isDirty || maintenanceActive,
disabled: submitDisabled,
loading: formState.isSubmitting,
},
}}
@@ -134,25 +167,25 @@ export default function AuthDomain() {
{...register('capacity')}
id="capacity"
name="capacity"
type="number"
type="text"
endAdornment={
<InputAdornment className="absolute right-2" position="end">
GB
</InputAdornment>
}
fullWidth
disabled={project.legacyPlan?.isFree}
className="lg:col-span-2"
error={Boolean(formState.errors.capacity?.message)}
helperText={formState.errors.capacity?.message}
slotProps={{
inputRoot: {
min: capacity,
},
}}
/>
</Box>
{!project.legacyPlan?.isFree && (
<Alert severity="info" className="col-span-6 text-left">
Note that volumes can only be increased (not decreased). Also, due
to an AWS limitation, the same volume can only be increased once
every 6 hours.
</Alert>
<DatabaseStorageCapacityWarning
state={state}
decreasingSize={decreasingSize}
isDirty={isDirty}
/>
)}
</SettingsContainer>
</Form>

View File

@@ -0,0 +1,73 @@
import { Alert } from '@/components/ui/v2/Alert';
import { Text } from '@/components/ui/v2/Text';
import { ApplicationStatus } from '@/types/application';
interface DatabaseStorageCapacityWarningProps {
state: ApplicationStatus;
decreasingSize: boolean;
isDirty: boolean;
}
export default function DatabaseStorageCapacityWarning({
state,
decreasingSize,
isDirty,
}: DatabaseStorageCapacityWarningProps) {
const applicationPause =
state === ApplicationStatus.Paused || state === ApplicationStatus.Pausing;
if (!isDirty) {
return null;
}
if (state === ApplicationStatus.Live && !decreasingSize) {
return (
<Alert severity="warning" className="flex flex-col gap-3 text-left">
<div className="flex flex-col gap-2 lg:flex-row lg:justify-between">
<Text className="flex items-start gap-1 font-semibold">
<span></span> Warning: Increasing disk size
</Text>
</div>
<div>
<Text>
Due to AWS limitations, disk size can only be modified once every 6
hours. Please ensure you increase capacity sufficiently to cover
your needs during this period.
</Text>
</div>
</Alert>
);
}
if (state === ApplicationStatus.Live && decreasingSize) {
return (
<Alert severity="warning" className="flex flex-col gap-3 text-left">
<div className="flex flex-col gap-2 lg:flex-row lg:justify-between">
<Text className="flex items-start gap-1 font-semibold">
<span></span> Warning: Decreasing disk size requires project to be
paused first.
</Text>
</div>
</Alert>
);
}
if (applicationPause && decreasingSize) {
return (
<Alert severity="warning" className="flex flex-col gap-3 text-left">
<div className="flex flex-col gap-2 lg:flex-row lg:justify-between">
<Text className="flex items-start gap-1 font-semibold">
<span></span> Warning: Ensure enough space before downsizing.
</Text>
</div>
<div>
<Text>
Before downsizing, ensure enough space for your database, WAL files,
and other supporting data to prevent issues when unpausing your
project.
</Text>
</div>
</Alert>
);
}
return null;
}

View File

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

View File

@@ -28,7 +28,7 @@ const smtpValidationSchema = yup
.required(),
user: yup.string().label('Username').required(),
password: yup.string().label('Password'),
sender: yup.string().label('SMTP Sender').email().required(),
sender: yup.string().label('SMTP Sender').required(),
})
.required();

View File

@@ -18,15 +18,19 @@ import { calculateBillableResources } from '@/features/orgs/projects/resources/s
import type { ResourceSettingsFormValues } from '@/features/orgs/projects/resources/settings/utils/resourceSettingsValidationSchema';
import { resourceSettingsValidationSchema } from '@/features/orgs/projects/resources/settings/utils/resourceSettingsValidationSchema';
import { execPromiseWithErrorToast } from '@/features/orgs/utils/execPromiseWithErrorToast';
import {
RESOURCE_VCPU_MULTIPLIER,
RESOURCE_VCPU_PRICE,
} from '@/utils/constants/common';
import type { GetResourcesQuery } from '@/utils/__generated__/graphql';
import type {
ConfigConfigUpdateInput,
GetResourcesQuery,
} from '@/utils/__generated__/graphql';
import {
useGetResourcesQuery,
useUpdateConfigMutation,
} from '@/utils/__generated__/graphql';
import {
RESOURCE_VCPU_MULTIPLIER,
RESOURCE_VCPU_PRICE,
} from '@/utils/constants/common';
import { removeTypename } from '@/utils/helpers';
import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, useForm } from 'react-hook-form';
import { twMerge } from 'tailwind-merge';
@@ -36,7 +40,7 @@ function getInitialServiceResources(
data: GetResourcesQuery,
service: Exclude<keyof GetResourcesQuery['config'], '__typename'>,
) {
const { compute, replicas, autoscaler } =
const { compute, replicas, autoscaler, ...rest } =
data?.config?.[service]?.resources || {};
return {
@@ -44,6 +48,7 @@ function getInitialServiceResources(
vcpu: compute?.cpu || 0,
memory: compute?.memory || 0,
autoscale: autoscaler || null,
rest,
};
}
@@ -176,76 +181,130 @@ export default function ResourcesForm() {
? (billableResources.vcpu / RESOURCE_VCPU_MULTIPLIER) * RESOURCE_VCPU_PRICE
: 0;
const getFormattedConfig = (
values: ResourceSettingsFormValues,
): ConfigConfigUpdateInput => {
const sanitizedValues = removeTypename(
values,
) as ResourceSettingsFormValues;
const sanitizedInitialDatabaseResources = removeTypename(
initialDatabaseResources,
);
const sanitizedInitialHasuraResources = removeTypename(
initialHasuraResources,
);
const sanitizedInitialAuthResources = removeTypename(initialAuthResources);
const sanitizedInitialStorageResources = removeTypename(
initialStorageResources,
);
if (sanitizedValues.enabled) {
return {
postgres: {
resources: {
compute: {
cpu: sanitizedValues.database.vcpu,
memory: sanitizedValues.database.memory,
},
replicas: sanitizedValues.database.replicas,
autoscaler: sanitizedValues.database.autoscale
? {
maxReplicas: sanitizedValues.database.maxReplicas,
}
: null,
...sanitizedInitialDatabaseResources.rest,
},
},
hasura: {
resources: {
compute: {
cpu: sanitizedValues.hasura.vcpu,
memory: sanitizedValues.hasura.memory,
},
replicas: sanitizedValues.hasura.replicas,
autoscaler: sanitizedValues.hasura.autoscale
? {
maxReplicas: sanitizedValues.hasura.maxReplicas,
}
: null,
...sanitizedInitialHasuraResources.rest,
},
},
auth: {
resources: {
compute: {
cpu: sanitizedValues.auth.vcpu,
memory: sanitizedValues.auth.memory,
},
replicas: sanitizedValues.auth.replicas,
autoscaler: sanitizedValues.auth.autoscale
? {
maxReplicas: sanitizedValues.auth.maxReplicas,
}
: null,
...sanitizedInitialAuthResources.rest,
},
},
storage: {
resources: {
compute: {
cpu: sanitizedValues.storage.vcpu,
memory: sanitizedValues.storage.memory,
},
replicas: sanitizedValues.storage.replicas,
autoscaler: sanitizedValues.storage.autoscale
? {
maxReplicas: sanitizedValues.storage.maxReplicas,
}
: null,
...sanitizedInitialStorageResources.rest,
},
},
};
}
return {
postgres: {
resources: {
compute: null,
replicas: null,
autoscaler: null,
...sanitizedInitialDatabaseResources.rest,
},
},
hasura: {
resources: {
compute: null,
replicas: null,
autoscaler: null,
...sanitizedInitialHasuraResources.rest,
},
},
auth: {
resources: {
compute: null,
replicas: null,
autoscaler: null,
...sanitizedInitialAuthResources.rest,
},
},
storage: {
resources: {
compute: null,
replicas: null,
autoscaler: null,
...sanitizedInitialStorageResources.rest,
},
},
};
};
async function handleSubmit(formValues: ResourceSettingsFormValues) {
const updateConfigPromise = updateConfig({
variables: {
appId: project?.id,
config: {
postgres: {
resources: formValues.enabled
? {
compute: {
cpu: formValues.database.vcpu,
memory: formValues.database.memory,
},
replicas: formValues.database.replicas,
autoscaler: formValues.database.autoscale
? {
maxReplicas: formValues.database.maxReplicas,
}
: null,
}
: null,
},
hasura: {
resources: formValues.enabled
? {
compute: {
cpu: formValues.hasura.vcpu,
memory: formValues.hasura.memory,
},
replicas: formValues.hasura.replicas,
autoscaler: formValues.hasura.autoscale
? {
maxReplicas: formValues.hasura.maxReplicas,
}
: null,
}
: null,
},
auth: {
resources: formValues.enabled
? {
compute: {
cpu: formValues.auth.vcpu,
memory: formValues.auth.memory,
},
replicas: formValues.auth.replicas,
autoscaler: formValues.auth.autoscale
? {
maxReplicas: formValues.auth.maxReplicas,
}
: null,
}
: null,
},
storage: {
resources: formValues.enabled
? {
compute: {
cpu: formValues.storage.vcpu,
memory: formValues.storage.memory,
},
replicas: formValues.storage.replicas,
autoscaler: formValues.storage.autoscale
? {
maxReplicas: formValues.storage.maxReplicas,
}
: null,
}
: null,
},
},
config: getFormattedConfig(formValues),
},
});

View File

@@ -171,7 +171,7 @@ export default function ServiceResourcesFormFragment({
</Box>
<Box className="grid grid-flow-row gap-2">
<Box className="grid items-center justify-between grid-flow-col gap-2">
<Box className="grid grid-flow-col items-center justify-between gap-2">
<Text>
Allocated vCPUs:{' '}
<span className="font-medium">
@@ -201,7 +201,7 @@ export default function ServiceResourcesFormFragment({
</Box>
<Box className="grid grid-flow-row gap-2">
<Box className="grid items-center justify-between grid-flow-col gap-2">
<Box className="grid grid-flow-col items-center justify-between gap-2">
<Text>
Allocated Memory:{' '}
<span className="font-medium">
@@ -246,7 +246,7 @@ export default function ServiceResourcesFormFragment({
>
<ExclamationIcon
color="error"
className="w-4 h-4"
className="h-4 w-4"
aria-hidden="false"
/>
</Tooltip>
@@ -274,7 +274,7 @@ export default function ServiceResourcesFormFragment({
>
<ExclamationIcon
color="error"
className="w-4 h-4"
className="h-4 w-4"
aria-hidden="false"
/>
</Tooltip>
@@ -306,7 +306,7 @@ export default function ServiceResourcesFormFragment({
<Tooltip
title={`Enable autoscaler to automatically provision extra ${title} replicas when needed.`}
>
<InfoOutlinedIcon className="w-4 h-4 text-black" />
<InfoOutlinedIcon className="h-4 w-4" />
</Tooltip>
</Box>
</Box>
@@ -323,7 +323,7 @@ export default function ServiceResourcesFormFragment({
className="font-medium"
>
Service Replicas
<ArrowSquareOutIcon className="w-4 h-4 ml-1" />
<ArrowSquareOutIcon className="ml-1 h-4 w-4" />
</Link>
</Text>
)}

View File

@@ -9,6 +9,11 @@ fragment ServiceResources on ConfigConfig {
autoscaler {
maxReplicas
}
networking {
ingresses {
fqdn
}
}
}
}
hasura {
@@ -21,10 +26,19 @@ fragment ServiceResources on ConfigConfig {
autoscaler {
maxReplicas
}
networking {
ingresses {
fqdn
}
}
}
}
postgres {
resources {
storage {
capacity
}
enablePublicAccess
compute {
cpu
memory

View File

@@ -19,7 +19,6 @@ import { StorageFormSection } from '@/features/orgs/projects/services/components
import { useHostName } from '@/features/projects/common/hooks/useHostName';
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
import { COST_PER_VCPU } from '@/features/projects/resources/settings/utils/resourceSettingsValidationSchema';
import { v4 as uuidv4 } from 'uuid';
import {
validationSchema,
@@ -29,16 +28,15 @@ import {
import { useProject } from '@/features/orgs/projects/hooks/useProject';
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
import {
useInsertRunServiceConfigMutation,
useReplaceRunServiceConfigMutation,
type ConfigRunServiceConfigInsertInput,
} from '@/utils/__generated__/graphql';
import { RESOURCE_VCPU_MULTIPLIER } from '@/utils/constants/common';
import { copy } from '@/utils/copy';
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { removeTypename } from '@/utils/helpers';
import {
useInsertRunServiceConfigMutation,
useInsertRunServiceMutation,
useReplaceRunServiceConfigMutation,
type ConfigRunServiceConfigInsertInput,
} from '@/utils/__generated__/graphql';
import { yupResolver } from '@hookform/resolvers/yup';
import { useEffect, useMemo, useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
@@ -58,9 +56,10 @@ export default function ServiceForm({
const isPlatform = useIsPlatform();
const localMimirClient = useLocalMimirClient();
const { onDirtyStateChange, openDialog, closeDialog } = useDialog();
const [insertRunService] = useInsertRunServiceMutation();
const { project } = useProject();
const [insertRunServiceConfig] = useInsertRunServiceConfigMutation();
const [insertRunServiceConfig] = useInsertRunServiceConfigMutation({
...(!isPlatform ? { client: localMimirClient } : {}),
});
const [replaceRunServiceConfig] = useReplaceRunServiceConfigMutation({
...(!isPlatform ? { client: localMimirClient } : {}),
});
@@ -96,14 +95,14 @@ export default function ServiceForm({
if (serviceID) {
return serviceID;
}
return uuidv4();
return '<uuid-to-be-generated-on-creation>';
}, [serviceID]);
const privateRegistryImage = `registry.${project?.region.name}.${project?.region.domain}/${newServiceID}`;
let initialImageType: 'public' | 'private' | 'nhost' = 'public';
if (initialData?.image?.startsWith(privateRegistryImage)) {
if (initialData?.image?.startsWith(privateRegistryImage.split('/')[0])) {
initialImageType = 'nhost';
}
@@ -225,33 +224,14 @@ export default function ServiceForm({
});
}
} else {
// Insert service config
const {
data: {
insertRunService: { id },
},
} = await insertRunService({
variables: {
object: {
appID: project.id,
id: newServiceID,
},
},
});
// Create service
await insertRunServiceConfig({
variables: {
appID: project.id,
serviceID: id,
config: {
...config,
image: {
// If the image field left empty then we auto-populate following this format
// registry.<region>.<nhost_domain>/<service_id>
image:
values.image.length > 0
? values.image
: `registry.${project.region.name}.${project.region.domain}/${newServiceID}`,
image: values.image,
pullCredentials:
values.pullCredentials?.length > 0
? values.pullCredentials
@@ -335,7 +315,7 @@ export default function ServiceForm({
<Tooltip title="Name of the service, must be unique per project.">
<InfoIcon
aria-label="Info"
className="w-4 h-4"
className="h-4 w-4"
color="primary"
/>
</Tooltip>
@@ -359,7 +339,7 @@ export default function ServiceForm({
<Tooltip title="Command to run when to start the service. This is optional as the image may already have a baked-in command.">
<InfoIcon
aria-label="Info"
className="w-4 h-4"
className="h-4 w-4"
color="primary"
/>
</Tooltip>
@@ -414,7 +394,7 @@ export default function ServiceForm({
{createServiceFormError && (
<Alert
severity="error"
className="grid items-center justify-between grid-flow-col px-4 py-3"
className="grid grid-flow-col items-center justify-between px-4 py-3"
>
<span className="text-left">
<strong>Error:</strong> {createServiceFormError.message}

View File

@@ -12,7 +12,11 @@ import {
export const validationSchema = Yup.object({
name: Yup.string().required('The name is required.'),
image: Yup.string().label('Image to run').required('The image is required.'),
image: Yup.string()
.trim()
.label('Image to run')
.required('The image is required.')
.min(1, 'Image must be at least 1 character long'),
pullCredentials: Yup.string().label('Pull credentials').nullable(),
command: Yup.string(),
environment: Yup.array().of(

View File

@@ -45,7 +45,7 @@ export default function ReplicasFormSection() {
};
return (
<Box className="p-4 space-y-4 rounded border-1">
<Box className="space-y-4 rounded border-1 p-4">
<Box className="flex flex-row items-center space-x-2">
<Text variant="h4" className="font-semibold">
Replicas ({replicas})
@@ -65,7 +65,7 @@ export default function ReplicasFormSection() {
</Text>
}
>
<InfoIcon aria-label="Info" className="w-4 h-4" color="primary" />
<InfoIcon aria-label="Info" className="h-4 w-4" color="primary" />
</Tooltip>
</Box>
@@ -121,7 +121,7 @@ export default function ReplicasFormSection() {
/>
<Text>Autoscaler</Text>
<Tooltip title="Enable autoscaler to automatically provision extra run service replicas when needed.">
<InfoOutlinedIcon className="w-4 h-4 text-black" />
<InfoOutlinedIcon className="h-4 w-4" />
</Tooltip>
</Box>
</Box>

View File

@@ -0,0 +1,108 @@
import type { CommonDataGridCellProps } from '@/components/dataGrid/DataGridCell';
import { useDataGridCell } from '@/components/dataGrid/DataGridCell';
import { Input, inputClasses } from '@/components/ui/v2/Input';
import { Text } from '@/components/ui/v2/Text';
import type { ChangeEvent, KeyboardEvent } from 'react';
export type DataGridDecimalCellProps<TData extends object> =
CommonDataGridCellProps<TData, number | string>;
export default function DataGridDecimalCell<TData extends object>({
onSave,
optimisticValue,
temporaryValue,
onTemporaryValueChange,
}: DataGridDecimalCellProps<TData>) {
const { inputRef, focusCell, isEditing, cancelEditCell } =
useDataGridCell<HTMLInputElement>();
async function handleSave() {
if (onSave) {
if (typeof temporaryValue === 'string') {
await onSave(parseFloat(temporaryValue));
} else if (typeof temporaryValue === 'number') {
await onSave(temporaryValue);
} else {
await onSave(null);
}
}
}
async function handleKeyDown(event: KeyboardEvent<HTMLInputElement>) {
if (
event.key === 'ArrowLeft' ||
event.key === 'ArrowRight' ||
event.key === 'ArrowUp' ||
event.key === 'ArrowDown' ||
event.key === 'Backspace'
) {
event.stopPropagation();
}
if (event.key === 'Tab') {
await handleSave();
}
if (event.key === 'Enter') {
await handleSave();
await focusCell();
cancelEditCell();
}
}
function handleChange(event: ChangeEvent<HTMLInputElement>) {
if (onTemporaryValueChange) {
onTemporaryValueChange(event.target.value ?? null);
}
}
if (isEditing) {
return (
<Input
type="text"
ref={inputRef}
value={
temporaryValue !== null && typeof temporaryValue !== 'undefined'
? temporaryValue
: ''
}
onKeyDown={handleKeyDown}
onChange={handleChange}
fullWidth
className="absolute top-0 z-10 -mx-0.5 h-full place-content-stretch"
sx={{
[`&.${inputClasses.focused}`]: {
boxShadow: `inset 0 0 0 1.5px rgba(0, 82, 205, 1)`,
borderColor: 'transparent !important',
borderRadius: 0,
backgroundColor: (theme) =>
theme.palette.mode === 'dark'
? `${theme.palette.secondary[100]} !important`
: `${theme.palette.common.white} !important`,
},
[`& .${inputClasses.input}`]: {
backgroundColor: 'transparent',
},
}}
slotProps={{
inputWrapper: { className: 'h-full' },
input: { className: 'h-full' },
inputRoot: {
className:
'resize-none outline-none focus:outline-none !text-xs focus:ring-0',
},
}}
/>
);
}
if (optimisticValue === null || typeof optimisticValue === 'undefined') {
return (
<Text className="truncate !text-xs" color="disabled">
null
</Text>
);
}
return <Text className="truncate !text-xs">{optimisticValue}</Text>;
}

View File

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

View File

@@ -4,15 +4,15 @@ import { Input, inputClasses } from '@/components/ui/v2/Input';
import { Text } from '@/components/ui/v2/Text';
import type { ChangeEvent, KeyboardEvent } from 'react';
export type DataGridNumericCellProps<TData extends object> =
export type DataGridIntegerCellProps<TData extends object> =
CommonDataGridCellProps<TData, number>;
export default function DataGridNumericCell<TData extends object>({
export default function DataGridIntegerCell<TData extends object>({
onSave,
optimisticValue,
temporaryValue,
onTemporaryValueChange,
}: DataGridNumericCellProps<TData>) {
}: DataGridIntegerCellProps<TData>) {
const { inputRef, focusCell, isEditing, cancelEditCell } =
useDataGridCell<HTMLInputElement>();

View File

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

View File

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

View File

@@ -28,16 +28,15 @@ import {
type ServiceFormValues,
} from '@/features/services/components/ServiceForm/ServiceFormTypes';
import { useLocalMimirClient } from '@/hooks/useLocalMimirClient';
import {
useInsertRunServiceConfigMutation,
useReplaceRunServiceConfigMutation,
type ConfigRunServiceConfigInsertInput,
} from '@/utils/__generated__/graphql';
import { RESOURCE_VCPU_MULTIPLIER } from '@/utils/constants/common';
import { copy } from '@/utils/copy';
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
import { removeTypename } from '@/utils/helpers';
import {
useInsertRunServiceConfigMutation,
useInsertRunServiceMutation,
useReplaceRunServiceConfigMutation,
type ConfigRunServiceConfigInsertInput,
} from '@/utils/__generated__/graphql';
import { yupResolver } from '@hookform/resolvers/yup';
import { useEffect, useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
@@ -57,7 +56,6 @@ export default function ServiceForm({
const isPlatform = useIsPlatform();
const localMimirClient = useLocalMimirClient();
const { onDirtyStateChange, openDialog, closeDialog } = useDialog();
const [insertRunService] = useInsertRunServiceMutation();
const { currentProject } = useCurrentWorkspaceAndProject();
const [insertRunServiceConfig] = useInsertRunServiceConfigMutation();
const [replaceRunServiceConfig] = useReplaceRunServiceConfigMutation({
@@ -187,20 +185,11 @@ export default function ServiceForm({
// Insert service config
const {
data: {
insertRunService: { id: newServiceID, subdomain },
insertRunServiceConfig: { serviceID: newServiceID },
},
} = await insertRunService({
variables: {
object: {
appID: currentProject.id,
},
},
});
await insertRunServiceConfig({
} = await insertRunServiceConfig({
variables: {
appID: currentProject.id,
serviceID: newServiceID,
config: {
...config,
image: {
@@ -209,14 +198,14 @@ export default function ServiceForm({
image:
values.image.length > 0
? values.image
: `registry.${currentProject.region.name}.${currentProject.region.domain}/${newServiceID}`,
: `registry.${currentProject.region.name}.${currentProject.region.domain}/<uuid-to-be-generated-on-creation>`,
},
},
},
});
setDetailsServiceId(newServiceID);
setDetailsServiceSubdomain(subdomain);
setDetailsServiceSubdomain('');
}
};
@@ -322,7 +311,7 @@ export default function ServiceForm({
<Tooltip title="Name of the service, must be unique per project.">
<InfoIcon
aria-label="Info"
className="w-4 h-4"
className="h-4 w-4"
color="primary"
/>
</Tooltip>
@@ -362,7 +351,7 @@ export default function ServiceForm({
>
<InfoIcon
aria-label="Info"
className="w-4 h-4"
className="h-4 w-4"
color="primary"
/>
</Tooltip>
@@ -393,7 +382,7 @@ export default function ServiceForm({
<Tooltip title="Command to run when to start the service. This is optional as the image may already have a baked-in command.">
<InfoIcon
aria-label="Info"
className="w-4 h-4"
className="h-4 w-4"
color="primary"
/>
</Tooltip>
@@ -441,7 +430,7 @@ export default function ServiceForm({
{createServiceFormError && (
<Alert
severity="error"
className="grid items-center justify-between grid-flow-col px-4 py-3"
className="grid grid-flow-col items-center justify-between px-4 py-3"
>
<span className="text-left">
<strong>Error:</strong> {createServiceFormError.message}

View File

@@ -1,6 +0,0 @@
mutation insertRunService($object: run_service_insert_input!) {
insertRunService(object: $object) {
id
subdomain
}
}

View File

@@ -1,13 +1,11 @@
mutation insertRunServiceConfig(
mutation InsertRunServiceConfig(
$appID: uuid!
$serviceID: uuid!
$config: ConfigRunServiceConfigInsertInput!
) {
insertRunServiceConfig(
appID: $appID
serviceID: $serviceID
config: $config
) {
name
insertRunServiceConfig(appID: $appID, config: $config) {
serviceID
config {
name
}
}
}

View File

@@ -4,7 +4,10 @@ import { Form } from '@/components/form/Form';
import { Container } from '@/components/layout/Container';
import { SettingsContainer } from '@/components/layout/SettingsContainer';
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
import { Alert } from '@/components/ui/v2/Alert';
import { Input } from '@/components/ui/v2/Input';
import { Link } from '@/components/ui/v2/Link';
import { Text } from '@/components/ui/v2/Text';
import { TransferProject } from '@/features/orgs/components/TransferProject';
import { ProjectLayout } from '@/features/orgs/layout/ProjectLayout';
import { SettingsLayout } from '@/features/orgs/layout/SettingsLayout';
@@ -12,6 +15,7 @@ import { RemoveApplicationModal } from '@/features/orgs/projects/common/componen
import { useAppState } from '@/features/orgs/projects/common/hooks/useAppState';
import { useIsCurrentUserOwner } from '@/features/orgs/projects/common/hooks/useIsCurrentUserOwner';
import { useIsPlatform } from '@/features/orgs/projects/common/hooks/useIsPlatform';
import { useRunServices } from '@/features/orgs/projects/common/hooks/useRunServices';
import { useOrgs } from '@/features/orgs/projects/hooks/useOrgs';
import { useProject } from '@/features/orgs/projects/hooks/useProject';
import { execPromiseWithErrorToast } from '@/features/orgs/utils/execPromiseWithErrorToast';
@@ -25,7 +29,7 @@ import { ApplicationStatus } from '@/types/application';
import { slugifyString } from '@/utils/helpers';
import { yupResolver } from '@hookform/resolvers/yup';
import { useRouter } from 'next/router';
import type { ReactElement } from 'react';
import { useMemo, type ReactElement } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import * as Yup from 'yup';
@@ -51,6 +55,20 @@ export default function SettingsGeneralPage() {
const { project, loading, refetch: refetchProject } = useProject();
const { state } = useAppState();
const { services } = useRunServices();
const showWarning = useMemo(() => {
const isPlanFree = org?.plan?.isFree;
if (isPlanFree) {
return false;
}
return services?.some(
(service) => service?.config?.resources?.storage?.length > 0,
);
}, [org?.plan?.isFree, services]);
const [updateApp] = useUpdateApplicationMutation();
const [deleteApplication] = useBillingDeleteAppMutation();
const [pauseApplication, { loading: pauseApplicationLoading }] =
@@ -242,9 +260,49 @@ export default function SettingsGeneralPage() {
onClick: () => {
openAlertDialog({
title: 'Pause Project?',
payload:
'Are you sure you want to pause this project? It will not be accessible until you unpause it.',
payload: (
<div className="flex flex-col gap-2">
{showWarning ? (
<Alert
severity="warning"
className="flex flex-col gap-3 text-left"
>
<div className="flex flex-col gap-2 lg:flex-row lg:justify-between">
<Text className="flex items-start gap-1 font-semibold">
<span></span> Warning: This action will delete
all volume data for your Run services.
</Text>
</div>
<div className="flex flex-col gap-4">
<Text>
Pausing this project will delete all persistent
volume data for your Run services. No automatic
backups are made. Please backup your data
manually to prevent loss. Contact{' '}
<Link
href="/support"
target="_blank"
className="underline"
sx={{
color: 'text.primary',
}}
rel="noopener noreferrer"
>
support
</Link>{' '}
with any questions.
</Text>
</div>
</Alert>
) : null}
<p className="text-pretty">
Are you sure you want to pause this project? It will
not be accessible until you unpause it.
</p>
</div>
),
props: {
maxWidth: 'sm',
onPrimaryAction: handlePauseApplication,
},
});

View File

@@ -19,7 +19,7 @@ const validationSchema = Yup.object({
email: Yup.string().label('Email').email().required(),
});
export type ResetPasswordFormValues = Yup.InferType<typeof validationSchema>;
export type NewPasswordFormValues = Yup.InferType<typeof validationSchema>;
const StyledInput = styled(Input)({
backgroundColor: 'transparent',
@@ -28,10 +28,10 @@ const StyledInput = styled(Input)({
},
});
export default function ResetPasswordPage() {
export default function NewPasswordPage() {
const { resetPassword, error, isSent } = useResetPassword();
const form = useForm<ResetPasswordFormValues>({
const form = useForm<NewPasswordFormValues>({
reValidateMode: 'onSubmit',
defaultValues: {
email: '',
@@ -52,9 +52,11 @@ export default function ResetPasswordPage() {
);
}, [error]);
async function handleSubmit({ email }: ResetPasswordFormValues) {
async function handleSubmit({ email }: NewPasswordFormValues) {
try {
await resetPassword(email);
await resetPassword(email, {
redirectTo: '/password/reset',
});
} catch {
toast.error(
'An error occurred while signing up. Please try again.',
@@ -124,8 +126,10 @@ export default function ResetPasswordPage() {
);
}
ResetPasswordPage.getLayout = function getLayout(page: ReactElement) {
NewPasswordPage.getLayout = function getLayout(page: ReactElement) {
return (
<UnauthenticatedLayout title="Reset Password">{page}</UnauthenticatedLayout>
<UnauthenticatedLayout title="Request Password Reset">
{page}
</UnauthenticatedLayout>
);
};

View File

@@ -0,0 +1,144 @@
import { NavLink } from '@/components/common/NavLink';
import { Form } from '@/components/form/Form';
import { UnauthenticatedLayout } from '@/components/layout/UnauthenticatedLayout';
import { Box } from '@/components/ui/v2/Box';
import { Button } from '@/components/ui/v2/Button';
import { Input, inputClasses } from '@/components/ui/v2/Input';
import { Text } from '@/components/ui/v2/Text';
import { getToastStyleProps } from '@/utils/constants/settings';
import { yupResolver } from '@hookform/resolvers/yup';
import { styled } from '@mui/material';
import { useChangePassword } from '@nhost/nextjs';
import { useRouter } from 'next/router';
import type { ReactElement } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import * as Yup from 'yup';
const validationSchema = Yup.object({
newPassword: Yup.string()
.label('New Password')
.required('New Password is required'),
confirmNewPassword: Yup.string()
.label('Confirm New Password')
.required('Confirm New Password is required')
.oneOf([Yup.ref('newPassword')], 'Passwords must match'),
});
export type ResetPasswordFormValues = Yup.InferType<typeof validationSchema>;
const StyledInput = styled(Input)({
backgroundColor: 'transparent',
[`& .${inputClasses.input}`]: {
backgroundColor: 'transparent !important',
},
});
export default function ResetPasswordPage() {
const router = useRouter();
const { changePassword } = useChangePassword();
const form = useForm<ResetPasswordFormValues>({
reValidateMode: 'onSubmit',
defaultValues: {
newPassword: '',
confirmNewPassword: '',
},
resolver: yupResolver(validationSchema),
});
const { register, formState } = form;
async function handleSubmit({ newPassword }: ResetPasswordFormValues) {
try {
const password = newPassword;
const { isError, error } = await changePassword(password);
if (isError) {
toast.error(
`An error occurred while changing your password: ${error.message}`,
getToastStyleProps(),
);
return;
}
toast.success('Password was updated successfully.');
router.push('/');
} catch {
toast.error(
'An error occurred while updating your password. Please try again.',
getToastStyleProps(),
);
}
}
return (
<>
<Text
variant="h2"
component="h1"
className="text-center text-3.5xl font-semibold lg:text-4.5xl"
>
Change password
</Text>
<Box className="grid grid-flow-row gap-4 rounded-md border bg-transparent p-6 lg:p-12">
<FormProvider {...form}>
<Form
onSubmit={handleSubmit}
className="grid grid-flow-row gap-4 bg-transparent"
>
<StyledInput
{...register('newPassword')}
type="password"
id="newPassword"
label="New Password"
fullWidth
inputProps={{ min: 2, max: 128 }}
error={!!formState.errors.newPassword}
helperText={formState.errors.newPassword?.message}
/>
<StyledInput
{...register('confirmNewPassword')}
type="password"
id="confirmNewPassword"
label="Confirm New Password"
fullWidth
inputProps={{ min: 2, max: 128 }}
error={!!formState.errors.confirmNewPassword}
helperText={formState.errors.confirmNewPassword?.message}
/>
<Button
className="!bg-white !text-black disabled:!text-black disabled:!text-opacity-60"
size="large"
type="submit"
disabled={formState.isSubmitting}
loading={formState.isSubmitting}
>
Change password
</Button>
</Form>
</FormProvider>
</Box>
<Text color="secondary" className="text-center text-base lg:text-lg">
Go back to{' '}
<NavLink href="/signin/email" color="white" className="font-medium">
Sign In
</NavLink>
</Text>
</>
);
}
ResetPasswordPage.getLayout = function getLayout(page: ReactElement) {
return (
<UnauthenticatedLayout title="Request Password Reset">
{page}
</UnauthenticatedLayout>
);
};

View File

@@ -85,7 +85,7 @@ export default function EmailSignUpPage() {
Sign In
</Text>
<Box className="grid grid-flow-row gap-4 p-6 bg-transparent border rounded-md lg:p-12">
<Box className="grid grid-flow-row gap-4 rounded-md border bg-transparent p-6 lg:p-12">
<FormProvider {...form}>
<Form
onSubmit={handleSubmit}
@@ -123,9 +123,9 @@ export default function EmailSignUpPage() {
/>
<NavLink
href="/reset-password"
href="/password/new"
color="white"
className="font-semibold justify-self-start"
className="justify-self-start font-semibold"
>
Forgot password?
</NavLink>
@@ -150,7 +150,7 @@ export default function EmailSignUpPage() {
</FormProvider>
</Box>
<Text color="secondary" className="text-base text-center lg:text-lg">
<Text color="secondary" className="text-center text-base lg:text-lg">
Don&apos;t have an account?{' '}
<NavLink href="/signup" color="white">
Sign Up

View File

@@ -3191,6 +3191,12 @@ export type ContainerError = {
name: Scalars['String'];
};
export type InsertRunServiceConfigResponse = {
__typename?: 'InsertRunServiceConfigResponse';
config: ConfigRunServiceConfig;
serviceID: Scalars['uuid'];
};
/** Boolean expression to compare columns of type "Int". All fields are combined with logical 'AND'. */
export type Int_Comparison_Exp = {
_eq?: InputMaybe<Scalars['Int']>;
@@ -13530,7 +13536,7 @@ export type Mutation_Root = {
insertRegionsAllowedWorkspaces?: Maybe<Regions_Allowed_Workspace_Mutation_Response>;
/** insert a single row into the table: "run_service" */
insertRunService?: Maybe<Run_Service>;
insertRunServiceConfig: ConfigRunServiceConfig;
insertRunServiceConfig: InsertRunServiceConfigResponse;
/** insert data into the table: "run_service" */
insertRunServices?: Maybe<Run_Service_Mutation_Response>;
insertSecret: ConfigEnvironmentVariable;
@@ -15213,7 +15219,6 @@ export type Mutation_RootInsertRunServiceArgs = {
export type Mutation_RootInsertRunServiceConfigArgs = {
appID: Scalars['uuid'];
config: ConfigRunServiceConfigInsertInput;
serviceID: Scalars['uuid'];
};
@@ -16986,7 +16991,7 @@ export type Organization_Member_Invites = {
role: Organization_Members_Role_Enum;
updateAt: Scalars['timestamptz'];
/** An object relationship */
user: Users;
user?: Maybe<Users>;
};
/** aggregated selection of "organization_member_invites" */
@@ -22517,9 +22522,6 @@ export type Run_Service = {
appID: Scalars['uuid'];
config?: Maybe<ConfigRunServiceConfig>;
createdAt: Scalars['timestamptz'];
/** An object relationship */
creator: Users;
creatorUserId: Scalars['uuid'];
id: Scalars['uuid'];
mimirConfigEnc?: Maybe<Scalars['String']>;
subdomain: Scalars['String'];
@@ -22587,8 +22589,6 @@ export type Run_Service_Bool_Exp = {
app?: InputMaybe<Apps_Bool_Exp>;
appID?: InputMaybe<Uuid_Comparison_Exp>;
createdAt?: InputMaybe<Timestamptz_Comparison_Exp>;
creator?: InputMaybe<Users_Bool_Exp>;
creatorUserId?: InputMaybe<Uuid_Comparison_Exp>;
id?: InputMaybe<Uuid_Comparison_Exp>;
mimirConfigEnc?: InputMaybe<String_Comparison_Exp>;
subdomain?: InputMaybe<String_Comparison_Exp>;
@@ -22608,8 +22608,6 @@ export type Run_Service_Insert_Input = {
app?: InputMaybe<Apps_Obj_Rel_Insert_Input>;
appID?: InputMaybe<Scalars['uuid']>;
createdAt?: InputMaybe<Scalars['timestamptz']>;
creator?: InputMaybe<Users_Obj_Rel_Insert_Input>;
creatorUserId?: InputMaybe<Scalars['uuid']>;
id?: InputMaybe<Scalars['uuid']>;
mimirConfigEnc?: InputMaybe<Scalars['String']>;
subdomain?: InputMaybe<Scalars['String']>;
@@ -22621,7 +22619,6 @@ export type Run_Service_Max_Fields = {
__typename?: 'run_service_max_fields';
appID?: Maybe<Scalars['uuid']>;
createdAt?: Maybe<Scalars['timestamptz']>;
creatorUserId?: Maybe<Scalars['uuid']>;
id?: Maybe<Scalars['uuid']>;
mimirConfigEnc?: Maybe<Scalars['String']>;
subdomain?: Maybe<Scalars['String']>;
@@ -22632,7 +22629,6 @@ export type Run_Service_Max_Fields = {
export type Run_Service_Max_Order_By = {
appID?: InputMaybe<Order_By>;
createdAt?: InputMaybe<Order_By>;
creatorUserId?: InputMaybe<Order_By>;
id?: InputMaybe<Order_By>;
mimirConfigEnc?: InputMaybe<Order_By>;
subdomain?: InputMaybe<Order_By>;
@@ -22644,7 +22640,6 @@ export type Run_Service_Min_Fields = {
__typename?: 'run_service_min_fields';
appID?: Maybe<Scalars['uuid']>;
createdAt?: Maybe<Scalars['timestamptz']>;
creatorUserId?: Maybe<Scalars['uuid']>;
id?: Maybe<Scalars['uuid']>;
mimirConfigEnc?: Maybe<Scalars['String']>;
subdomain?: Maybe<Scalars['String']>;
@@ -22655,7 +22650,6 @@ export type Run_Service_Min_Fields = {
export type Run_Service_Min_Order_By = {
appID?: InputMaybe<Order_By>;
createdAt?: InputMaybe<Order_By>;
creatorUserId?: InputMaybe<Order_By>;
id?: InputMaybe<Order_By>;
mimirConfigEnc?: InputMaybe<Order_By>;
subdomain?: InputMaybe<Order_By>;
@@ -22683,8 +22677,6 @@ export type Run_Service_Order_By = {
app?: InputMaybe<Apps_Order_By>;
appID?: InputMaybe<Order_By>;
createdAt?: InputMaybe<Order_By>;
creator?: InputMaybe<Users_Order_By>;
creatorUserId?: InputMaybe<Order_By>;
id?: InputMaybe<Order_By>;
mimirConfigEnc?: InputMaybe<Order_By>;
subdomain?: InputMaybe<Order_By>;
@@ -22703,8 +22695,6 @@ export enum Run_Service_Select_Column {
/** column name */
CreatedAt = 'createdAt',
/** column name */
CreatorUserId = 'creatorUserId',
/** column name */
Id = 'id',
/** column name */
MimirConfigEnc = 'mimirConfigEnc',
@@ -22718,7 +22708,6 @@ export enum Run_Service_Select_Column {
export type Run_Service_Set_Input = {
appID?: InputMaybe<Scalars['uuid']>;
createdAt?: InputMaybe<Scalars['timestamptz']>;
creatorUserId?: InputMaybe<Scalars['uuid']>;
id?: InputMaybe<Scalars['uuid']>;
mimirConfigEnc?: InputMaybe<Scalars['String']>;
subdomain?: InputMaybe<Scalars['String']>;
@@ -22737,7 +22726,6 @@ export type Run_Service_Stream_Cursor_Input = {
export type Run_Service_Stream_Cursor_Value_Input = {
appID?: InputMaybe<Scalars['uuid']>;
createdAt?: InputMaybe<Scalars['timestamptz']>;
creatorUserId?: InputMaybe<Scalars['uuid']>;
id?: InputMaybe<Scalars['uuid']>;
mimirConfigEnc?: InputMaybe<Scalars['String']>;
subdomain?: InputMaybe<Scalars['String']>;
@@ -22751,8 +22739,6 @@ export enum Run_Service_Update_Column {
/** column name */
CreatedAt = 'createdAt',
/** column name */
CreatorUserId = 'creatorUserId',
/** column name */
Id = 'id',
/** column name */
MimirConfigEnc = 'mimirConfigEnc',
@@ -25315,10 +25301,6 @@ export type Users = {
/** An aggregate relationship */
roles_aggregate: AuthUserRoles_Aggregate;
/** An array relationship */
runServices: Array<Run_Service>;
/** An aggregate relationship */
runServices_aggregate: Run_Service_Aggregate;
/** An array relationship */
securityKeys: Array<AuthUserSecurityKeys>;
/** An aggregate relationship */
securityKeys_aggregate: AuthUserSecurityKeys_Aggregate;
@@ -25511,26 +25493,6 @@ export type UsersRoles_AggregateArgs = {
};
/** User account information. Don't modify its structure as Hasura Auth relies on it to function properly. */
export type UsersRunServicesArgs = {
distinct_on?: InputMaybe<Array<Run_Service_Select_Column>>;
limit?: InputMaybe<Scalars['Int']>;
offset?: InputMaybe<Scalars['Int']>;
order_by?: InputMaybe<Array<Run_Service_Order_By>>;
where?: InputMaybe<Run_Service_Bool_Exp>;
};
/** User account information. Don't modify its structure as Hasura Auth relies on it to function properly. */
export type UsersRunServices_AggregateArgs = {
distinct_on?: InputMaybe<Array<Run_Service_Select_Column>>;
limit?: InputMaybe<Scalars['Int']>;
offset?: InputMaybe<Scalars['Int']>;
order_by?: InputMaybe<Array<Run_Service_Order_By>>;
where?: InputMaybe<Run_Service_Bool_Exp>;
};
/** User account information. Don't modify its structure as Hasura Auth relies on it to function properly. */
export type UsersSecurityKeysArgs = {
distinct_on?: InputMaybe<Array<AuthUserSecurityKeys_Select_Column>>;
@@ -25742,8 +25704,6 @@ export type Users_Bool_Exp = {
role?: InputMaybe<AuthRoles_Bool_Exp>;
roles?: InputMaybe<AuthUserRoles_Bool_Exp>;
roles_aggregate?: InputMaybe<AuthUserRoles_Aggregate_Bool_Exp>;
runServices?: InputMaybe<Run_Service_Bool_Exp>;
runServices_aggregate?: InputMaybe<Run_Service_Aggregate_Bool_Exp>;
securityKeys?: InputMaybe<AuthUserSecurityKeys_Bool_Exp>;
securityKeys_aggregate?: InputMaybe<AuthUserSecurityKeys_Aggregate_Bool_Exp>;
ticket?: InputMaybe<String_Comparison_Exp>;
@@ -25818,7 +25778,6 @@ export type Users_Insert_Input = {
refreshTokens?: InputMaybe<AuthRefreshTokens_Arr_Rel_Insert_Input>;
role?: InputMaybe<AuthRoles_Obj_Rel_Insert_Input>;
roles?: InputMaybe<AuthUserRoles_Arr_Rel_Insert_Input>;
runServices?: InputMaybe<Run_Service_Arr_Rel_Insert_Input>;
securityKeys?: InputMaybe<AuthUserSecurityKeys_Arr_Rel_Insert_Input>;
ticket?: InputMaybe<Scalars['String']>;
ticketExpiresAt?: InputMaybe<Scalars['timestamptz']>;
@@ -25984,7 +25943,6 @@ export type Users_Order_By = {
refreshTokens_aggregate?: InputMaybe<AuthRefreshTokens_Aggregate_Order_By>;
role?: InputMaybe<AuthRoles_Order_By>;
roles_aggregate?: InputMaybe<AuthUserRoles_Aggregate_Order_By>;
runServices_aggregate?: InputMaybe<Run_Service_Aggregate_Order_By>;
securityKeys_aggregate?: InputMaybe<AuthUserSecurityKeys_Aggregate_Order_By>;
ticket?: InputMaybe<Order_By>;
ticketExpiresAt?: InputMaybe<Order_By>;
@@ -27738,14 +27696,14 @@ export type GetObservabilitySettingsQueryVariables = Exact<{
export type GetObservabilitySettingsQuery = { __typename?: 'query_root', config?: { __typename: 'ConfigConfig', id: 'ConfigConfig', observability: { __typename?: 'ConfigObservability', grafana: { __typename?: 'ConfigGrafana', alerting?: { __typename?: 'ConfigGrafanaAlerting', enabled?: boolean | null } | null, smtp?: { __typename?: 'ConfigGrafanaSmtp', host: string, password: string, port: any, sender: string, user: string } | null, contacts?: { __typename?: 'ConfigGrafanaContacts', emails?: Array<string> | null, discord?: Array<{ __typename?: 'ConfigGrafanacontactsDiscord', avatarUrl: string, url: string }> | null, pagerduty?: Array<{ __typename?: 'ConfigGrafanacontactsPagerduty', integrationKey: string, severity: string, class: string, component: string, group: string }> | null, slack?: Array<{ __typename?: 'ConfigGrafanacontactsSlack', recipient: string, token: string, username: string, iconEmoji: string, iconURL: string, mentionUsers: Array<string>, mentionGroups: Array<string>, mentionChannel: string, url: string, endpointURL: string }> | null, webhook?: Array<{ __typename?: 'ConfigGrafanacontactsWebhook', url: string, httpMethod: string, username: string, password: string, authorizationScheme: string, authorizationCredentials: string, maxAlerts: number }> | null } | null } } } | null };
export type ServiceResourcesFragment = { __typename?: 'ConfigConfig', auth?: { __typename?: 'ConfigAuth', resources?: { __typename?: 'ConfigResources', replicas?: any | null, compute?: { __typename?: 'ConfigResourcesCompute', cpu: any, memory: any } | null, autoscaler?: { __typename?: 'ConfigAutoscaler', maxReplicas: any } | null } | null } | null, hasura: { __typename?: 'ConfigHasura', resources?: { __typename?: 'ConfigResources', replicas?: any | null, compute?: { __typename?: 'ConfigResourcesCompute', cpu: any, memory: any } | null, autoscaler?: { __typename?: 'ConfigAutoscaler', maxReplicas: any } | null } | null }, postgres?: { __typename?: 'ConfigPostgres', resources?: { __typename?: 'ConfigPostgresResources', replicas?: any | null, compute?: { __typename?: 'ConfigResourcesCompute', cpu: any, memory: any } | null, autoscaler?: { __typename?: 'ConfigAutoscaler', maxReplicas: any } | null } | null } | null, storage?: { __typename?: 'ConfigStorage', resources?: { __typename?: 'ConfigResources', replicas?: any | null, compute?: { __typename?: 'ConfigResourcesCompute', cpu: any, memory: any } | null, autoscaler?: { __typename?: 'ConfigAutoscaler', maxReplicas: any } | null } | null } | null };
export type ServiceResourcesFragment = { __typename?: 'ConfigConfig', auth?: { __typename?: 'ConfigAuth', resources?: { __typename?: 'ConfigResources', replicas?: any | null, compute?: { __typename?: 'ConfigResourcesCompute', cpu: any, memory: any } | null, autoscaler?: { __typename?: 'ConfigAutoscaler', maxReplicas: any } | null, networking?: { __typename?: 'ConfigNetworking', ingresses?: Array<{ __typename?: 'ConfigIngress', fqdn?: Array<string> | null }> | null } | null } | null } | null, hasura: { __typename?: 'ConfigHasura', resources?: { __typename?: 'ConfigResources', replicas?: any | null, compute?: { __typename?: 'ConfigResourcesCompute', cpu: any, memory: any } | null, autoscaler?: { __typename?: 'ConfigAutoscaler', maxReplicas: any } | null, networking?: { __typename?: 'ConfigNetworking', ingresses?: Array<{ __typename?: 'ConfigIngress', fqdn?: Array<string> | null }> | null } | null } | null }, postgres?: { __typename?: 'ConfigPostgres', resources?: { __typename?: 'ConfigPostgresResources', enablePublicAccess?: boolean | null, replicas?: any | null, storage?: { __typename?: 'ConfigPostgresStorage', capacity: any } | null, compute?: { __typename?: 'ConfigResourcesCompute', cpu: any, memory: any } | null, autoscaler?: { __typename?: 'ConfigAutoscaler', maxReplicas: any } | null } | null } | null, storage?: { __typename?: 'ConfigStorage', resources?: { __typename?: 'ConfigResources', replicas?: any | null, compute?: { __typename?: 'ConfigResourcesCompute', cpu: any, memory: any } | null, autoscaler?: { __typename?: 'ConfigAutoscaler', maxReplicas: any } | null } | null } | null };
export type GetResourcesQueryVariables = Exact<{
appId: Scalars['uuid'];
}>;
export type GetResourcesQuery = { __typename?: 'query_root', config?: { __typename?: 'ConfigConfig', auth?: { __typename?: 'ConfigAuth', resources?: { __typename?: 'ConfigResources', replicas?: any | null, compute?: { __typename?: 'ConfigResourcesCompute', cpu: any, memory: any } | null, autoscaler?: { __typename?: 'ConfigAutoscaler', maxReplicas: any } | null } | null } | null, hasura: { __typename?: 'ConfigHasura', resources?: { __typename?: 'ConfigResources', replicas?: any | null, compute?: { __typename?: 'ConfigResourcesCompute', cpu: any, memory: any } | null, autoscaler?: { __typename?: 'ConfigAutoscaler', maxReplicas: any } | null } | null }, postgres?: { __typename?: 'ConfigPostgres', resources?: { __typename?: 'ConfigPostgresResources', replicas?: any | null, compute?: { __typename?: 'ConfigResourcesCompute', cpu: any, memory: any } | null, autoscaler?: { __typename?: 'ConfigAutoscaler', maxReplicas: any } | null } | null } | null, storage?: { __typename?: 'ConfigStorage', resources?: { __typename?: 'ConfigResources', replicas?: any | null, compute?: { __typename?: 'ConfigResourcesCompute', cpu: any, memory: any } | null, autoscaler?: { __typename?: 'ConfigAutoscaler', maxReplicas: any } | null } | null } | null } | null };
export type GetResourcesQuery = { __typename?: 'query_root', config?: { __typename?: 'ConfigConfig', auth?: { __typename?: 'ConfigAuth', resources?: { __typename?: 'ConfigResources', replicas?: any | null, compute?: { __typename?: 'ConfigResourcesCompute', cpu: any, memory: any } | null, autoscaler?: { __typename?: 'ConfigAutoscaler', maxReplicas: any } | null, networking?: { __typename?: 'ConfigNetworking', ingresses?: Array<{ __typename?: 'ConfigIngress', fqdn?: Array<string> | null }> | null } | null } | null } | null, hasura: { __typename?: 'ConfigHasura', resources?: { __typename?: 'ConfigResources', replicas?: any | null, compute?: { __typename?: 'ConfigResourcesCompute', cpu: any, memory: any } | null, autoscaler?: { __typename?: 'ConfigAutoscaler', maxReplicas: any } | null, networking?: { __typename?: 'ConfigNetworking', ingresses?: Array<{ __typename?: 'ConfigIngress', fqdn?: Array<string> | null }> | null } | null } | null }, postgres?: { __typename?: 'ConfigPostgres', resources?: { __typename?: 'ConfigPostgresResources', enablePublicAccess?: boolean | null, replicas?: any | null, storage?: { __typename?: 'ConfigPostgresStorage', capacity: any } | null, compute?: { __typename?: 'ConfigResourcesCompute', cpu: any, memory: any } | null, autoscaler?: { __typename?: 'ConfigAutoscaler', maxReplicas: any } | null } | null } | null, storage?: { __typename?: 'ConfigStorage', resources?: { __typename?: 'ConfigResources', replicas?: any | null, compute?: { __typename?: 'ConfigResourcesCompute', cpu: any, memory: any } | null, autoscaler?: { __typename?: 'ConfigAutoscaler', maxReplicas: any } | null } | null } | null } | null };
export type GetStorageSettingsQueryVariables = Exact<{
appId: Scalars['uuid'];
@@ -28592,21 +28550,13 @@ export type GetLocalRunServiceRateLimitQueryVariables = Exact<{
export type GetLocalRunServiceRateLimitQuery = { __typename?: 'query_root', runServiceConfigs: Array<{ __typename?: 'ConfigRunServiceConfigWithID', serviceID: any, config: { __typename?: 'ConfigRunServiceConfig', name: any, ports?: Array<{ __typename?: 'ConfigRunServicePort', port: any, type: string, publish?: boolean | null, rateLimit?: { __typename?: 'ConfigRateLimit', limit: any, interval: string } | null, ingresses?: Array<{ __typename?: 'ConfigIngress', fqdn?: Array<string> | null }> | null }> | null } }> };
export type InsertRunServiceMutationVariables = Exact<{
object: Run_Service_Insert_Input;
}>;
export type InsertRunServiceMutation = { __typename?: 'mutation_root', insertRunService?: { __typename?: 'run_service', id: any, subdomain: string } | null };
export type InsertRunServiceConfigMutationVariables = Exact<{
appID: Scalars['uuid'];
serviceID: Scalars['uuid'];
config: ConfigRunServiceConfigInsertInput;
}>;
export type InsertRunServiceConfigMutation = { __typename?: 'mutation_root', insertRunServiceConfig: { __typename?: 'ConfigRunServiceConfig', name: any } };
export type InsertRunServiceConfigMutation = { __typename?: 'mutation_root', insertRunServiceConfig: { __typename?: 'InsertRunServiceConfigResponse', serviceID: any, config: { __typename?: 'ConfigRunServiceConfig', name: any } } };
export type ReplaceRunServiceConfigMutationVariables = Exact<{
appID: Scalars['uuid'];
@@ -28730,6 +28680,11 @@ export const ServiceResourcesFragmentDoc = gql`
autoscaler {
maxReplicas
}
networking {
ingresses {
fqdn
}
}
}
}
hasura {
@@ -28742,10 +28697,19 @@ export const ServiceResourcesFragmentDoc = gql`
autoscaler {
maxReplicas
}
networking {
ingresses {
fqdn
}
}
}
}
postgres {
resources {
storage {
capacity
}
enablePublicAccess
compute {
cpu
memory
@@ -34696,44 +34660,13 @@ export type GetLocalRunServiceRateLimitQueryResult = Apollo.QueryResult<GetLocal
export function refetchGetLocalRunServiceRateLimitQuery(variables: GetLocalRunServiceRateLimitQueryVariables) {
return { query: GetLocalRunServiceRateLimitDocument, variables: variables }
}
export const InsertRunServiceDocument = gql`
mutation insertRunService($object: run_service_insert_input!) {
insertRunService(object: $object) {
id
subdomain
}
}
`;
export type InsertRunServiceMutationFn = Apollo.MutationFunction<InsertRunServiceMutation, InsertRunServiceMutationVariables>;
/**
* __useInsertRunServiceMutation__
*
* To run a mutation, you first call `useInsertRunServiceMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useInsertRunServiceMutation` returns a tuple that includes:
* - A mutate function that you can call at any time to execute the mutation
* - An object with fields that represent the current status of the mutation's execution
*
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
*
* @example
* const [insertRunServiceMutation, { data, loading, error }] = useInsertRunServiceMutation({
* variables: {
* object: // value for 'object'
* },
* });
*/
export function useInsertRunServiceMutation(baseOptions?: Apollo.MutationHookOptions<InsertRunServiceMutation, InsertRunServiceMutationVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useMutation<InsertRunServiceMutation, InsertRunServiceMutationVariables>(InsertRunServiceDocument, options);
}
export type InsertRunServiceMutationHookResult = ReturnType<typeof useInsertRunServiceMutation>;
export type InsertRunServiceMutationResult = Apollo.MutationResult<InsertRunServiceMutation>;
export type InsertRunServiceMutationOptions = Apollo.BaseMutationOptions<InsertRunServiceMutation, InsertRunServiceMutationVariables>;
export const InsertRunServiceConfigDocument = gql`
mutation insertRunServiceConfig($appID: uuid!, $serviceID: uuid!, $config: ConfigRunServiceConfigInsertInput!) {
insertRunServiceConfig(appID: $appID, serviceID: $serviceID, config: $config) {
name
mutation InsertRunServiceConfig($appID: uuid!, $config: ConfigRunServiceConfigInsertInput!) {
insertRunServiceConfig(appID: $appID, config: $config) {
serviceID
config {
name
}
}
}
`;
@@ -34753,7 +34686,6 @@ export type InsertRunServiceConfigMutationFn = Apollo.MutationFunction<InsertRun
* const [insertRunServiceConfigMutation, { data, loading, error }] = useInsertRunServiceConfigMutation({
* variables: {
* appID: // value for 'appID'
* serviceID: // value for 'serviceID'
* config: // value for 'config'
* },
* });

View File

@@ -1,5 +1,12 @@
# @nhost/docs
## 2.25.0
### Minor Changes
- 46fc520: chore: add support to next.js 15, update quickstart template commands in docs
- cdf6776: fix: update links to create new project in dashboard
## 2.24.0
### Minor Changes

View File

@@ -7,7 +7,7 @@ icon: react
<Steps>
<Step title="Create Project">
If you haven't, please create a project through the [Nhost Dashboard](https://app.nhost.io/new).
If you haven't, please create a project through the [Nhost Dashboard](https://app.nhost.io).
</Step>
<Step title="Setup Database">
@@ -47,7 +47,7 @@ icon: react
Create a Next.js application.
```bash Terminal
npx create-next-app@latest --no-eslint \
npx create-next-app@next-14 --no-eslint \
--src-dir \
--no-tailwind \
--import-alias "@/*" \
@@ -59,7 +59,7 @@ icon: react
</Step>
<Step title="Install the Nhost package for Next.js">
Navidate to the React application and install `@nhost/nextjs`.
Navigate to the React application and install `@nhost/nextjs`.
```bash Terminal
cd nhost-nextjs-quickstart && npm install @nhost/nextjs

View File

@@ -20,7 +20,7 @@ icon: mobile-notch
<Steps>
<Step title="Create Nhost Project">
Create your project through the [Nhost Dashboard](https://app.nhost.io/new).
Create your project through the [Nhost Dashboard](https://app.nhost.io).
</Step>
<Step title="Setup Database">

View File

@@ -7,7 +7,7 @@ icon: react
<Steps>
<Step title="Create Nhost Project">
Create your project through the [Nhost Dashboard](https://app.nhost.io/new).
Create your project through the [Nhost Dashboard](https://app.nhost.io).
</Step>
<Step title="Setup Database">

View File

@@ -7,7 +7,7 @@ icon: vuejs
<Steps>
<Step title="Create Project">
If you haven't, please create a project through the [Nhost Dashboard](https://app.nhost.io/new).
If you haven't, please create a project through the [Nhost Dashboard](https://app.nhost.io).
</Step>
<Step title="Setup Database">
@@ -53,7 +53,7 @@ icon: vuejs
</Step>
<Step title="Install the Nhost package for Vue">
Navidate to the React application and install `@nhost/vue`.
Navigate to the React application and install `@nhost/vue`.
```bash Terminal
cd nhost-vue-quickstart && npm install @nhost/vue

View File

@@ -30,7 +30,7 @@ In this section, you will create and setup your first Nhost project.
### Create project
Create a new project in the [Nhost Dashboard](https://app.nhost.io/new).
Create a new project in the [Nhost Dashboard](https://app.nhost.io).
Enter the details for your project and wait a couple of minutes while Nhost provisions your backend infrastructure:
@@ -156,7 +156,7 @@ Now that we have Nhost configured, let's move on to setup the React application
Run the following command in your terminal to create a React application using Vite.
```bash Terminal
npx create-next-app@latest --no-eslint \
npx create-next-app@next-14 --no-eslint \
--src-dir \
--no-tailwind \
--import-alias "@/*" \

View File

@@ -30,7 +30,7 @@ In this section, you will create and setup your first Nhost project.
### Create project
Create a new project in the [Nhost Dashboard](https://app.nhost.io/new).
Create a new project in the [Nhost Dashboard](https://app.nhost.io).
Enter the details for your project and wait a couple of minutes while Nhost provisions your backend infrastructure:

View File

@@ -29,7 +29,7 @@ In this section, you will create and setup your first Nhost project.
### Create project
Create a new project in the [Nhost Dashboard](https://app.nhost.io/new).
Create a new project in the [Nhost Dashboard](https://app.nhost.io).
Enter the details for your project and wait a couple of minutes while Nhost provisions your backend infrastructure:

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/docs",
"version": "2.24.0",
"version": "2.25.0",
"private": true,
"scripts": {
"start": "mintlify dev"

View File

@@ -1,5 +1,11 @@
# @nhost-examples/cli
## 0.3.15
### Patch Changes
- @nhost/nhost-js@3.2.2
## 0.3.14
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost-examples/cli",
"version": "0.3.14",
"version": "0.3.15",
"main": "src/index.mjs",
"private": true,
"scripts": {

View File

@@ -1,5 +1,12 @@
# @nhost-examples/codegen-react-apollo
## 0.4.16
### Patch Changes
- @nhost/react@3.8.1
- @nhost/react-apollo@15.0.1
## 0.4.15
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost-examples/codegen-react-apollo",
"version": "0.4.15",
"version": "0.4.16",
"private": true,
"scripts": {
"codegen": "graphql-codegen",

View File

@@ -1,5 +1,11 @@
# @nhost-examples/codegen-react-query
## 0.4.16
### Patch Changes
- @nhost/react@3.8.1
## 0.4.15
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost-examples/codegen-react-query",
"version": "0.4.15",
"version": "0.4.16",
"private": true,
"scripts": {
"codegen": "graphql-codegen",

View File

@@ -1,5 +1,12 @@
# @nhost-examples/react-urql
## 0.3.16
### Patch Changes
- @nhost/react@3.8.1
- @nhost/react-urql@12.0.1
## 0.3.15
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "@nhost-examples/codegen-react-urql",
"private": true,
"version": "0.3.15",
"version": "0.3.16",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",

View File

@@ -1,5 +1,11 @@
# @nhost-examples/multi-tenant-one-to-many
## 2.2.16
### Patch Changes
- @nhost/nhost-js@3.2.2
## 2.2.15
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "@nhost-examples/multi-tenant-one-to-many",
"private": true,
"version": "2.2.15",
"version": "2.2.16",
"description": "",
"main": "index.js",
"scripts": {},

View File

@@ -1,5 +1,19 @@
# @nhost-examples/nextjs
## 0.4.0
### Minor Changes
- 29d27e1: chore: update `next` to v14.2.22 to fix vulnerabilities
### Patch Changes
- Updated dependencies [46fc520]
- Updated dependencies [29d27e1]
- @nhost/nextjs@2.2.0
- @nhost/react@3.8.1
- @nhost/react-apollo@15.0.1
## 0.3.15
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost-examples/nextjs",
"version": "0.3.15",
"version": "0.4.0",
"private": true,
"scripts": {
"dev": "next dev",
@@ -24,7 +24,7 @@
"@nhost/react": "workspace:^",
"@nhost/react-apollo": "workspace:^",
"graphql": "16.8.1",
"next": "^14.2.10",
"next": "^14.2.22",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-icons": "^4.12.0"

View File

@@ -1,5 +1,11 @@
# @nhost-examples/node-storage
## 0.2.15
### Patch Changes
- @nhost/nhost-js@3.2.2
## 0.2.14
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost-examples/node-storage",
"version": "0.2.14",
"version": "0.2.15",
"private": true,
"description": "This is an example of how to use the Storage with Node.js",
"main": "src/index.mjs",

View File

@@ -1,5 +1,16 @@
# @nhost-examples/nextjs-server-components
## 0.5.0
### Minor Changes
- b944d05: chore: simplify Nhost client initialization with session and remove xstate dependency
- 29d27e1: chore: update `next` to v14.2.22 to fix vulnerabilities
### Patch Changes
- @nhost/nhost-js@3.2.2
## 0.4.16
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost-examples/nextjs-server-components",
"version": "0.4.16",
"version": "0.5.0",
"private": true,
"scripts": {
"dev": "next dev",
@@ -18,14 +18,13 @@
"form-data": "^4.0.0",
"graphql": "16.8.1",
"js-cookie": "^3.0.5",
"next": "^14.2.10",
"next": "^14.2.22",
"postcss": "^8.4.38",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"tailwind-merge": "^1.14.0",
"tailwindcss": "3.3.3",
"typescript": "5.2.2",
"xstate": "^4.38.3"
"typescript": "5.2.2"
},
"devDependencies": {
"@types/js-cookie": "^3.0.6",

View File

@@ -1,10 +1,6 @@
import { AuthErrorPayload, NhostClient, NhostSession } from '@nhost/nhost-js'
import { cookies } from 'next/headers'
import { NextRequest, NextResponse } from 'next/server'
import { type StateFrom } from 'xstate/lib/types'
import { waitFor } from 'xstate/lib/waitFor'
export const NHOST_SESSION_KEY = 'nhostSession'
export const getNhost = async (request?: NextRequest) => {
@@ -20,9 +16,7 @@ export const getNhost = async (request?: NextRequest) => {
const sessionCookieValue = $cookies.get(NHOST_SESSION_KEY)?.value || ''
const initialSession: NhostSession = JSON.parse(atob(sessionCookieValue) || 'null')
nhost.auth.client.start({ initialSession })
await waitFor(nhost.auth.client.interpreter!, (state: StateFrom<any>) => !state.hasTag('loading'))
await nhost.auth.initWithSession({ session: initialSession })
return nhost
}

View File

@@ -1,5 +1,12 @@
# @nhost-examples/react-apollo
## 1.1.2
### Patch Changes
- @nhost/react@3.8.1
- @nhost/react-apollo@15.0.1
## 1.1.1
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost-examples/react-apollo",
"version": "1.1.1",
"version": "1.1.2",
"private": true,
"type": "module",
"scripts": {

View File

@@ -1,5 +1,11 @@
# @nhost-examples/react-gqty
## 1.2.16
### Patch Changes
- @nhost/react@3.8.1
## 1.2.15
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "@nhost-examples/react-gqty",
"private": true,
"version": "1.2.15",
"version": "1.2.16",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,12 @@
# @nhost-examples/react-native
## 0.1.1
### Patch Changes
- @nhost/react@3.8.1
- @nhost/react-apollo@15.0.1
## 0.1.0
### Minor Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost-examples/react-native",
"version": "0.1.0",
"version": "0.1.1",
"private": true,
"scripts": {
"android": "react-native run-android",

View File

@@ -1,5 +1,13 @@
# @nhost-examples/vue-apollo
## 0.7.2
### Patch Changes
- @nhost/nhost-js@3.2.2
- @nhost/apollo@8.0.2
- @nhost/vue@2.8.1
## 0.7.1
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "@nhost-examples/vue-apollo",
"private": true,
"version": "0.7.1",
"version": "0.7.2",
"scripts": {
"dev": "vite",
"build": "vite build",

View File

@@ -1,5 +1,12 @@
# @nhost-examples/vue-quickstart
## 0.2.16
### Patch Changes
- @nhost/apollo@8.0.2
- @nhost/vue@2.8.1
## 0.2.15
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost-examples/vue-quickstart",
"version": "0.2.15",
"version": "0.2.16",
"private": true,
"scripts": {
"build": "vite build",

View File

@@ -1,5 +1,11 @@
# @nhost/apollo
## 8.0.2
### Patch Changes
- @nhost/nhost-js@3.2.2
## 8.0.1
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/apollo",
"version": "8.0.1",
"version": "8.0.2",
"description": "Nhost Apollo Client library",
"license": "MIT",
"keywords": [

View File

@@ -1,5 +1,12 @@
# @nhost/react-apollo
## 15.0.1
### Patch Changes
- @nhost/apollo@8.0.2
- @nhost/react@3.8.1
## 15.0.0
### Patch Changes

View File

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

View File

@@ -1,5 +1,11 @@
# @nhost/react-urql
## 12.0.1
### Patch Changes
- @nhost/react@3.8.1
## 12.0.0
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/react-urql",
"version": "12.0.0",
"version": "12.0.1",
"description": "Nhost React URQL client",
"license": "MIT",
"keywords": [

View File

@@ -1,5 +1,11 @@
# @nhost/hasura-auth-js
## 2.9.0
### Minor Changes
- b944d05: feat: introduce `initWithSession` to initialize auth client with an existing session
## 2.8.0
### Minor Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/hasura-auth-js",
"version": "2.8.0",
"version": "2.9.0",
"description": "Hasura-auth client",
"license": "MIT",
"keywords": [

View File

@@ -55,6 +55,7 @@ import {
JWTHasuraClaims,
LinkIdTokenParams,
NhostAuthConstructorParams,
NhostSession,
NhostSessionResponse,
OnTokenChangedFunction,
ResetPasswordParams,
@@ -857,6 +858,23 @@ export class HasuraAuthClient {
return getSession(this._client.interpreter?.getSnapshot()?.context)
}
/**
* Initialize the auth client with an existing session
*
* @example
* ### Initialize with an existing Nhost session
* ```ts
* await nhost.auth.initWithSession({ session: initialSession })
* ```
*
* @param session - The Nhost session object to initialize the client with
* @docs https://docs.nhost.io/reference/javascript/auth/init-with-session
*/
async initWithSession({ session }: { session: NhostSession }): Promise<void> {
this.client.start({ initialSession: session })
await this.waitUntilReady()
}
/**
*
* Use `nhost.auth.getUser()` to get the signed-in user.

View File

@@ -1,5 +1,11 @@
# @nhost/hasura-storage-js
## 2.6.0
### Minor Changes
- 4148964: fix: stack overflow on storage client getHeaders method call
## 2.5.1
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/hasura-storage-js",
"version": "2.5.1",
"version": "2.6.0",
"description": "Hasura-storage client",
"license": "MIT",
"keywords": [

View File

@@ -242,7 +242,7 @@ export class HasuraStorageClient {
* @docs https://docs.nhost.io/reference/javascript/storage/get-headers
*/
getHeaders(): Record<string, string> {
return this.getHeaders()
return this.api.getHeaders()
}
/**

View File

@@ -1,5 +1,16 @@
# @nhost/nextjs
## 2.2.0
### Minor Changes
- 46fc520: chore: add support to next.js 15, update quickstart template commands in docs
- 29d27e1: chore: update `next` to v14.2.22 to fix vulnerabilities
### Patch Changes
- @nhost/react@3.8.1
## 2.1.24
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/nextjs",
"version": "2.1.24",
"version": "2.2.0",
"description": "Nhost NextJS library",
"license": "MIT",
"keywords": [
@@ -71,15 +71,15 @@
"xstate": "^4.38.3"
},
"peerDependencies": {
"next": "^12.0.10 || ^13.0.0 || ^14.0.0",
"react": "^17.0.0 || ^18.0.0",
"react-dom": "^17.0.0 || ^18.0.0"
"next": "^12.0.10 || ^13.0.0 || ^14.0.0 || ^15.0.0",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"devDependencies": {
"@nhost/docgen": "workspace:*",
"@types/js-cookie": "^3.0.6",
"next": "^14.2.10",
"next": "^14.2.22",
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
}
}

View File

@@ -1,5 +1,14 @@
# @nhost/nhost-js
## 3.2.2
### Patch Changes
- Updated dependencies [b944d05]
- Updated dependencies [4148964]
- @nhost/hasura-auth-js@2.9.0
- @nhost/hasura-storage-js@2.6.0
## 3.2.1
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/nhost-js",
"version": "3.2.1",
"version": "3.2.2",
"description": "Nhost JavaScript SDK",
"license": "MIT",
"keywords": [

View File

@@ -1,5 +1,11 @@
# @nhost/react
## 3.8.1
### Patch Changes
- @nhost/nhost-js@3.2.2
## 3.8.0
### Minor Changes

View File

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

View File

@@ -1,5 +1,11 @@
# @nhost/vue
## 2.8.1
### Patch Changes
- @nhost/nhost-js@3.2.2
## 2.8.0
### Minor Changes

View File

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

643
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -6,8 +6,8 @@
"@craco/craco": "^7.1.0",
"@hookform/resolvers": "^3.9.0",
"@icons-pack/react-simple-icons": "^9.6.0",
"@nhost/react": "^3.5.4",
"@nhost/react-apollo": "^12.0.4",
"@nhost/react": "^3.8.0",
"@nhost/react-apollo": "^12.0.5",
"@radix-ui/react-dialog": "^1.1.1",
"@radix-ui/react-dropdown-menu": "^2.1.1",
"@radix-ui/react-label": "^2.1.0",