Compare commits

...

15 Commits

Author SHA1 Message Date
github-actions[bot]
60d4d28627 chore: update versions (#3239)
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/dashboard@2.25.0

### Minor Changes

- 34fdcb8: chore: add prettier plugins as devDependencies to root of
monorepo
- 4937c5e: fix: stop content overflowing in projects and database
permissions page
- 1542132: fix: update babel dependencies to address security audit
vulnerabilities

### Patch Changes

- 78436ca: chore (dashboard): add tests and small updates to PiTR
settings and restore page
- b5a3895: chore (dashboard): update page context after each navigation
-   9b24807: chore: fix link to PiTR documentation
-   ea65846: chore (dashboard): update nextjs to fix middleware exploit

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-03-25 08:39:49 +01:00
David BM
34fdcb8863 chore (changeset): add dashboard prettier plugins to root of monorepo as devDependencies (#3252)
### **PR Type**
Enhancement


___

### **Description**
- Add Prettier plugins to root monorepo as devDependencies

- Include Prettier plugin for organizing imports

- Add Prettier plugin for Tailwind CSS

- Update changeset for @nhost/dashboard minor version bump


___



### **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>angry-rabbits-fly.md</strong><dd><code>Add changeset
for Prettier plugins addition</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

.changeset/angry-rabbits-fly.md

<li>Add new changeset file for @nhost/dashboard<br> <li> Specify minor
version bump<br> <li> Describe addition of Prettier plugins as
devDependencies


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3252/files#diff-1dc91a69351de73036aee86088b5553c604a0b7b726d1134bc679c71e288eea8">+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>Add Prettier plugins to
package.json</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>

package.json

<li>Add prettier-plugin-organize-imports as devDependency<br> <li> Add
prettier-plugin-tailwindcss as devDependency


</details>


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

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

___

> <details> <summary> Need help?</summary><li>Type <code>/help how to
...</code> in the comments thread for any questions about PR-Agent
usage.</li><li>Check out the <a
href="https://qodo-merge-docs.qodo.ai/usage-guide/">documentation</a>
for more information.</li></details>
2025-03-24 19:44:17 +01:00
robertkasza
78436ca29e chore (dashboard): update PiTR (#3247)
- add tests
- add price to PiTR settings
- update link in PiTR settings
- add note with recommendation about restore
- add link to PiTR docs to restore page
- small bug fixes
2025-03-24 15:53:34 +01:00
robertkasza
ea6584614b chore (dashboard): update nextjs to fix middleware exploit (#3251)
### **User description**
More info:
https://zeropath.com/blog/nextjs-middleware-cve-2025-29927-auth-bypass


___

### **PR Type**
Enhancement


___

### **Description**
- Update Next.js to version 14.2.25

- Address middleware exploit vulnerability

- Improve dashboard security


___



### **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>nervous-shirts-rush.md</strong><dd><code>Add changeset
for Next.js update</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/nervous-shirts-rush.md

<li>Add new changeset file<br> <li> Specify patch update for
'@nhost/dashboard'<br> <li> Include description of Next.js update


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3251/files#diff-f9ef884a817466b3e2f2e10938fd046e15c764241ea5a8b841e0fea8cb2242e9">+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>Upgrade Next.js to
version 14.2.25</code>&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>

dashboard/package.json

- Update Next.js dependency from 14.2.22 to 14.2.25


</details>


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

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

___

> <details> <summary> Need help?</summary><li>Type <code>/help how to
...</code> in the comments thread for any questions about PR-Agent
usage.</li><li>Check out the <a
href="https://qodo-merge-docs.qodo.ai/usage-guide/">documentation</a>
for more information.</li></details>
2025-03-24 10:35:04 +01:00
David BM
4937c5e055 fix (dashboard): stop content overflowing in projects and database permissions page (#3240) 2025-03-21 12:05:39 +01:00
robertkasza
b5a3895e16 chore (dashboard): update page context after each navigation (#3248)
### **PR Type**
Tests


___

### **Description**
- Added `updatePageContext` utility function for consistent page context
updates.

- Refactored e2e tests to use `updatePageContext` and `gotoAuthURL`.

- Improved test setup by centralizing navigation logic.

- Enhanced maintainability of e2e tests with reusable utilities.


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Tests</strong></td><td><details><summary>13
files</summary><table>
<tr>
<td><strong>manage-pat.test.ts</strong><dd><code>Integrated
`updatePageContext` in PAT management tests</code>&nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3248/files#diff-891790fa0d9b0e0b23b12af547a6dc7736fad9eaf76b14a56f310e531e6db098">+2/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>assistants.test.ts</strong><dd><code>Added
`updatePageContext` to AI assistants tests</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3248/files#diff-95533e004b514add57a2c87201a68cac11c20ffa458afd78e045ed89559e7546">+2/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>auto-embeddings.test.ts</strong><dd><code>Added
`updatePageContext` to auto-embeddings tests</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3248/files#diff-d3a5b860634fd36dd33ac9236210632eb5f8ad322aa15bedfc61a8e2c60dbd68">+2/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>ban-user.test.ts</strong><dd><code>Refactored ban-user tests
with `gotoAuthURL`</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3248/files#diff-8d8d853b89f4a44454e4400182cbfe900f3c15eebe04d43a8d43f9c782b39f57">+16/-6</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>create-user.test.ts</strong><dd><code>Refactored create-user
tests with `gotoAuthURL`</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3248/files#diff-b5d83f9ceb9d621a5fe72789a6c961773548d7f459c72fad953b2a09694ff0a7">+2/-5</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>delete-user.test.ts</strong><dd><code>Refactored delete-user
tests with `gotoAuthURL`</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3248/files#diff-a9d249f139e75a681888115b925e171c856c94f99c4077be6d954be4e58e0d74">+2/-5</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>edit-user.test.ts</strong><dd><code>Refactored edit-user
tests with `gotoAuthURL`</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3248/files#diff-fc232b4d225c1367489733ede6bf5ebe88967b0353aa76c88c5e712c35b31be5">+2/-5</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>verify-user.test.ts</strong><dd><code>Refactored verify-user
tests with `gotoAuthURL`</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3248/files#diff-a8425690a42ed772a97d3a17f062cb5713cc3180032c1d5eb1ef3f6d55cc110e">+2/-5</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>create-table.test.ts</strong><dd><code>Added
`updatePageContext` to create-table tests</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3248/files#diff-1e7aa9f3e379ca90a94b82c14be48e2c98a722d85ee1b0785a082b7076d8e58c">+6/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>delete-table.test.ts</strong><dd><code>Added
`updatePageContext` to delete-table tests</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3248/files#diff-9e8c87f8e8f11bcfa2b7b2e5cf9dffe54a0fdeb3385ccb82b74e4e1c18fb9c43">+7/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>permissions-table.test.ts</strong><dd><code>Added
`updatePageContext` to permissions-table tests</code>&nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3248/files#diff-f4b586f5b8f3bb97ddf64f8f38c461ac0424e101789f61e325d1b80bb8dc1047">+2/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>overview.test.ts</strong><dd><code>Integrated
`updatePageContext` in overview tests</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3248/files#diff-4c6f1ff0b9d3b7fc7517aa50d9002bed56902f5b31557fa460f633f98da9cf01">+4/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>run.test.ts</strong><dd><code>Integrated `updatePageContext`
in run tests</code>&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/3248/files#diff-3b81821630a8e66e8f580609a834499bdfec9ac228ff07b99f398ec07c329095">+2/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

</table></details></td></tr><tr><td><strong>Enhancement</strong></td><td><details><summary>1
files</summary><table>
<tr>
<td><strong>utils.ts</strong><dd><code>Added `updatePageContext` and
`gotoAuthURL` utility functions</code></dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3248/files#diff-490448aa83585151d8c61d698273c43486fdcac6a5d28a9b7e5be2729bbffd12">+13/-0</a>&nbsp;
&nbsp; </td>

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

___

> <details> <summary> Need help?</summary><li>Type <code>/help how to
...</code> in the comments thread for any questions about PR-Agent
usage.</li><li>Check out the <a
href="https://qodo-merge-docs.qodo.ai/usage-guide/">documentation</a>
for more information.</li></details>
2025-03-20 14:46:42 +01:00
Alex
9b24807562 fix (dashboard) Update DatabasePiTRSettings.tsx to point to actual PiTR documentation (#3243)
Updated the docsLink of `DatabasePiTRSettings.tsx` to point to the
actual documentation of PiTR

---------

Co-authored-by: David Barroso <dbarrosop@dravetech.com>
2025-03-18 12:31:53 +01:00
David BM
15421321f4 fix (ci): update PNPM dependencies to fix audit security vulnerabilities (#3236)
### **PR Type**
Enhancement, Bug fix


___

### **Description**
- Update Babel dependencies to latest versions

- Add overrides for Babel runtime and helpers

- Address security vulnerabilities in dependencies

- Improve CI/CD pipeline security and stability


___



### **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>package.json</strong><dd><code>Update Babel and address
dependency vulnerabilities</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></summary>
<hr>

package.json

<li>Updated Babel core and plugin dependencies<br> <li> Added overrides
for @babel/runtime and @babel/helpers<br> <li> Updated various
dependency version constraints<br> <li> Addressed multiple security
vulnerabilities in dependencies


</details>


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

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

___

> <details> <summary> Need help?</summary><li>Type <code>/help how to
...</code> in the comments thread for any questions about PR-Agent
usage.</li><li>Check out the <a
href="https://qodo-merge-docs.qodo.ai/usage-guide/">documentation</a>
for more information.</li></details>
2025-03-14 15:31:18 +01:00
github-actions[bot]
a4790c6eac chore: update versions (#3238)
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/dashboard@2.24.0

# @nhost/dashboard

## 2.17.0

### Minor Changes

-   fd59918: fix: redirect to 404 with nhost cli dashboard

## 2.16.0

### Minor Changes

-   f8e6b61: fix: can add rule groups in table permissions
-   9e404c8: fix: not redirect to 404 page if using local Nhost backend
-   ac4aa01: fix: can delete column in database page
-   4385524: fix: update url to check service health in local dashboard

### Patch Changes

-   @nhost/react-apollo@16.0.1
-   @nhost/nextjs@2.2.2

## 2.15.0

### Minor Changes

- f1052a8: fix: improve stability of the dashboard when pausing projects
-   30daa41: fix: update links to docs in overview page
-   7537237: feat: add image preview toggle in storage

## 2.14.0

### Minor Changes

- d43931e: fix: invalid organization slug/project subdomain doesn't open
404 page
- 5df6fa2: feat: add unencrypted disk warning in storage capacity
settings

### Patch Changes

-   44c1e17: chore: update `msw` to v1.3.5 to fix vulnerabilities
    -   @nhost/react-apollo@16.0.0
    -   @nhost/nextjs@2.2.1

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

## 2.12.0

### Minor Changes

- eb95562: fix: show all available permission variables in permission
dropdown select

### Patch Changes

- 8b5c4a0: chore: cleanup layout and add disable duplicate atom key
checking in development mode

## 2.11.3

### Patch Changes

- 714dffa: fix: improve project polling logic and unify usage across
components

## 2.11.2

### Patch Changes

- 6a34f89: fix: improve project polling logic and unify usage across
components

## 2.11.1

### Patch Changes

-   0f6ce52: fix: consolidate useProject hook and fix jwt expired error

## 2.11.0

### Minor Changes

-   cea3ef5: Feat: add org and project placeholders

## 2.10.0

### Minor Changes

-   86ecf27: feat: add support for additional metrics in overview
- 21708be: feat: dashboard: add support for storage buckets to AI
assistants

## 1.30.0

### Minor Changes

- 50441a8: feat: add ui for project autoscaler settings and run services
autoscaler settings

## 1.29.0

### Minor Changes

-   55d8bb5: feat: integrate turnstile for signup verification
-   2a2e54c: fix: update docs url in run services form tooltip
- 18f942f: fix: display long error messages in error toast without
overflow

### Patch Changes

-   @nhost/react-apollo@13.0.0
-   @nhost/nextjs@2.1.22

## 1.28.2

### Patch Changes

- 52a38fe: chore: update dependencies to address security
vulnerabilities
-   Updated dependencies [52a38fe]
    -   @nhost/nextjs@2.1.21

## 1.28.1

### Patch Changes

-   9735fa2: chore: remove broken link

## 1.28.0

### Minor Changes

- 526183a: feat: allow filtering users in "make request as" in graphql
section
-   be3b85b: feat: add conceal errors toggle on auth settings page

### Patch Changes

- 35a2f12: fix: prevent run service details from opening when attempting
to delete
    -   @nhost/react-apollo@12.0.6
    -   @nhost/nextjs@2.1.20

## 1.27.0

### Minor Changes

-   a7cd02c: fix: resolve rate limit query

## 1.26.0

### Minor Changes

-   3773ad7: chore: update pricing information
- b63250d: fix: not allow run service creation form resubmission while
creating a run service
-   a44a1d4: feat: add rate limits settings page

### Patch Changes

-   @nhost/react-apollo@12.0.5
-   @nhost/nextjs@2.1.19

## 1.25.0

### Minor Changes

- d1ceede: feat: add setting to migrate postgres major and/or minor
versions
- e5d3d1a: fix: allow manually typing column for custom check in
database row permissions

### Patch Changes

-   @nhost/react-apollo@12.0.4
-   @nhost/nextjs@2.1.18

## 1.24.1

### Patch Changes

- 49f2e55: fix: use service subdomain in service form and service
details dialog
- 598b988: fix: use current project subdomain in ServiceDetailsDialog
component

## 1.24.0

### Minor Changes

-   abb24af: chore: add redirect to support page when project is locked
- 18a6455: feat: show contact us info and locked reason when project is
locked

### Patch Changes

-   e31eefa: fix: include ingresses field when updating run services

## 1.23.0

### Minor Changes

-   33284d3: fix: don't show double scrollbar in configuration editor

### Patch Changes

-   @nhost/react-apollo@12.0.3
-   @nhost/nextjs@2.1.17

## 1.22.0

### Minor Changes

-   998c037: fix: align drop-down list in select component
- 807b8c0: fix: show city name in region selection for project creation

## 1.21.0

### Minor Changes

- a2efeed: fix: improve project health error handling, add unknown state
and polling interval for health state

## 1.20.0

### Minor Changes

- 8ea4210: fix: error toasts can be closed individually, instead of
dismissing all toasts at once
- 58919ba: chore: add blink animation when project health service is
updating

## 1.19.0

### Minor Changes

- b519862: fix: get configuration in configuration editor using local
development environment

## 1.18.0

### Minor Changes

- 502abad: feat: add services health checks indicators to the overview
page
-   b3ff6ad: chore: update title text on service status modal
- dbadf59: feat: add project configuration TOML editor to the settings
page

## 1.17.0

### Minor Changes

- 77fba27: fix: postgres version validation when activating ai in ai
settings page
-   ac6d1b6: feat: use name instead of awsName

## 1.16.3

### Patch Changes

- 87a37cf: fix: remove unnecessary isPlatform check from verify button
disable logic on custom domains
    -   @nhost/react-apollo@12.0.2
    -   @nhost/nextjs@2.1.16

## 1.16.2

### Patch Changes

- a9413af: fix: update `GetAllWorkspacesAndProjects` query polling to
use exponential backoff
    -   @nhost/react-apollo@12.0.1
    -   @nhost/nextjs@2.1.15

## 1.16.1

### Patch Changes

-   @nhost/react-apollo@12.0.0
-   @nhost/nextjs@2.1.14

## 1.16.0

### Minor Changes

- c6d5c5c: feat: add toggle switch to enable/disable public access in
the database settings

## 1.15.2

### Patch Changes

-   @nhost/react-apollo@11.0.4
-   @nhost/nextjs@2.1.13

## 1.15.1

### Patch Changes

-   @nhost/react-apollo@11.0.3
-   @nhost/nextjs@2.1.12

## 1.15.0

### Minor Changes

-   a7bde37: feat: send metadata in the edit form

### Patch Changes

- 1bc615b: feat: improve error message handling in `ErrorToast`
component
    -   @nhost/react-apollo@11.0.2
    -   @nhost/nextjs@2.1.11

## 1.14.0

### Minor Changes

-   a448d7d: feat: allow configuring postmark and delete SMTP settings

## 1.13.3

### Patch Changes

-   5924bc3: fix: include password in `GetSmtpSettings` query
- c5ad634: fix: resolved an issue where one-click install links were
broken on Safari
- 7278991: fix: update graphql auto-embeddings configuration to use
String type for model field

## 1.13.2

### Patch Changes

-   026f84f: fix: use configuration server URL from environment variable

## 1.13.1

### Patch Changes

-   7e9a2ce: fix: resolve issue where run services form fails to open

## 1.13.0

### Minor Changes

-   dd5d262: feat: add model field to the auto-embeddings form
- 09962be: feat: enable settings and run services when running the
dashboard locally
- 9cdecb6: feat: enable users to update their email address from the
account settings page

## 1.12.2

### Patch Changes

-   c195c51: fix: send email upon signin for unverified users

## 1.12.1

### Patch Changes

- 93ebdf8: fix: use service urls when initilizaing NhostClient running
local dashboard
    -   @nhost/react-apollo@11.0.1
    -   @nhost/nextjs@2.1.10

## 1.12.0

### Minor Changes

- f242e4b: feat: add connect with github to the user's account settings
-   768ca17: chore: update dependencies
- d62bd0f: fix: "Track this" option within the SQL editor now correctly
updates the metadata
- 91c2bb6: feat: refactor sign-in and sign-up pages to enforce email
verification

### Patch Changes

-   943831f: fix: resolve an error toast issue when unpausing a project
-   Updated dependencies [768ca17]
    -   @nhost/react-apollo@11.0.0
    -   @nhost/nextjs@2.1.9

## 1.11.2

### Patch Changes

-   @nhost/react-apollo@10.0.2
-   @nhost/nextjs@2.1.8

## 1.11.1

### Patch Changes

-   981404f: fix: set default value for healthCheck field validation

## 1.11.0

### Minor Changes

- 7789469: chore: upgrade dependency `@graphql-codegen/cli` to `5.0.2`
to address vulnerability
- 6c11b75: feat: add update user displayName section in account settings

### Patch Changes

-   @nhost/react-apollo@10.0.1
-   @nhost/nextjs@2.1.7

## 1.10.0

### Minor Changes

-   49a80c2: chore: update dependencies
-   150c04a: feat: add healthcheck config to run services

### Patch Changes

- e03f141: fix: allow insert, update and delete on tables in `auth` and
`storage` schemas
- 28676f4: feat: add min postgres version check to enable the ai service
-   Updated dependencies [49a80c2]
    -   @nhost/react-apollo@10.0.0
    -   @nhost/nextjs@2.1.6

## 1.9.0

### Minor Changes

-   d86e5c9: feat: add support for filtering the logs using a RegExp

## 1.8.3

### Patch Changes

-   @nhost/react-apollo@9.0.3
-   @nhost/nextjs@2.1.5

## 1.8.2

### Patch Changes

- 6df4f02: fix: use custom error toast and show correct message when
sending an invite

## 1.8.1

### Patch Changes

-   @nhost/react-apollo@9.0.2
-   @nhost/nextjs@2.1.4

## 1.8.0

### Minor Changes

- 713d53c: feat: add catch-all route for workspace/project - useful for
documentation

### Patch Changes

-   3db2999: fix: refresh table list after running SQL using the editor
- 3c4dd55: fix: handle `Error` objects properly in the `ErrorToast`
component
- 92b434e: fix: resolve an issue where the checkbox in the data-grid
header did not select all rows
    -   @nhost/react-apollo@9.0.1
    -   @nhost/nextjs@2.1.3

## 1.7.0

### Minor Changes

-   0d8d0eb: Update docs and dashboard references

## 1.6.9

### Patch Changes

-   @nhost/react-apollo@9.0.0
-   @nhost/nextjs@2.1.2

## 1.6.8

### Patch Changes

-   @nhost/react-apollo@8.0.1
-   @nhost/nextjs@2.1.1

## 1.6.7

### Patch Changes

-   5ef5189: fix: update `@apollo/client` to `3.9.4` to fix a cache bug

## 1.6.6

### Patch Changes

-   3ba485e: fix: added discord.com to connect-src
-   e5bab6a: chore: update dependencies
-   Updated dependencies [b19ffed]
-   Updated dependencies [e5bab6a]
    -   @nhost/nextjs@2.1.0
    -   @nhost/react-apollo@8.0.0

## 1.6.5

### Patch Changes

- ba73bb4: fix: update ErrorToast component to show the internal graphql
error
- d5337ff: fix: utilize accumulator in the creation of validation schema
within data grid utils

## 1.6.4

### Patch Changes

-   7c2a1c2: feat: show error and debug info in the error toast

## 1.6.3

### Patch Changes

-   6b8aad5: fix: add bare nhost.run to CSP

## 1.6.2

### Patch Changes

-   b18edc0: feat: added CSP and X-Frame-Options

## 1.6.1

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
- 3b8473b: chore: update turbo to `1.11.3` and pnpm to `8.10.5` in
Dockerfile
-   Updated dependencies [8d91f71]
    -   @nhost/react-apollo@7.0.2
    -   @nhost/nextjs@2.0.2

## 1.6.0

### Minor Changes

-   3ff1c2b53: fix: show upgrade option for pro projects

## 1.5.0

### Minor Changes

-   c2ef17c0a: feat: add support for new Team plan

## 1.4.0

### Minor Changes

-   7883bbcbd: feat: don't show deprecated plans
- 44be6dc0a: feat: set redirectTo during sign-in to support preview
environments

### Patch Changes

- 3c3594898: fix: allow access to graphite when configured running in
local dashboard
-   32c246b7a: chore: update docs icon

## 1.3.2

### Patch Changes

-   174b4165b: chore: use env variables when running graphql codegen
-   7c977e714: chore: change `Allowed Roles` to `Default Allowed Roles`
-   46f028b9f: fix: remove hardcoded ai version setting

## 1.3.1

### Patch Changes

- af33c21d1: chore: remove backendUrl deprecation notice and remove all
references to `providersUpdated`

## 1.3.0

### Minor Changes

-   04784d880: Fix graphite's default version

## 1.2.0

### Minor Changes

-   5733162ed: feat: add settings and ui for graphite

## 1.1.0

### Minor Changes

-   e2b79b5ec: chore: remove sharp from deps

## 1.0.1

### Patch Changes

-   @nhost/react-apollo@7.0.1
-   @nhost/nextjs@2.0.1

## 1.0.0

### Major Changes

- bc9eff6e4: chore: remove support for using backendUrl when
instantiating the Nhost client

### Patch Changes

-   Updated dependencies [bc9eff6e4]
    -   @nhost/nextjs@2.0.0
    -   @nhost/react-apollo@7.0.0

## 0.21.1

### Patch Changes

-   97ced73a3: fix(dashboard): prevent dashboard from resolving secrets

## 0.21.0

### Minor Changes

- ed1a8d458: Update alert message on increasing PostgreSQL's volume
capacity
-   2e2248fd4: feat(dashboard): add SQL editor

## 0.20.28

### Patch Changes

-   7c2c31082: feat: add support for users to delete their account
    -   @nhost/react-apollo@6.0.1
    -   @nhost/nextjs@1.13.40

## 0.20.27

### Patch Changes

- fa79b7709: chore(dashboard): tweaks and fixes to the service form and
dialog
-   8df84d782: fix(dashboard): allow resetting custom domains
    -   @nhost/react-apollo@6.0.0
    -   @nhost/nextjs@1.13.39

## 0.20.26

### Patch Changes

- 331ba0376: feat(dashboard): add postgres storage capacity modifier in
the settings
-   b7f801874: feat(dashboard): add new settings page for custom domains

## 0.20.25

### Patch Changes

-   @nhost/react-apollo@5.0.38

## 0.20.24

### Patch Changes

-   e10389ecf: fix(dashboard): disable run tab when developing locally
    -   @nhost/react-apollo@5.0.37

## 0.20.23

### Patch Changes

-   c01568a7d: chore(dashboard): show alert to update oauth providers

## 0.20.22

### Patch Changes

-   c3efb7ec8: feat(dashboard): query latest announcement from platform

## 0.20.21

### Patch Changes

-   3e46d3873: chore: update link to node18 announcement

## 0.20.20

### Patch Changes

-   @nhost/react-apollo@5.0.36
-   @nhost/nextjs@1.13.38

## 0.20.19

### Patch Changes

-   75c4c8ae3: feat(dashboard): make env value input multiline

## 0.20.18

### Patch Changes

- 425d485f8: fix(dashboard): make sure dedicated resources pricing
follows total resources

## 0.20.17

### Patch Changes

-   ae324f67f: fix(dashboard): remove unused graphql fields

## 0.20.16

### Patch Changes

-   df5b4302c: chore(dashboard): remove run feature flag
- bf4a1f6c2: feat(dashboard): fetch auth, postgres, hasura and storage
versions from dashboard
- 34fc08ca7: fix(dashboard/run): show correct private registry in
service details
-   885d10620: chore(dashboard): change feedback to contact us

## 0.20.15

### Patch Changes

- ed16c8b5d: feat(run): add a confirmation dialog when deleting a run
service
- 216990888: fix(run): center loading indicator when selecting a project

## 0.20.14

### Patch Changes

-   9fbea9787: feat: add node18 announcement

## 0.20.13

### Patch Changes

- e84acf469: fix(run): handle subdomain undefined error when creating a
new service

## 0.20.12

### Patch Changes

-   b7c799d62: feat(run): add dialog to copy registry and URLs

## 0.20.11

### Patch Changes

-   8903e6abd: fix(dashboard): show correct egress limit in usage stats

## 0.20.10

### Patch Changes

- 666a75a23: feat(dashboard): add functions execution time and egress
volume to usage stats

## 0.20.9

### Patch Changes

-   5e1e80aa8: fix(dashboard): show correct locales in user details
    -   @nhost/react-apollo@5.0.35
    -   @nhost/nextjs@1.13.37

## 0.20.8

### Patch Changes

-   @nhost/react-apollo@5.0.34
-   @nhost/nextjs@1.13.36

## 0.20.7

### Patch Changes

-   4a7ede11e: fix: distinguish files that were not uploaded
- 202b64723: feat(nhost-run): add support for one-click-install run
services
- 074a0fa11: feat(dashboard): add settings toggle to enable/disable
antivirus
    -   @nhost/react-apollo@5.0.33
    -   @nhost/nextjs@1.13.35

## 0.20.6

### Patch Changes

-   b20761e97: feat(services): add pricing info and confirmation dialog
-   90df6d81d: fix(services): handle null values when editing a service
-   aa8508467: fix: query service logs correctly
    feat: enable multiline support for environment value input

## 0.20.5

### Patch Changes

-   8d7f84b8d: fix: make announcement adapt to theme

## 0.20.4

### Patch Changes

-   3b75bfce2: fix: make announcement close properly
- f49819075: fix: show correct values when dedicated resources are
disabled

## 0.20.3

### Patch Changes

-   e643bd362: fix(services): fix errors when config is null
-   bcdab66bf: feat: add annoucement for nhost run
-   f967a2e59: added note about storage not being able to be downsized
-   311c7756d: chore(services): consistent naming for compute

## 0.20.2

### Patch Changes

-   9073182d5: chore(dashboard): bump `turbo` to 1.10.11
-   ece717d6e: feat(logs): show services in the logs page
- 82b335311: feat(metrics): change grafana link to point to the
dashboards
- b135ef695: fix(services): set command as optional and set min replicas
to 0

## 0.20.1

### Patch Changes

-   3d5c34f4c: fix(auth): fix users pagination limit

## 0.20.0

### Minor Changes

-   c99d117d1: feat(services): add support for custom services

## 0.19.2

### Patch Changes

-   face99ccd: chore(deps): bump turbo version
-   cfe527307: style: tweak pull config warning in dark mode
- a9d7da8af: chore(deps): update dependency @types/pluralize to ^0.0.30
-   9aa4371ef: chore: add hasura-auth version 0.21.2
- d14e112bf: chore(deps): update dependency prettier-plugin-tailwindcss
to ^0.4.0
-   d3e8bb94a: chore(deps): update dependency vite-plugin-dts to v3

## 0.19.1

### Patch Changes

-   @nhost/react-apollo@5.0.32
-   @nhost/nextjs@1.13.34

## 0.19.0

### Minor Changes

- 9c61c69a7: chore(dashboard):add postgres 14.6-20230705-1 to the
version selector

### Patch Changes

-   47bda15ff: feat(settings): add warning to pull config

## 0.18.0

### Minor Changes

- ee0b9b8ed: chore(dashboard):add hasura v2.28.2 and v2.29.0 to the
version selector

## 0.17.20

### Patch Changes

-   @nhost/react-apollo@5.0.31
-   @nhost/nextjs@1.13.33

## 0.17.19

### Patch Changes

-   f866120a6: fix(users): use the password length from the config

## 0.17.18

### Patch Changes

-   @nhost/react-apollo@5.0.30
-   @nhost/nextjs@1.13.32

## 0.17.17

### Patch Changes

-   ea7b102c0: fix(pat): highlight expired tokens

## 0.17.16

### Patch Changes

- b3b64a3b7: chore(deps): bump `@types/react` to `v18.2.14` and
`@types/react-dom` to `v18.2.6`
-   32b221f94: chore(deps): bump `graphiql` to `v3`
-   3a56c12df: chore(deps): bump `turbo` to `v1.10.6`
-   Updated dependencies [b3b64a3b7]
    -   @nhost/react-apollo@5.0.29
    -   @nhost/nextjs@1.13.31

## 0.17.15

### Patch Changes

-   f41fdc12a: chore(deps): bump `turbo` to `1.10.5`
-   6199c1c55: fix(projects): don't redirect to 404 page
-   Updated dependencies [07a45fde0]
    -   @nhost/react-apollo@5.0.28
    -   @nhost/nextjs@1.13.30

## 0.17.14

### Patch Changes

- 80b22724d: chore(deps): bump `@types/react` to `v18.2.13`,
`@types/react-dom` to `v18.2.6` and `@storybook/testing-library` to
`v0.2.0`

## 0.17.13

### Patch Changes

-   cc02902cb: chore(docs): update environment variable documentation

## 0.17.12

### Patch Changes

-   660d339e1: fix(storybook): don't break storybook
-   660d339e1: fix(tests): prevent warnings during tests
    -   @nhost/react-apollo@5.0.27
    -   @nhost/nextjs@1.13.29

## 0.17.11

### Patch Changes

- bd4d0c270: chore(dashboard):add postgres 14.6-20230613-1 to the
version selector

## 0.17.10

### Patch Changes

-   c8c2a10b2: fix(database): don't break the password reset flow
- e70b45498: chore(deps): bump `@types/react` to `v18.2.12` and
`@types/react-dom` to `v18.2.5`

## 0.17.9

### Patch Changes

- 842055099: chore(deps): bump `turbo` to `v1.10.3` and `pnpm` to
`v8.6.2`
- fd12aa0a8: chore(projects): remove the postgres password input from
the project creation screen
-   022b76e78: chore(deps): bump `@types/react` to `v18.2.11`
-   3555ab2b7: chore(deps): bump `vitest` monorepo to `v0.32.0`
-   c43e54922: feat(backups): add download button to backups

## 0.17.8

### Patch Changes

-   d0457fe5c: feat(settings): improve the dashboard and config parity
    -   @nhost/react-apollo@5.0.26
    -   @nhost/nextjs@1.13.28

## 0.17.7

### Patch Changes

-   4f0368b95: fix(account): don't break account settings page

## 0.17.6

### Patch Changes

- 64a8f41d0: chore(resources): lower the maximum allowed resources per
service

## 0.17.5

### Patch Changes

-   @nhost/react-apollo@5.0.25
-   @nhost/nextjs@1.13.27

## 0.17.4

### Patch Changes

- 9b1d0f7a5: fix(deployments): use correct timestamp for deployment
details
-   6d2963ffa: chore(deps): bump `@types/react` to `v18.2.8`
- 8871267b9: chore(deps): downgrade `pnpm` to `v8.5.1` because of no
Turborepo support

## 0.17.3

### Patch Changes

-   01eeef9de: chore(misc): under the hood improvements
- 21e13db05: chore(deps): bump `@types/react` to `v18.2.7` and `turbo`
to `v1.10.1`
- f16433ae6: chore(secrets): allow empty secrets and environment
variables
-   aa3c62989: chore(cli): bump Nhost CLI version to v1.0
    -   @nhost/react-apollo@5.0.24
    -   @nhost/nextjs@1.13.26

## 0.17.2

### Patch Changes

-   88a4983f: chore(misc): under the hood improvements

## 0.17.1

### Patch Changes

-   9b0d4dde: feat(secrets): enable secrets

## 0.17.0

### Minor Changes

-   15d84a19: Add postgres 14.6-20230525

## 0.16.14

### Patch Changes

-   4c626174: chore: updated import paths, improved directory structure
-   cc047b71: chore(deps): bump `@fontsource` monorepo to `v5.0.0`
-   99edd012: feat(account): add support for personal access tokens

## 0.16.13

### Patch Changes

-   78c7109c: feat(settings): allow selecting service versions

## 0.16.12

### Patch Changes

- 399009d6: fix(gql): don't enter an infinite loop when fetching remote
app data
- 329e5a91: fix(deployments): use the same sorting of deployments
everywhere
- 6d559d6e: chore(settings): add under the hood improvements to the
settings page
- 12eb236c: chore(deps): bump `prettier-plugin-tailwindcss` to `v0.3.0`
-   f9b81a2a: chore(deps): bump `turbo` to `v1.9.8`
-   1345741b: fix(projects): don't redirect to 404 on project creation
-   Updated dependencies [7fea29a8]
    -   @nhost/react-apollo@5.0.23
    -   @nhost/nextjs@1.13.25

## 0.16.11

### Patch Changes

- 1230b722: fix(projects): don't redirect to 404 on when the project is
renamed
    -   @nhost/react-apollo@5.0.22
    -   @nhost/nextjs@1.13.24

## 0.16.10

### Patch Changes

-   Updated dependencies [da03bf39]
    -   @nhost/react-apollo@5.0.21
    -   @nhost/nextjs@1.13.23

## 0.16.9

### Patch Changes

- 349aac36: fix(settings): use region domain when constructing the
postgres connection string

## 0.16.8

### Patch Changes

- 20fb69fa: chore(projects): change the way how API URLs are constructed

## 0.16.7

### Patch Changes

- 49f9b837: chore(docker): bump `pnpm` to `v8.4.0` and `turbo` to
`v1.9.3`
- 3f478a4e: chore(deps): bump `vitest` to `v0.31.0`, `@types/react` to
`v18.2.6` and `@types/react-dom` to `v18.2.4`

## 0.16.6

### Patch Changes

- d926f156: fix(projects): redirect to 404 when an invalid project is
opened
- 49b99728: fix(projects): disable features for non-owner members of
workspaces

## 0.16.5

### Patch Changes

-   12e2855f: chore(deps): bump `jsdom` to v22
-   e4972b83: feat(metrics): add Grafana page

## 0.16.4

### Patch Changes

- 3f396a9e: fix(projects): unpause after upgrading a paused project to
pro
- 3f396a9e: fix(projects): don't redirect to 404 page after project
creation

## 0.16.3

### Patch Changes

-   Updated dependencies [90c60311]
    -   @nhost/react-apollo@5.0.20
    -   @nhost/nextjs@1.13.22

## 0.16.2

### Patch Changes

-   0f34f0c6: fix(projects): disallow downgrading to free plan
- 8da291ad: chore(deps): bump `@types/react` to v18.2.0 and
`@types/react-dom` to v18.2.1

## 0.16.1

### Patch Changes

- adc828a5: fix(gql): don't enter an infinite loop when fetching remote
app data

## 0.16.0

### Minor Changes

-   2fb1145f: feat(compute): add support for replicas

### Patch Changes

- d8ceccec: chore(env): remove deprecated `NHOST_BACKEND_URL`
environment variable

## 0.15.2

### Patch Changes

-   84b84ab7: fix(projects): filter projects by workspace

## 0.15.1

### Patch Changes

-   2faf7907: chore(deps): bump `graphql-request` to v6
-   f1b5a944: chore(deps): bump `@vitejs/plugin-react` to v4
-   7f1785ac: chore(deps): bump `@types/react` to v18.0.37
    -   @nhost/react-apollo@5.0.19

## 0.15.0

### Minor Changes

-   85889ee8: feat(dashboard): add Compute management to the settings

## 0.14.8

### Patch Changes

-   668c8771: chore(dialogs): unify dialog management of payment dialogs

## 0.14.7

### Patch Changes

-   d4ccc656: chore: cleanup unused code
    -   @nhost/react-apollo@5.0.18
    -   @nhost/nextjs@1.13.21

## 0.14.6

### Patch Changes

-   b299cfc9: chore(deps): bump `vitest` to v0.30.0
-   411cb65b: chore(projects): refactor workspace and project hooks
- 43b1b144: chore(deps): bump `@types/react` to v18.0.34 and
`@types/react-dom` to v18.0.11
-   Updated dependencies [43b1b144]
    -   @nhost/react-apollo@5.0.17
    -   @nhost/nextjs@1.13.20

## 0.14.5

### Patch Changes

-   ba0d57ee: fix(i18n): revert i18n library
-   3328ed05: feat(projects): improve overview when there is an error

## 0.14.4

### Patch Changes

-   5e0920ba: chore(deps): bump `next-seo` to v6
-   706c9dc3: chore(deps): bump `@types/react` to 18.0.33
-   99f8f6b3: feat(metrics): show metrics on the overview

## 0.14.3

### Patch Changes

-   @nhost/react-apollo@5.0.16

## 0.14.2

### Patch Changes

-   3cb67300: fix(logs): don't break UI when clearing time picker
-   7453bf3b: feat(projects): show project creator info
-   c166dad0: chore(tests): improve auth page tests
-   6a290bb2: chore(deps): bump `@types/react` to 18.0.32

## 0.14.1

### Patch Changes

-   @nhost/react-apollo@5.0.15
-   @nhost/nextjs@1.13.19

## 0.14.0

### Minor Changes

-   6e1f03ea: feat(dashboard): add support for the Azure AD provider

### Patch Changes

-   1bd2c373: chore(deps): bump `turbo` to 1.8.6
-   d329b621: chore(deps): bump `@types/react` to 18.0.30
-   cb248f0d: fix(tests): avoid name collision in database tests
-   867c8076: chore(deps): bump `@types/react` to 18.0.29

## 0.13.10

### Patch Changes

- e93b06ab: fix(dashboard): remove left margin from workspace list on
mobile
-   1c4806bf: chore(deps): bump `sharp` to 0.32.0
    -   @nhost/react-apollo@5.0.14
    -   @nhost/nextjs@1.13.18

## 0.13.9

### Patch Changes

-   912ed76c: chore(dashboard): bump `@apollo/client` to 3.7.10
-   Updated dependencies [912ed76c]
    -   @nhost/react-apollo@5.0.13

## 0.13.8

### Patch Changes

-   7c127372: chore(dashboard): bump `react-error-boundary` to v4

## 0.13.7

### Patch Changes

- 9130ab12: chore(dashboard): bump `yup` to v1 and `@hookform/resolvers`
to v3

## 0.13.6

### Patch Changes

- 253dd235: using new mutation to create projects + refactor Create
Project page.

## 0.13.5

### Patch Changes

-   @nhost/react-apollo@5.0.12
-   @nhost/nextjs@1.13.17

## 0.13.4

### Patch Changes

-   b48bc034: fix(dashboard): disable new users
-   798e591b: fix(dashboard): show correct date in data grid

## 0.13.3

### Patch Changes

-   bfb4c1a6: chore(dashboard): remove `useAxios` property
-   d8d8394b: Dashboard: allow to override hasura admin secret in docker
-   Updated dependencies [ce1ee40d]
    -   @nhost/nextjs@1.13.16
    -   @nhost/react-apollo@5.0.11

## 0.13.2

### Patch Changes

-   beed2eba: Fix docker entrypoint for dashboard
- 2c8559a3: fix(dashboard): refresh project list after deleting a
project
-   4329d048: chore(dashboard): bump `graphiql` dependencies

## 0.13.1

### Patch Changes

-   cbb1fc5b: chore(dashboard): cleanup GraphQL operations

## 0.13.0

### Minor Changes

-   088584e7: feat(dashboard): add support for custom local subdomains

### Patch Changes

-   2ac90dfd: fix(dashboard): improve mobile responsive layout
-   Updated dependencies [f375eacc]
    -   @nhost/nextjs@1.13.15
    -   @nhost/react-apollo@5.0.10

## 0.12.4

### Patch Changes

-   @nhost/react-apollo@5.0.9
-   @nhost/nextjs@1.13.14

## 0.12.3

### Patch Changes

-   2b1338f7: chore(dashboard): bump `turbo` to 1.8.3
- 5223ee93: fix(dashboard): show correct deployment status on the main
page
-   850a049c: chore(deps): update docker/build-push-action action to v4
-   Updated dependencies [850a049c]
    -   @nhost/nextjs@1.13.13
    -   @nhost/react-apollo@5.0.8

## 0.12.2

### Patch Changes

-   4bf40995: chore(deps): bump `typescript` to `4.9.5`
-   8bb097c9: chore(deps): bump `vitest`
- 35d52aab: chore(deps): replace `cross-fetch` with `isomorphic-unfetch`
-   Updated dependencies [4bf40995]
-   Updated dependencies [8bb097c9]
-   Updated dependencies [35d52aab]
    -   @nhost/react-apollo@5.0.7
    -   @nhost/nextjs@1.13.12

## 0.12.1

### Patch Changes

-   c96d7ccd: fix(dashboard): fix docker builds

## 0.12.0

### Minor Changes

-   d1671210: feat(dashboard): use mimir to manage project configuration

### Patch Changes

-   f65e4de9: chore(deps): bump @graphql-codegen monorepo to v3

## 0.11.20

### Patch Changes

-   4b4f0d01: chore(dashboard): improve dialog management

## 0.11.19

### Patch Changes

-   @nhost/react-apollo@5.0.6
-   @nhost/nextjs@1.13.11

## 0.11.18

### Patch Changes

-   01318860: fix(nhost-js): use correct URL for functions requests
-   Updated dependencies [01318860]
    -   @nhost/react-apollo@5.0.5
    -   @nhost/nextjs@1.13.10

## 0.11.17

### Patch Changes

-   f673adea: fix(dashboard): set correct Content-Type for user creation
-   445d8ef4: chore(deps): bump `@nhost/react-apollo` to 5.0.4
-   445d8ef4: chore(deps): bump `@nhost/nextjs` to 1.13.9
- 0368663d: fix(dashboard): allow permission editing for auth and
storage schemas
-   Updated dependencies [445d8ef4]
-   Updated dependencies [445d8ef4]
    -   @nhost/react-apollo@5.0.4
    -   @nhost/nextjs@1.13.9

## 0.11.16

### Patch Changes

-   b755e908: fix(dashboard): use correct date for last seen
-   2d9145f9: chore(deps): revert GraphQL client
- 1ddf704c: fix(dashboard): don't show false positive message for failed
user creation
    -   @nhost/react-apollo@5.0.3
    -   @nhost/nextjs@1.13.8

## 0.11.15

### Patch Changes

-   @nhost/react-apollo@5.0.2
-   @nhost/nextjs@1.13.7

## 0.11.14

### Patch Changes

- 2cc18dcb: fix(dashboard): prevent permission editor dropdown from
being always open

## 0.11.13

### Patch Changes

- 3343a363: chore(dashboard): bump `@testing-library/react` to v14 and
`@testing-library/dom` to v9
    -   @nhost/react-apollo@5.0.1
    -   @nhost/nextjs@1.13.6

## 0.11.12

### Patch Changes

- 87eda76e: chore(dashboard): bump `@types/react` to v18.0.28 and
`@types/react-dom` to v18.0.11
-   6f0ac570: feat(dashboard): show dashboard version in account menu

## 0.11.11

### Patch Changes

-   bf1e4071: chore(dashboard): bump `react-is` version to `18.2.0`
-   Updated dependencies [bf1e4071]
-   Updated dependencies [5013213b]
    -   @nhost/nextjs@1.13.5
    -   @nhost/react-apollo@4.13.5

## 0.11.10

### Patch Changes

- a37a430b: fix(dashboard): don't break UI when deployments are
unavailable
    -   @nhost/react-apollo@4.13.4
    -   @nhost/nextjs@1.13.4

## 0.11.9

### Patch Changes

-   7b970e68: fix(dashboard): fix header link color

## 0.11.8

### Patch Changes

- f33242f2: feat(dashboard): add new sign up, sign in and reset password
pages

## 0.11.7

### Patch Changes

-   e9c8909c: fix(dashboard): use correct theme color in dark mode

## 0.11.6

### Patch Changes

-   902f486b: fix(dashboard): re-enable Hasura on logs page

## 0.11.5

### Patch Changes

-   1f9720fa: fix(dashboard): apply select permissions properly

## 0.11.4

### Patch Changes

-   deb14b51: fix(dashboard): don't break billing form

## 0.11.3

### Patch Changes

-   @nhost/react-apollo@4.13.3
-   @nhost/nextjs@1.13.3

## 0.11.2

### Patch Changes

-   f143e51d: chore(dashboard): pin Turborepo to 1.6.3

## 0.11.1

### Patch Changes

-   c2b5a41a: chore(dashboard): select system colors by default

## 0.11.0

### Minor Changes

-   1ebaf429: feat(dashboard): introduce Dark Mode 🌚

### Patch Changes

- 63b445c4: fixed duplicated logs bug and made to date count during live
mode

## 0.10.1

### Patch Changes

-   e146d32e: chore(deps): update dependency @types/react to v18.0.27
-   59347fcd: correct allowed role name
-   5b65cac9: updated authentication documentation
-   963f9b5e: feat(dashboard): include project info in feedback

## 0.10.0

### Minor Changes

-   ed4c7801: chore(dashboard): remove Functions section

## 0.9.10

### Patch Changes

-   4e2f8ccd: fix(dashboard): don't break Auth page in local mode

## 0.9.9

### Patch Changes

-   31abbe5f: fix(dashboard): enable toggle when settings are filled in

## 0.9.8

### Patch Changes

- 5bdd31ad: chore(dashboard): list fewer images per page on the Storage
page
- 5121851c: fix(dashboard): don't throw validation error for valid
permission rules

## 0.9.7

### Patch Changes

-   c126b20d: fix(dashboard): correct redeployment button

## 0.9.6

### Patch Changes

-   36c3519c: feat(dashboard): retrigger deployments

## 0.9.5

### Patch Changes

- 200e9f77: chore(deps): update dependency @types/react-dom to v18.0.10
-   Updated dependencies [200e9f77]
    -   @nhost/nextjs@1.13.2
    -   @nhost/react-apollo@4.13.2

## 0.9.4

### Patch Changes

- dbd3ded5: fix(dashboard): workspaces creation, new form, correct
redirects.

## 0.9.3

### Patch Changes

-   85f0f943: fix(dashboard): don't break the table creation process

## 0.9.2

### Patch Changes

-   Updated dependencies [d42c27ae]
-   Updated dependencies [927be4a2]
    -   @nhost/nextjs@1.13.1
    -   @nhost/react-apollo@4.13.1

## 0.9.1

### Patch Changes

-   d0f80811: fix(dashboard): don't show error when signing out the user

## 0.9.0

### Minor Changes

- d92891b2: feat(dashboard): add Permission Editor to the Database
section

### Patch Changes

-   3d379128: fix(dashboard): create new user
    -   @nhost/react-apollo@4.13.0
    -   @nhost/nextjs@1.13.0

## 0.8.1

### Patch Changes

-   7cadd944: fix(dashboard): display Twitter provider settings

## 0.8.0

### Minor Changes

-   9a1aa7bb: add functions to the log dashboard
-   f29abe62: feat(dashboard): Users Management v2

### Patch Changes

-   7766624b: feat(dashboard): add JWT secret editor modal
    -   @nhost/react-apollo@4.12.1
    -   @nhost/nextjs@1.12.1

## 0.7.13

### Patch Changes

-   dd0738d5: fix(dashboard): provisioning status polling

## 0.7.12

### Patch Changes

-   b21222b3: chore(deps): update dependency @types/node to v16
-   9e0486a3: fix(dashboard): close modals when navigating
-   Updated dependencies [b21222b3]
-   Updated dependencies [65687bee]
-   Updated dependencies [54df0df4]
    -   @nhost/nextjs@1.12.0
    -   @nhost/react-apollo@4.12.0

## 0.7.11

### Patch Changes

-   d6527122: fix(dashboard): use correct service URLs

## 0.7.10

### Patch Changes

-   Updated dependencies [57db5b83]
    -   @nhost/nextjs@1.11.0
    -   @nhost/nhost-js@1.7.0
    -   @nhost/react@0.17.0
    -   @nhost/react-apollo@4.11.0

## 0.7.9

### Patch Changes

- a6d31dc2: fix(dashboard): don't break the UI when project is not
loaded yet

## 0.7.8

### Patch Changes

- 7f251111: Use `NhostProvider` instead of `NhostReactProvider` and
`NhostNextProvider`

    `NhostReactProvider` and `NhostNextProvider` are now deprecated

-   f4d70f88: fix(dashboard): do not break when region is nullish

- 4a9471cc: Windows Live Provider displayed link updated to match
backend url

- 594488e4: fix(dashboard): do not show error when submitting Apple
provider settings

-   Updated dependencies [7f251111]
    -   @nhost/nextjs@1.10.0
    -   @nhost/react@0.16.0
    -   @nhost/react-apollo@4.10.0

## 0.7.7

### Patch Changes

-   80b604ad: fix(dashboard): use correct Hasura slug

## 0.7.6

### Patch Changes

-   2d2beb53: fix(dashboard): prevent error on GraphQL page
-   ac8efcbd: chore(dashboard): deprecate old DNS name

## 0.7.5

### Patch Changes

-   132a4f4b: chore(dashboard): remove unused dependencies
- 132a4f4b: chore(deps): synchronize @types/react-dom and @types/react
versions
-   db57572f: fix(dashboard): correct section paddings when no env vars
-   Updated dependencies [132a4f4b]
    -   @nhost/react@0.15.2
    -   @nhost/react-apollo@4.9.2
    -   @nhost/nextjs@1.9.3

## 0.7.4

### Patch Changes

-   34d85e54: chore(deps): update dependency critters to ^0.0.16
- 9b93cf95: chore(deps): update dependency @netlify/functions to ^0.11.0
-   e0439030: chore(deps): update dependency @types/react-dom to v18.0.9
-   Updated dependencies [82124329]
    -   @nhost/nextjs@1.9.2

## 0.7.3

### Patch Changes

-   a1193da4: fix(dashboard): remove character limit from env var inputs

## 0.7.2

### Patch Changes

-   44f13f62: chore(dashboard): cleanup unused files

## 0.7.1

### Patch Changes

- e01cb2ed: chore(dashboard): change settings sidebar menu item density

## 0.7.0

### Minor Changes

- db342f45: chore(dashboard): refactor Roles and Permissions settings
sections
-   8b9fa0b1: feat(dashboard): add Environment Variables page

### Patch Changes

-   Updated dependencies [66b4f3d0]
-   Updated dependencies [2e6923dc]
-   Updated dependencies [ef117c28]
-   Updated dependencies [aebb8225]
    -   @nhost/core@0.9.4
    -   @nhost/nhost-js@1.6.2
    -   @nhost/nextjs@1.9.1
    -   @nhost/react@0.15.1
    -   @nhost/react-apollo@4.9.1

## 0.6.0

### Minor Changes

-   eef9c914: feat(dashboard): add Roles and Permissions page

## 0.5.0

### Minor Changes

-   a48dd5bf: feat(dashboard): make backend port configurable

## 0.4.3

### Patch Changes

-   5de965d9: fix(dashboard): alphabetic ordering of providers
-   b9087a4a: fix(dashboard): console -> dashboard terminology
-   ca012d79: docs(workos): WorkOS Docs

## 0.4.2

### Patch Changes

-   89bd37bc: fix(dashboard): correct redirect URL input opacity
-   Updated dependencies [4601d84e]
-   Updated dependencies [843087cb]
    -   @nhost/react@0.15.0
    -   @nhost/nextjs@1.9.0
    -   @nhost/react-apollo@4.9.0

## 0.4.1

### Patch Changes

-   766cb612: fix(dashboard): correct redirect URL for oauth providers
-   Updated dependencies [53bdc294]
-   Updated dependencies [f2aaff05]
    -   @nhost/nextjs@1.8.3
    -   @nhost/core@0.9.3
    -   @nhost/react@0.14.3
    -   @nhost/nhost-js@1.6.1
    -   @nhost/react-apollo@4.8.3

## 0.4.0

### Minor Changes

-   9211743d: feat(dashboard): migrate Settings page features

## 0.3.0

### Minor Changes

-   73da6a67: fix(dashboard): avoid using BACKEND_URL locally

## 0.2.0

### Minor Changes

-   db118f97: feat(dashboard): generate Docker image

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-03-14 12:43:51 -01:00
Nuno Pato
992aa997d5 fix: dashboard: remove cspHeader (#3237)
### **PR Type**
Bug fix, Enhancement


___

### **Description**
- Remove Content-Security-Policy header from dashboard

- Fix signup functionality in dashboard

- Update changeset for @nhost/dashboard package


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Security</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>next.config.js</strong><dd><code>Remove
Content-Security-Policy header</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/next.config.js

<li>Commented out Content-Security-Policy header<br> <li> Kept
X-Frame-Options header as DENY


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>serious-pugs-remember.md</strong><dd><code>Add
changeset for dashboard signup 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/serious-pugs-remember.md

<li>Added new changeset file<br> <li> Specified minor version bump for
@nhost/dashboard<br> <li> Included fix for dashboard signup


</details>


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

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

___

> <details> <summary> Need help?</summary><li>Type <code>/help how to
...</code> in the comments thread for any questions about PR-Agent
usage.</li><li>Check out the <a
href="https://qodo-merge-docs.qodo.ai/usage-guide/">documentation</a>
for more information.</li></details>
2025-03-14 12:29:15 -01:00
Sumit Saurabh
382dc11aaa Update README.md (#3235)
### **User description**
update auth example credential


___

### **PR Type**
Documentation


___

### **Description**
- Update authentication example with generic credentials

- Fix minor formatting issue in README


___



### **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>README.md</strong><dd><code>Update auth example and fix
EOF newline</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></summary>
<hr>

README.md

<li>Replace specific email and password with generic ones<br> <li> Add
newline at the end of the file


</details>


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

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

___

> <details> <summary> Need help?</summary><li>Type <code>/help how to
...</code> in the comments thread for any questions about PR-Agent
usage.</li><li>Check out the <a
href="https://qodo-merge-docs.qodo.ai/usage-guide/">documentation</a>
for more information.</li></details>
2025-03-14 14:46:36 +05:30
github-actions[bot]
1976bc48a5 chore: update versions (#3234)
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/dashboard@2.23.0

# @nhost/dashboard

## 2.17.0

### Minor Changes

-   fd59918: fix: redirect to 404 with nhost cli dashboard

## 2.16.0

### Minor Changes

-   f8e6b61: fix: can add rule groups in table permissions
-   9e404c8: fix: not redirect to 404 page if using local Nhost backend
-   ac4aa01: fix: can delete column in database page
-   4385524: fix: update url to check service health in local dashboard

### Patch Changes

-   @nhost/react-apollo@16.0.1
-   @nhost/nextjs@2.2.2

## 2.15.0

### Minor Changes

- f1052a8: fix: improve stability of the dashboard when pausing projects
-   30daa41: fix: update links to docs in overview page
-   7537237: feat: add image preview toggle in storage

## 2.14.0

### Minor Changes

- d43931e: fix: invalid organization slug/project subdomain doesn't open
404 page
- 5df6fa2: feat: add unencrypted disk warning in storage capacity
settings

### Patch Changes

-   44c1e17: chore: update `msw` to v1.3.5 to fix vulnerabilities
    -   @nhost/react-apollo@16.0.0
    -   @nhost/nextjs@2.2.1

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

## 2.12.0

### Minor Changes

- eb95562: fix: show all available permission variables in permission
dropdown select

### Patch Changes

- 8b5c4a0: chore: cleanup layout and add disable duplicate atom key
checking in development mode

## 2.11.3

### Patch Changes

- 714dffa: fix: improve project polling logic and unify usage across
components

## 2.11.2

### Patch Changes

- 6a34f89: fix: improve project polling logic and unify usage across
components

## 2.11.1

### Patch Changes

-   0f6ce52: fix: consolidate useProject hook and fix jwt expired error

## 2.11.0

### Minor Changes

-   cea3ef5: Feat: add org and project placeholders

## 2.10.0

### Minor Changes

-   86ecf27: feat: add support for additional metrics in overview
- 21708be: feat: dashboard: add support for storage buckets to AI
assistants

## 1.30.0

### Minor Changes

- 50441a8: feat: add ui for project autoscaler settings and run services
autoscaler settings

## 1.29.0

### Minor Changes

-   55d8bb5: feat: integrate turnstile for signup verification
-   2a2e54c: fix: update docs url in run services form tooltip
- 18f942f: fix: display long error messages in error toast without
overflow

### Patch Changes

-   @nhost/react-apollo@13.0.0
-   @nhost/nextjs@2.1.22

## 1.28.2

### Patch Changes

- 52a38fe: chore: update dependencies to address security
vulnerabilities
-   Updated dependencies [52a38fe]
    -   @nhost/nextjs@2.1.21

## 1.28.1

### Patch Changes

-   9735fa2: chore: remove broken link

## 1.28.0

### Minor Changes

- 526183a: feat: allow filtering users in "make request as" in graphql
section
-   be3b85b: feat: add conceal errors toggle on auth settings page

### Patch Changes

- 35a2f12: fix: prevent run service details from opening when attempting
to delete
    -   @nhost/react-apollo@12.0.6
    -   @nhost/nextjs@2.1.20

## 1.27.0

### Minor Changes

-   a7cd02c: fix: resolve rate limit query

## 1.26.0

### Minor Changes

-   3773ad7: chore: update pricing information
- b63250d: fix: not allow run service creation form resubmission while
creating a run service
-   a44a1d4: feat: add rate limits settings page

### Patch Changes

-   @nhost/react-apollo@12.0.5
-   @nhost/nextjs@2.1.19

## 1.25.0

### Minor Changes

- d1ceede: feat: add setting to migrate postgres major and/or minor
versions
- e5d3d1a: fix: allow manually typing column for custom check in
database row permissions

### Patch Changes

-   @nhost/react-apollo@12.0.4
-   @nhost/nextjs@2.1.18

## 1.24.1

### Patch Changes

- 49f2e55: fix: use service subdomain in service form and service
details dialog
- 598b988: fix: use current project subdomain in ServiceDetailsDialog
component

## 1.24.0

### Minor Changes

-   abb24af: chore: add redirect to support page when project is locked
- 18a6455: feat: show contact us info and locked reason when project is
locked

### Patch Changes

-   e31eefa: fix: include ingresses field when updating run services

## 1.23.0

### Minor Changes

-   33284d3: fix: don't show double scrollbar in configuration editor

### Patch Changes

-   @nhost/react-apollo@12.0.3
-   @nhost/nextjs@2.1.17

## 1.22.0

### Minor Changes

-   998c037: fix: align drop-down list in select component
- 807b8c0: fix: show city name in region selection for project creation

## 1.21.0

### Minor Changes

- a2efeed: fix: improve project health error handling, add unknown state
and polling interval for health state

## 1.20.0

### Minor Changes

- 8ea4210: fix: error toasts can be closed individually, instead of
dismissing all toasts at once
- 58919ba: chore: add blink animation when project health service is
updating

## 1.19.0

### Minor Changes

- b519862: fix: get configuration in configuration editor using local
development environment

## 1.18.0

### Minor Changes

- 502abad: feat: add services health checks indicators to the overview
page
-   b3ff6ad: chore: update title text on service status modal
- dbadf59: feat: add project configuration TOML editor to the settings
page

## 1.17.0

### Minor Changes

- 77fba27: fix: postgres version validation when activating ai in ai
settings page
-   ac6d1b6: feat: use name instead of awsName

## 1.16.3

### Patch Changes

- 87a37cf: fix: remove unnecessary isPlatform check from verify button
disable logic on custom domains
    -   @nhost/react-apollo@12.0.2
    -   @nhost/nextjs@2.1.16

## 1.16.2

### Patch Changes

- a9413af: fix: update `GetAllWorkspacesAndProjects` query polling to
use exponential backoff
    -   @nhost/react-apollo@12.0.1
    -   @nhost/nextjs@2.1.15

## 1.16.1

### Patch Changes

-   @nhost/react-apollo@12.0.0
-   @nhost/nextjs@2.1.14

## 1.16.0

### Minor Changes

- c6d5c5c: feat: add toggle switch to enable/disable public access in
the database settings

## 1.15.2

### Patch Changes

-   @nhost/react-apollo@11.0.4
-   @nhost/nextjs@2.1.13

## 1.15.1

### Patch Changes

-   @nhost/react-apollo@11.0.3
-   @nhost/nextjs@2.1.12

## 1.15.0

### Minor Changes

-   a7bde37: feat: send metadata in the edit form

### Patch Changes

- 1bc615b: feat: improve error message handling in `ErrorToast`
component
    -   @nhost/react-apollo@11.0.2
    -   @nhost/nextjs@2.1.11

## 1.14.0

### Minor Changes

-   a448d7d: feat: allow configuring postmark and delete SMTP settings

## 1.13.3

### Patch Changes

-   5924bc3: fix: include password in `GetSmtpSettings` query
- c5ad634: fix: resolved an issue where one-click install links were
broken on Safari
- 7278991: fix: update graphql auto-embeddings configuration to use
String type for model field

## 1.13.2

### Patch Changes

-   026f84f: fix: use configuration server URL from environment variable

## 1.13.1

### Patch Changes

-   7e9a2ce: fix: resolve issue where run services form fails to open

## 1.13.0

### Minor Changes

-   dd5d262: feat: add model field to the auto-embeddings form
- 09962be: feat: enable settings and run services when running the
dashboard locally
- 9cdecb6: feat: enable users to update their email address from the
account settings page

## 1.12.2

### Patch Changes

-   c195c51: fix: send email upon signin for unverified users

## 1.12.1

### Patch Changes

- 93ebdf8: fix: use service urls when initilizaing NhostClient running
local dashboard
    -   @nhost/react-apollo@11.0.1
    -   @nhost/nextjs@2.1.10

## 1.12.0

### Minor Changes

- f242e4b: feat: add connect with github to the user's account settings
-   768ca17: chore: update dependencies
- d62bd0f: fix: "Track this" option within the SQL editor now correctly
updates the metadata
- 91c2bb6: feat: refactor sign-in and sign-up pages to enforce email
verification

### Patch Changes

-   943831f: fix: resolve an error toast issue when unpausing a project
-   Updated dependencies [768ca17]
    -   @nhost/react-apollo@11.0.0
    -   @nhost/nextjs@2.1.9

## 1.11.2

### Patch Changes

-   @nhost/react-apollo@10.0.2
-   @nhost/nextjs@2.1.8

## 1.11.1

### Patch Changes

-   981404f: fix: set default value for healthCheck field validation

## 1.11.0

### Minor Changes

- 7789469: chore: upgrade dependency `@graphql-codegen/cli` to `5.0.2`
to address vulnerability
- 6c11b75: feat: add update user displayName section in account settings

### Patch Changes

-   @nhost/react-apollo@10.0.1
-   @nhost/nextjs@2.1.7

## 1.10.0

### Minor Changes

-   49a80c2: chore: update dependencies
-   150c04a: feat: add healthcheck config to run services

### Patch Changes

- e03f141: fix: allow insert, update and delete on tables in `auth` and
`storage` schemas
- 28676f4: feat: add min postgres version check to enable the ai service
-   Updated dependencies [49a80c2]
    -   @nhost/react-apollo@10.0.0
    -   @nhost/nextjs@2.1.6

## 1.9.0

### Minor Changes

-   d86e5c9: feat: add support for filtering the logs using a RegExp

## 1.8.3

### Patch Changes

-   @nhost/react-apollo@9.0.3
-   @nhost/nextjs@2.1.5

## 1.8.2

### Patch Changes

- 6df4f02: fix: use custom error toast and show correct message when
sending an invite

## 1.8.1

### Patch Changes

-   @nhost/react-apollo@9.0.2
-   @nhost/nextjs@2.1.4

## 1.8.0

### Minor Changes

- 713d53c: feat: add catch-all route for workspace/project - useful for
documentation

### Patch Changes

-   3db2999: fix: refresh table list after running SQL using the editor
- 3c4dd55: fix: handle `Error` objects properly in the `ErrorToast`
component
- 92b434e: fix: resolve an issue where the checkbox in the data-grid
header did not select all rows
    -   @nhost/react-apollo@9.0.1
    -   @nhost/nextjs@2.1.3

## 1.7.0

### Minor Changes

-   0d8d0eb: Update docs and dashboard references

## 1.6.9

### Patch Changes

-   @nhost/react-apollo@9.0.0
-   @nhost/nextjs@2.1.2

## 1.6.8

### Patch Changes

-   @nhost/react-apollo@8.0.1
-   @nhost/nextjs@2.1.1

## 1.6.7

### Patch Changes

-   5ef5189: fix: update `@apollo/client` to `3.9.4` to fix a cache bug

## 1.6.6

### Patch Changes

-   3ba485e: fix: added discord.com to connect-src
-   e5bab6a: chore: update dependencies
-   Updated dependencies [b19ffed]
-   Updated dependencies [e5bab6a]
    -   @nhost/nextjs@2.1.0
    -   @nhost/react-apollo@8.0.0

## 1.6.5

### Patch Changes

- ba73bb4: fix: update ErrorToast component to show the internal graphql
error
- d5337ff: fix: utilize accumulator in the creation of validation schema
within data grid utils

## 1.6.4

### Patch Changes

-   7c2a1c2: feat: show error and debug info in the error toast

## 1.6.3

### Patch Changes

-   6b8aad5: fix: add bare nhost.run to CSP

## 1.6.2

### Patch Changes

-   b18edc0: feat: added CSP and X-Frame-Options

## 1.6.1

### Patch Changes

-   8d91f71: chore: update deps and enable pnpm audit
- 3b8473b: chore: update turbo to `1.11.3` and pnpm to `8.10.5` in
Dockerfile
-   Updated dependencies [8d91f71]
    -   @nhost/react-apollo@7.0.2
    -   @nhost/nextjs@2.0.2

## 1.6.0

### Minor Changes

-   3ff1c2b53: fix: show upgrade option for pro projects

## 1.5.0

### Minor Changes

-   c2ef17c0a: feat: add support for new Team plan

## 1.4.0

### Minor Changes

-   7883bbcbd: feat: don't show deprecated plans
- 44be6dc0a: feat: set redirectTo during sign-in to support preview
environments

### Patch Changes

- 3c3594898: fix: allow access to graphite when configured running in
local dashboard
-   32c246b7a: chore: update docs icon

## 1.3.2

### Patch Changes

-   174b4165b: chore: use env variables when running graphql codegen
-   7c977e714: chore: change `Allowed Roles` to `Default Allowed Roles`
-   46f028b9f: fix: remove hardcoded ai version setting

## 1.3.1

### Patch Changes

- af33c21d1: chore: remove backendUrl deprecation notice and remove all
references to `providersUpdated`

## 1.3.0

### Minor Changes

-   04784d880: Fix graphite's default version

## 1.2.0

### Minor Changes

-   5733162ed: feat: add settings and ui for graphite

## 1.1.0

### Minor Changes

-   e2b79b5ec: chore: remove sharp from deps

## 1.0.1

### Patch Changes

-   @nhost/react-apollo@7.0.1
-   @nhost/nextjs@2.0.1

## 1.0.0

### Major Changes

- bc9eff6e4: chore: remove support for using backendUrl when
instantiating the Nhost client

### Patch Changes

-   Updated dependencies [bc9eff6e4]
    -   @nhost/nextjs@2.0.0
    -   @nhost/react-apollo@7.0.0

## 0.21.1

### Patch Changes

-   97ced73a3: fix(dashboard): prevent dashboard from resolving secrets

## 0.21.0

### Minor Changes

- ed1a8d458: Update alert message on increasing PostgreSQL's volume
capacity
-   2e2248fd4: feat(dashboard): add SQL editor

## 0.20.28

### Patch Changes

-   7c2c31082: feat: add support for users to delete their account
    -   @nhost/react-apollo@6.0.1
    -   @nhost/nextjs@1.13.40

## 0.20.27

### Patch Changes

- fa79b7709: chore(dashboard): tweaks and fixes to the service form and
dialog
-   8df84d782: fix(dashboard): allow resetting custom domains
    -   @nhost/react-apollo@6.0.0
    -   @nhost/nextjs@1.13.39

## 0.20.26

### Patch Changes

- 331ba0376: feat(dashboard): add postgres storage capacity modifier in
the settings
-   b7f801874: feat(dashboard): add new settings page for custom domains

## 0.20.25

### Patch Changes

-   @nhost/react-apollo@5.0.38

## 0.20.24

### Patch Changes

-   e10389ecf: fix(dashboard): disable run tab when developing locally
    -   @nhost/react-apollo@5.0.37

## 0.20.23

### Patch Changes

-   c01568a7d: chore(dashboard): show alert to update oauth providers

## 0.20.22

### Patch Changes

-   c3efb7ec8: feat(dashboard): query latest announcement from platform

## 0.20.21

### Patch Changes

-   3e46d3873: chore: update link to node18 announcement

## 0.20.20

### Patch Changes

-   @nhost/react-apollo@5.0.36
-   @nhost/nextjs@1.13.38

## 0.20.19

### Patch Changes

-   75c4c8ae3: feat(dashboard): make env value input multiline

## 0.20.18

### Patch Changes

- 425d485f8: fix(dashboard): make sure dedicated resources pricing
follows total resources

## 0.20.17

### Patch Changes

-   ae324f67f: fix(dashboard): remove unused graphql fields

## 0.20.16

### Patch Changes

-   df5b4302c: chore(dashboard): remove run feature flag
- bf4a1f6c2: feat(dashboard): fetch auth, postgres, hasura and storage
versions from dashboard
- 34fc08ca7: fix(dashboard/run): show correct private registry in
service details
-   885d10620: chore(dashboard): change feedback to contact us

## 0.20.15

### Patch Changes

- ed16c8b5d: feat(run): add a confirmation dialog when deleting a run
service
- 216990888: fix(run): center loading indicator when selecting a project

## 0.20.14

### Patch Changes

-   9fbea9787: feat: add node18 announcement

## 0.20.13

### Patch Changes

- e84acf469: fix(run): handle subdomain undefined error when creating a
new service

## 0.20.12

### Patch Changes

-   b7c799d62: feat(run): add dialog to copy registry and URLs

## 0.20.11

### Patch Changes

-   8903e6abd: fix(dashboard): show correct egress limit in usage stats

## 0.20.10

### Patch Changes

- 666a75a23: feat(dashboard): add functions execution time and egress
volume to usage stats

## 0.20.9

### Patch Changes

-   5e1e80aa8: fix(dashboard): show correct locales in user details
    -   @nhost/react-apollo@5.0.35
    -   @nhost/nextjs@1.13.37

## 0.20.8

### Patch Changes

-   @nhost/react-apollo@5.0.34
-   @nhost/nextjs@1.13.36

## 0.20.7

### Patch Changes

-   4a7ede11e: fix: distinguish files that were not uploaded
- 202b64723: feat(nhost-run): add support for one-click-install run
services
- 074a0fa11: feat(dashboard): add settings toggle to enable/disable
antivirus
    -   @nhost/react-apollo@5.0.33
    -   @nhost/nextjs@1.13.35

## 0.20.6

### Patch Changes

-   b20761e97: feat(services): add pricing info and confirmation dialog
-   90df6d81d: fix(services): handle null values when editing a service
-   aa8508467: fix: query service logs correctly
    feat: enable multiline support for environment value input

## 0.20.5

### Patch Changes

-   8d7f84b8d: fix: make announcement adapt to theme

## 0.20.4

### Patch Changes

-   3b75bfce2: fix: make announcement close properly
- f49819075: fix: show correct values when dedicated resources are
disabled

## 0.20.3

### Patch Changes

-   e643bd362: fix(services): fix errors when config is null
-   bcdab66bf: feat: add annoucement for nhost run
-   f967a2e59: added note about storage not being able to be downsized
-   311c7756d: chore(services): consistent naming for compute

## 0.20.2

### Patch Changes

-   9073182d5: chore(dashboard): bump `turbo` to 1.10.11
-   ece717d6e: feat(logs): show services in the logs page
- 82b335311: feat(metrics): change grafana link to point to the
dashboards
- b135ef695: fix(services): set command as optional and set min replicas
to 0

## 0.20.1

### Patch Changes

-   3d5c34f4c: fix(auth): fix users pagination limit

## 0.20.0

### Minor Changes

-   c99d117d1: feat(services): add support for custom services

## 0.19.2

### Patch Changes

-   face99ccd: chore(deps): bump turbo version
-   cfe527307: style: tweak pull config warning in dark mode
- a9d7da8af: chore(deps): update dependency @types/pluralize to ^0.0.30
-   9aa4371ef: chore: add hasura-auth version 0.21.2
- d14e112bf: chore(deps): update dependency prettier-plugin-tailwindcss
to ^0.4.0
-   d3e8bb94a: chore(deps): update dependency vite-plugin-dts to v3

## 0.19.1

### Patch Changes

-   @nhost/react-apollo@5.0.32
-   @nhost/nextjs@1.13.34

## 0.19.0

### Minor Changes

- 9c61c69a7: chore(dashboard):add postgres 14.6-20230705-1 to the
version selector

### Patch Changes

-   47bda15ff: feat(settings): add warning to pull config

## 0.18.0

### Minor Changes

- ee0b9b8ed: chore(dashboard):add hasura v2.28.2 and v2.29.0 to the
version selector

## 0.17.20

### Patch Changes

-   @nhost/react-apollo@5.0.31
-   @nhost/nextjs@1.13.33

## 0.17.19

### Patch Changes

-   f866120a6: fix(users): use the password length from the config

## 0.17.18

### Patch Changes

-   @nhost/react-apollo@5.0.30
-   @nhost/nextjs@1.13.32

## 0.17.17

### Patch Changes

-   ea7b102c0: fix(pat): highlight expired tokens

## 0.17.16

### Patch Changes

- b3b64a3b7: chore(deps): bump `@types/react` to `v18.2.14` and
`@types/react-dom` to `v18.2.6`
-   32b221f94: chore(deps): bump `graphiql` to `v3`
-   3a56c12df: chore(deps): bump `turbo` to `v1.10.6`
-   Updated dependencies [b3b64a3b7]
    -   @nhost/react-apollo@5.0.29
    -   @nhost/nextjs@1.13.31

## 0.17.15

### Patch Changes

-   f41fdc12a: chore(deps): bump `turbo` to `1.10.5`
-   6199c1c55: fix(projects): don't redirect to 404 page
-   Updated dependencies [07a45fde0]
    -   @nhost/react-apollo@5.0.28
    -   @nhost/nextjs@1.13.30

## 0.17.14

### Patch Changes

- 80b22724d: chore(deps): bump `@types/react` to `v18.2.13`,
`@types/react-dom` to `v18.2.6` and `@storybook/testing-library` to
`v0.2.0`

## 0.17.13

### Patch Changes

-   cc02902cb: chore(docs): update environment variable documentation

## 0.17.12

### Patch Changes

-   660d339e1: fix(storybook): don't break storybook
-   660d339e1: fix(tests): prevent warnings during tests
    -   @nhost/react-apollo@5.0.27
    -   @nhost/nextjs@1.13.29

## 0.17.11

### Patch Changes

- bd4d0c270: chore(dashboard):add postgres 14.6-20230613-1 to the
version selector

## 0.17.10

### Patch Changes

-   c8c2a10b2: fix(database): don't break the password reset flow
- e70b45498: chore(deps): bump `@types/react` to `v18.2.12` and
`@types/react-dom` to `v18.2.5`

## 0.17.9

### Patch Changes

- 842055099: chore(deps): bump `turbo` to `v1.10.3` and `pnpm` to
`v8.6.2`
- fd12aa0a8: chore(projects): remove the postgres password input from
the project creation screen
-   022b76e78: chore(deps): bump `@types/react` to `v18.2.11`
-   3555ab2b7: chore(deps): bump `vitest` monorepo to `v0.32.0`
-   c43e54922: feat(backups): add download button to backups

## 0.17.8

### Patch Changes

-   d0457fe5c: feat(settings): improve the dashboard and config parity
    -   @nhost/react-apollo@5.0.26
    -   @nhost/nextjs@1.13.28

## 0.17.7

### Patch Changes

-   4f0368b95: fix(account): don't break account settings page

## 0.17.6

### Patch Changes

- 64a8f41d0: chore(resources): lower the maximum allowed resources per
service

## 0.17.5

### Patch Changes

-   @nhost/react-apollo@5.0.25
-   @nhost/nextjs@1.13.27

## 0.17.4

### Patch Changes

- 9b1d0f7a5: fix(deployments): use correct timestamp for deployment
details
-   6d2963ffa: chore(deps): bump `@types/react` to `v18.2.8`
- 8871267b9: chore(deps): downgrade `pnpm` to `v8.5.1` because of no
Turborepo support

## 0.17.3

### Patch Changes

-   01eeef9de: chore(misc): under the hood improvements
- 21e13db05: chore(deps): bump `@types/react` to `v18.2.7` and `turbo`
to `v1.10.1`
- f16433ae6: chore(secrets): allow empty secrets and environment
variables
-   aa3c62989: chore(cli): bump Nhost CLI version to v1.0
    -   @nhost/react-apollo@5.0.24
    -   @nhost/nextjs@1.13.26

## 0.17.2

### Patch Changes

-   88a4983f: chore(misc): under the hood improvements

## 0.17.1

### Patch Changes

-   9b0d4dde: feat(secrets): enable secrets

## 0.17.0

### Minor Changes

-   15d84a19: Add postgres 14.6-20230525

## 0.16.14

### Patch Changes

-   4c626174: chore: updated import paths, improved directory structure
-   cc047b71: chore(deps): bump `@fontsource` monorepo to `v5.0.0`
-   99edd012: feat(account): add support for personal access tokens

## 0.16.13

### Patch Changes

-   78c7109c: feat(settings): allow selecting service versions

## 0.16.12

### Patch Changes

- 399009d6: fix(gql): don't enter an infinite loop when fetching remote
app data
- 329e5a91: fix(deployments): use the same sorting of deployments
everywhere
- 6d559d6e: chore(settings): add under the hood improvements to the
settings page
- 12eb236c: chore(deps): bump `prettier-plugin-tailwindcss` to `v0.3.0`
-   f9b81a2a: chore(deps): bump `turbo` to `v1.9.8`
-   1345741b: fix(projects): don't redirect to 404 on project creation
-   Updated dependencies [7fea29a8]
    -   @nhost/react-apollo@5.0.23
    -   @nhost/nextjs@1.13.25

## 0.16.11

### Patch Changes

- 1230b722: fix(projects): don't redirect to 404 on when the project is
renamed
    -   @nhost/react-apollo@5.0.22
    -   @nhost/nextjs@1.13.24

## 0.16.10

### Patch Changes

-   Updated dependencies [da03bf39]
    -   @nhost/react-apollo@5.0.21
    -   @nhost/nextjs@1.13.23

## 0.16.9

### Patch Changes

- 349aac36: fix(settings): use region domain when constructing the
postgres connection string

## 0.16.8

### Patch Changes

- 20fb69fa: chore(projects): change the way how API URLs are constructed

## 0.16.7

### Patch Changes

- 49f9b837: chore(docker): bump `pnpm` to `v8.4.0` and `turbo` to
`v1.9.3`
- 3f478a4e: chore(deps): bump `vitest` to `v0.31.0`, `@types/react` to
`v18.2.6` and `@types/react-dom` to `v18.2.4`

## 0.16.6

### Patch Changes

- d926f156: fix(projects): redirect to 404 when an invalid project is
opened
- 49b99728: fix(projects): disable features for non-owner members of
workspaces

## 0.16.5

### Patch Changes

-   12e2855f: chore(deps): bump `jsdom` to v22
-   e4972b83: feat(metrics): add Grafana page

## 0.16.4

### Patch Changes

- 3f396a9e: fix(projects): unpause after upgrading a paused project to
pro
- 3f396a9e: fix(projects): don't redirect to 404 page after project
creation

## 0.16.3

### Patch Changes

-   Updated dependencies [90c60311]
    -   @nhost/react-apollo@5.0.20
    -   @nhost/nextjs@1.13.22

## 0.16.2

### Patch Changes

-   0f34f0c6: fix(projects): disallow downgrading to free plan
- 8da291ad: chore(deps): bump `@types/react` to v18.2.0 and
`@types/react-dom` to v18.2.1

## 0.16.1

### Patch Changes

- adc828a5: fix(gql): don't enter an infinite loop when fetching remote
app data

## 0.16.0

### Minor Changes

-   2fb1145f: feat(compute): add support for replicas

### Patch Changes

- d8ceccec: chore(env): remove deprecated `NHOST_BACKEND_URL`
environment variable

## 0.15.2

### Patch Changes

-   84b84ab7: fix(projects): filter projects by workspace

## 0.15.1

### Patch Changes

-   2faf7907: chore(deps): bump `graphql-request` to v6
-   f1b5a944: chore(deps): bump `@vitejs/plugin-react` to v4
-   7f1785ac: chore(deps): bump `@types/react` to v18.0.37
    -   @nhost/react-apollo@5.0.19

## 0.15.0

### Minor Changes

-   85889ee8: feat(dashboard): add Compute management to the settings

## 0.14.8

### Patch Changes

-   668c8771: chore(dialogs): unify dialog management of payment dialogs

## 0.14.7

### Patch Changes

-   d4ccc656: chore: cleanup unused code
    -   @nhost/react-apollo@5.0.18
    -   @nhost/nextjs@1.13.21

## 0.14.6

### Patch Changes

-   b299cfc9: chore(deps): bump `vitest` to v0.30.0
-   411cb65b: chore(projects): refactor workspace and project hooks
- 43b1b144: chore(deps): bump `@types/react` to v18.0.34 and
`@types/react-dom` to v18.0.11
-   Updated dependencies [43b1b144]
    -   @nhost/react-apollo@5.0.17
    -   @nhost/nextjs@1.13.20

## 0.14.5

### Patch Changes

-   ba0d57ee: fix(i18n): revert i18n library
-   3328ed05: feat(projects): improve overview when there is an error

## 0.14.4

### Patch Changes

-   5e0920ba: chore(deps): bump `next-seo` to v6
-   706c9dc3: chore(deps): bump `@types/react` to 18.0.33
-   99f8f6b3: feat(metrics): show metrics on the overview

## 0.14.3

### Patch Changes

-   @nhost/react-apollo@5.0.16

## 0.14.2

### Patch Changes

-   3cb67300: fix(logs): don't break UI when clearing time picker
-   7453bf3b: feat(projects): show project creator info
-   c166dad0: chore(tests): improve auth page tests
-   6a290bb2: chore(deps): bump `@types/react` to 18.0.32

## 0.14.1

### Patch Changes

-   @nhost/react-apollo@5.0.15
-   @nhost/nextjs@1.13.19

## 0.14.0

### Minor Changes

-   6e1f03ea: feat(dashboard): add support for the Azure AD provider

### Patch Changes

-   1bd2c373: chore(deps): bump `turbo` to 1.8.6
-   d329b621: chore(deps): bump `@types/react` to 18.0.30
-   cb248f0d: fix(tests): avoid name collision in database tests
-   867c8076: chore(deps): bump `@types/react` to 18.0.29

## 0.13.10

### Patch Changes

- e93b06ab: fix(dashboard): remove left margin from workspace list on
mobile
-   1c4806bf: chore(deps): bump `sharp` to 0.32.0
    -   @nhost/react-apollo@5.0.14
    -   @nhost/nextjs@1.13.18

## 0.13.9

### Patch Changes

-   912ed76c: chore(dashboard): bump `@apollo/client` to 3.7.10
-   Updated dependencies [912ed76c]
    -   @nhost/react-apollo@5.0.13

## 0.13.8

### Patch Changes

-   7c127372: chore(dashboard): bump `react-error-boundary` to v4

## 0.13.7

### Patch Changes

- 9130ab12: chore(dashboard): bump `yup` to v1 and `@hookform/resolvers`
to v3

## 0.13.6

### Patch Changes

- 253dd235: using new mutation to create projects + refactor Create
Project page.

## 0.13.5

### Patch Changes

-   @nhost/react-apollo@5.0.12
-   @nhost/nextjs@1.13.17

## 0.13.4

### Patch Changes

-   b48bc034: fix(dashboard): disable new users
-   798e591b: fix(dashboard): show correct date in data grid

## 0.13.3

### Patch Changes

-   bfb4c1a6: chore(dashboard): remove `useAxios` property
-   d8d8394b: Dashboard: allow to override hasura admin secret in docker
-   Updated dependencies [ce1ee40d]
    -   @nhost/nextjs@1.13.16
    -   @nhost/react-apollo@5.0.11

## 0.13.2

### Patch Changes

-   beed2eba: Fix docker entrypoint for dashboard
- 2c8559a3: fix(dashboard): refresh project list after deleting a
project
-   4329d048: chore(dashboard): bump `graphiql` dependencies

## 0.13.1

### Patch Changes

-   cbb1fc5b: chore(dashboard): cleanup GraphQL operations

## 0.13.0

### Minor Changes

-   088584e7: feat(dashboard): add support for custom local subdomains

### Patch Changes

-   2ac90dfd: fix(dashboard): improve mobile responsive layout
-   Updated dependencies [f375eacc]
    -   @nhost/nextjs@1.13.15
    -   @nhost/react-apollo@5.0.10

## 0.12.4

### Patch Changes

-   @nhost/react-apollo@5.0.9
-   @nhost/nextjs@1.13.14

## 0.12.3

### Patch Changes

-   2b1338f7: chore(dashboard): bump `turbo` to 1.8.3
- 5223ee93: fix(dashboard): show correct deployment status on the main
page
-   850a049c: chore(deps): update docker/build-push-action action to v4
-   Updated dependencies [850a049c]
    -   @nhost/nextjs@1.13.13
    -   @nhost/react-apollo@5.0.8

## 0.12.2

### Patch Changes

-   4bf40995: chore(deps): bump `typescript` to `4.9.5`
-   8bb097c9: chore(deps): bump `vitest`
- 35d52aab: chore(deps): replace `cross-fetch` with `isomorphic-unfetch`
-   Updated dependencies [4bf40995]
-   Updated dependencies [8bb097c9]
-   Updated dependencies [35d52aab]
    -   @nhost/react-apollo@5.0.7
    -   @nhost/nextjs@1.13.12

## 0.12.1

### Patch Changes

-   c96d7ccd: fix(dashboard): fix docker builds

## 0.12.0

### Minor Changes

-   d1671210: feat(dashboard): use mimir to manage project configuration

### Patch Changes

-   f65e4de9: chore(deps): bump @graphql-codegen monorepo to v3

## 0.11.20

### Patch Changes

-   4b4f0d01: chore(dashboard): improve dialog management

## 0.11.19

### Patch Changes

-   @nhost/react-apollo@5.0.6
-   @nhost/nextjs@1.13.11

## 0.11.18

### Patch Changes

-   01318860: fix(nhost-js): use correct URL for functions requests
-   Updated dependencies [01318860]
    -   @nhost/react-apollo@5.0.5
    -   @nhost/nextjs@1.13.10

## 0.11.17

### Patch Changes

-   f673adea: fix(dashboard): set correct Content-Type for user creation
-   445d8ef4: chore(deps): bump `@nhost/react-apollo` to 5.0.4
-   445d8ef4: chore(deps): bump `@nhost/nextjs` to 1.13.9
- 0368663d: fix(dashboard): allow permission editing for auth and
storage schemas
-   Updated dependencies [445d8ef4]
-   Updated dependencies [445d8ef4]
    -   @nhost/react-apollo@5.0.4
    -   @nhost/nextjs@1.13.9

## 0.11.16

### Patch Changes

-   b755e908: fix(dashboard): use correct date for last seen
-   2d9145f9: chore(deps): revert GraphQL client
- 1ddf704c: fix(dashboard): don't show false positive message for failed
user creation
    -   @nhost/react-apollo@5.0.3
    -   @nhost/nextjs@1.13.8

## 0.11.15

### Patch Changes

-   @nhost/react-apollo@5.0.2
-   @nhost/nextjs@1.13.7

## 0.11.14

### Patch Changes

- 2cc18dcb: fix(dashboard): prevent permission editor dropdown from
being always open

## 0.11.13

### Patch Changes

- 3343a363: chore(dashboard): bump `@testing-library/react` to v14 and
`@testing-library/dom` to v9
    -   @nhost/react-apollo@5.0.1
    -   @nhost/nextjs@1.13.6

## 0.11.12

### Patch Changes

- 87eda76e: chore(dashboard): bump `@types/react` to v18.0.28 and
`@types/react-dom` to v18.0.11
-   6f0ac570: feat(dashboard): show dashboard version in account menu

## 0.11.11

### Patch Changes

-   bf1e4071: chore(dashboard): bump `react-is` version to `18.2.0`
-   Updated dependencies [bf1e4071]
-   Updated dependencies [5013213b]
    -   @nhost/nextjs@1.13.5
    -   @nhost/react-apollo@4.13.5

## 0.11.10

### Patch Changes

- a37a430b: fix(dashboard): don't break UI when deployments are
unavailable
    -   @nhost/react-apollo@4.13.4
    -   @nhost/nextjs@1.13.4

## 0.11.9

### Patch Changes

-   7b970e68: fix(dashboard): fix header link color

## 0.11.8

### Patch Changes

- f33242f2: feat(dashboard): add new sign up, sign in and reset password
pages

## 0.11.7

### Patch Changes

-   e9c8909c: fix(dashboard): use correct theme color in dark mode

## 0.11.6

### Patch Changes

-   902f486b: fix(dashboard): re-enable Hasura on logs page

## 0.11.5

### Patch Changes

-   1f9720fa: fix(dashboard): apply select permissions properly

## 0.11.4

### Patch Changes

-   deb14b51: fix(dashboard): don't break billing form

## 0.11.3

### Patch Changes

-   @nhost/react-apollo@4.13.3
-   @nhost/nextjs@1.13.3

## 0.11.2

### Patch Changes

-   f143e51d: chore(dashboard): pin Turborepo to 1.6.3

## 0.11.1

### Patch Changes

-   c2b5a41a: chore(dashboard): select system colors by default

## 0.11.0

### Minor Changes

-   1ebaf429: feat(dashboard): introduce Dark Mode 🌚

### Patch Changes

- 63b445c4: fixed duplicated logs bug and made to date count during live
mode

## 0.10.1

### Patch Changes

-   e146d32e: chore(deps): update dependency @types/react to v18.0.27
-   59347fcd: correct allowed role name
-   5b65cac9: updated authentication documentation
-   963f9b5e: feat(dashboard): include project info in feedback

## 0.10.0

### Minor Changes

-   ed4c7801: chore(dashboard): remove Functions section

## 0.9.10

### Patch Changes

-   4e2f8ccd: fix(dashboard): don't break Auth page in local mode

## 0.9.9

### Patch Changes

-   31abbe5f: fix(dashboard): enable toggle when settings are filled in

## 0.9.8

### Patch Changes

- 5bdd31ad: chore(dashboard): list fewer images per page on the Storage
page
- 5121851c: fix(dashboard): don't throw validation error for valid
permission rules

## 0.9.7

### Patch Changes

-   c126b20d: fix(dashboard): correct redeployment button

## 0.9.6

### Patch Changes

-   36c3519c: feat(dashboard): retrigger deployments

## 0.9.5

### Patch Changes

- 200e9f77: chore(deps): update dependency @types/react-dom to v18.0.10
-   Updated dependencies [200e9f77]
    -   @nhost/nextjs@1.13.2
    -   @nhost/react-apollo@4.13.2

## 0.9.4

### Patch Changes

- dbd3ded5: fix(dashboard): workspaces creation, new form, correct
redirects.

## 0.9.3

### Patch Changes

-   85f0f943: fix(dashboard): don't break the table creation process

## 0.9.2

### Patch Changes

-   Updated dependencies [d42c27ae]
-   Updated dependencies [927be4a2]
    -   @nhost/nextjs@1.13.1
    -   @nhost/react-apollo@4.13.1

## 0.9.1

### Patch Changes

-   d0f80811: fix(dashboard): don't show error when signing out the user

## 0.9.0

### Minor Changes

- d92891b2: feat(dashboard): add Permission Editor to the Database
section

### Patch Changes

-   3d379128: fix(dashboard): create new user
    -   @nhost/react-apollo@4.13.0
    -   @nhost/nextjs@1.13.0

## 0.8.1

### Patch Changes

-   7cadd944: fix(dashboard): display Twitter provider settings

## 0.8.0

### Minor Changes

-   9a1aa7bb: add functions to the log dashboard
-   f29abe62: feat(dashboard): Users Management v2

### Patch Changes

-   7766624b: feat(dashboard): add JWT secret editor modal
    -   @nhost/react-apollo@4.12.1
    -   @nhost/nextjs@1.12.1

## 0.7.13

### Patch Changes

-   dd0738d5: fix(dashboard): provisioning status polling

## 0.7.12

### Patch Changes

-   b21222b3: chore(deps): update dependency @types/node to v16
-   9e0486a3: fix(dashboard): close modals when navigating
-   Updated dependencies [b21222b3]
-   Updated dependencies [65687bee]
-   Updated dependencies [54df0df4]
    -   @nhost/nextjs@1.12.0
    -   @nhost/react-apollo@4.12.0

## 0.7.11

### Patch Changes

-   d6527122: fix(dashboard): use correct service URLs

## 0.7.10

### Patch Changes

-   Updated dependencies [57db5b83]
    -   @nhost/nextjs@1.11.0
    -   @nhost/nhost-js@1.7.0
    -   @nhost/react@0.17.0
    -   @nhost/react-apollo@4.11.0

## 0.7.9

### Patch Changes

- a6d31dc2: fix(dashboard): don't break the UI when project is not
loaded yet

## 0.7.8

### Patch Changes

- 7f251111: Use `NhostProvider` instead of `NhostReactProvider` and
`NhostNextProvider`

    `NhostReactProvider` and `NhostNextProvider` are now deprecated

-   f4d70f88: fix(dashboard): do not break when region is nullish

- 4a9471cc: Windows Live Provider displayed link updated to match
backend url

- 594488e4: fix(dashboard): do not show error when submitting Apple
provider settings

-   Updated dependencies [7f251111]
    -   @nhost/nextjs@1.10.0
    -   @nhost/react@0.16.0
    -   @nhost/react-apollo@4.10.0

## 0.7.7

### Patch Changes

-   80b604ad: fix(dashboard): use correct Hasura slug

## 0.7.6

### Patch Changes

-   2d2beb53: fix(dashboard): prevent error on GraphQL page
-   ac8efcbd: chore(dashboard): deprecate old DNS name

## 0.7.5

### Patch Changes

-   132a4f4b: chore(dashboard): remove unused dependencies
- 132a4f4b: chore(deps): synchronize @types/react-dom and @types/react
versions
-   db57572f: fix(dashboard): correct section paddings when no env vars
-   Updated dependencies [132a4f4b]
    -   @nhost/react@0.15.2
    -   @nhost/react-apollo@4.9.2
    -   @nhost/nextjs@1.9.3

## 0.7.4

### Patch Changes

-   34d85e54: chore(deps): update dependency critters to ^0.0.16
- 9b93cf95: chore(deps): update dependency @netlify/functions to ^0.11.0
-   e0439030: chore(deps): update dependency @types/react-dom to v18.0.9
-   Updated dependencies [82124329]
    -   @nhost/nextjs@1.9.2

## 0.7.3

### Patch Changes

-   a1193da4: fix(dashboard): remove character limit from env var inputs

## 0.7.2

### Patch Changes

-   44f13f62: chore(dashboard): cleanup unused files

## 0.7.1

### Patch Changes

- e01cb2ed: chore(dashboard): change settings sidebar menu item density

## 0.7.0

### Minor Changes

- db342f45: chore(dashboard): refactor Roles and Permissions settings
sections
-   8b9fa0b1: feat(dashboard): add Environment Variables page

### Patch Changes

-   Updated dependencies [66b4f3d0]
-   Updated dependencies [2e6923dc]
-   Updated dependencies [ef117c28]
-   Updated dependencies [aebb8225]
    -   @nhost/core@0.9.4
    -   @nhost/nhost-js@1.6.2
    -   @nhost/nextjs@1.9.1
    -   @nhost/react@0.15.1
    -   @nhost/react-apollo@4.9.1

## 0.6.0

### Minor Changes

-   eef9c914: feat(dashboard): add Roles and Permissions page

## 0.5.0

### Minor Changes

-   a48dd5bf: feat(dashboard): make backend port configurable

## 0.4.3

### Patch Changes

-   5de965d9: fix(dashboard): alphabetic ordering of providers
-   b9087a4a: fix(dashboard): console -> dashboard terminology
-   ca012d79: docs(workos): WorkOS Docs

## 0.4.2

### Patch Changes

-   89bd37bc: fix(dashboard): correct redirect URL input opacity
-   Updated dependencies [4601d84e]
-   Updated dependencies [843087cb]
    -   @nhost/react@0.15.0
    -   @nhost/nextjs@1.9.0
    -   @nhost/react-apollo@4.9.0

## 0.4.1

### Patch Changes

-   766cb612: fix(dashboard): correct redirect URL for oauth providers
-   Updated dependencies [53bdc294]
-   Updated dependencies [f2aaff05]
    -   @nhost/nextjs@1.8.3
    -   @nhost/core@0.9.3
    -   @nhost/react@0.14.3
    -   @nhost/nhost-js@1.6.1
    -   @nhost/react-apollo@4.8.3

## 0.4.0

### Minor Changes

-   9211743d: feat(dashboard): migrate Settings page features

## 0.3.0

### Minor Changes

-   73da6a67: fix(dashboard): avoid using BACKEND_URL locally

## 0.2.0

### Minor Changes

-   db118f97: feat(dashboard): generate Docker image

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-03-13 19:25:42 -01:00
Nuno Pato
38696f5e88 fix: dashboard: add zendesk to csp header (#3233)
### **PR Type**
Enhancement


___

### **Description**
- Add Zendesk to Content Security Policy header

- Update connect-src directive in CSP

- Create changeset for dashboard package


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Configuration
changes</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>next.config.js</strong><dd><code>Update CSP header to
include Zendesk domain</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

dashboard/next.config.js

- Added 'nhost.zendesk.com' to connect-src directive in CSP header


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>cool-meals-suffer.md</strong><dd><code>Add changeset
for Zendesk CSP header update</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

.changeset/cool-meals-suffer.md

<li>Created new changeset file for dashboard package<br> <li> Added
minor version bump for '@nhost/dashboard'<br> <li> Described the change
as adding Zendesk to CSP header


</details>


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

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

___

> <details> <summary> Need help?</summary><li>Type <code>/help how to
...</code> in the comments thread for any questions about PR-Agent
usage.</li><li>Check out the <a
href="https://qodo-merge-docs.qodo.ai/usage-guide/">documentation</a>
for more information.</li></details>
2025-03-13 18:43:51 -01:00
RayRemnant
064ea6a337 chore (nextjs): Update create-server-side-client.ts comment - typo (#3228)
fixed typo 'refesh'

Co-authored-by: David Barroso <dbarrosop@dravetech.com>
2025-03-13 11:42:49 +01:00
Dimitri POSTOLOV
0d323e10f5 chore (react/react-apollo): replace depreacted NhostReactProvider with NhostProvider in README.md (#3227)
<img width="346" alt="image"
src="https://github.com/user-attachments/assets/2f59075c-78e7-420e-8d0b-aa427662f2fd"
/>

---------

Co-authored-by: David Barroso <dbarrosop@dravetech.com>
2025-03-13 11:16:46 +01:00
64 changed files with 3630 additions and 1016 deletions

View File

@@ -73,7 +73,7 @@ const nhost = new NhostClient({
region: '<your-region>'
})
await nhost.auth.signIn({ email: 'elon@musk.com', password: 'spaceX' })
await nhost.auth.signIn({ email: 'user@domain.com', password: 'userPassword' })
await nhost.graphql.request(`{
users {
@@ -150,4 +150,4 @@ Here are some ways of contributing to making Nhost better:
<p align="center">
<img width="720" src="https://contrib.rocks/image?repo=nhost/nhost" alt="A table of avatars from the project's contributors" />
</p>
</a>
</a>

View File

@@ -1,5 +1,20 @@
# @nhost/dashboard
## 2.25.0
### Minor Changes
- 34fdcb8: chore: add prettier plugins as devDependencies to root of monorepo
- 4937c5e: fix: stop content overflowing in projects and database permissions page
- 1542132: fix: update babel dependencies to address security audit vulnerabilities
### Patch Changes
- 78436ca: chore (dashboard): add tests and small updates to PiTR settings and restore page
- b5a3895: chore (dashboard): update page context after each navigation
- 9b24807: chore: fix link to PiTR documentation
- ea65846: chore (dashboard): update nextjs to fix middleware exploit
## 2.17.0
### Minor Changes

View File

@@ -1,22 +1,10 @@
import { expect, test } from '@/e2e/fixtures/auth-hook';
import { faker } from '@faker-js/faker';
import type { Page } from '@playwright/test';
import { expect, test } from '@playwright/test';
let page: Page;
test.beforeAll(async ({ browser }) => {
page = await browser.newPage();
});
test.beforeEach(async () => {
await page.goto('/');
});
test.afterAll(async () => {
await page.close();
});
test('should be able to create then delete a personal access token', async () => {
test('should be able to create then delete a personal access token', async ({
authenticatedNhostPage: page,
}) => {
await page.waitForTimeout(1000);
await page.getByRole('banner').getByRole('button').last().click();
await page.getByRole('link', { name: /account settings/i }).click();

View File

@@ -1,17 +1,8 @@
import { TEST_ORGANIZATION_SLUG, TEST_PROJECT_SUBDOMAIN } from '@/e2e/env';
import { expect, test } from '@/e2e/fixtures/auth-hook';
import { navigateToProject } from '@/e2e/utils';
import type { Page } from '@playwright/test';
import { expect, test } from '@playwright/test';
let page: Page;
test.beforeAll(async ({ browser }) => {
page = await browser.newPage();
});
test.beforeEach(async () => {
await page.goto('/');
test.beforeEach(async ({ authenticatedNhostPage: page }) => {
await navigateToProject({
page,
orgSlug: TEST_ORGANIZATION_SLUG,
@@ -23,11 +14,9 @@ test.beforeEach(async () => {
await page.waitForURL(AIRoute);
});
test.afterAll(async () => {
await page.close();
});
test('should create and delete an Assistant', async () => {
test('should create and delete an Assistant', async ({
authenticatedNhostPage: page,
}) => {
await page.getByRole('link', { name: 'Assistants' }).click();
await expect(page.getByText(/no assistants are configured/i)).toBeVisible();

View File

@@ -1,17 +1,9 @@
import { TEST_ORGANIZATION_SLUG, TEST_PROJECT_SUBDOMAIN } from '@/e2e/env';
import { navigateToProject } from '@/e2e/utils';
import type { Page } from '@playwright/test';
import { expect, test } from '@playwright/test';
let page: Page;
test.beforeAll(async ({ browser }) => {
page = await browser.newPage();
});
test.beforeEach(async () => {
await page.goto('/');
import { expect, test } from '@/e2e/fixtures/auth-hook';
test.beforeEach(async ({ authenticatedNhostPage: page }) => {
await navigateToProject({
page,
orgSlug: TEST_ORGANIZATION_SLUG,
@@ -23,11 +15,9 @@ test.beforeEach(async () => {
await page.waitForURL(AIRoute);
});
test.afterAll(async () => {
await page.close();
});
test('should create and delete an Auto-Embeddings', async () => {
test('should create and delete an Auto-Embeddings', async ({
authenticatedNhostPage: page,
}) => {
await page.getByRole('button', { name: 'Add a new Auto-Embeddings' }).click();
await page.getByLabel('Name').fill('test');

View File

@@ -1,13 +1,14 @@
import { TEST_ORGANIZATION_SLUG, TEST_PROJECT_SUBDOMAIN } from '@/e2e/env';
import { createUser, generateTestEmail } from '@/e2e/utils';
import { expect, test } from '@/e2e/fixtures/auth-hook';
import { createUser, generateTestEmail, gotoAuthURL } from '@/e2e/utils';
import { faker } from '@faker-js/faker';
import test, { expect } from '@playwright/test';
test('should be able to ban and unban a user', async ({ page }) => {
const authUrl = `/orgs/${TEST_ORGANIZATION_SLUG}/projects/${TEST_PROJECT_SUBDOMAIN}/users`;
await page.goto(authUrl);
await page.waitForURL(authUrl, { waitUntil: 'networkidle' });
test.beforeEach(async ({ authenticatedNhostPage: page }) => {
await gotoAuthURL(page);
});
test('should be able to ban and unban a user', async ({
authenticatedNhostPage: page,
}) => {
const email = generateTestEmail();
const password = faker.internet.password();

View File

@@ -1,26 +1,12 @@
import { TEST_ORGANIZATION_SLUG, TEST_PROJECT_SUBDOMAIN } from '@/e2e/env';
import { createUser, generateTestEmail } from '@/e2e/utils';
import { expect, test } from '@/e2e/fixtures/auth-hook';
import { createUser, generateTestEmail, gotoAuthURL } from '@/e2e/utils';
import { faker } from '@faker-js/faker';
import type { Page } from '@playwright/test';
import test, { expect } from '@playwright/test';
let page: Page;
test.beforeAll(async ({ browser }) => {
page = await browser.newPage();
test.beforeEach(async ({ authenticatedNhostPage: page }) => {
await gotoAuthURL(page);
});
test.beforeEach(async () => {
const authUrl = `/orgs/${TEST_ORGANIZATION_SLUG}/projects/${TEST_PROJECT_SUBDOMAIN}/users`;
await page.goto(authUrl);
await page.waitForURL(authUrl, { waitUntil: 'networkidle' });
});
test.afterAll(async () => {
await page.close();
});
test('should create a user', async () => {
test('should create a user', async ({ authenticatedNhostPage: page }) => {
const email = generateTestEmail();
const password = faker.internet.password();
@@ -31,7 +17,9 @@ test('should create a user', async () => {
).toBeVisible();
});
test('should not be able to create a user with an existing email', async () => {
test('should not be able to create a user with an existing email', async ({
authenticatedNhostPage: page,
}) => {
const email = generateTestEmail();
const password = faker.internet.password();

View File

@@ -1,26 +1,15 @@
import { TEST_ORGANIZATION_SLUG, TEST_PROJECT_SUBDOMAIN } from '@/e2e/env';
import { createUser, generateTestEmail } from '@/e2e/utils';
import { createUser, generateTestEmail, gotoAuthURL } from '@/e2e/utils';
import { faker } from '@faker-js/faker';
import type { Page } from '@playwright/test';
import test, { expect } from '@playwright/test';
let page: Page;
import { expect, test } from '@/e2e/fixtures/auth-hook';
test.beforeAll(async ({ browser }) => {
page = await browser.newPage();
test.beforeEach(async ({ authenticatedNhostPage: page }) => {
await gotoAuthURL(page);
});
test.beforeEach(async () => {
const authUrl = `/orgs/${TEST_ORGANIZATION_SLUG}/projects/${TEST_PROJECT_SUBDOMAIN}/users`;
await page.goto(authUrl);
await page.waitForURL(authUrl, { waitUntil: 'networkidle' });
});
test.afterAll(async () => {
await page.close();
});
test('should be able to delete a user', async () => {
test('should be able to delete a user', async ({
authenticatedNhostPage: page,
}) => {
const email = generateTestEmail();
const password = faker.internet.password();
@@ -52,7 +41,9 @@ test('should be able to delete a user', async () => {
).not.toBeVisible();
});
test('should be able to delete a user from the details page', async () => {
test('should be able to delete a user from the details page', async ({
authenticatedNhostPage: page,
}) => {
const email = generateTestEmail();
const password = faker.internet.password();

View File

@@ -1,26 +1,14 @@
import { TEST_ORGANIZATION_SLUG, TEST_PROJECT_SUBDOMAIN } from '@/e2e/env';
import { createUser, generateTestEmail } from '@/e2e/utils';
import { expect, test } from '@/e2e/fixtures/auth-hook';
import { createUser, generateTestEmail, gotoAuthURL } from '@/e2e/utils';
import { faker } from '@faker-js/faker';
import type { Page } from '@playwright/test';
import test, { expect } from '@playwright/test';
let page: Page;
test.beforeAll(async ({ browser }) => {
page = await browser.newPage();
test.beforeEach(async ({ authenticatedNhostPage: page }) => {
await gotoAuthURL(page);
});
test.beforeEach(async () => {
const authUrl = `/orgs/${TEST_ORGANIZATION_SLUG}/projects/${TEST_PROJECT_SUBDOMAIN}/users`;
await page.goto(authUrl);
await page.waitForURL(authUrl, { waitUntil: 'networkidle' });
});
test.afterAll(async () => {
await page.close();
});
test('should be able to edit user roles from the details page', async () => {
test('should be able to edit user roles from the details page', async ({
authenticatedNhostPage: page,
}) => {
const email = generateTestEmail();
const password = faker.internet.password();

View File

@@ -1,26 +1,14 @@
import { TEST_ORGANIZATION_SLUG, TEST_PROJECT_SUBDOMAIN } from '@/e2e/env';
import { createUser, generateTestEmail } from '@/e2e/utils';
import { expect, test } from '@/e2e/fixtures/auth-hook';
import { createUser, generateTestEmail, gotoAuthURL } from '@/e2e/utils';
import { faker } from '@faker-js/faker';
import type { Page } from '@playwright/test';
import { expect, test } from '@playwright/test';
let page: Page;
test.beforeAll(async ({ browser }) => {
page = await browser.newPage();
test.beforeEach(async ({ authenticatedNhostPage: page }) => {
await gotoAuthURL(page);
});
test.beforeEach(async () => {
const authUrl = `/orgs/${TEST_ORGANIZATION_SLUG}/projects/${TEST_PROJECT_SUBDOMAIN}/users`;
await page.goto(authUrl);
await page.waitForURL(authUrl, { waitUntil: 'networkidle' });
});
test.afterAll(async () => {
await page.close();
});
test('should be able to verify the email of a user', async () => {
test('should be able to verify the email of a user', async ({
authenticatedNhostPage: page,
}) => {
const email = generateTestEmail();
const password = faker.internet.password();
@@ -50,7 +38,9 @@ test('should be able to verify the email of a user', async () => {
).toBeChecked();
});
test('should be able to verify the phone number of a user', async () => {
test('should be able to verify the phone number of a user', async ({
authenticatedNhostPage: page,
}) => {
const email = generateTestEmail();
const password = faker.internet.password();
const phoneNumber = faker.phone.number();

View File

@@ -1,35 +1,18 @@
import { TEST_ORGANIZATION_SLUG, TEST_PROJECT_SUBDOMAIN } from '@/e2e/env';
import { navigateToProject, prepareTable } from '@/e2e/utils';
import { expect, test } from '@/e2e/fixtures/auth-hook';
import { prepareTable } from '@/e2e/utils';
import { faker } from '@faker-js/faker';
import type { Page } from '@playwright/test';
import { expect, test } from '@playwright/test';
import { snakeCase } from 'snake-case';
let page: Page;
test.beforeAll(async ({ browser }) => {
page = await browser.newPage();
});
test.beforeEach(async () => {
await page.goto('/');
await navigateToProject({
page,
orgSlug: TEST_ORGANIZATION_SLUG,
projectSubdomain: TEST_PROJECT_SUBDOMAIN,
});
test.beforeEach(async ({ authenticatedNhostPage: page }) => {
const databaseRoute = `/orgs/${TEST_ORGANIZATION_SLUG}/projects/${TEST_PROJECT_SUBDOMAIN}/database/browser/default`;
await page.goto(databaseRoute);
await page.waitForURL(databaseRoute);
});
test.afterAll(async () => {
await page.close();
});
test('should create a simple table', async () => {
test('should create a simple table', async ({
authenticatedNhostPage: page,
}) => {
await page.getByRole('button', { name: /new table/i }).click();
await expect(page.getByText(/create a new table/i)).toBeVisible();
@@ -57,7 +40,9 @@ test('should create a simple table', async () => {
).toBeVisible();
});
test('should create a table with unique constraints', async () => {
test('should create a table with unique constraints', async ({
authenticatedNhostPage: page,
}) => {
await page.getByRole('button', { name: /new table/i }).click();
await expect(page.getByText(/create a new table/i)).toBeVisible();
@@ -86,7 +71,9 @@ test('should create a table with unique constraints', async () => {
).toBeVisible();
});
test('should create a table with nullable columns', async () => {
test('should create a table with nullable columns', async ({
authenticatedNhostPage: page,
}) => {
await page.getByRole('button', { name: /new table/i }).click();
await expect(page.getByText(/create a new table/i)).toBeVisible();
@@ -115,7 +102,9 @@ test('should create a table with nullable columns', async () => {
).toBeVisible();
});
test('should create a table with an identity column', async () => {
test('should create a table with an identity column', async ({
authenticatedNhostPage: page,
}) => {
await page.getByRole('button', { name: /new table/i }).click();
await expect(page.getByText(/create a new table/i)).toBeVisible();
@@ -148,7 +137,9 @@ test('should create a table with an identity column', async () => {
).toBeVisible();
});
test('should create table with foreign key constraint', async () => {
test('should create table with foreign key constraint', async ({
authenticatedNhostPage: page,
}) => {
await page.getByRole('button', { name: /new table/i }).click();
await expect(page.getByText(/create a new table/i)).toBeVisible();
@@ -221,7 +212,9 @@ test('should create table with foreign key constraint', async () => {
).toBeVisible();
});
test('should not be able to create a table with a name that already exists', async () => {
test('should not be able to create a table with a name that already exists', async ({
authenticatedNhostPage: page,
}) => {
await page.getByRole('button', { name: /new table/i }).click();
await expect(page.getByText(/create a new table/i)).toBeVisible();

View File

@@ -1,35 +1,17 @@
import { TEST_ORGANIZATION_SLUG, TEST_PROJECT_SUBDOMAIN } from '@/e2e/env';
import { deleteTable, navigateToProject, prepareTable } from '@/e2e/utils';
import { deleteTable, prepareTable } from '@/e2e/utils';
import { faker } from '@faker-js/faker';
import type { Page } from '@playwright/test';
import { expect, test } from '@playwright/test';
import { expect, test } from '@/e2e/fixtures/auth-hook';
import { snakeCase } from 'snake-case';
let page: Page;
test.beforeAll(async ({ browser }) => {
page = await browser.newPage();
});
test.beforeEach(async () => {
await page.goto('/');
await navigateToProject({
page,
orgSlug: TEST_ORGANIZATION_SLUG,
projectSubdomain: TEST_PROJECT_SUBDOMAIN,
});
test.beforeEach(async ({ authenticatedNhostPage: page }) => {
const databaseRoute = `/orgs/${TEST_ORGANIZATION_SLUG}/projects/${TEST_PROJECT_SUBDOMAIN}/database/browser/default`;
await page.goto(databaseRoute);
await page.waitForURL(databaseRoute);
});
test.afterAll(async () => {
await page.close();
});
test('should delete a table', async () => {
test('should delete a table', async ({ authenticatedNhostPage: page }) => {
const tableName = snakeCase(faker.lorem.words(3));
await page.getByRole('button', { name: /new table/i }).click();
@@ -65,7 +47,9 @@ test('should delete a table', async () => {
).not.toBeVisible();
});
test('should not be able to delete a table if other tables have foreign keys referencing it', async () => {
test('should not be able to delete a table if other tables have foreign keys referencing it', async ({
authenticatedNhostPage: page,
}) => {
test.setTimeout(60000);
await page.getByRole('button', { name: /new table/i }).click();
await expect(page.getByText(/create a new table/i)).toBeVisible();

View File

@@ -1,39 +1,18 @@
import { TEST_ORGANIZATION_SLUG, TEST_PROJECT_SUBDOMAIN } from '@/e2e/env';
import {
clickPermissionButton,
navigateToProject,
prepareTable,
} from '@/e2e/utils';
import { expect, test } from '@/e2e/fixtures/auth-hook';
import { clickPermissionButton, prepareTable } from '@/e2e/utils';
import { faker } from '@faker-js/faker';
import type { Page } from '@playwright/test';
import { expect, test } from '@playwright/test';
import { snakeCase } from 'snake-case';
let page: Page;
test.beforeAll(async ({ browser }) => {
page = await browser.newPage();
});
test.beforeEach(async () => {
await page.goto('/');
await navigateToProject({
page,
orgSlug: TEST_ORGANIZATION_SLUG,
projectSubdomain: TEST_PROJECT_SUBDOMAIN,
});
test.beforeEach(async ({ authenticatedNhostPage: page }) => {
const databaseRoute = `/orgs/${TEST_ORGANIZATION_SLUG}/projects/${TEST_PROJECT_SUBDOMAIN}/database/browser/default`;
await page.goto(databaseRoute);
await page.waitForURL(databaseRoute);
});
test.afterAll(async () => {
await page.close();
});
test('should create a table with role permissions to select row', async () => {
test('should create a table with role permissions to select row', async ({
authenticatedNhostPage: page,
}) => {
await page.getByRole('button', { name: /new table/i }).click();
await expect(page.getByText(/create a new table/i)).toBeVisible();
@@ -79,7 +58,9 @@ test('should create a table with role permissions to select row', async () => {
).toBeVisible();
});
test('should create a table with role permissions and a custom check to select rows', async () => {
test('should create a table with role permissions and a custom check to select rows', async ({
authenticatedNhostPage: page,
}) => {
await page.getByRole('button', { name: /new table/i }).click();
await expect(page.getByText(/create a new table/i)).toBeVisible();

View File

@@ -0,0 +1,22 @@
import { TEST_DASHBOARD_URL, TEST_PERSONAL_ORG_SLUG } from '@/e2e/env';
import { type Page, test as base } from '@playwright/test';
export const AUTH_CONTEXT = 'e2e/.auth/user.json';
export const test = base.extend<{ authenticatedNhostPage: Page }>({
authenticatedNhostPage: async ({ browser }, use) => {
const context = await browser.newContext({ storageState: AUTH_CONTEXT });
const page = await context.newPage();
await page.goto('/');
await page.waitForURL(
`${TEST_DASHBOARD_URL}/orgs/${TEST_PERSONAL_ORG_SLUG}/projects`,
{ waitUntil: 'networkidle' },
);
await use(page);
// update the context to get the new refresh token
await page.context().storageState({ path: AUTH_CONTEXT });
await page.close();
},
});
export { expect } from '@playwright/test';

View File

@@ -1,15 +1,8 @@
import { TEST_ORGANIZATION_SLUG, TEST_PROJECT_SUBDOMAIN } from '@/e2e/env';
import type { Page } from '@playwright/test';
import { expect, test } from '@playwright/test';
import { navigateToProject } from '../utils';
let page: Page;
test.beforeAll(async ({ browser }) => {
page = await browser.newPage();
await page.goto('/');
import { expect, test } from '@/e2e/fixtures/auth-hook';
import { navigateToProject } from '@/e2e/utils';
test.beforeEach(async ({ authenticatedNhostPage: page }) => {
await navigateToProject({
page,
orgSlug: TEST_ORGANIZATION_SLUG,
@@ -17,11 +10,9 @@ test.beforeAll(async ({ browser }) => {
});
});
test.afterAll(async () => {
await page.close();
});
test('should show the navtree with all links visible', async () => {
test('should show the navtree with all links visible', async ({
authenticatedNhostPage: page,
}) => {
const navLocator = page.getByLabel('Navigation Tree');
await expect(navLocator).toBeVisible();
@@ -42,16 +33,20 @@ test('should show the navtree with all links visible', async () => {
'Settings',
];
// eslint-disable-next-line no-restricted-syntax
for (const linkName of links) {
const link =
linkName === 'Settings'
? page.getByRole('link', { name: linkName }).first()
: page.getByRole('link', { name: linkName });
// eslint-disable-next-line no-await-in-loop
await expect(link).toBeVisible();
}
});
test("should show the project's region and subdomain", async () => {
test("should show the project's region and subdomain", async ({
authenticatedNhostPage: page,
}) => {
await expect(page.locator('p:has-text("Region") + div p').nth(0)).toHaveText(
/frankfurt \(eu-central-1\)/i,
);
@@ -60,7 +55,9 @@ test("should show the project's region and subdomain", async () => {
).toHaveText(/[a-z]{20}/i);
});
test('should not have a GitHub repository connected', async () => {
test('should not have a GitHub repository connected', async ({
authenticatedNhostPage: page,
}) => {
await expect(
page.getByRole('button', { name: /connect to github/i }).first(),
).toBeVisible();

View File

@@ -1,33 +1,15 @@
import { TEST_ORGANIZATION_SLUG, TEST_PROJECT_SUBDOMAIN } from '@/e2e/env';
import type { Page } from '@playwright/test';
import { expect, test } from '@playwright/test';
import { navigateToProject } from '../utils';
let page: Page;
test.beforeAll(async ({ browser }) => {
page = await browser.newPage();
});
test.beforeEach(async () => {
await page.goto('/');
await navigateToProject({
page,
orgSlug: TEST_ORGANIZATION_SLUG,
projectSubdomain: TEST_PROJECT_SUBDOMAIN,
});
import { expect, test } from '@/e2e/fixtures/auth-hook';
test.beforeEach(async ({ authenticatedNhostPage: page }) => {
const runRoute = `/orgs/${TEST_ORGANIZATION_SLUG}/projects/${TEST_PROJECT_SUBDOMAIN}/run`;
await page.goto(runRoute);
await page.waitForURL(runRoute);
});
test.afterAll(async () => {
await page.close();
});
test('should create and delete a run service', async () => {
test('should create and delete a run service', async ({
authenticatedNhostPage: page,
}) => {
await page.getByRole('button', { name: 'Add service' }).first().click();
await expect(page.getByText(/create a new service/i)).toBeVisible();
await page.getByPlaceholder(/service name/i).click();

View File

@@ -1,49 +1,23 @@
import {
TEST_DASHBOARD_URL,
TEST_ORGANIZATION_SLUG,
TEST_PROJECT_SUBDOMAIN,
} from '@/e2e/env';
import { navigateToProject } from '@/e2e/utils';
import { type Page, expect, test as teardown } from '@playwright/test';
let page: Page;
teardown.beforeAll(async ({ browser }) => {
const context = await browser.newContext({
baseURL: TEST_DASHBOARD_URL,
storageState: 'e2e/.auth/user.json',
});
page = await context.newPage();
});
teardown.beforeEach(async () => {
await page.goto('/');
await navigateToProject({
page,
orgSlug: TEST_ORGANIZATION_SLUG,
projectSubdomain: TEST_PROJECT_SUBDOMAIN,
});
import { TEST_ORGANIZATION_SLUG, TEST_PROJECT_SUBDOMAIN } from '@/e2e/env';
import { expect, test as teardown } from '@/e2e/fixtures/auth-hook';
teardown.beforeEach(async ({ authenticatedNhostPage: page }) => {
const databaseRoute = `/orgs/${TEST_ORGANIZATION_SLUG}/projects/${TEST_PROJECT_SUBDOMAIN}/database/browser/default`;
await page.goto(databaseRoute);
await page.waitForURL(databaseRoute);
});
teardown.afterAll(async () => {
await page.close();
});
teardown(
'clean up database tables',
async ({ authenticatedNhostPage: page }) => {
await page.getByRole('link', { name: /sql editor/i }).click();
teardown('clean up database tables', async () => {
await page.getByRole('link', { name: /sql editor/i }).click();
await page.waitForURL(
`/orgs/${TEST_ORGANIZATION_SLUG}/projects/${TEST_PROJECT_SUBDOMAIN}/database/browser/default/editor`,
);
await page.waitForURL(
`/orgs/${TEST_ORGANIZATION_SLUG}/projects/${TEST_PROJECT_SUBDOMAIN}/database/browser/default/editor`,
);
const inputField = page.locator('[contenteditable]');
await inputField.fill(`
const inputField = page.locator('[contenteditable]');
await inputField.fill(`
DO $$ DECLARE
tablename text;
BEGIN
@@ -56,6 +30,7 @@ teardown('clean up database tables', async () => {
END $$;
`);
await page.locator('button[type="button"]', { hasText: /run/i }).click();
await expect(page.getByText(/success/i)).toBeVisible();
});
await page.locator('button[type="button"]', { hasText: /run/i }).click();
await expect(page.getByText(/success/i)).toBeVisible();
},
);

View File

@@ -1,3 +1,4 @@
import { TEST_ORGANIZATION_SLUG, TEST_PROJECT_SUBDOMAIN } from '@/e2e/env';
import { faker } from '@faker-js/faker';
import type { Page } from '@playwright/test';
@@ -211,3 +212,9 @@ export async function clickPermissionButton({
.locator('button')
.click();
}
export async function gotoAuthURL(page) {
const authUrl = `/orgs/${TEST_ORGANIZATION_SLUG}/projects/${TEST_PROJECT_SUBDOMAIN}/users`;
await page.goto(authUrl);
await page.waitForURL(authUrl, { waitUntil: 'networkidle' });
}

View File

@@ -7,7 +7,7 @@ const { version } = require('./package.json');
const cspHeader = `
default-src 'self' *.nhost.run ws://*.nhost.run nhost.run ws://nhost.run;
script-src 'self' 'unsafe-eval' 'unsafe-inline' cdn.segment.com js.stripe.com;
connect-src 'self' *.nhost.run ws://*.nhost.run nhost.run ws://nhost.run discord.com api.segment.io api.segment.com cdn.segment.com;
connect-src 'self' *.nhost.run ws://*.nhost.run nhost.run ws://nhost.run discord.com api.segment.io api.segment.com cdn.segment.com nhost.zendesk.com;
style-src 'self' 'unsafe-inline';
img-src 'self' blob: data: avatars.githubusercontent.com s.gravatar.com *.nhost.run nhost.run;
font-src 'self' data:;
@@ -38,10 +38,10 @@ module.exports = withBundleAnalyzer({
{
source: '/(.*)',
headers: [
{
key: 'Content-Security-Policy',
value: cspHeader.replace(/\s+/g, ' ').trim(),
},
// {
// key: 'Content-Security-Policy',
// hgvalue: cspHeader.replace(/\s+/g, ' ').trim(),
// },
{
key: 'X-Frame-Options',
value: 'DENY',

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/dashboard",
"version": "2.22.0",
"version": "2.25.0",
"private": true,
"scripts": {
"preinstall": "npx only-allow pnpm",
@@ -87,7 +87,7 @@
"just-kebab-case": "^4.2.0",
"lodash.debounce": "^4.0.8",
"lucide-react": "^0.416.0",
"next": "^14.2.22",
"next": "^14.2.25",
"next-nprogress-bar": "^2.3.13",
"next-seo": "^6.5.0",
"next-themes": "^0.3.0",
@@ -96,7 +96,7 @@
"react": "18.2.0",
"react-children-utilities": "^2.10.0",
"react-complex-tree": "^2.4.5",
"react-day-picker": "8.10.1",
"react-day-picker": "9.6.3",
"react-dom": "18.2.0",
"react-error-boundary": "^4.0.13",
"react-hook-form": "^7.53.0",

View File

@@ -0,0 +1,178 @@
import { isTZDate } from '@/components/common/TimePicker/time-picker-utils';
import { render, screen, waitFor } from '@/tests/orgs/testUtils';
import userEvent from '@testing-library/user-event';
import { isBefore, startOfDay } from 'date-fns-v4';
import { useState } from 'react';
import { TZDate } from 'react-day-picker';
import { vi } from 'vitest';
import DateTimePicker, { type DateTimePickerProps } from './DateTimePicker';
vi.mock('@/utils/timezoneUtils', async () => {
const actualTimezoneUtils = await vi.importActual<any>(
'@/utils/timezoneUtils',
);
return {
...actualTimezoneUtils,
guessTimezone: () => 'Europe/Helsinki',
};
});
const earliestBackupDate = '2025-03-13T02:00:05.000Z';
function TestComponent(
props: Omit<DateTimePickerProps, 'dateTime' | 'onDateTimeChange'>,
) {
const [dateTime, setDateTime] = useState(earliestBackupDate);
function isCalendarDayDisabled(date: Date | TZDate) {
if (isTZDate(date)) {
const utcDay = new Date(date.getTime()).toISOString();
const tzDate = new TZDate(utcDay, date.timeZone);
const earliestBackupDateInTz = new TZDate(
earliestBackupDate,
date.timeZone,
);
return isBefore(startOfDay(tzDate), startOfDay(earliestBackupDateInTz));
}
return isBefore(
startOfDay(new Date(date.getTime()).toISOString()),
startOfDay(earliestBackupDate),
);
}
return (
<>
<h1 data-testid="utcDate">{dateTime}</h1>
<DateTimePicker
{...props}
isCalendarDayDisabled={isCalendarDayDisabled}
dateTime={dateTime}
onDateTimeChange={setDateTime}
/>
</>
);
}
describe('DateTimePicker', () => {
test('when the date changes datetime is emitted in utc string format', async () => {
render(<TestComponent />);
const user = userEvent.setup();
await user.click(await screen.findByTestId('dateTimePickerTrigger'));
expect(
await screen.findByRole('button', { name: 'Select' }),
).toBeInTheDocument();
expect(await screen.getByText('March 2025')).toBeInTheDocument();
await user.click(
screen.getByRole('button', { name: 'Go to the Next Month' }),
);
expect(screen.getByText('April 2025')).toBeInTheDocument();
await user.click(await screen.getByText('13'));
const hoursInput = await screen.getByLabelText('Hours');
await user.type(hoursInput, '11');
const minutesInput = await screen.getByLabelText('Minutes');
await user.type(minutesInput, '12');
const secondsInput = await screen.getByLabelText('Seconds');
await user.type(secondsInput, '13');
user.click(await screen.getByRole('button', { name: 'Select' }));
await waitFor(async () =>
expect(
await screen.queryByRole('button', { name: 'Select' }),
).not.toBeInTheDocument(),
);
expect(screen.getByTestId('utcDate')).toHaveTextContent(
'2025-04-13T08:12:13.000Z',
);
});
test('timezone can be changed and the calendar is updated', async () => {
await waitFor(() => render(<TestComponent withTimezone />));
const user = userEvent.setup();
await user.click(await screen.findByTestId('dateTimePickerTrigger'));
expect(await screen.findByText(/Timezone:/)).toBeInTheDocument();
expect(
await screen.findByTestId('timezoneSettingsButton'),
).toBeInTheDocument();
expect(await screen.findByText(/Timezone: /i)).toHaveTextContent(
'Timezone: UTC+02:00',
);
expect(await screen.getByText('12')).toBeDisabled();
await user.click(await screen.findByTestId('timezoneSettingsButton'));
const tzInput = await screen.findByPlaceholderText('Search timezones...');
expect(tzInput).toBeInTheDocument();
await user.type(tzInput, 'America/Chicago{ArrowDown}{Enter}');
expect(
await screen.queryByPlaceholderText('Search timezones...'),
).not.toBeInTheDocument();
expect(await screen.findByText(/Timezone: /i)).toHaveTextContent(
'Timezone: UTC-05:00',
);
const selectedDay = screen.getByText('12');
expect(selectedDay).not.toBeDisabled();
expect(await screen.getByText('11')).toBeDisabled();
const gridCell = selectedDay.closest('[role="gridcell"]');
expect(gridCell).toHaveClass('[&>button]:bg-primary');
});
test('Displays the correct time zone offset when changing the selected date from standard time (ST) to daylight saving time (DST)', async () => {
await waitFor(() => render(<TestComponent withTimezone />));
const user = userEvent.setup();
await user.click(await screen.findByTestId('dateTimePickerTrigger'));
expect(await screen.findByText(/Timezone:/)).toBeInTheDocument();
expect(
await screen.findByTestId('timezoneSettingsButton'),
).toBeInTheDocument();
expect(await screen.findByText(/Timezone: /i)).toHaveTextContent(
'Timezone: UTC+02:00',
);
expect(await screen.getByText('March 2025')).toBeInTheDocument();
await user.click(
screen.getByRole('button', { name: 'Go to the Next Month' }),
);
expect(screen.getByText('April 2025')).toBeInTheDocument();
await user.click(await screen.getByText('18'));
expect(await screen.findByText(/Timezone: /i)).toHaveTextContent(
'Timezone: UTC+03:00',
);
await user.click(
screen.getByRole('button', { name: 'Go to the Previous Month' }),
);
expect(await screen.getByText('March 2025')).toBeInTheDocument();
await user.click(await screen.getByText('21'));
expect(await screen.findByText(/Timezone: /i)).toHaveTextContent(
'Timezone: UTC+02:00',
);
});
});

View File

@@ -27,8 +27,6 @@ export interface DateTimePickerProps {
align?: 'start' | 'center' | 'end';
validateDateFn?: (date: Date) => string;
}
// in: UTC datetime
// out: UTC dateTime
function DateTimePicker({
dateTime,
@@ -49,6 +47,10 @@ function DateTimePicker({
});
const [open, setOpen] = useState(false);
const [timezone, setTimezone] = useState(
() => defaultTimezone || guessTimezone(),
);
function emitNewDateTime() {
onDateTimeChange(new Date(date.getTime()).toISOString());
}
@@ -73,6 +75,7 @@ function DateTimePicker({
function handleTimezoneChange(newTimezone: string) {
const newDateWithTimezone = new TZDate(date.toISOString(), newTimezone);
setTimezone(newTimezone);
setDate(newDateWithTimezone);
}
@@ -80,6 +83,7 @@ function DateTimePicker({
if (!newOpenState) {
if (withTimezone) {
const tz = defaultTimezone || guessTimezone();
setTimezone(tz);
setDate(new TZDate(dateTime, tz));
}
setDate(parseISO(dateTime));
@@ -92,6 +96,8 @@ function DateTimePicker({
setOpen(false);
}
const selectedDateInUTC = new Date(date.getTime()).toISOString();
const dateString = formatDateFn?.(date) || format(date, 'PPP HH:mm:ss');
const errorText = validateDateFn?.(date);
@@ -101,6 +107,7 @@ function DateTimePicker({
<Popover open={open} onOpenChange={handleOpenChange}>
<PopoverTrigger asChild>
<Button
data-testid="dateTimePickerTrigger"
variant="outline"
className={cn(
'w-full justify-between text-left font-normal',
@@ -113,6 +120,7 @@ function DateTimePicker({
<CalendarIcon className="h-4 w-4" />
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto p-0" align={align}>
<div className="flex">
<div className="flex">
@@ -120,8 +128,8 @@ function DateTimePicker({
mode="single"
selected={date}
onSelect={(d) => handleSelect(d)}
initialFocus
disabled={isCalendarDayDisabled}
timeZone={timezone}
/>
<div className="flex flex-col justify-between">
<div>
@@ -131,7 +139,7 @@ function DateTimePicker({
{withTimezone && (
<div className="border-t border-border p-3">
<TimezoneSettings
dateTime={dateTime}
dateTime={selectedDateInUTC}
onTimezoneChange={handleTimezoneChange}
/>
</div>

View File

@@ -18,16 +18,23 @@ function TimezoneSettings({ dateTime, onTimezoneChange }: Props) {
setTimezone(tz.value);
onTimezoneChange?.(tz.value);
}
const utcOffset = getUTCOffsetInHours(selectedTimezone, dateTime, 'OOOO');
return (
<div className="flex w-full items-center justify-between">
Timezone: {utcOffset}{' '}
<span>Timezone: {utcOffset}</span>
<TimezonePicker
dateTime={dateTime}
selectedTimezone={selectedTimezone}
onTimezoneSelect={handleTimezoneSelect}
button={
<Button variant="ghost" size="icon">
<Button
variant="ghost"
size="icon"
aria-label="Open timezone settings"
data-testid="timezoneSettingsButton"
>
<Settings2 className="h-4 w-4 dark:text-foreground" />
</Button>
}

View File

@@ -229,7 +229,7 @@ export function getArrowByType(
}
}
function isTZDate(date: Date | TZDate): date is TZDate {
export function isTZDate(date: Date | TZDate): date is TZDate {
return date instanceof TZDate;
}

View File

@@ -9,6 +9,26 @@ interface Props {
dateTime: string;
}
function getOrderedTimezones(dateTime: string, selectedTimezone: string) {
const [utcTimezone, browserTimezone, ...timezones] =
createTimezoneOptions(dateTime);
let orderedTimezones = [...timezones];
if (
selectedTimezone !== browserTimezone.value &&
selectedTimezone !== 'UTC'
) {
const selectedTimezoneOption = timezones.find(
(tz) => tz.value === selectedTimezone,
);
orderedTimezones = [
selectedTimezoneOption,
...timezones.filter((tz) => tz.value !== selectedTimezone),
];
}
return [utcTimezone, browserTimezone, ...orderedTimezones];
}
function TimezonePicker({
selectedTimezone,
onTimezoneSelect,
@@ -16,9 +36,10 @@ function TimezonePicker({
dateTime,
}: Props) {
const timezoneOptions = useMemo(
() => createTimezoneOptions(dateTime),
[dateTime],
() => getOrderedTimezones(dateTime, selectedTimezone),
[dateTime, selectedTimezone],
);
return (
<VirtualizedCombobox
options={timezoneOptions}
@@ -27,6 +48,7 @@ function TimezonePicker({
searchPlaceholder="Search timezones..."
button={button}
side="right"
width="370px"
/>
);
}

View File

@@ -105,20 +105,12 @@ function VirtualizedCommand<O extends Option>({
}
};
React.useEffect(() => {
if (selectedOption) {
const option = filteredOptions.find(
(opt) => opt.value === selectedOption,
);
if (option) {
const index = filteredOptions.indexOf(option);
setFocusedIndex(index);
}
}
}, [selectedOption, filteredOptions, virtualizer]);
return (
<Command shouldFilter={false} onKeyDown={handleKeyDown}>
<Command
shouldFilter={false}
onKeyDown={handleKeyDown}
value={selectedOption}
>
<CommandInput onValueChange={handleSearch} placeholder={placeholder} />
<CommandList
ref={parentRef}
@@ -145,7 +137,6 @@ function VirtualizedCommand<O extends Option>({
filteredOptions[virtualOption.index].key ??
filteredOptions[virtualOption.index].value
}
disabled={isKeyboardNavActive}
className={cn(
'absolute left-0 top-0 w-full bg-transparent',
focusedIndex === virtualOption.index &&

View File

@@ -1,75 +1,174 @@
'use client';
/* eslint-disable react/no-unstable-nested-components */
import { ChevronLeft, ChevronRight } from 'lucide-react';
import {
DayPicker,
type DayPickerProps,
type StyledComponent,
} from 'react-day-picker';
'use client';
import { buttonVariants } from '@/components/ui/v3/button';
import { cn } from '@/lib/utils';
import { ChevronLeft, ChevronRight } from 'lucide-react';
import { DayPicker, type DayPickerProps } from 'react-day-picker';
const IconLeft = ({ className, ...props }: StyledComponent) => (
<ChevronLeft className={cn('h-4 w-4', className)} {...props} />
);
const IconRight = ({ className, ...props }: StyledComponent) => (
<ChevronRight className={cn('h-4 w-4', className)} {...props} />
);
export type CalendarProps = DayPickerProps & {
/**
* In the year view, the number of years to display at once.
* @default 12
*/
yearRange?: number;
/**
* Wether to show the year switcher in the caption.
* @default true
*/
showYearSwitcher?: boolean;
monthsClassName?: string;
monthCaptionClassName?: string;
weekdaysClassName?: string;
weekdayClassName?: string;
monthClassName?: string;
captionClassName?: string;
captionLabelClassName?: string;
buttonNextClassName?: string;
buttonPreviousClassName?: string;
navClassName?: string;
monthGridClassName?: string;
weekClassName?: string;
dayClassName?: string;
dayButtonClassName?: string;
rangeStartClassName?: string;
rangeEndClassName?: string;
selectedClassName?: string;
todayClassName?: string;
outsideClassName?: string;
disabledClassName?: string;
rangeMiddleClassName?: string;
hiddenClassName?: string;
};
/**
* A custom calendar component built on top of react-day-picker.
* @param props The props for the calendar.
* @default yearRange 12
* @returns
*/
function Calendar({
className,
classNames,
showOutsideDays = true,
numberOfMonths,
...props
}: DayPickerProps) {
}: CalendarProps) {
const monthsClassName = cn('relative flex', props.monthsClassName);
const monthCaptionClassName = cn(
'relative mx-10 flex h-7 items-center justify-center',
props.monthCaptionClassName,
);
const weekdaysClassName = cn('flex flex-row', props.weekdaysClassName);
const weekdayClassName = cn(
'w-8 text-sm font-normal text-muted-foreground',
props.weekdayClassName,
);
const monthClassName = cn('w-full', props.monthClassName);
const captionClassName = cn(
'relative flex items-center justify-center pt-1',
props.captionClassName,
);
const captionLabelClassName = cn(
'truncate text-sm font-medium',
props.captionLabelClassName,
);
const buttonNavClassName = buttonVariants({
variant: 'outline',
className:
'absolute h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100',
});
const buttonNextClassName = cn(
buttonNavClassName,
'right-0',
props.buttonNextClassName,
);
const buttonPreviousClassName = cn(
buttonNavClassName,
'left-0',
props.buttonPreviousClassName,
);
const navClassName = cn('flex items-start', props.navClassName);
const monthGridClassName = cn('mx-auto mt-4', props.monthGridClassName);
const weekClassName = cn('mt-2 flex w-max items-start', props.weekClassName);
const dayClassName = cn(
'flex size-8 flex-1 items-center justify-center p-0 text-sm',
props.dayClassName,
);
const dayButtonClassName = cn(
buttonVariants({ variant: 'ghost' }),
'size-8 rounded-md p-0 font-normal transition-none aria-selected:opacity-100',
props.dayButtonClassName,
);
const buttonRangeClassName =
'bg-accent [&>button]:bg-primary [&>button]:text-primary-foreground [&>button]:hover:bg-primary [&>button]:hover:text-primary-foreground';
const rangeStartClassName = cn(
buttonRangeClassName,
'day-range-start rounded-s-md',
props.rangeStartClassName,
);
const rangeEndClassName = cn(
buttonRangeClassName,
'day-range-end rounded-e-md',
props.rangeEndClassName,
);
const rangeMiddleClassName = cn(
'bg-accent !text-foreground [&>button]:bg-transparent [&>button]:!text-foreground [&>button]:hover:bg-transparent [&>button]:hover:!text-foreground',
props.rangeMiddleClassName,
);
const selectedClassName = cn(
'[&>button]:bg-primary [&>button]:text-primary-foreground [&>button]:hover:bg-primary [&>button]:hover:text-primary-foreground',
props.selectedClassName,
);
const todayClassName = cn(
'[&>button]:bg-accent [&>button]:text-accent-foreground',
props.todayClassName,
);
const outsideClassName = cn(
'day-outside text-muted-foreground opacity-50 aria-selected:bg-accent/50 aria-selected:text-muted-foreground aria-selected:opacity-30',
props.outsideClassName,
);
const disabledClassName = cn(
'text-muted-foreground opacity-50',
props.disabledClassName,
);
const hiddenClassName = cn('invisible flex-1', props.hiddenClassName);
return (
<DayPicker
showOutsideDays={showOutsideDays}
className={cn('p-3', className)}
classNames={{
months: 'flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0',
month: 'space-y-4',
caption: 'flex justify-center pt-1 relative items-center',
caption_label: 'text-sm font-medium',
nav: 'space-x-1 flex items-center',
nav_button: cn(
buttonVariants({ variant: 'outline' }),
'h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100',
),
nav_button_previous: 'absolute left-1',
nav_button_next: 'absolute right-1',
table: 'w-full border-collapse space-y-1',
head_row: 'flex',
head_cell:
'text-muted-foreground rounded-md w-8 font-normal text-[0.8rem]',
row: 'flex w-full mt-2',
cell: cn(
'relative p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([aria-selected])]:bg-accent [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected].day-range-end)]:rounded-r-md',
props.mode === 'range'
? '[&:has(>.day-range-end)]:rounded-r-md [&:has(>.day-range-start)]:rounded-l-md first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md'
: '[&:has([aria-selected])]:rounded-md',
),
day: cn(
buttonVariants({ variant: 'ghost' }),
'h-8 w-8 p-0 font-normal aria-selected:opacity-100',
),
day_range_start: 'day-range-start',
day_range_end: 'day-range-end',
day_selected:
'bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground',
day_today: 'bg-accent text-accent-foreground',
day_outside:
'day-outside text-muted-foreground aria-selected:bg-accent/50 aria-selected:text-muted-foreground',
day_disabled: 'text-muted-foreground opacity-50',
day_range_middle:
'aria-selected:bg-accent aria-selected:text-accent-foreground',
day_hidden: 'invisible',
...classNames,
months: monthsClassName,
month_caption: monthCaptionClassName,
weekdays: weekdaysClassName,
weekday: weekdayClassName,
month: monthClassName,
caption: captionClassName,
caption_label: captionLabelClassName,
button_next: buttonNextClassName,
button_previous: buttonPreviousClassName,
nav: navClassName,
month_grid: monthGridClassName,
week: weekClassName,
day: dayClassName,
day_button: dayButtonClassName,
range_start: rangeStartClassName,
range_middle: rangeMiddleClassName,
range_end: rangeEndClassName,
selected: selectedClassName,
today: todayClassName,
outside: outsideClassName,
disabled: disabledClassName,
hidden: hiddenClassName,
}}
components={{
IconLeft,
IconRight,
Chevron: ({ orientation }) => {
const Icon = orientation === 'left' ? ChevronLeft : ChevronRight;
return <Icon className="h-4 w-4" />;
},
}}
{...props}
/>

View File

@@ -35,16 +35,23 @@ const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
);
};
interface CommandInputProps {
prefix?: React.ReactNode;
prefixClassName?: string;
}
const CommandInput = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Input>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input> & {
prefix?: React.ReactNode;
}
>(({ className, prefix, ...props }, ref) => (
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input> &
CommandInputProps
>(({ className, prefix, prefixClassName, ...props }, ref) => (
<div className="flex items-center border-b px-3" cmdk-input-wrapper="">
<Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
{prefix && (
<span className="pointer-events-none flex items-center text-muted-foreground">
<span
title={prefix}
className={cn('text-muted-foreground', prefixClassName)}
>
{prefix}
</span>
)}

View File

@@ -5,24 +5,33 @@ import { type PropsWithChildren, type ReactNode } from 'react';
interface Props {
title?: string;
icon?: ReactNode;
borderLess?: boolean;
}
function InfoAlert({ children, title, icon }: PropsWithChildren<Props>) {
function InfoAlert({
children,
title,
icon,
borderLess = false,
}: PropsWithChildren<Props>) {
const alertClassNames = cn('bg-[#ebf3ff] dark:bg-muted', {
'flex gap-2 items-center': !!icon,
'border-none': borderLess,
});
const descClassNames = cn('text-[0.9375rem] leading-[22px]', {
'text-[0.875rem] leading-[1rem]': !!icon,
const descClassNames = cn('text-[0.9375rem] leading-6', {
'text-[0.875rem] leading-6': !!icon,
});
return (
<Alert className={alertClassNames}>
{icon && <div>{icon}</div>}
<div>
{title && <AlertTitle>{title}</AlertTitle>}
<AlertDescription className={descClassNames}>
{children}
</AlertDescription>
{children && (
<AlertDescription className={descClassNames}>
{children}
</AlertDescription>
)}
</div>
</Alert>
);

View File

@@ -57,6 +57,7 @@ const getUseRouterObject = (session_id?: string) => ({
},
isFallback: false,
});
const mocks = vi.hoisted(() => ({
useRouter: vi.fn(),
useOrgs: vi.fn(),

View File

@@ -27,8 +27,10 @@ function ProjectCard({ project }: { project: Project }) {
>
<div className="flex flex-row items-start gap-2">
<Box className="mt-[2px] h-5 w-5 flex-shrink-0" />
<div className="flex w-full flex-col">
<p className="truncate font-bold">{project.name}</p>
<div className="flex w-full flex-col overflow-hidden">
<p title={project.name} className="truncate font-bold">
{project.name}
</p>
<span className="text-xs text-muted-foreground">
{project.region.name}
</span>

View File

@@ -0,0 +1,73 @@
import { TabsContent } from '@/components/ui/v3/tabs';
import { useIsPiTREnabled } from '@/features/orgs/hooks/useIsPiTREnabled';
import {
getPiTRNotEnabledPostgresSettings,
getPostgresSettings,
} from '@/tests/msw/mocks/graphql/getPostgresSettings';
import { getProjectQuery } from '@/tests/msw/mocks/graphql/getProjectQuery';
import tokenQuery from '@/tests/msw/mocks/rest/tokenQuery';
import { render, screen } from '@/tests/orgs/testUtils';
import { setupServer } from 'msw/node';
import { vi } from 'vitest';
import BackupsContent from './BackupsContent';
function TestComponent() {
const { isPiTREnabled, loading } = useIsPiTREnabled();
if (loading) {
return <h1>Loading...</h1>;
}
return <BackupsContent isPiTREnabled={isPiTREnabled} />;
}
vi.mock(
'@/features/orgs/projects/backups/components/ScheduledBackupTabContent',
() => ({
ScheduledBackupTabContent: () => (
<TabsContent value="scheduledBackups">
<h1>Scheduled backups is loaded</h1>
</TabsContent>
),
}),
);
vi.mock(
'@/features/orgs/projects/backups/components/PointInTimeTabsContent',
() => ({
PointInTimeTabsContent: () => (
<TabsContent value="pointInTime">
<h1>PiTR tab is loaded</h1>
</TabsContent>
),
}),
);
const server = setupServer(tokenQuery);
describe('BackupsContent', () => {
beforeAll(() => {
process.env.NEXT_PUBLIC_NHOST_PLATFORM = 'true';
process.env.NEXT_PUBLIC_ENV = 'production';
server.listen();
});
afterAll(() => {
server.close();
vi.restoreAllMocks();
});
test('that Scheduled backups tab is loaded when PiTR is not enabled', async () => {
server.use(getPiTRNotEnabledPostgresSettings);
server.use(getProjectQuery);
render(<TestComponent />);
expect(
await screen.findByText('Scheduled backups is loaded'),
).toBeInTheDocument();
});
test('that Point-in-Time tab is loaded when PiTR is enabled', async () => {
server.use(getPostgresSettings);
server.use(getProjectQuery);
render(<TestComponent />);
expect(await screen.findByText('PiTR tab is loaded')).toBeInTheDocument();
});
});

View File

@@ -8,11 +8,12 @@ function BackupsContent({ isPiTREnabled }: { isPiTREnabled: boolean }) {
const [tab, setTab] = useState(() =>
isPiTREnabled ? 'pointInTime' : 'scheduledBackups',
);
return (
<Tabs value={tab} onValueChange={setTab}>
<TabsList>
<TabsTrigger value="scheduledBackups">Scheduled backups</TabsTrigger>
<TabsTrigger value="pointInTime">Point-in-time</TabsTrigger>
<TabsTrigger value="pointInTime">Point-in-Time</TabsTrigger>
<TabsTrigger value="importBackup">Import backup</TabsTrigger>
</TabsList>
<div className="pt-7">

View File

@@ -0,0 +1,268 @@
import {
fetchPiTRBaseBackups,
mockApplication,
mockMatchMediaValue,
} from '@/tests/mocks';
import tokenQuery from '@/tests/msw/mocks/rest/tokenQuery';
import {
mockPointerEvent,
render,
screen,
waitFor,
} from '@/tests/orgs/testUtils';
import { setupServer } from 'msw/node';
import { vi } from 'vitest';
import { Tabs } from '@/components/ui/v3/tabs';
import { getOrganization } from '@/tests/msw/mocks/graphql/getOrganizationQuery';
import {
getPiTRNotEnabledPostgresSettings,
getPostgresSettings,
} from '@/tests/msw/mocks/graphql/getPostgresSettings';
import {
getEmptyProjectsQuery,
getProjectsQuery,
} from '@/tests/msw/mocks/graphql/getProjectsQuery';
import userEvent from '@testing-library/user-event';
import ImportBackupContent from './ImportBackupTabContent';
function TestComponent() {
return (
<Tabs value="importBackup">
<ImportBackupContent />
</Tabs>
);
}
mockPointerEvent();
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: vi.fn().mockImplementation(mockMatchMediaValue),
});
const server = setupServer(tokenQuery);
const mocks = vi.hoisted(() => ({
useGetPiTrBaseBackupsLazyQuery: vi.fn(),
fetchPiTRBaseBackups: vi.fn(),
restoreApplicationDatabase: vi.fn(),
}));
vi.mock('@/utils/__generated__/graphql', async () => {
const actual = await vi.importActual<any>('@/utils/__generated__/graphql');
return {
...actual,
useGetPiTrBaseBackupsLazyQuery: mocks.useGetPiTrBaseBackupsLazyQuery,
};
});
vi.mock('@/utils/timezoneUtils', async () => {
const actualTimezoneUtils = await vi.importActual<any>(
'@/utils/timezoneUtils',
);
return {
...actualTimezoneUtils,
guessTimezone: () => 'Europe/Helsinki',
};
});
vi.mock('@/features/orgs/hooks/useRestoreApplicationDatabasePiTR', () => ({
useRestoreApplicationDatabasePiTR: () => ({
restoreApplicationDatabase: mocks.restoreApplicationDatabase,
loading: false,
}),
}));
vi.mock('@/features/orgs/projects/hooks/useProject', async () => ({
useProject: () => ({ project: mockApplication }),
}));
describe('ImportBackupContent', () => {
beforeAll(() => {
process.env.NEXT_PUBLIC_NHOST_PLATFORM = 'true';
process.env.NEXT_PUBLIC_ENV = 'production';
server.listen();
});
afterAll(() => {
server.close();
vi.restoreAllMocks();
});
test("will display the target project's name and a select with the projects from the same region", async () => {
server.use(getOrganization);
server.use(getProjectsQuery);
const user = userEvent.setup();
render(<TestComponent />);
expect(
await screen.getByText(
`${mockApplication.name} (${mockApplication.region.name})`,
),
).toBeInTheDocument();
const projectComboBox = await screen.findByRole('combobox');
await user.click(projectComboBox);
// check for only projects from the same region are listed
expect(screen.getByRole('option', { name: /pitr14/i })).toBeInTheDocument();
expect(
screen.getByRole('option', { name: /pitr-not-enabled/i }),
).toBeInTheDocument();
expect(
screen.getByRole('option', { name: /pitr-test/i }),
).toBeInTheDocument();
expect(
screen.queryByRole('option', { name: /pitr-region-test-eu/i }),
).not.toBeInTheDocument();
});
test('that warning is displayed if there are no other projects in the same organization', async () => {
server.use(getOrganization);
server.use(getEmptyProjectsQuery);
render(<TestComponent />);
expect(
await screen.findByText(
/There are no other projects within the region:/i,
),
).toBeInTheDocument();
});
test('will schedule an import from the selected project', async () => {
server.use(getOrganization);
server.use(getProjectsQuery);
server.use(getPostgresSettings);
mocks.useGetPiTrBaseBackupsLazyQuery.mockImplementation(() => [
fetchPiTRBaseBackups,
{ loading: false },
]);
const user = userEvent.setup();
render(<TestComponent />);
expect(
await screen.getByText(
`${mockApplication.name} (${mockApplication.region.name})`,
),
).toBeInTheDocument();
const projectComboBox = await screen.findByRole('combobox');
await user.click(projectComboBox);
await user.click(
screen.getByRole('option', {
name: 'pitr14 (us-east-1)',
}),
);
expect(
await screen.getByText('Import backup from pitr14 (us-east-1)'),
).toBeInTheDocument();
const startImportButton = await screen.getByRole('button', {
name: 'Start import',
});
await user.click(startImportButton);
await waitFor(async () =>
expect(
await screen.getByRole('button', { name: 'Import backup' }),
).toBeInTheDocument(),
);
const dateTimePickerButton = await screen.getByRole('button', {
name: /UTC/i,
});
await user.click(dateTimePickerButton);
await waitFor(async () =>
expect(
await screen.getByRole('button', { name: 'Select' }),
).toBeInTheDocument(),
);
await user.click(await screen.getByText('13'));
const hoursInput = await screen.getByLabelText('Hours');
await user.type(hoursInput, '18');
const updatedDateTimeButton = await screen.getByRole('button', {
name: /UTC/i,
});
expect(updatedDateTimeButton).toHaveTextContent(
'13 Mar 2025, 18:00:05 (UTC+02:00)',
);
await user.click(await screen.getByRole('button', { name: 'Select' }));
await waitFor(async () =>
expect(
await screen.queryByRole('button', { name: 'Select' }),
).not.toBeInTheDocument(),
);
expect(updatedDateTimeButton).toHaveTextContent(
'13 Mar 2025, 18:00:05 (UTC+02:00)',
);
// check checkboxes
await user.click(
await screen.getByLabelText(/I understand that restoring this backup/),
);
await user.click(
await screen.getByLabelText(/I understand this cannot be undone/),
);
await waitFor(async () =>
expect(
await screen.getByRole('button', { name: 'Import backup' }),
).not.toBeDisabled(),
);
await user.click(
await screen.getByRole('button', { name: 'Import backup' }),
);
expect(mocks.restoreApplicationDatabase.mock.calls[0][0].fromAppId).toBe(
'pitr14-id',
);
expect(
mocks.restoreApplicationDatabase.mock.calls[0][0].recoveryTarget,
).toBe('2025-03-13T16:00:05.000Z');
});
// TODO
test('Pitr is not enabled on project', async () => {
server.use(getOrganization);
server.use(getProjectsQuery);
server.use(getPiTRNotEnabledPostgresSettings);
const user = userEvent.setup();
render(<TestComponent />);
const projectComboBox = await screen.findByRole('combobox');
await user.click(projectComboBox);
await user.click(
screen.getByRole('option', {
name: 'pitr-not-enabled-usa (us-east-1)',
}),
);
expect(
screen.getByText(
'Point-in-Time Recovery is not enabled on the selected project',
),
).toBeInTheDocument();
});
});

View File

@@ -4,7 +4,7 @@ import { DatabaseZap } from 'lucide-react';
function PiTRNotEnabledOnSourceProject() {
return (
<InfoAlert
title="Point-in-Time recovery is not enabled on the selected project"
title="Point-in-Time Recovery is not enabled on the selected project"
icon={<DatabaseZap className="h-[38px] w-[38px]" />}
>
Importing from scheduled backups is not supported yet. Coming soon!

View File

@@ -1,13 +1,15 @@
import { PointInTimeBackupInfo } from '@/features/orgs/projects/backups/components/common/PointInTimeBackupInfo';
import { useProject } from '@/features/orgs/projects/hooks/useProject';
import RecoveryRetentionPeriod from './RecoveryRetentionPeriod';
import RestoreRecommendationNote from './RestoreRecommendationNote';
function PointInTimeRecovery() {
const { project } = useProject();
return (
<div className="flex flex-col gap-[1.875rem]">
<RecoveryRetentionPeriod />
<PointInTimeBackupInfo appId={project?.id} />
<RestoreRecommendationNote />
<PointInTimeBackupInfo appId={project?.id} showLink />
</div>
);
}

View File

@@ -0,0 +1,57 @@
import { Tabs } from '@/components/ui/v3/tabs';
import { getOrganization } from '@/tests/msw/mocks/graphql/getOrganizationQuery';
import {
getPiTRNotEnabledPostgresSettings,
getPostgresSettings,
} from '@/tests/msw/mocks/graphql/getPostgresSettings';
import { getProjectQuery } from '@/tests/msw/mocks/graphql/getProjectQuery';
import tokenQuery from '@/tests/msw/mocks/rest/tokenQuery';
import { render, screen } from '@/tests/orgs/testUtils';
import { setupServer } from 'msw/node';
import { vi } from 'vitest';
import PointInTimeTabsContent from './PointInTimeTabsContent';
function TestComponent() {
return (
<Tabs value="pointInTime">
<PointInTimeTabsContent />
</Tabs>
);
}
vi.mock('./PointInTimeRecovery', () => ({
default: () => <h1>PiTR enabled</h1>,
}));
const server = setupServer(tokenQuery);
describe('PointInTimeTabsContent', () => {
beforeAll(() => {
process.env.NEXT_PUBLIC_NHOST_PLATFORM = 'true';
process.env.NEXT_PUBLIC_ENV = 'production';
server.listen();
});
afterAll(() => {
server.close();
vi.restoreAllMocks();
});
test('if Point-in-Time Recovery is enabled', async () => {
server.use(getPostgresSettings);
server.use(getProjectQuery);
render(<TestComponent />);
expect(await screen.findByText('PiTR enabled')).toBeInTheDocument();
});
test('if Point-in-sTime Recovery is not enabled', async () => {
server.use(getOrganization);
server.use(getProjectQuery);
server.use(getPiTRNotEnabledPostgresSettings);
render(<TestComponent />);
expect(
await screen.findByText(/To enable Point-in-Time recovery/i),
).toBeInTheDocument();
});
});

View File

@@ -0,0 +1,15 @@
import { InfoAlert } from '@/features/orgs/components/InfoAlert';
import { ShieldAlertIcon } from 'lucide-react';
function RestoreRecommendationNote() {
return (
<InfoAlert icon={<ShieldAlertIcon className="h-[38px] w-[38px]" />}>
<p className="!leading-[1.5]">
We recommend importing the backup to a different project first to ensure
everything works as expected before applying it to this project.
</p>
</InfoAlert>
);
}
export default RestoreRecommendationNote;

View File

@@ -3,8 +3,9 @@ import { InfoAlert } from '@/features/orgs/components/InfoAlert';
function PiTREnabledInfoBanner() {
return (
<InfoAlert>
With PiTR enabled, Scheduled backups are no longer taken. PiTR provides
more precise recovery, making additional backups unnecessary.
With Point-in-Time Recovery enabled, Scheduled backups are no longer
taken. Point-in-Time Recovery provides more precise recovery, making
additional backups unnecessary.
</InfoAlert>
);
}

View File

@@ -0,0 +1,57 @@
import { Tabs } from '@/components/ui/v3/tabs';
import {
getPiTRNotEnabledPostgresSettings,
getPostgresSettings,
} from '@/tests/msw/mocks/graphql/getPostgresSettings';
import { getProjectQuery } from '@/tests/msw/mocks/graphql/getProjectQuery';
import tokenQuery from '@/tests/msw/mocks/rest/tokenQuery';
import { render, screen } from '@/tests/orgs/testUtils';
import { setupServer } from 'msw/node';
import { vi } from 'vitest';
import ScheduledBackupTabContent from './ScheduledBackupTabContent';
function TestComponent() {
return (
<Tabs value="scheduledBackups">
<ScheduledBackupTabContent />
</Tabs>
);
}
vi.mock('./BackupList', () => ({
default: () => <h1>Backup list</h1>,
}));
const server = setupServer(tokenQuery);
describe('ScheduledBackupTabContent', () => {
beforeAll(() => {
process.env.NEXT_PUBLIC_NHOST_PLATFORM = 'true';
process.env.NEXT_PUBLIC_ENV = 'production';
server.listen();
});
afterAll(() => {
server.close();
vi.restoreAllMocks();
});
test('that Scheduled backups is loaded if PiTR is not enabled', async () => {
server.use(getPiTRNotEnabledPostgresSettings);
server.use(getProjectQuery);
render(<TestComponent />);
expect(
await screen.findByText(/The database backup includes database schema/i),
).toBeInTheDocument();
});
test('that a warning message is displayed if Point-in-Time Recovery is enabled ', async () => {
server.use(getProjectQuery);
server.use(getPostgresSettings);
render(<TestComponent />);
expect(
await screen.findByText(/With Point-in-Time Recovery enabled/i),
).toBeInTheDocument();
});
});

View File

@@ -1,22 +1,8 @@
import { Button } from '@/components/ui/v3/button';
import { DialogFooter } from '@/components/ui/v3/dialog';
import Link from 'next/link';
import type { PropsWithChildren } from 'react';
import TextLink from '@/features/orgs/projects/common/components/TextLink/TextLink';
import { memo } from 'react';
function LogsLink({ href, children }: PropsWithChildren<{ href: string }>) {
return (
<Link
href={href}
className="text-[0.9375rem] leading-[1.375rem] text-[#0052cd] hover:underline dark:text-[#3888ff]"
target="_blank"
rel="noopener noreferrer"
>
{children}
</Link>
);
}
interface Props {
onClose: () => void;
orgSlug: string;
@@ -29,10 +15,10 @@ function BackupScheduledInfo({ onClose, orgSlug, subdomain }: Props) {
<p>Your backup has been scheduled successfully and will start shortly.</p>
<p>
To follow its process go to the{' '}
<LogsLink href={`/orgs/${orgSlug}/projects/${subdomain}/logs`}>
<TextLink href={`/orgs/${orgSlug}/projects/${subdomain}/logs`}>
Logs page
</LogsLink>{' '}
and select the service &quot;Backup Job&quot; to see the restore logs.
</TextLink>{' '}
and select the service &quot;Backup Jobs&quot; to see the restore logs.
</p>
<DialogFooter>
<Button type="button" onClick={onClose}>

View File

@@ -8,7 +8,7 @@ import tokenQuery from '@/tests/msw/mocks/rest/tokenQuery';
import { render, screen, waitFor } from '@/tests/orgs/testUtils';
import userEvent from '@testing-library/user-event';
import { setupServer } from 'msw/node';
import { vi } from 'vitest';
import { test, vi } from 'vitest';
import { getOrganization } from '@/tests/msw/mocks/graphql/getOrganizationQuery';
import { getProjectQuery } from '@/tests/msw/mocks/graphql/getProjectQuery';
@@ -64,37 +64,62 @@ describe('PointInTimeBackupInfo', () => {
server.listen();
});
afterAll(() => {
server.close();
afterEach(() => {
server.resetHandlers();
vi.restoreAllMocks();
});
test('will fetch the earliest backup and will display the date in with timezone', async () => {
server.use(getOrganization);
afterAll(() => {
server.close();
});
test("will display the earliest backup's date with the local timezone", async () => {
server.use(getProjectQuery);
server.use(getOrganization);
mocks.useGetPiTrBaseBackupsLazyQuery.mockImplementation(() => [
fetchPiTRBaseBackups,
{ loading: false },
]);
await waitFor(() => render(<PointInTimeBackupInfo appId="randomId" />));
// '10 March 2025, 05:00:05 (UTC+02:00)'
await waitFor(() =>
render(<PointInTimeBackupInfo appId={mockApplication.id} />),
);
const earliestBackup = await screen.getByTestId('EarliestBackupDateTime');
expect(earliestBackup).toHaveTextContent(
'10 Mar 2025, 05:00:05 (UTC+02:00)',
);
});
test('will update the date after the timezone is changed', async () => {
test("that the system fetches the earliest backup, displays 'Project has no backups yet' message when no backups exist, and verifies that the restore button is disabled.", async () => {
server.use(getOrganization);
mocks.useGetPiTrBaseBackupsLazyQuery.mockImplementation(() => [
fetchEmptyPiTRBaseBackups,
{ loading: false },
]);
await waitFor(() =>
render(<PointInTimeBackupInfo appId={mockApplication.id} />),
);
const earliestBackup = await screen.getByText(
'Project has no backups yet.',
);
expect(earliestBackup).toBeInTheDocument();
const startRestoreButton = await screen.getByRole('button', {
name: 'Start restore',
});
expect(startRestoreButton).toBeDisabled();
});
test('will update the date after the timezone has changed', async () => {
server.use(getOrganization);
server.use(getProjectQuery);
mocks.useGetPiTrBaseBackupsLazyQuery.mockImplementation(() => [
fetchPiTRBaseBackups,
{ loading: false },
]);
await waitFor(() => render(<PointInTimeBackupInfo appId="randomId" />));
const user = userEvent.setup();
// '10 March 2025, 05:00:05 (UTC+02:00)'
const earliestBackup = await screen.getByTestId('EarliestBackupDateTime');
expect(earliestBackup).toHaveTextContent(
'10 Mar 2025, 05:00:05 (UTC+02:00)',
@@ -116,29 +141,8 @@ describe('PointInTimeBackupInfo', () => {
);
});
test('will fetch the earliest backup and display "Project has no backups yet." test if there are now backups and start restore is disabled', async () => {
server.use(getOrganization);
server.use(getProjectQuery);
mocks.useGetPiTrBaseBackupsLazyQuery.mockImplementation(() => [
fetchEmptyPiTRBaseBackups,
{ loading: false },
]);
await waitFor(() => render(<PointInTimeBackupInfo appId="randomId" />));
// '10 March 2025, 05:00:05 (UTC+02:00)'
const earliestBackup = await screen.getByText(
'Project has no backups yet.',
);
expect(earliestBackup).toBeInTheDocument();
const startRestoreButton = await screen.getByRole('button', {
name: 'Start restore',
});
expect(startRestoreButton).toBeDisabled();
});
test('will schedule a restore', async () => {
server.use(getOrganization);
server.use(getProjectQuery);
mocks.useGetPiTrBaseBackupsLazyQuery.mockImplementation(() => [
fetchPiTRBaseBackups,
{ loading: false },
@@ -167,11 +171,8 @@ describe('PointInTimeBackupInfo', () => {
await screen.getByRole('button', { name: 'Select' }),
).toBeInTheDocument(),
);
await user.click(
await screen.getByRole('gridcell', {
name: /13/i,
}),
);
await user.click(await screen.getByText('13'));
const hoursInput = await screen.getByLabelText('Hours');
await user.type(hoursInput, '18');
@@ -236,5 +237,121 @@ describe('PointInTimeBackupInfo', () => {
expect(
mocks.restoreApplicationDatabase.mock.calls[0][0].recoveryTarget,
).toBe('2025-03-13T16:00:05.000Z');
// call the onCompleted cb
await waitFor(() => mocks.restoreApplicationDatabase.mock.calls[0][1]());
expect(
screen.getByText('Backup has been scheduled successfully.'),
).toBeInTheDocument();
});
test('that dates before the earliest backup cannot be selected', async () => {
server.use(getOrganization);
mocks.useGetPiTrBaseBackupsLazyQuery.mockImplementation(() => [
fetchPiTRBaseBackups,
{ loading: false },
]);
await waitFor(() =>
render(<PointInTimeBackupInfo appId={mockApplication.id} />),
);
const user = userEvent.setup();
const startRestoreButton = await screen.getByRole('button', {
name: 'Start restore',
});
await user.click(startRestoreButton);
await waitFor(async () =>
expect(
await screen.getByText('Recover your database from a backup'),
).toBeInTheDocument(),
);
const dateTimePickerButton = await screen.getByRole('button', {
name: /UTC/i,
});
await user.click(dateTimePickerButton);
await waitFor(async () =>
expect(
await screen.getByRole('button', { name: 'Select' }),
).toBeInTheDocument(),
);
expect(await screen.getByText('March 2025')).toBeInTheDocument();
expect(await screen.getByText('9')).toBeDisabled();
expect(await screen.getAllByText('1')[0]).toBeDisabled();
expect(await screen.getAllByText('5')[0]).toBeDisabled();
expect(await screen.getByText('10')).not.toBeDisabled();
expect(await screen.getByText('15')).not.toBeDisabled();
const hoursInput = await screen.getByLabelText('Hours');
await user.type(hoursInput, '{ArrowDown}');
expect(await screen.getByLabelText('Hours')).toHaveValue('04');
const updatedDateTimeButton = await screen.getByRole('button', {
name: /UTC/i,
});
expect(updatedDateTimeButton).toHaveTextContent(
'10 Mar 2025, 04:00:05 (UTC+02:00)',
);
expect(
await screen.queryByRole('button', { name: 'Select' }),
).toBeDisabled();
expect(
await screen.queryByText(
'Selected date and time is before the earliest available backup',
),
).toBeInTheDocument();
expect(
await screen.getByRole('button', {
name: /UTC/i,
}),
).toHaveClass('border-destructive');
});
test('Learn more link is displayed in the "footer" and aligned to the left and the "Start restore" button is to the right', async () => {
server.use(getOrganization);
mocks.useGetPiTrBaseBackupsLazyQuery.mockImplementation(() => [
fetchPiTRBaseBackups,
{ loading: false },
]);
await waitFor(() =>
render(<PointInTimeBackupInfo appId={mockApplication.id} showLink />),
);
const learMoreAboutPiTRLink = screen.getByText(
/Learn more about Point-in-Time Recover/,
);
expect(learMoreAboutPiTRLink).toBeInTheDocument();
const linkWrapper = learMoreAboutPiTRLink.closest('div');
expect(linkWrapper).toHaveClass('justify-between');
expect(linkWrapper).not.toHaveClass('justify-end');
});
test('Learn more link is in not displayed in the "footer" the "Start restore" button is aligned to the right', async () => {
server.use(getOrganization);
mocks.useGetPiTrBaseBackupsLazyQuery.mockImplementation(() => [
fetchPiTRBaseBackups,
{ loading: false },
]);
await waitFor(() =>
render(<PointInTimeBackupInfo appId={mockApplication.id} />),
);
expect(
screen.queryByText(/Learn more about Point-in-Time Recover/),
).not.toBeInTheDocument();
const startRestoreButton = screen.getByText('Start restore');
const linkWrapper = startRestoreButton.closest('div');
expect(linkWrapper).not.toHaveClass('justify-between');
expect(linkWrapper).toHaveClass('justify-end');
});
});

View File

@@ -1,15 +1,31 @@
import usePiTRBaseBackups from '@/features/orgs/hooks/usePiTRBaseBackups/usePiTRBaseBackups';
import { isEmptyValue } from '@/lib/utils';
import { Info } from 'lucide-react';
import { cn, isEmptyValue } from '@/lib/utils';
import { Info, SquareArrowUpRightIcon } from 'lucide-react';
import Link from 'next/link';
import EarliestBackup from './EarliestBackup';
import RestoreBackupDialogButton from './RestoreBackupDialogButton';
function LearnMoreAboutPiTRLink() {
return (
<Link
href="https://docs.nhost.io/guides/database/backups#point-in-time-recovery"
className="flex items-center gap-1 text-[0.9375rem] leading-[1.375rem] text-[#0052cd] hover:underline dark:text-[#3888ff]"
target="_blank"
rel="noopener noreferrer"
>
Learn more about Point-in-Time Recovery{' '}
<SquareArrowUpRightIcon className="h-4 w-4" />
</Link>
);
}
interface Props {
appId: string;
title?: string;
dialogTitle?: string;
dialogButtonText?: string;
dialogTriggerText?: string;
showLink?: boolean;
}
function PointInTimeBackupInfo({
@@ -18,12 +34,13 @@ function PointInTimeBackupInfo({
dialogTitle = 'Recover your database from a backup',
dialogButtonText,
dialogTriggerText,
showLink = false,
}: Props) {
const { earliestBackupDate, loading } = usePiTRBaseBackups(appId);
const disableStartRestoreButton = loading || isEmptyValue(earliestBackupDate);
return (
/* Move this part to a different component */
<div className="rounded-lg border border-[#EAEDF0] dark:border-[#2F363D]">
<div className="flex w-full flex-col items-start gap-6 p-4">
<h3 className="leading-[1.375] text-[0.9375]">
@@ -46,7 +63,13 @@ function PointInTimeBackupInfo({
</div>
</div>
</div>
<div className="flex w-full items-center justify-end border-t border-[#EAEDF0] p-4 dark:border-[#2F363D]">
<div
className={cn(
'flex w-full items-center border-t border-[#EAEDF0] p-4 dark:border-[#2F363D]',
{ 'justify-between': showLink, 'justify-end': !showLink },
)}
>
{showLink && <LearnMoreAboutPiTRLink />}
<RestoreBackupDialogButton
disabled={disableStartRestoreButton}
earliestBackupDate={earliestBackupDate}

View File

@@ -1,4 +1,5 @@
import { DateTimePicker } from '@/components/common/DateTimePicker';
import { isTZDate } from '@/components/common/TimePicker/time-picker-utils';
import { ButtonWithLoading as Button } from '@/components/ui/v3/button';
import {
Dialog,
@@ -12,7 +13,7 @@ import {
import { useRestoreApplicationDatabasePiTR } from '@/features/orgs/hooks/useRestoreApplicationDatabasePiTR';
import { useCurrentOrg } from '@/features/orgs/projects/hooks/useCurrentOrg';
import { useProject } from '@/features/orgs/projects/hooks/useProject';
import type { TZDate } from '@date-fns/tz';
import { TZDate } from '@date-fns/tz';
import { DialogDescription } from '@radix-ui/react-dialog';
import { format, isBefore, startOfDay } from 'date-fns-v4';
import { memo, useCallback, useEffect, useState } from 'react';
@@ -77,8 +78,21 @@ function RestoreBackupDialogButton({
return format(date, 'dd MMM yyyy, HH:mm:ss (OOOO)').replace('GMT', 'UTC');
}
function isCalendarDayDisabled(date: Date) {
return isBefore(startOfDay(date), startOfDay(earliestBackupDate));
function isCalendarDayDisabled(date: Date | TZDate) {
if (isTZDate(date)) {
const utcDay = new Date(date.getTime()).toISOString();
const tzDate = new TZDate(utcDay, date.timeZone);
const earliestBackupDateInTz = new TZDate(
earliestBackupDate,
date.timeZone,
);
return isBefore(startOfDay(tzDate), startOfDay(earliestBackupDateInTz));
}
return isBefore(
startOfDay(new Date(date.getTime()).toISOString()),
startOfDay(earliestBackupDate),
);
}
const resetState = useCallback(() => {

View File

@@ -0,0 +1,21 @@
import Link from 'next/link';
import type { PropsWithChildren } from 'react';
function TextLink({
href,
children,
target = '_blank',
}: PropsWithChildren<{ href: string; target?: string }>) {
return (
<Link
href={href}
className="text-[0.9375rem] leading-[1.375rem] text-[#0052cd] hover:underline dark:text-[#3888ff]"
target={target}
rel="noopener noreferrer"
>
{children}
</Link>
);
}
export default TextLink;

View File

@@ -198,24 +198,33 @@ function ColumnAutocomplete(
return (
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<PopoverTrigger
asChild
title={
buttonPrefix
? `${buttonPrefix}.${selectedColumn?.label}`
: selectedColumn?.label || 'Select a column'
}
>
<Button
ref={ref}
disabled={disabled}
variant="outline"
role="combobox"
aria-expanded={open}
className="justify-between"
className="w-full justify-between"
>
{buttonPrefix ? (
<div className="flex flex-shrink-0 gap-0 truncate">
<span className="flex-shrink-0 truncate text-sm text-muted-foreground lg:max-w-[200px]">
<div className="flex min-w-0 flex-shrink items-center gap-0">
<span className="flex-shrink truncate text-sm text-muted-foreground lg:max-w-[200px]">
{buttonPrefix}.
</span>
{selectedColumn?.label}
<span className="truncate">{selectedColumn?.label}</span>
</div>
) : (
selectedColumn?.label || 'Select a column'
<span className="truncate">
{selectedColumn?.label || 'Select a column'}
</span>
)}
<ChevronsUpDown className="ml-2 h-5 w-5 shrink-0 opacity-50" />
</Button>
@@ -244,10 +253,11 @@ function ColumnAutocomplete(
placeholder=""
prefix={
relationshipDotNotation
? `
${selectedTable}.${relationshipDotNotation}.`
: ``
? `${selectedTable}.${relationshipDotNotation}.`
: ''
}
className="w-auto min-w-0 flex-grow items-center gap-0 pl-0"
prefixClassName="flex-shrink truncate max-w-[200px]"
/>
{pages?.length > 0 ? (
<div className="flex flex-row items-center gap-2 px-2 py-1.5">
@@ -286,7 +296,10 @@ function ColumnAutocomplete(
)}
/>
<div className="flex gap-3">
<span className="line-clamp-2 break-all">
<span
title={option.label}
className="line-clamp-2 break-all"
>
{option.label}
</span>
<div className="flex items-center">
@@ -330,7 +343,10 @@ function ColumnAutocomplete(
)}
/>
<div className="flex gap-3">
<span className="line-clamp-2 break-all">
<span
title={option.label}
className="line-clamp-2 break-all"
>
{option.label}
</span>
<div className="flex items-center">

View File

@@ -1,6 +1,8 @@
import { SettingsContainer } from '@/components/layout/SettingsContainer';
import { InfoAlert } from '@/features/orgs/components/InfoAlert';
import { useDatabasePiTRSettings } from '@/features/orgs/hooks/useDatabasePiTRSettings/';
import { useUpdateDatabasePiTRConfig } from '@/features/orgs/hooks/useUpdateDatabasePiTRConfig';
import TextLink from '@/features/orgs/projects/common/components/TextLink/TextLink';
import { UpgradeNotification } from '@/features/orgs/projects/database/settings/components/UpgradeNotification';
import { useCurrentOrg } from '@/features/orgs/projects/hooks/useCurrentOrg';
import { isEmptyValue } from '@/lib/utils';
@@ -29,8 +31,8 @@ export default function DatabasePiTRSettings() {
return (
<SettingsContainer
title="Point-in-time recovery"
description="Enable Point-in-Time recovery (PiTR). Available as an add-on for organizations on Pro, Team, or Enterprise plans."
title="Point-in-Time Recovery"
description="Enable Point-in-Time Recovery (PiTR)."
slotProps={{
submitButton: {
disabled: isSwitchDisabled,
@@ -43,11 +45,19 @@ export default function DatabasePiTRSettings() {
showSwitch={shouldShowSwitch}
enabled={isPiTREnabled}
onEnabledChange={handleEnabledChange}
docsLink="https://docs.nhost.io/product/database#point-in-time-recovery"
docsLink="https://docs.nhost.io/guides/database/backups#point-in-time-recovery"
docsTitle="enabling or disabling PiTR"
>
{isFreeProject && (
{isFreeProject ? (
<UpgradeNotification description="To unlock this add-on, transfer this project to a Pro or Team organization." />
) : (
<InfoAlert borderLess>
Available as an add-on for organizations on Pro, Team, or Enterprise
plans for <strong>$100 per month.</strong>{' '}
<TextLink href="https://nhost.io/pricing">
View pricing details
</TextLink>
</InfoAlert>
)}
</SettingsContainer>
);

View File

@@ -49,7 +49,7 @@ export const mockApplication: Project = {
name: 'Test Application',
slug: 'test-application',
appStates: [],
subdomain: '',
subdomain: 'subdomain',
region: {
name: 'us-east-1',
city: 'New York',

View File

@@ -0,0 +1,69 @@
import nhostGraphQLLink from './nhostGraphQLLink';
export const getPostgresSettings = nhostGraphQLLink.query(
'GetPostgresSettings',
(_req, res, ctx) =>
res(
ctx.data({
systemConfig: {
postgres: {
database: 'gnlivtcgjxctuujxpslj',
__typename: 'ConfigSystemConfigPostgres',
},
__typename: 'ConfigSystemConfig',
},
config: {
id: 'ConfigConfig',
__typename: 'ConfigConfig',
postgres: {
version: '14.15-20250311-rc2',
resources: {
storage: {
capacity: 1,
__typename: 'ConfigPostgresResourcesStorage',
},
enablePublicAccess: null,
__typename: 'ConfigPostgresResources',
},
pitr: { retention: 7, __typename: 'ConfigPostgresPitr' },
__typename: 'ConfigPostgres',
},
},
}),
),
);
export const getPiTRNotEnabledPostgresSettings = nhostGraphQLLink.query(
'GetPostgresSettings',
(_req, res, ctx) =>
res(
ctx.data({
systemConfig: {
postgres: {
database: 'gnlivtcgjxctuujxpslj',
__typename: 'ConfigSystemConfigPostgres',
},
__typename: 'ConfigSystemConfig',
},
config: {
id: 'ConfigConfig',
__typename: 'ConfigConfig',
postgres: {
version: '14.15-20250311-rc2',
resources: {
storage: {
capacity: 1,
__typename: 'ConfigPostgresResourcesStorage',
},
enablePublicAccess: null,
__typename: 'ConfigPostgresResources',
},
pitr: null,
__typename: 'ConfigPostgres',
},
},
}),
),
);
// {"data":}

View File

@@ -0,0 +1,144 @@
import nhostGraphQLLink from './nhostGraphQLLink';
export const getProjectsQuery = nhostGraphQLLink.query(
'getProjects',
(_req, res, ctx) =>
res(
ctx.data({
apps: [
{
id: 'pitr-usa-id',
name: 'pitr-not-enabled-usa',
slug: 'pitr-not-enabled-usa',
createdAt: '2025-03-10T12:35:23.193578+00:00',
subdomain: 'ocrnpctsphttfxkuefyx',
region: {
id: '1',
name: 'us-east-1',
__typename: 'regions',
},
deployments: [],
creator: {
id: 'creator-r-elek-id',
email: 'robert@elek.com',
displayName: 'Robert',
__typename: 'users',
},
appStates: [
{
id: 'cd2b77ac-3ef1-4a76-819b-ff1caca09213',
appId: 'pitr-usa-id',
message:
'failed to get dns manager: unknown region: 55985cd4-af14-4d2a-90a5-2a1253ebc1db',
stateId: 8,
createdAt: '2025-03-10T12:39:23.734345+00:00',
__typename: 'appStateHistory',
},
],
__typename: 'apps',
},
{
id: 'pitr-region-TEST-eu-id',
name: 'pitr-region-test-eu',
slug: 'pitr-region-test-eu',
createdAt: '2025-03-10T12:45:40.813234+00:00',
subdomain: 'doszbxwibtopsbfgbjpg',
region: {
id: 'dd6f8e01-35a9-4ba6-8dc6-ed972f2db93c',
name: 'eu-central-1',
__typename: 'regions',
},
deployments: [],
creator: {
id: 'creator-r-elek-id',
email: 'robert@elek.com',
displayName: 'Robert',
__typename: 'users',
},
appStates: [
{
id: 'c7fbf7ad-b60c-432b-86c2-5a9509054c47',
appId: 'pitr-region-TEST-eu-id',
message: '',
stateId: 5,
createdAt: '2025-03-12T11:08:59.926611+00:00',
__typename: 'appStateHistory',
},
],
__typename: 'apps',
},
{
id: 'pitr-test-id',
name: 'pitr-test',
slug: 'pitr-test',
createdAt: '2025-03-04T13:48:59.76498+00:00',
subdomain: 'gnlivtcgjxctuujxpslj',
region: {
id: '1',
name: 'us-east-1',
__typename: 'regions',
},
deployments: [],
creator: {
id: 'creator-d-elek-id',
email: 'dbarrosop@dravetech.com',
displayName: 'David Elek',
__typename: 'users',
},
appStates: [
{
id: 'fc344bc6-1c59-447a-813f-e0f65754b0e0',
appId: 'pitr-test-id',
message:
'failed to deploy application to kubernetes: failed to deploy application: failed to check rollout status: error running kubectl: exit status 1',
stateId: 8,
createdAt: '2025-03-11T15:34:41.25304+00:00',
__typename: 'appStateHistory',
},
],
__typename: 'apps',
},
{
id: 'pitr14-id',
name: 'pitr14',
slug: 'pitr14',
createdAt: '2025-02-25T08:55:22.82937+00:00',
subdomain: 'jqumebxpocjytrhevonb',
region: {
id: '1',
name: 'us-east-1',
__typename: 'regions',
},
deployments: [],
creator: {
id: 'creator-d-elek-id',
email: 'david@elek.com',
displayName: 'David Elek',
__typename: 'users',
},
appStates: [
{
id: '04bc2db3-a948-48fb-b674-7a8a0133dd2b',
appId: 'pitr14-id',
message: '',
stateId: 5,
createdAt: '2025-03-11T20:47:03.102948+00:00',
__typename: 'appStateHistory',
},
],
__typename: 'apps',
},
],
}),
),
);
export const getEmptyProjectsQuery = nhostGraphQLLink.query(
'getProjects',
(_req, res, ctx) =>
res(
ctx.data({
apps: [],
}),
),
);

View File

@@ -23,18 +23,17 @@ declare namespace Intl {
// eslint-disable-next-line vars-on-top, no-var
var DateTimeFormat: DateTimeFormat;
}
// Common
export const UTC_GMT_TIMEZONE = {
label: 'UTC, GMT (UTC+00:00)',
value: 'UTC',
key: 'UTC',
};
// Common
// Common
export function guessTimezone() {
return Intl.DateTimeFormat().resolvedOptions().timeZone;
}
// Common
export function getUTCOffsetInHours(
timezone: string,
dateTime: string,
@@ -43,7 +42,7 @@ export function getUTCOffsetInHours(
const date = new TZDate(dateTime, timezone);
return format(date, dateFormat).replace('GMT', 'UTC');
}
// Common
export function createTimezoneOptions(dateTime: string) {
const validTimezones = new Set(Intl.supportedValuesOf('timeZone'));

View File

@@ -6,6 +6,7 @@ export default defineConfig({
// @ts-ignore
plugins: [tsconfigPaths({ projects: ['./tsconfig.test.json'] }), react()],
test: {
globalSetup: './vitest.global-setup.ts',
testTimeout: 30000,
environment: 'jsdom',
globals: true,

View File

@@ -0,0 +1,3 @@
export const setup = () => {
process.env.TZ = 'Europe/Helsinki';
};

View File

@@ -24,7 +24,7 @@
"@nhost/react": "workspace:^",
"@nhost/react-apollo": "workspace:^",
"graphql": "16.8.1",
"next": "^14.2.22",
"next": "^14.2.25",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-icons": "^4.12.0"

View File

@@ -18,7 +18,7 @@
"form-data": "^4.0.0",
"graphql": "16.8.1",
"js-cookie": "^3.0.5",
"next": "^14.2.22",
"next": "^14.2.25",
"postcss": "^8.4.38",
"react": "^18.2.0",
"react-dom": "^18.2.0",

View File

@@ -15,6 +15,7 @@
"devDependencies": {
"@playwright/test": "^1.41.0",
"@sveltejs/adapter-auto": "^3.3.1",
"@sveltejs/adapter-vercel": "^5.6.3",
"@sveltejs/kit": "^2.11.1",
"@sveltejs/vite-plugin-svelte": "^5.0.2",
"@types/js-cookie": "^3.0.6",

View File

@@ -26,7 +26,7 @@ or
```js
import React from 'react'
import ReactDOM from 'react-dom'
import { NhostClient, NhostReactProvider } from '@nhost/react'
import { NhostClient, NhostProvider } from '@nhost/react'
import { NhostApolloProvider } from '@nhost/react-apollo'
import App from './App'
@@ -38,11 +38,11 @@ const nhost = new NhostClient({
ReactDOM.render(
<React.StrictMode>
<NhostReactProvider nhost={nhost}>
<NhostProvider nhost={nhost}>
<NhostApolloProvider nhost={nhost}>
<App />
</NhostApolloProvider>
</NhostReactProvider>
</NhostProvider>
</React.StrictMode>,
document.getElementById('root')
)

View File

@@ -56,10 +56,10 @@
"dashboard"
],
"devDependencies": {
"@babel/core": "^7.24.7",
"@babel/eslint-parser": "^7.24.7",
"@babel/plugin-syntax-flow": "^7.24.7",
"@babel/plugin-transform-react-jsx": "^7.24.7",
"@babel/core": "^7.26.10",
"@babel/eslint-parser": "^7.26.10",
"@babel/plugin-syntax-flow": "^7.26.0",
"@babel/plugin-transform-react-jsx": "^7.25.9",
"@changesets/cli": "^2.27.5",
"@faker-js/faker": "^7.6.0",
"@rollup/plugin-replace": "^5.0.7",
@@ -82,6 +82,8 @@
"husky": "^8.0.3",
"npm-run-all": "^4.1.5",
"prettier": "^3.3.3",
"prettier-plugin-organize-imports": "^4.1.0",
"prettier-plugin-tailwindcss": "^0.6.11",
"turbo": "2.3.3",
"typedoc": "^0.22.18",
"typescript": "4.9.5",
@@ -137,6 +139,8 @@
"tough-cookie@<4.1.3": ">=4.1.3",
"protobufjs@>=7.0.0 <7.2.4": ">=7.2.4",
"vite@=4.5.0": ">=4.5.1",
"@babel/runtime@<7.26.10": ">=7.26.10",
"@babel/helpers@<7.26.10": ">=7.26.10",
"@babel/traverse@<7.23.2": ">=7.23.2",
"@adobe/css-tools@<4.3.2": ">=4.3.2",
"semver@<5.7.2": ">=5.7.2",

View File

@@ -78,7 +78,7 @@
"devDependencies": {
"@nhost/docgen": "workspace:*",
"@types/js-cookie": "^3.0.6",
"next": "^14.2.22",
"next": "^14.2.25",
"react": "^18.2.0",
"react-dom": "^18.2.0"
}

View File

@@ -21,7 +21,7 @@ export type CreateServerSideClientParams = Partial<
/**
* Creates an Nhost client that runs on the server side.
* It will try to get the refesh token in cookies, or from the request URL
* It will try to get the refresh token in cookies, or from the request URL
* If a refresh token is found, it uses it to get an up to date access token (JWT) and a user session
* This method resolves when the authentication status is known eventually
* @param config - An object containing connection information

View File

@@ -27,7 +27,7 @@ Initialize a single `nhost` instance and wrap your app with the `NhostReactProvi
import React from 'react'
import ReactDOM from 'react-dom'
import { NhostClient, NhostReactProvider } from '@nhost/react'
import { NhostClient, NhostProvider } from '@nhost/react'
import App from './App'
@@ -38,9 +38,9 @@ const nhost = new NhostClient({
ReactDOM.render(
<React.StrictMode>
<NhostReactProvider nhost={nhost}>
<NhostProvider nhost={nhost}>
<App />
</NhostReactProvider>
</NhostProvider>
</React.StrictMode>,
document.getElementById('root')
)

2563
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@
"@craco/craco": "^7.1.0",
"@hookform/resolvers": "^3.9.0",
"@icons-pack/react-simple-icons": "^9.6.0",
"@nhost/react": "^3.10.1",
"@nhost/react": "^3.10.2",
"@nhost/react-apollo": "^16.0.1",
"@radix-ui/react-dialog": "^1.1.1",
"@radix-ui/react-dropdown-menu": "^2.1.1",

View File

@@ -13,7 +13,7 @@
"@nhost-examples/sveltekit#build": {
"dependsOn": ["^build"],
"outputs": [".svelte-kit/**", ".vercel/**"],
"env": ["PUBLIC_NHOST_SUBDOMAIN", "PUBLIC_NHOST_REGION"]
"env": ["PUBLIC_NHOST_SUBDOMAIN", "PUBLIC_NHOST_REGION", "ENABLE_EXPERIMENTAL_COREPACK"]
},
"@nhost-examples/vue-apollo#build": {
"dependsOn": ["^build"],