Compare commits

..

132 Commits

Author SHA1 Message Date
github-actions[bot]
bf17981596 chore: update versions (#3453)
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.36.0

### Minor Changes

-   a30da08: feat (dashboard): add custom types to column types

### Patch Changes

-   73a7ba8: fix (dashboard): Show errors in row permission rule form
-   397bfc9: fix (dashboard): Parse foreign key relations correctly
- 2f4b376: fix (dashboard): allow permission variables with in operator
- 88836f3: fix (dashboard): use correct fallback endpoint for migration
in the CLI
- ba3c49e: fix (dashboard): Show nested relationships in row permissions
-   92e71a6: fix: minor fixes to csp
- 81716d9: fix (dashboard): Show validation error on save when editing
database columns

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-09-16 13:41:37 +02:00
robertkasza
2f4b3768c7 fix (dashboard): allow permission variables with in operator (#3461)
### **PR Type**
Bug fix, Tests, Enhancement


___

### **Description**
- Refactor FancyMultiSelect to controlled component

- Enhance RuleValueInput `_in` operator for system variables

- Add unit tests for RuleValueInput variable selection

- Include `Allowed-Ids` in permission variables list


___

### Diagram Walkthrough


```mermaid
flowchart LR
  FV["Form value"]
  GD["getDefaultValueForMultiSelect"]
  FMS["FancyMultiSelect"]
  OC["handleOnChange"]
  SV["setValue"]
  FV -- "parsed by" --> GD
  GD -- "initializes" --> FMS
  FMS -- "user selects" --> OC
  OC -- "updates" --> SV
```



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>fancy-multi-select.tsx</strong><dd><code>Make
FancyMultiSelect controlled and test-friendly</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

dashboard/src/components/ui/v3/fancy-multi-select.tsx

<ul><li>Export <code>Option</code> type<br> <li> Use controlled
<code>value</code> instead of <code>defaultValue</code><br> <li> Sync
selected via <code>useEffect</code> on <code>value</code> changes<br>
<li> Add <code>data-testid</code> to badge span</ul>


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3461/files#diff-6e6a7965a2c8e30e9a2c021a5009ff79e71de73892b86a3468d3474163dfeb03">+13/-5</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>getAllPermissionVariables.ts</strong><dd><code>Add
Allowed-Ids system variable</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></summary>
<hr>


dashboard/src/features/orgs/projects/permissions/settings/utils/getAllPermissionVariables/getAllPermissionVariables.ts

- Include `Allowed-Ids` as system variable


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3461/files#diff-9973106a26aa99d744772d8dfb09281b3f4f2cdaa3f865b2510f47fb9061089c">+6/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></td></tr><tr><td><strong>Bug fix</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>RuleValueInput.tsx</strong><dd><code>Enhance
RuleValueInput for in-operator variables</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/features/orgs/projects/database/dataGrid/components/RuleGroupEditor/RuleValueInput.tsx

<ul><li>Import <code>Option</code> type<br> <li> Add
<code>getDefaultValueForMultiSelect</code> util<br> <li> Implement
<code>handleOnChange</code> for permission variables<br> <li> Switch
<code>FancyMultiSelect</code> to use controlled props</ul>


</details>


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

</tr>
</table></td></tr><tr><td><strong>Tests</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>RuleValueInput.test.tsx</strong><dd><code>Add tests for
RuleValueInput selection logic</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/features/orgs/projects/database/dataGrid/components/RuleGroupEditor/RuleValueInput.test.tsx

<ul><li>Add tests for <code>_in</code> operator variable selection<br>
<li> Mock project and permissions hooks<br> <li> Verify system and
custom variable behaviors</ul>


</details>


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

</tr>
</table></td></tr><tr><td><strong>Miscellaneous</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>signup.tsx</strong><dd><code>Cleanup console logs in
signup page</code>&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/src/pages/signup.tsx

- Remove debugging `console.log` statements


</details>


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

</tr>
</table></td></tr><tr><td><strong>Configuration
changes</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>dry-snails-type.md</strong><dd><code>Add changelog for
permission variables fix</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

.changeset/dry-snails-type.md

- Add changeset entry for dashboard patch


</details>


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

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

</details>

___
2025-09-16 13:38:25 +02:00
robertkasza
73a7ba82ae fix (dashboard): Show errors in row permission rule form (#3471)
### **PR Type**
Bug fix, Tests, Enhancement


___

### **Description**
- Improve row permission form error handling

- Integrate `FormField` for validation feedback

- Update tests using `TestUserEvent.fireClickEvent`

- Extend MSW mocks for metadata and table queries


___



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Tests</strong></td><td><details><summary>5
files</summary><table>
<tr>
<td><strong>TransferProjectDialog.test.tsx</strong><dd><code>Replace
`asyncFireEvent` with `TestUserEvent.fireClickEvent`</code></dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3471/files#diff-d4ebdb8af76a7c9e73606708718c3448445545259ad553d73b6d322408e3eb8c">+3/-16</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>RowPermissionSection.test.tsx</strong><dd><code>Add
comprehensive tests for row permissions section</code>&nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3471/files#diff-2a32fbb9eda12ec8eb93746c5c8b171e8ae20d18e661a5e2eb0c4996fee8376b">+211/-0</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>hasuraMetadataQuery.ts</strong><dd><code>Add
`hasuraColumnMetadataQuery` mock endpoint</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3471/files#diff-2828f4a1163f0d281abf2517e76fc9dd393bb870478aea874019a42f9c4b7ac3">+260/-0</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>tableQuery.ts</strong><dd><code>Extend actor table mock with
column and row data</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3471/files#diff-fdb6ad2a7e58c374f3a6772219e7f7e72ca2927def74ec75893b064caba12639">+40/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>testUtils.tsx</strong><dd><code>Add `fireClickEvent` helper
to `TestUserEvent`</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3471/files#diff-78f29250407edf853a353b48242d3cee59aa5724f38a60bb23bebdfc1ea2f9b5">+13/-0</a>&nbsp;
&nbsp; </td>

</tr>

</table></details></td></tr><tr><td><strong>Enhancement</strong></td><td><details><summary>4
files</summary><table>
<tr>
<td><strong>ColumnAutocomplete.tsx</strong><dd><code>Add `className`
prop and merge via `cn`</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3471/files#diff-c89efa530042890e7d6277c2e3c763cb7c9b9fc1d7c14c62839f4cf7c42528f7">+6/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>RowPermissionsSection.tsx</strong><dd><code>Refactor filter
logic and default row check type</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3471/files#diff-663956d9adae1f6255151599b1cbd6ad03fea1246e87ab89329fcddcdbec2b20">+12/-28</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>RuleEditorRow.tsx</strong><dd><code>Wrap column input with
`FormField` and error styling</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3471/files#diff-a7a1d2aa882735a2b9cfb41e95b05c6777d706570eec5deec6bf5d2381a51252">+47/-28</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>RuleValueInput.tsx</strong><dd><code>Introduce
`RuleInputWrapper` with validation messages</code>&nbsp; &nbsp; &nbsp;
&nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3471/files#diff-e3198b245b5963e81e4566758b7d60c8d2784a7ca0ad0b17b354b33074ef1bb0">+43/-6</a>&nbsp;
&nbsp; </td>

</tr>
</table></details></td></tr><tr><td><strong>Bug
fix</strong></td><td><details><summary>1 files</summary><table>
<tr>
<td><strong>OperatorComboBox.tsx</strong><dd><code>Reset value and clear
errors on operator change</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3471/files#diff-bf3aa91fe39fe48522262f0f908b7d151ce75cb005ec50fe38c2429d0e81ddb1">+4/-5</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></details></td></tr><tr><td><strong>Configuration
changes</strong></td><td><details><summary>1 files</summary><table>
<tr>
<td><strong>vitest.config.ts</strong><dd><code>Enable silent logging in
Vitest config</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3471/files#diff-09548f3bfb7c005a1d2f3d9d7f1f5d00c608d821572250400d92eda63ae7251a">+1/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

</table></details></td></tr><tr><td><strong>Documentation</strong></td><td><details><summary>1
files</summary><table>
<tr>
<td><strong>brave-fans-sit.md</strong><dd><code>Add changeset for
dashboard patch release</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3471/files#diff-25c255427ffb291f4e9d7ab56622f3fee8bc9ea2ca0b38242d9b7e41273bea88">+5/-0</a>&nbsp;
&nbsp; &nbsp; </td>

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

</details>

___
2025-09-16 10:45:39 +02:00
robertkasza
ba3c49e443 fix (dashboard): Show nested relationships in row permissions (#3473)
### **PR Type**
Bug fix, Tests, Enhancement


___

### **Description**
- Add MSW mock for nested relationship metadata

- Add test verifying nested relationships display

- Simplify `CommandList` rendering logic

- Introduce `fireClickEvent` helper in tests


___

### Diagram Walkthrough


```mermaid
flowchart LR
  metadata["\"MSW nested metadata mock\""]
  component["\"ColumnAutocomplete component\""]
  ui["\"Displays nested relationship options\""]
  metadata -- "provides nested data" --> component
  component -- "renders options" --> ui
```



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Tests</strong></td><td><details><summary>4
files</summary><table>
<tr>
<td><strong>ColumnAutocomplete.test.tsx</strong><dd><code>Add nested
relationship test and router mock</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/3473/files#diff-2da9237ad932fa46d684a3c8fe3afb6686af561e136e6aea5fa588f3979e131e">+76/-12</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>hasuraMetadataQuery.ts</strong><dd><code>Add
`hasuraRelationShipsMetadataQuery` mock</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/3473/files#diff-2828f4a1163f0d281abf2517e76fc9dd393bb870478aea874019a42f9c4b7ac3">+98/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>tableQuery.ts</strong><dd><code>Add `town` table MSW mock
data</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3473/files#diff-fdb6ad2a7e58c374f3a6772219e7f7e72ca2927def74ec75893b064caba12639">+42/-1</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>testUtils.tsx</strong><dd><code>Add `fireClickEvent` helper
method</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></td>
<td><a
href="https://github.com/nhost/nhost/pull/3473/files#diff-78f29250407edf853a353b48242d3cee59aa5724f38a60bb23bebdfc1ea2f9b5">+13/-0</a>&nbsp;
&nbsp; </td>

</tr>

</table></details></td></tr><tr><td><strong>Enhancement</strong></td><td><details><summary>1
files</summary><table>
<tr>
<td><strong>ColumnAutocomplete.tsx</strong><dd><code>Simplify
CommandList and support nested relationships</code>&nbsp; &nbsp; &nbsp;
&nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3473/files#diff-c89efa530042890e7d6277c2e3c763cb7c9b9fc1d7c14c62839f4cf7c42528f7">+45/-85</a>&nbsp;
</td>

</tr>

</table></details></td></tr><tr><td><strong>Formatting</strong></td><td><details><summary>1
files</summary><table>
<tr>
<td><strong>useTableQuery.ts</strong><dd><code>Remove extra blank line
in hook implementation</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3473/files#diff-13ce245133be3c4bbcd9fe302cacd42e3e8472dc57d8ce27371e59818240d942">+1/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></details></td></tr><tr><td><strong>Configuration
changes</strong></td><td><details><summary>1 files</summary><table>
<tr>
<td><strong>new-eels-run.md</strong><dd><code>Add changeset for nested
relationships fix</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3473/files#diff-5ed65e898211e2d9e7614fed8b4bccc0c501b0767a564baaace82ca7bd185d36">+5/-0</a>&nbsp;
&nbsp; &nbsp; </td>

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

</details>

___
2025-09-16 08:33:08 +02:00
robertkasza
88836f3b1f fix (dashboard): use correct fallback endpoint for migration in the CLI (#3472)
### **PR Type**
Bug fix


___

### **Description**
- Remove `/apis/migrate` suffix in migration fetch URLs

- Update default fallback Hasura migrations API endpoint

- Add changeset entry for migration endpoint fix


___



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Bug
fix</strong></td><td><details><summary>9 files</summary><table>
<tr>
<td><strong>createColumnMigration.ts</strong><dd><code>Remove
`/apis/migrate` suffix from fetch URL</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/3472/files#diff-806e4808866ca6ba76c359ef8ae68346cd83f8bec034f6057210b86c2cfd11ec">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>createTableMigration.ts</strong><dd><code>Remove
`/apis/migrate` suffix from fetch URL</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/3472/files#diff-e033710673c18c205655684e8a930963aff2363f314faa8d7dd36bd645e8a3f6">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>deleteColumnMigration.ts</strong><dd><code>Remove
`/apis/migrate` suffix from fetch URL</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/3472/files#diff-b0c2fc34ff94579ef93ee14aae60a6d2df3d2986014d8740f56508f321dec8cb">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>deleteTableMigration.ts</strong><dd><code>Remove
`/apis/migrate` suffix from fetch URL</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/3472/files#diff-2e192aca09dca7ff2a9cb105daa94330629e1fccfdf9a1bdee9fdba510c23abd">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>managePermissionMigration.ts</strong><dd><code>Remove
`/apis/migrate` suffix from fetch URL</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/3472/files#diff-6618ac02347ee4e55aaeacece7894330d86f9716d8fbd9a907a11c9a977461d2">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>

<td><strong>trackForeignKeyRelationsMigration.ts</strong><dd><code>Remove
`/apis/migrate` suffix from fetch URL</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/3472/files#diff-8562c65950e2ff578d8db135790713bbff282ff6a61ff98bb5558a51944927d2">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>trackTableMigration.ts</strong><dd><code>Remove
`/apis/migrate` suffix from fetch URL</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/3472/files#diff-c7cb8539796fe51acbde04b83f33bbce0474284e3a3840d65eb8cd9b21f951bc">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>updateColumnMigration.ts</strong><dd><code>Remove
`/apis/migrate` suffix from fetch URL</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/3472/files#diff-11cb8c97ec6d26491538e7032840513127cb4044b9ff3a8890e3602c4ae4a6c6">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>updateTableMigration.ts</strong><dd><code>Remove
`/apis/migrate` suffix from fetch URL</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/3472/files#diff-7817a436afa62e58c14d5b0570093de17b57c8abc5b17ad7f191465b75a86cb2">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></details></td></tr><tr><td><strong>Configuration
changes</strong></td><td><details><summary>1 files</summary><table>
<tr>
<td><strong>env.ts</strong><dd><code>Update default Hasura migrations
API URL</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3472/files#diff-38801f053432e037993a6c8359ff512d7a6cfa9579597b92449f12c05c9c14e9">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

</table></details></td></tr><tr><td><strong>Documentation</strong></td><td><details><summary>1
files</summary><table>
<tr>
<td><strong>neat-coins-hide.md</strong><dd><code>Add changeset for
migration endpoint fix</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3472/files#diff-198c242704f17162fd3bc020b3e0284494eb752bb0c27866953742a2c08f2026">+5/-0</a>&nbsp;
&nbsp; &nbsp; </td>

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

</details>

___
2025-09-12 15:48:57 +02:00
robertkasza
81716d9d9c fix (dashboard): Show validation error on save when editing database columns (#3464)
### **PR Type**
Bug fix


___

### **Description**
- Simplify useFormState name path

- Fix error path in ColumnErrorMessage

- Include patch changeset for dashboard


___



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Bug
fix</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>ColumnEditorRow.tsx</strong><dd><code>Simplify
useFormState name path</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>


dashboard/src/features/orgs/projects/database/dataGrid/components/BaseTableForm/ColumnEditorRow/ColumnEditorRow.tsx

<ul><li>Removed redundant <code>columns</code> entry from field name
array<br> <li> Targets errors specifically for column name field</ul>


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>ColumnEditorTable.tsx</strong><dd><code>Fix error
message path usage</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/features/orgs/projects/database/dataGrid/components/BaseTableForm/ColumnEditorTable.tsx

<ul><li>Check <code>errors.columns.root.message</code> instead of
<code>errors.columns.message</code><br> <li> Ensure correct validation
message in HelperText</ul>


</details>


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

</tr>
</table></td></tr><tr><td><strong>Configuration
changes</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>unlucky-terms-hang.md</strong><dd><code>Add dashboard
patch changeset</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></summary>
<hr>

.changeset/unlucky-terms-hang.md

<ul><li>Add changeset entry for dashboard patch release<br> <li> Note
validation error display fix</ul>


</details>


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

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

</details>

___
2025-09-11 15:54:28 +02:00
robertkasza
a30da08e9b feat (dashboard): add custom types to column types (#3442)
### **PR Type**
Enhancement


___

### **Description**
- Add custom column types to database tables

- Improve handling of user-defined data types

- Update UI components for custom type support

- Refactor column type normalization and validation


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["Column Type Handling"] -- "Extend" --> B["Custom Types"]
  B -- "Update" --> C["UI Components"]
  B -- "Refactor" --> D["Type Normalization"]
  D -- "Improve" --> E["Data Validation"]
```



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><details><summary>15
files</summary><table>
<tr>
<td><strong>Autocomplete.tsx</strong><dd><code>Enhance Autocomplete
component for custom types</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3442/files#diff-b185666714ca832d5c45c366618b79862f6b4f03e4f7657c78afa38a52e7c4c2">+27/-3</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>BaseColumnForm.tsx</strong><dd><code>Update BaseColumnForm
to support custom column types</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3442/files#diff-9750f922830f8637c2d1b81c5e40128bc4fca7a9349a5314e421353d73bf6f38">+43/-16</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>ColumnEditorRow.tsx</strong><dd><code>Modify ColumnEditorRow
to handle custom types</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3442/files#diff-264f067037cfa5d08dbb97964a9ddb8f6296129441682b78f6984c37051ea3f8">+37/-10</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>DataBrowserGrid.tsx</strong><dd><code>Update DataBrowserGrid
to display full data type</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3442/files#diff-5910fd8730fbe65c60aa5f54031989a7868e944d5958f69535e5684b72ca1396">+6/-11</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>DatabaseRecordInputGroup.tsx</strong><dd><code>Adjust
DatabaseRecordInputGroup for custom types</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3442/files#diff-52b5499e9afc3c5e4929046b487de649d421dda3250a4131462ec710575abc12">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>prepareCreateColumnQuery.ts</strong><dd><code>Modify
prepareCreateColumnQuery for custom types</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3442/files#diff-9b3695fb28760e86fc966e2149082b798664f145a8b64ef66184e55a905f5071">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>prepareCreateTableQuery.ts</strong><dd><code>Adjust
prepareCreateTableQuery for custom types</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3442/files#diff-1458307108df70f7037fa516ccab3a028533cf23f752778fcb09ed8d326530e5">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>fetchTable.ts</strong><dd><code>Modify fetchTable to include
full data type</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/3442/files#diff-a58cb7660972ff84991cdd9777de5cf0834485072cbd421f8809638227c36820">+36/-28</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>prepareUpdateColumnQuery.ts</strong><dd><code>Adjust
prepareUpdateColumnQuery for custom types</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3442/files#diff-ef957000505e4ba437656c38b4371d4041471ce5a4c193ef381aa55e0c51c308">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>dataBrowser.ts</strong><dd><code>Update type definitions for
custom column types</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3442/files#diff-33c6810dbd7e2910c86a15009467a348f064380b0e1dd787ef320b4e7543403b">+2/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>index.ts</strong><dd><code>Add new utility for normalizing
column types</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/3442/files#diff-df62570fe4a332639b789274e3db4ea98cc695bc306f6dc1692851280bdb2fde">+1/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>normalizeColumnType.ts</strong><dd><code>Implement
normalizeColumnType utility function</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3442/files#diff-6bc7935091971eb83f99ba700e11f7214599d4d86e41f96d0d8295bdd6441d8f">+11/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>normalizeDatabaseColumn.ts</strong><dd><code>Modify
normalizeDatabaseColumn to use new utility</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3442/files#diff-e00d1c71fcbc63286896b597ce820388987e0a7edb005bda8a13bb0c0813434b">+2/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>postgresqlConstants.ts</strong><dd><code>Update PostgreSQL
type constants and groups</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/3442/files#diff-b497da90feca5bff94b0d38b69e519d171d43acc292098054d672a73a89b4717">+6/-8</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>DataGridTextCell.tsx</strong><dd><code>Adjust
DataGridTextCell for custom type handling</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3442/files#diff-d1ed74fe8eb7a61053dfe908966311e13915ad2127ee107b62f725d6c5282492">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

</table></details></td></tr><tr><td><strong>Tests</strong></td><td><details><summary>5
files</summary><table>
<tr>
<td><strong>prepareCreateTableQuery.test.ts</strong><dd><code>Update
tests for custom column type support</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/3442/files#diff-348ba7ca6fc037a9d0de76a24efc36846c634d82755bbf33dd5062a7face06ec">+232/-198</a></td>

</tr>

<tr>
<td><strong>prepareUpdateColumnQuery.test.ts</strong><dd><code>Update
tests for custom column type changes</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/3442/files#diff-65420c7003a95c03b31fc4b0e45f6a22387f81c1ce8e41a2d7cb89cc44dbda26">+557/-494</a></td>

</tr>

<tr>
<td><strong>prepareUpdateTableQuery.test.ts</strong><dd><code>Update
tests for custom column type support</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/3442/files#diff-57c2f882497d653700d68905bb54c891592a6bf302040d3008d624900f1bdf64">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>getInputType.test.ts</strong><dd><code>Update tests for
input type handling</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3442/files#diff-01a507828b9440cd99bd0722ab5b577d8dd1774f2320168ad88222138960e831">+3/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>normalizeDatabaseColumn.test.ts</strong><dd><code>Update
tests for database column normalization</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3442/files#diff-a451c29ffa35243d4dbb462e3a048088c514f8056effedf782fcc57d5235e338">+5/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

</table></details></td></tr><tr><td><strong>Documentation</strong></td><td><details><summary>1
files</summary><table>
<tr>
<td><strong>rich-dragons-attend.md</strong><dd><code>Add changeset for
custom column types feature</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3442/files#diff-bb90b20cf816a7c7bfc628f9daae90b9deff5d8c00f36361190d6147b46fb6be">+5/-0</a>&nbsp;
&nbsp; &nbsp; </td>

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

</details>

___
2025-09-08 14:24:43 +02:00
robertkasza
397bfc948c fix (dashboard): Parse foreign key relations correctly (#3458)
### **PR Type**
Bug fix, Tests


___

### **Description**
- Pass updated table name to refetch queries

- Extend `onSubmit` callbacks with `tableName`

- Strip quotes from foreign key column names

- Add and restructure tests for extractor


___



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Bug
fix</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>DataBrowserSidebar.tsx</strong><dd><code>Update
refetchQueries with new tableName</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/features/orgs/projects/database/dataGrid/components/DataBrowserSidebar/DataBrowserSidebar.tsx

<ul><li>Accept <code>tableName</code> in <code>onSubmit</code>
callback<br> <li> Use <code>tableName</code> for
<code>refetchQueries</code> key</ul>


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>EditTableForm.tsx</strong><dd><code>Extend onSubmit to
receive tableName</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/features/orgs/projects/database/dataGrid/components/EditTableForm/EditTableForm.tsx

<ul><li>Change <code>onSubmit</code> prop to accept
<code>tableName</code><br> <li> Pass <code>updatedTable.name</code> to
<code>onSubmit</code></ul>


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>extractForeignKeyRelation.ts</strong><dd><code>Strip
quotes from extracted column names</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/features/orgs/projects/database/dataGrid/utils/extractForeignKeyRelation/extractForeignKeyRelation.ts

- Remove surrounding parentheses and double quotes from `columnName`


</details>


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

</tr>
</table></td></tr><tr><td><strong>Tests</strong></td><td><table>
<tr>
  <td>
    <details>

<summary><strong>extractForeignKeyRelation.test.ts</strong><dd><code>Restructure
extractor tests and add cases</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></summary>
<hr>


dashboard/src/features/orgs/projects/database/dataGrid/utils/extractForeignKeyRelation/extractForeignKeyRelation.test.ts

<ul><li>Group tests under <code>describe</code> blocks<br> <li> Add test
for capital-letter column names<br> <li> Consolidate no-action
scenarios</ul>


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3458/files#diff-9f5bd2c96f0cdcb925343201e389d2d57d8f1fb2adf7daf522338939c613f426">+126/-109</a></td>

</tr>
</table></td></tr><tr><td><strong>Configuration
changes</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>cold-toys-bow.md</strong><dd><code>Add changelog for
foreign key fix</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

.changeset/cold-toys-bow.md

- Add dashboard patch changelog entry


</details>


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

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

</details>

___
2025-09-04 11:00:52 +02:00
robertkasza
0d183761ae fix (dashboard): allow any service to be filtered (#3452)
### **PR Type**
Bug fix, Enhancement


___

### **Description**
- Allow filtering logs by any service

- Refactor log service constants and types

- Update tests for new service filtering

- Improve DateTimePicker component tests


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["Old Service Enum"] --> B["Dynamic Service List"]
  C["Fixed Service Labels"] --> D["Flexible Service Labels"]
  E["Limited Service Filter"] --> F["Any Service Filter"]
  G["DateTimePicker Tests"] --> H["Improved DateTimePicker Tests"]
```



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Tests</strong></td><td><details><summary>4
files</summary><table>
<tr>
<td><strong>DateTimePicker.test.tsx</strong><dd><code>Improve
DateTimePicker component tests</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3452/files#diff-c7076012eb33d6f60049710638b5ad19c2f310b8c250c79f1905be7e0a30b00a">+12/-12</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>DeploymentServcieLogsHeader.test.tsx</strong><dd><code>Add
tests for DeploymentServiceLogsHeader</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3452/files#diff-46fb5d0c9528168323c0e16ef4186d91fe6274b64292f43841258bdfc45dd581">+81/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>useProjectLogs.test.ts</strong><dd><code>Update
useProjectLogs tests for new service handling</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3452/files#diff-13d900aa08d06962a09628136b893801ad62a96c3ff89d380c5c4b7ae92d891e">+9/-9</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>LogsHeader.test.tsx</strong><dd><code>Add tests for
LogsHeader with new service handling</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3452/files#diff-6a348a6b3f868aac854020f2b85ff9a7cf5d61f362a5201e77681e4d5a576f20">+86/-0</a>&nbsp;
&nbsp; </td>

</tr>

</table></details></td></tr><tr><td><strong>Enhancement</strong></td><td><details><summary>8
files</summary><table>
<tr>
<td><strong>LogsServiceFilter.tsx</strong><dd><code>Update
LogsServiceFilter to support any service</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3452/files#diff-a590a7298a9f040df9f26c4eb37d10fc36f47c32996f71aec47796f08c44e892">+8/-7</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>DeploymentServiceLogs.tsx</strong><dd><code>Update
DeploymentServiceLogs to use CoreLogService</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3452/files#diff-333a9783713e9a4bad1b5327e117cbe69148091abe8b9038d36132b5f4635bbe">+3/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>DeploymentServiceLogsHeader.tsx</strong><dd><code>Refactor
DeploymentLogsHeader to use CoreLogService</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3452/files#diff-4f102c06ed32bb3d8245e415e76b0b14d2d4ae3abca6e234edf69278325c7a95">+3/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>useProjectLogs.ts</strong><dd><code>Refactor useProjectLogs
to handle any service</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3452/files#diff-10efc67700b3f024dd03442eacd339802e951696d04caa76bd5a864bd5c7c83f">+3/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>LogsBody.tsx</strong><dd><code>Update LogsBody to use
CORE_LOG_SERVICE_TO_LABEL</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3452/files#diff-b628e511a7fb9b237ac691b27ab9585eed0d0803144cde66c3af7fa6f9a2dc40">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>LogsHeader.tsx</strong><dd><code>Refactor LogsHeader to
support any service</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3452/files#diff-ebb3285aa776c9c5ea8b72672c4aafd55994c6c694998bbf56ca9c56d1e77664">+3/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>services.ts</strong><dd><code>Rename AvailableLogsService to
CoreLogService</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3452/files#diff-8fcdaed33322718091b613ae22c65cc3eb61972904b5af46866b160c9bbbe48c">+13/-13</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>logs.tsx</strong><dd><code>Update logs page to use
CoreLogService</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3452/files#diff-77489a68a7526d74f06d59019ad68c44728b7620637308d70fba38d6649b73fa">+3/-3</a>&nbsp;
&nbsp; &nbsp; </td>

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

</details>

___
2025-09-01 15:41:55 +02:00
robertkasza
1902a114ec chore: update nextjs version because of vulnerabilities (#3454)
### **PR Type**
Enhancement


___

### **Description**
- Bump Next.js to v14.2.31 across multiple packages

- Update dependency to address vulnerabilities


___



<details> <summary><h3> File Walkthrough</h3></summary>

<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>Bump Next.js in
dashboard</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

dashboard/package.json

- Updated `next` version from ^14.2.30 to ^14.2.31


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>package.json</strong><dd><code>Bump Next.js in example
app</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></summary>
<hr>

examples/nextjs/package.json

- Updated `next` version from ^14.2.30 to ^14.2.31


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>package.json</strong><dd><code>Bump Next.js in
quickstart</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

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

- Updated `next` version from ^14.2.30 to ^14.2.31


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>package.json</strong><dd><code>Bump Next.js in core
package</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></summary>
<hr>

packages/nextjs/package.json

- Updated `next` version from ^14.2.30 to ^14.2.31 in devDependencies


</details>


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

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

</details>

___
2025-09-01 09:29:36 +02:00
David Barroso
92e71a61f9 fix (dashboard): minor fixes to csp (#3451)
### **PR Type**
Enhancement


___

### **Description**
- Update CSP header in next.config.js

- Add googletagmanager.com to script-src

- Include github.com in img-src sources

- Create changeset for @nhost/dashboard patch


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["CSP Header"] --> B["Script Sources"]
  A --> C["Image Sources"]
  B -->|"Add"| D["googletagmanager.com"]
  C -->|"Add"| E["github.com"]
  F["Changeset"] -->|"Create"| G["@nhost/dashboard patch"]
```



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>next.config.js</strong><dd><code>Update 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

<ul><li>Added googletagmanager.com to script-src in CSP header<br> <li>
Included github.com in img-src sources in CSP header</ul>


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>tough-cougars-guess.md</strong><dd><code>Add changeset
for dashboard CSP fixes</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

.changeset/tough-cougars-guess.md

<ul><li>Created new changeset file for @nhost/dashboard patch<br> <li>
Added description: "fix: minor fixes to csp"</ul>


</details>


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

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

</details>

___
2025-09-01 08:38:15 +02:00
github-actions[bot]
9790bcfe3e chore: update versions (#3421)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


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

### Minor Changes

- 2f5bc04: fix (hasura-storage-js/docs): use correct way of specifying
metadata\[] in formData

## @nhost/apollo@9.0.1

### Patch Changes

-   @nhost/nhost-js@3.3.1

## @nhost/react-apollo@18.0.2

### Patch Changes

-   @nhost/apollo@9.0.1
-   @nhost/react@3.11.2

## @nhost/react-urql@15.0.2

### Patch Changes

-   @nhost/react@3.11.2

## @nhost/nextjs@2.3.1

### Patch Changes

-   @nhost/react@3.11.2

## @nhost/nhost-js@3.3.1

### Patch Changes

-   Updated dependencies [2f5bc04]
    -   @nhost/hasura-storage-js@2.9.0

## @nhost/react@3.11.2

### Patch Changes

-   @nhost/nhost-js@3.3.1

## @nhost/vue@2.9.8

### Patch Changes

-   @nhost/nhost-js@3.3.1

## @nhost/dashboard@2.35.0

### Minor Changes

-   7633d04: feat (dashbord): Allow composite primary keys
-   c4f383f: fix: dashboard: don't allow for upgrading to starter
- 4c6400f: fix: handle redirect to verify email page if sign in with
github
-   7f0db21: feat: added entraid support
-   412692c: chore (dashboard): Turn on strictNullChecks config

### Patch Changes

- 1708578: fix (dashboard): Update navbar after org and project
operations
-   34ede5c: fix: enable csp again
-   96228df: chore (dashboard): update nhost-js to the latest version
-   d8c5117: fix (dashboard): Allow creating tables without primary key
-   89f6fe6: chore (docker-example): update dashboard image version
- e8a3789: fix (dashboard): scroll to active element in navbar when
navigating

## @nhost/docs@2.35.0

### Minor Changes

- 2f5bc04: fix (hasura-storage-js/docs): use correct way of specifying
metadata\[] in formData
-   7f0db21: feat: added entraid support

### Patch Changes

-   06b47e0: fix: fixes to changes in mintlify breaking our docs
-   d98e73e: fix: workaround for mintlify breaking our docs again

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

### Minor Changes

- 2f5bc04: fix (hasura-storage-js/docs): use correct way of specifying
metadata\[] in formData

### Patch Changes

-   @nhost/nhost-js@3.3.1

## @nhost-examples/cli@0.3.24

### Patch Changes

-   @nhost/nhost-js@3.3.1

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

### Patch Changes

-   @nhost/react@3.11.2
-   @nhost/react-apollo@18.0.2

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

### Patch Changes

-   @nhost/react@3.11.2

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

### Patch Changes

-   @nhost/react@3.11.2
-   @nhost/react-urql@15.0.2

## @nhost-examples/docker-compose@0.4.1

### Patch Changes

-   89f6fe6: chore (docker-example): update dashboard image version

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

### Patch Changes

-   @nhost/nhost-js@3.3.1

## @nhost-examples/nextjs@0.5.1

### Patch Changes

-   @nhost/react@3.11.2
-   @nhost/react-apollo@18.0.2
-   @nhost/nextjs@2.3.1

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

### Patch Changes

-   @nhost/nhost-js@3.3.1

## @nhost-examples/sveltekit@0.8.3

### Patch Changes

-   @nhost/nhost-js@3.3.1

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

### Patch Changes

-   @nhost/react@3.11.2
-   @nhost/react-apollo@18.0.2

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

### Patch Changes

-   @nhost/react@3.11.2

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

### Patch Changes

-   @nhost/react@3.11.2
-   @nhost/react-apollo@18.0.2

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

### Patch Changes

-   @nhost/nhost-js@3.3.1
-   @nhost/apollo@9.0.1
-   @nhost/vue@2.9.8

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

### Patch Changes

-   @nhost/apollo@9.0.1
-   @nhost/vue@2.9.8

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-08-29 16:48:22 +02:00
robertkasza
811b48eccf fix (dashboard): Disable segment (#3450)
### **PR Type**
Enhancement, Bug fix


___

### **Description**
- Disable Segment analytics across the dashboard

- Remove anonId from authentication processes

- Adjust Google Ads initialization with logging


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["Segment Analytics"] -- "Disabled" --> B["Dashboard"]
  C["Authentication"] -- "Remove anonId" --> D["Auth Flows"]
  E["Google Ads"] -- "Add logging" --> F["Initialization"]
```



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>useGithubAuthentication.ts</strong><dd><code>Remove
Segment anonId from GitHub authentication</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/features/auth/AuthProviders/Github/hooks/useGithubAuthentication/useGithubAuthentication.ts

<ul><li>Removed import of <code>getAnonId</code> from Segment<br> <li>
Removed <code>anonId</code> from metadata in authentication options</ul>


</details>


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

</tr>

<tr>
  <td>
    <details>

<summary><strong>useOnSignUpWithPasswordHandler.ts</strong><dd><code>Remove
Segment anonId from email/password sign-up</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/features/auth/SignUp/SignUpTabs/SignUpWithEmailAndPassword/hooks/useOnSignUpWithPasswordHandler.ts

<ul><li>Removed import of <code>getAnonId</code> from Segment<br> <li>
Removed <code>anonId</code> from metadata in sign-up options</ul>


</details>


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

</tr>

<tr>
  <td>
    <details>

<summary><strong>useSignupWithSecurityKeyHandler.ts</strong><dd><code>Remove
Segment anonId from security key sign-up</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/features/auth/SignUp/SignUpTabs/SignUpWithSecurityKey/hooks/useSignupWithSecurityKeyHandler.ts

<ul><li>Removed import of <code>getAnonId</code> from Segment<br> <li>
Removed <code>metadata</code> object with <code>anonId</code> from
sign-up options</ul>


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>SignUpWithGithub.tsx</strong><dd><code>Remove anonId
prop from GitHub sign-up button</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

dashboard/src/features/auth/SignUp/SignUpWithGithub/SignUpWithGithub.tsx

- Removed `withAnonId` prop from `GithubAuthButton` component


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>segment.ts</strong><dd><code>Disable Segment analytics
globally</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/src/lib/segment.ts

<ul><li>Removed imports for <code>isPlatform</code> and
<code>isDevOrStaging</code><br> <li> Set <code>disable</code> option to
<code>true</code> for Segment analytics</ul>


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>signup.tsx</strong><dd><code>Add logging to Google Ads
initialization</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

dashboard/src/pages/signup.tsx

<ul><li>Added console log statements for Google Ads initialization<br>
<li> Added ESLint disable comments for console logs</ul>


</details>


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

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

</details>

___
2025-08-29 16:40:02 +02:00
robertkasza
57987ed3a9 fix (dashboard): update packages because of vulnerability (#3447)
### **PR Type**
Enhancement, Bug fix


___

### **Description**
- Update package dependencies to address vulnerabilities

- Add new security overrides for `tmp` and `devalue`

- Enhance overall project security and stability


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["package.json"] --> B["Update Dependencies"]
  B --> C["Add Security Overrides"]
  C --> D["tmp >= 0.2.4"]
  C --> E["devalue >= 5.3.2"]
```



<details> <summary><h3> File Walkthrough</h3></summary>

<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 package.json with
new security overrides</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

package.json

<ul><li>Added security override for <code>tmp</code> package (version >=
0.2.4)<br> <li> Added security override for <code>devalue</code> package
(version >= 5.3.2)<br> <li> Updated existing security overrides</ul>


</details>


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

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

</details>

___
2025-08-28 08:12:20 +02:00
David Barroso
7f0db210ba feat (dashboard/docs): added entraid support (#3440)
### **PR Type**
Enhancement, Documentation


___

### **Description**
- Added Entra ID support for authentication

- Deprecated Azure AD in favor of Entra ID

- Updated documentation for Entra ID integration

- Modified GraphQL schema to include Entra ID


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["Azure AD"] -->|Deprecated| B["Entra ID"]
  B -->|Added| C["Authentication Methods"]
  D["GraphQL Schema"] -->|Updated| E["Include Entra ID"]
  F["Documentation"] -->|Updated| G["Entra ID Guide"]
```



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Documentation</strong></td><td><details><summary>6
files</summary><table>
<tr>
<td><strong>AzureADProviderSettings.tsx</strong><dd><code>Update Azure
AD description to indicate deprecation</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3440/files#diff-6150a6fccfbe403a8349cd1393f783bad24c0937fad3fe5514d16f1ad0a06ded">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>neat-paws-flash.md</strong><dd><code>Add changeset for Entra
ID support</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></td>
<td><a
href="https://github.com/nhost/nhost/pull/3440/files#diff-05455eeb0f3e19db8a47bda2fbc8d620bdff1a9abe0e40a415dd1a89fdf03284">+6/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>docs.json</strong><dd><code>Add Entra ID to documentation
navigation</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3440/files#diff-873ce17c654718debe2fe308a2f2279bde8663686423c51f97fab2dd0722b8d9">+1/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>overview.mdx</strong><dd><code>Add Entra ID to OAuth
providers list</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3440/files#diff-fcb8a858a73ee17bb801d63453716d58b940d7b1e51f48c5fb184e34971866f2">+2/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>sign-in-azuread.mdx</strong><dd><code>Add deprecation
warning for Azure AD</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3440/files#diff-1dc8d804f0d233fb4a540f9bfa2ce768de2d1164645240923a2ab6f22c7efc39">+2/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>sign-in-entraid.mdx</strong><dd><code>Add new documentation
for Entra ID sign-in</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3440/files#diff-3abbff0cd035a60ceda760d1f82c74ff93bd3567897d2bbef7c421e8d28cfe20">+47/-0</a>&nbsp;
&nbsp; </td>

</tr>

</table></details></td></tr><tr><td><strong>Enhancement</strong></td><td><details><summary>5
files</summary><table>
<tr>
<td><strong>EntraIDProviderSettings.tsx</strong><dd><code>Add new Entra
ID provider settings component</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/3440/files#diff-5153daa8ad16e43f0246a74b57935910415c968fb14a149e0c38eef3beae7329">+225/-0</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>index.ts</strong><dd><code>Create index file for Entra ID
provider settings</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3440/files#diff-942638473827ec8cea7e0530dd0b45cd41fbfed4c8535b4b45a2ba44d17b98ca">+1/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>sign-in-methods.tsx</strong><dd><code>Add Entra ID provider
to sign-in methods page</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3440/files#diff-e9726f37d2b20d7802e29c8d9b202e6ccce35ce82a4993fb9bc0a22ea5601d5f">+2/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>graphql.ts</strong><dd><code>Update GraphQL schema to
include Entra ID types</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3440/files#diff-fbd5db84b560b1c91675004448c6c7fa0dcbfb28b9eb05d53b03e6cb7b83ebac">+43/-1</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>getSignInMethods.graphql</strong><dd><code>Update GraphQL
query to include Entra ID fields</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3440/files#diff-31ad2ccce8e92a85c9e8e22285150a9e0bc042d2dd449706d9ef44aca8606ee9">+6/-0</a>&nbsp;
&nbsp; &nbsp; </td>

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

</details>

___
2025-08-26 15:42:02 +02:00
robertkasza
d8c5117046 fix (dashboard): Allow creating tables without primary key (#3441)
### **PR Type**
Bug fix


___

### **Description**
- Allow creating database tables without primary key

- Update logic to handle empty primary key values


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["Table Creation"] --> B["Primary Key Check"]
  B -- "Empty" --> C["Skip Primary Key"]
  B -- "Not Empty" --> D["Add Primary Key"]
```



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Bug
fix</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>prepareCreateTableQuery.ts</strong><dd><code>Update
primary key check in table creation query</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/features/orgs/projects/database/dataGrid/hooks/useCreateTableMutation/prepareCreateTableQuery.ts

<ul><li>Modified condition to check for non-empty primary key<br> <li>
Uses <code>isNotEmptyValue</code> function to validate primary key</ul>


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>little-coats-call.md</strong><dd><code>Add changeset
for dashboard patch update</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></summary>
<hr>

.changeset/little-coats-call.md

<ul><li>Added changeset file for patch update<br> <li> Describes fix for
creating tables without primary key</ul>


</details>


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

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

</details>

___
2025-08-26 15:18:19 +02:00
robertkasza
7633d04121 feat (dashboard): Allow composite keys (#3424)
### **PR Type**
Enhancement


___

### **Description**
- Allow composite primary keys in tables

- Update UI to support multiple primary keys

- Modify backend logic for primary key handling

- Adjust tests for new primary key functionality


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["Single Primary Key"] -- "Extend to" --> B["Composite Primary Keys"]
  B -- "Update" --> C["UI Components"]
  B -- "Modify" --> D["Backend Logic"]
  B -- "Adjust" --> E["Tests"]
```



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Tests</strong></td><td><details><summary>7
files</summary><table>
<tr>
<td><strong>create-table.test.ts</strong><dd><code>Update tests for
composite primary keys</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3424/files#diff-1e7aa9f3e379ca90a94b82c14be48e2c98a722d85ee1b0785a082b7076d8e58c">+38/-8</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>delete-table.test.ts</strong><dd><code>Modify delete table
tests for new primary key structure</code>&nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3424/files#diff-9e8c87f8e8f11bcfa2b7b2e5cf9dffe54a0fdeb3385ccb82b74e4e1c18fb9c43">+3/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>permissions-table.test.ts</strong><dd><code>Adjust
permissions table tests for composite keys</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3424/files#diff-f4b586f5b8f3bb97ddf64f8f38c461ac0424e101789f61e325d1b80bb8dc1047">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>PrimaryKeyRow.test.tsx</strong><dd><code>Add tests for
PrimaryKeyRow component</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3424/files#diff-19ffdca665913249d140f824acdd7e3742daf7cc9efb4ebd4dd6e69c2e74dff0">+105/-0</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>PrimaryKeySelect.test.tsx</strong><dd><code>Add tests for
PrimaryKeySelect component</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3424/files#diff-3502ffb4e30888c495a7aac784a9f018ab42e3b374b8716b92c72165f9ea52b7">+159/-0</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>prepareCreateTableQuery.test.ts</strong><dd><code>Update
create table query tests for composite keys</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3424/files#diff-348ba7ca6fc037a9d0de76a24efc36846c634d82755bbf33dd5062a7face06ec">+6/-6</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>prepareUpdateTableQuery.test.ts</strong><dd><code>Adjust
update table query tests for new primary key structure</code></dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3424/files#diff-57c2f882497d653700d68905bb54c891592a6bf302040d3008d624900f1bdf64">+7/-7</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

</table></details></td></tr><tr><td><strong>Enhancement</strong></td><td><details><summary>13
files</summary><table>
<tr>
<td><strong>utils.ts</strong><dd><code>Update utility functions to
support multiple primary keys</code></dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3424/files#diff-490448aa83585151d8c61d698273c43486fdcac6a5d28a9b7e5be2729bbffd12">+12/-8</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>IconButton.tsx</strong><dd><code>Add disabled prop to
IconButton interface</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3424/files#diff-b83e92498e35096782ffeaafbae74794026da0f75d0a48c489efd23e3b255b6d">+3/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>BaseTableForm.tsx</strong><dd><code>Refactor BaseTableForm
for composite primary keys</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3424/files#diff-33e0bcf77738162f71af2ab673966d2e61d1e270ad09179c23e2d29d18582f80">+11/-10</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>ColumnEditorRow.tsx</strong><dd><code>Update ColumnEditorRow
for new primary key structure</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3424/files#diff-4bbb8e759f348b872cff14e3d2f0339f1e7138b4b71d75c2d7b2bc58333b18ce">+1/-54</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>PrimaryKeyRow.tsx</strong><dd><code>Implement PrimaryKeyRow
component for multiple primary keys</code></dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3424/files#diff-8dcde8064e12fdfc7d5361ab791644e8a17383b18ded898969ca84d54f24920a">+45/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>PrimaryKeySelect.tsx</strong><dd><code>Implement
PrimaryKeySelect component for composite keys</code>&nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3424/files#diff-f2e73f580c635656112d25f47243027e936e8cc09edd43597b21132517207c5b">+92/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>index.ts</strong><dd><code>Add index file for PrimaryKeyRow
component</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3424/files#diff-e0def2b671d157fb86f15f7ef5e47d4155119ae8be4c153da46d6907611ebe6c">+1/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>PrimaryKeySelect.tsx</strong><dd><code>Remove old
PrimaryKeySelect component</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3424/files#diff-a72fdfc5e09e373d8bc16bd33f39bf9f59b8ea3e39702c5f0d0e0f5f67da92ae">+0/-49</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>RemoveButton.tsx</strong><dd><code>Implement RemoveButton
component for primary keys</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3424/files#diff-99f91e5bded6fc202a11683c619572d9e4c4a38fe7c3a63b88093c0757a9f5de">+63/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>CreateTableForm.tsx</strong><dd><code>Update CreateTableForm
for composite primary keys</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3424/files#diff-ccbaedba43e2b50ee80f458d1ff1dc37739dae73f266e1f18aeaebb427be1c4c">+12/-2</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>EditTableForm.tsx</strong><dd><code>Modify EditTableForm to
handle multiple primary keys</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3424/files#diff-e628e74884ed048e1498960b80ad4d2a9fa6b4e05c89545c404e0ed50b43e50a">+25/-6</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>prepareUpdateTableQuery.ts</strong><dd><code>Refactor update
table query preparation for composite keys</code></dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3424/files#diff-24dec66b099f48969413c6744a5b69e18e06f3c3df41ed7c712b4a0f31994f5c">+28/-12</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>dataBrowser.ts</strong><dd><code>Update DatabaseTable
interface for composite primary keys</code></dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3424/files#diff-33c6810dbd7e2910c86a15009467a348f064380b0e1dd787ef320b4e7543403b">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

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

</details>

___
2025-08-26 08:29:28 +02:00
robertkasza
e8a378906a fix (dashboard): scroll to active element in navbar when navigating (#3431)
### **PR Type**
Bug fix, Enhancement


___

### **Description**
- Scroll to active element in navbar when navigating

- Update react-complex-tree package to version 2.6.0

- Fix database slug in ProjectPagesComboBox component

- Improve NavTree component styling and focus handling


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["Navbar Navigation"] --> B["Scroll to Active"]
  A --> C["Update react-complex-tree"]
  D["Database Slug"] --> E["Fix in ProjectPagesComboBox"]
  F["NavTree Component"] --> G["Improve Styling"]
  F --> H["Enhance Focus Handling"]
```



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Bug
fix</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>ProjectPagesComboBox.tsx</strong><dd><code>Fix database
slug in ProjectPagesComboBox</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></summary>
<hr>

dashboard/src/components/layout/Header/ProjectPagesComboBox.tsx

- Fixed database slug by removing leading slash


</details>


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

</tr>
</table></td></tr><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>NavTree.tsx</strong><dd><code>Enhance NavTree styling
and focus handling</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

dashboard/src/components/layout/MainNav/NavTree.tsx

<ul><li>Improved styling for focused items using object syntax<br> <li>
Enhanced readability and maintainability of className conditional</ul>


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>PinnedMainNav.tsx</strong><dd><code>Implement scroll to
active element in navbar</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

dashboard/src/components/layout/MainNav/PinnedMainNav.tsx

<ul><li>Added attribute filter to MutationObserver for class changes<br>
<li> Improved scrolling to active element when navigating</ul>


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>rude-carrots-unite.md</strong><dd><code>Add changeset
for navbar navigation fix</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

.changeset/rude-carrots-unite.md

<ul><li>Added changeset file for patch update<br> <li> Described fix for
scrolling to active element in navbar</ul>


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3431/files#diff-c1f5c9ca73815ce214e78fa0a5fc675cc4b33f5dc31a136b067e36aa097cd83c">+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>Update
react-complex-tree dependency</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

dashboard/package.json

- Updated react-complex-tree package from 2.4.5 to 2.6.0


</details>


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

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

</details>

___
2025-08-25 12:21:41 +02:00
David Barroso
34ede5cf2c fix (dashboard): enable csp again (#3439)
### **PR Type**
Enhancement, Security


___

### **Description**
- Re-enable Content Security Policy (CSP) for production

- Disable CSP headers in development environment

- Improve security configuration in Next.js


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["Environment Check"] --> B{"Is Production?"}
  B -->|Yes| C["Apply CSP"]
  B -->|No| D["Skip CSP"]
  C --> E["Apply Other Security Headers"]
  D --> E
```



<details> <summary><h3> File Walkthrough</h3></summary>

<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>Conditional CSP
application based on environment</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

dashboard/next.config.js

<ul><li>Added environment check for CSP application<br> <li> Re-enabled
Content-Security-Policy header<br> <li> Removed commented-out CSP
code</ul>


</details>


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

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

</details>

___
2025-08-25 09:50:45 +02:00
David Barroso
2deeb39a28 chore (ci): encrypt traces (#3437)
### **PR Type**
Enhancement, Other


___

### **Description**
- Implement encryption for Playwright reports

- Update artifact upload process for encrypted reports

- Remove file name transformation step

- Adjust conditional checks for report handling


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["Playwright Test Failure"] --> B["Encrypt Report"]
  B --> C["Upload Encrypted Artifact"]
  C --> D["Secure Storage"]
```



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>ci.yaml</strong><dd><code>Implement encryption and
streamline Playwright report handling</code></dd></summary>
<hr>

.github/workflows/ci.yaml

<ul><li>Added step to encrypt Playwright report using OpenSSL<br> <li>
Updated artifact upload to use encrypted report<br> <li> Removed file
name transformation step<br> <li> Adjusted conditional checks for report
handling</ul>


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3437/files#diff-944291df2c9c06359d37cc8833d182d705c9e8c3108e7cfe132d61a06e9133dd">+15/-10</a>&nbsp;
</td>

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

</details>

___
2025-08-22 12:52:55 +02:00
David Barroso
d98e73e57e fix (docs): workaround for mintlify breaking our docs again (#3436)
### **PR Type**
Bug fix, Documentation


___

### **Description**
- Fix Mintlify documentation breaking issue

- Update file naming convention for JWKS endpoint

- Adjust docs.json to reflect new file name

- Add metadata to JWKS endpoint documentation file


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["Mintlify breaking issue"] --> B["File renaming"]
  B --> C["docs.json update"]
  B --> D["Metadata addition"]
  C --> E["Fixed documentation"]
  D --> E
```



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Bug
fix</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>docs.json</strong><dd><code>Update JWKS endpoint file
reference in docs.json</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

docs/docs.json

<ul><li>Updated file path for JWKS endpoint documentation<br> <li>
Changed <code>get-.well-known-jwks.json</code> to
<code>get-.well-known-jwks_json</code></ul>


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>get-.well-known-jwks_json.mdx</strong><dd><code>Add
metadata to JWKS endpoint documentation file</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

docs/reference/auth/get-.well-known-jwks_json.mdx

<ul><li>Added frontmatter metadata to the file<br> <li> Included title
and OpenAPI reference for the JWKS endpoint</ul>


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3436/files#diff-70bc360afe951a74a46fadda220916c5248dde71aeb2b99e2d641e748d501524">[link]</a>&nbsp;
&nbsp; </td>

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

</details>

___
2025-08-22 09:24:17 +02:00
David BM
4c6400fc52 fix (dashboard): GitHub verify email redirect (#3434) 2025-08-20 10:35:38 +02:00
Nuno Pato
c4f383f695 fix: dashboard: show correct plan prices (#3428)
### **PR Type**
Bug fix


___

### **Description**
- Fixed pricing display for subscription plans

- Prevented upgrading to starter plan

- Updated logic for free plan identification


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["Subscription Plan Component"] --> B["Price Display"]
  A --> C["Plan Upgrade"]
  B --> D["Use `plan.isFree` instead of `isFreeOrg`"]
  C --> E["Restrict upgrade to starter"]
```



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Bug
fix</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>SubscriptionPlan.tsx</strong><dd><code>Update free plan
detection and price display</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/features/orgs/components/billing/SubscriptionPlan/SubscriptionPlan.tsx

<ul><li>Changed condition for displaying 'Free' from
<code>isFreeOrg</code> to <code>plan.isFree</code><br> <li> Updated
price display logic in the subscription plan component</ul>


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>great-bugs-leave.md</strong><dd><code>Add changeset for
dashboard upgrade restriction</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

.changeset/great-bugs-leave.md

<ul><li>Added changeset file to document the fix<br> <li> Specified
minor version bump for @nhost/dashboard<br> <li> Described preventing
upgrade to starter plan</ul>


</details>


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

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

</details>

___

---------

Co-authored-by: robertkasza <167509084+robertkasza@users.noreply.github.com>
2025-08-19 16:53:23 +00:00
robertkasza
1708578f8f fix (dashboard): Update navbar after org and project operations (#3433)
### **PR Type**
Bug fix, Enhancement


___

### **Description**
- Update navbar after organization and project operations

- Remove unnecessary useMemo and refetch calls

- Improve UI responsiveness in upgrade process

- Add changeset for patch version bump


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["NavTree Component"] -- "Remove useMemo" --> B["Improved Performance"]
  C["FinishUpgradeOrganizationProcess"] -- "Remove refetchOrgs" --> D["Optimized Upgrade Flow"]
  E["Changeset"] -- "Add patch version" --> F["Version Control"]
```



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>NavTree.tsx</strong><dd><code>Optimize NavTree
rendering by removing useMemo</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

dashboard/src/components/layout/MainNav/NavTree.tsx

<ul><li>Removed useMemo hook for navTree calculation<br> <li> Directly
call buildNavTreeData function with org</ul>


</details>


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

</tr>

<tr>
  <td>
    <details>

<summary><strong>FinishUpgradeOrganizationProcess.tsx</strong><dd><code>Streamline
organization upgrade process</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/features/orgs/components/billing/FinishUpgradeOrganizationProcess/FinishUpgradeOrganizationProcess.tsx

<ul><li>Removed useOrgs hook and refetchOrgs call<br> <li> Set
hideCloseButton initial state to true<br> <li> Removed unnecessary await
for refetchOrgs</ul>


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>few-fans-collect.md</strong><dd><code>Add changeset for
dashboard patch update</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></summary>
<hr>

.changeset/few-fans-collect.md

<ul><li>Added new changeset file for patch version bump<br> <li>
Included description of navbar update fix</ul>


</details>


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

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

</details>

___
2025-08-19 15:11:02 +02:00
robertkasza
96228dfe69 chore (dashboard): update nhost-js to the latest version (#3423)
### **PR Type**
Enhancement


___

### **Description**
- Update `@nhost/nhost-js` to version 5.0.0-beta.9

- Add changeset for patch update to `@nhost/dashboard`


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["Old Version"] -- "Update" --> B["New Version"]
  B -- "Patch" --> C["@nhost/dashboard"]
```



<details> <summary><h3> File Walkthrough</h3></summary>

<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>hip-zebras-brake.md</strong><dd><code>Add changeset for
dashboard patch update</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></summary>
<hr>

.changeset/hip-zebras-brake.md

<ul><li>Add new changeset file for patch update<br> <li> Specify update
for <code>@nhost/dashboard</code> package</ul>


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3423/files#diff-f09c9c310fdc68df24300582060be3d86c38f269a9fa8fb1a9cccc60b3ac407b">+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>Update nhost-js
dependency version</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

dashboard/package.json

<ul><li>Update <code>@nhost/nhost-js-beta</code> from version
5.0.0-beta.8 to 5.0.0-beta.9</ul>


</details>


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

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

</details>

___
2025-08-14 10:30:48 +02:00
David Barroso
2f5bc04e0c fix (hasura-storage-js/docs): use correct way of specifying metadata[] in formData (#3418)
### **PR Type**
Bug fix


___

### **Description**
- Fix metadata[] specification in formData for file uploads

- Use Blob with JSON.stringify for metadata[] in multiple files

- Update documentation and example code for correct usage

- Ensure compatibility across different environments (browser/Node.js)


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["Old metadata[] handling"] --> B["New metadata[] handling"]
  B --> C["Use Blob"]
  C --> D["JSON.stringify"]
  D --> E["Set content type"]
  E --> F["Empty filename"]
```



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Bug
fix</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>hasura-storage-api.ts</strong><dd><code>Update
metadata[] handling in file upload</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></summary>
<hr>

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

<ul><li>Replace direct JSON.stringify with Blob for metadata[]<br> <li>
Set content type to 'application/json'<br> <li> Add empty string as
third argument for filename</ul>


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>upload-file.mdx</strong><dd><code>Update documentation
for correct metadata[] usage</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

docs/reference/storage/upload-file.mdx

<ul><li>Update example code for correct metadata[] usage<br> <li> Use
Blob with JSON.stringify for metadata[]<br> <li> Set content type and
add empty filename</ul>


</details>


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

</tr>
</table></td></tr><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>uploadFormData.mjs</strong><dd><code>Update example
code for correct metadata[] handling</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></summary>
<hr>

examples/node-storage/src/uploadFormData.mjs

<ul><li>Update example code for multiple file uploads<br> <li> Use Blob
with JSON.stringify for each metadata[] entry<br> <li> Set content type
and add empty filename for each entry</ul>


</details>


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

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

</details>

___
2025-08-13 14:16:56 +02:00
David Barroso
06b47e0fb9 fix (docs): fixes to changes in mintlify breaking our docs (#3422)
### **PR Type**
Bug fix, Documentation


___

### **Description**
- Update Mintlify dependency to fix documentation issues

- Adjust CSS for better display of hero section

- Ensure proper styling in both light and dark modes


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["Mintlify Update"] --> B["CSS Adjustments"]
  B --> C["Hero Section Display"]
  B --> D["Light/Dark Mode Styling"]
```



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>style.css</strong><dd><code>Enhance hero section
display and mode-specific styling</code>&nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

docs/style.css

<ul><li>Added <code>display: inline-block;</code> to hero section h1<br>
<li> Adjusted styling for welcome-hero and welcome-get-started
sections<br> <li> Ensured proper color contrast in light and dark
modes</ul>


</details>


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

</tr>
</table></td></tr><tr><td><strong>Dependencies</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>package.json</strong><dd><code>Update Mintlify
dependency to latest version</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

docs/package.json

- Updated Mintlify dependency from version 4.0.476 to 4.2.67


</details>


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

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

</details>

___
2025-08-13 10:38:55 +02:00
robertkasza
412692c2f6 chore (dashboard): turn on null checks (#3390) 2025-08-12 15:45:49 +02:00
robertkasza
89f6fe6346 chore (docker-example): update dashboard image version (#3420)
### **PR Type**
Enhancement, Documentation


___

### **Description**
- Update dashboard image version in docker-compose.yaml

- Improve DialogTitle styling in SubscriptionPlan component

- Add changeset for version bump documentation


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["Docker Compose"] --> B["Dashboard Image"]
  B --> C["Version 2.34.0"]
  D["SubscriptionPlan Component"] --> E["DialogTitle Styling"]
  F["Changeset"] --> G["Version Documentation"]
```



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>docker-compose.yaml</strong><dd><code>Update dashboard
image version in docker-compose</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

examples/docker-compose/docker-compose.yaml

- Update `nhost/dashboard` image version from 2.20.0 to 2.34.0


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>SubscriptionPlan.tsx</strong><dd><code>Enhance
DialogTitle styling in SubscriptionPlan component</code></dd></summary>
<hr>


dashboard/src/features/orgs/components/billing/SubscriptionPlan/SubscriptionPlan.tsx

<ul><li>Add <code>className="pr-3"</code> to DialogTitle in
SubscriptionPlan component<br> <li> Improve layout of DialogTitle by
wrapping content</ul>


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>quick-kangaroos-perform.md</strong><dd><code>Add
changeset for version documentation</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

.changeset/quick-kangaroos-perform.md

<ul><li>Add new changeset file for version bump documentation<br> <li>
Include patch updates for docker-compose example and dashboard</ul>


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3420/files#diff-713b8652a6e08329df8c0d54a9e596ab60c2bc6c376cd8684dcaae5fc2af36da">+6/-0</a>&nbsp;
&nbsp; &nbsp; </td>

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

</details>

___
2025-08-12 13:21:25 +02:00
github-actions[bot]
2e34d7b9d0 chore: update versions (#3383)
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/nextjs@2.3.0

### Minor Changes

-   b8cb491: fix: update dependencies to fix vulnerabilities

## @nhost/dashboard@2.34.0

### Minor Changes

-   7eb9539: feat (dashboard): Allow upgrading free organizations
-   129ec1e: feat: dashboard: new onboarding
-   59249e5: fix: elevate permissions in password reset
-   5e9ddb4: fix: show Run service name in logs page
- 4ffff86: fix (dashboard): Disable settings pages when config server
env variable is not set
-   b8cb491: fix: update dependencies to fix vulnerabilities
- 5565451: fix: support page, can scroll all the way down in Chrome for
iOS
-   f7d7080: chore: dashboard: add gtag

### Patch Changes

-   181c0ab: fix (dashboard): Fix upgrade project e2e tests
- 56c87da: fix (dashboard): Use the correct http method when conneting
to new github
-   00132bd: fix (dashboard): Clear isSigningOut variable on Signin page
- 66e0cc8: fix (dashboard): Check if user is logged in before
redirecting
-   9c0a118: chore (dashboard): Add RetryLink to ApolloClient
-   df6b85e: fix (dashboard): fix password reset redirect url
-   ec24567: fix (dashboard): Add content-type header
-   57b2615: chore (dashboard): refactor redirect behaviour
- cffa161: fix (dashboard): disable settings in the header when
self-hosting
- 85316e8: fix (dashboard): Remove second loading indicator on projects
page
- 47ab341: fix (dashboard): Fix announcement layout when title is too
short

## @nhost/docs@2.34.0

### Minor Changes

- 40439b9: chore: updated postgres extension and added new custom claims
default option

### Patch Changes

-   906620a: fix: functions: added response payload limit

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

### Minor Changes

-   b8cb491: fix: update dependencies to fix vulnerabilities

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

### Minor Changes

-   b8cb491: fix: update dependencies to fix vulnerabilities

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

### Minor Changes

-   b8cb491: fix: update dependencies to fix vulnerabilities

## @nhost-examples/nextjs@0.5.0

### Minor Changes

-   b8cb491: fix: update dependencies to fix vulnerabilities

### Patch Changes

-   Updated dependencies [b8cb491]
    -   @nhost/nextjs@2.3.0

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

### Minor Changes

-   b8cb491: fix: update dependencies to fix vulnerabilities

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-08-12 09:37:10 +02:00
robertkasza
66e0cc8261 fix (dashboard): Check if user is logged in before redirecting (#3419)
### **PR Type**
Bug fix


___

### **Description**
- Check user authentication before redirecting

- Prevent unnecessary redirects for unauthenticated users

- Update logic in OrganizationGuard and ProjectLayoutContent

- Add isUserLoggedIn check in IndexPage component


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["User Authentication"] --> B["isUserLoggedIn"]
  B --> C{"Redirect?"}
  C -->|Yes| D["Authenticated Redirect"]
  C -->|No| E["No Redirect"]
```



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Bug
fix</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>OrganizationGuard.tsx</strong><dd><code>Add
authentication check in OrganizationGuard</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

dashboard/src/features/orgs/layout/OrgLayout/OrganizationGuard.tsx

<ul><li>Import useAuth hook<br> <li> Add isUserLoggedIn check<br> <li>
Update useEffect dependency array<br> <li> Modify return statement
condition</ul>


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>ProjectLayoutContent.tsx</strong><dd><code>Implement
user authentication check in ProjectLayoutContent</code></dd></summary>
<hr>

dashboard/src/features/orgs/layout/OrgLayout/ProjectLayoutContent.tsx

<ul><li>Import useAuth hook<br> <li> Add isUserLoggedIn check<br> <li>
Update useEffect and conditional rendering</ul>


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>index.tsx</strong><dd><code>Add authentication check
for IndexPage navigation</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></summary>
<hr>

dashboard/src/pages/index.tsx

<ul><li>Import useAuth hook<br> <li> Add isUserLoggedIn check<br> <li>
Update navigateToSlug function</ul>


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>mighty-kids-double.md</strong><dd><code>Add changeset
for dashboard authentication fix</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

.changeset/mighty-kids-double.md

- Add changeset for patch update


</details>


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

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

</details>

___
2025-08-12 08:38:32 +02:00
robertkasza
7eb9539807 feat (dashboard): Allow upgrading free organizations (#3411)
### **PR Type**
Enhancement, Bug fix


___

### **Description**
- Allow upgrading free organizations to paid plans

- Refactor transfer project dialog and related components

- Update billing estimate and subscription plan components

- Fix issues in e2e tests and dialog components


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["Free Org"] -- "Upgrade" --> B["Paid Org"]
  C["Transfer Dialog"] -- "Refactor" --> D["New Components"]
  E["Billing UI"] -- "Update" --> F["New Features"]
  G["E2E Tests"] -- "Fix" --> H["Improved Reliability"]
```



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody></tr></tbody></table>

</details>

___
2025-08-11 16:03:39 +02:00
David Barroso
906620a755 fix (docs): functions: added response payload limit (#3416)
### **PR Type**
Documentation


___

### **Description**
- Added response payload limit information

- Clarified execution timeout limits by project tier

- Improved structure of limits section in documentation


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["Functions Limits"] --> B["Execution Timeout"]
  A --> C["Response Payload"]
  B --> D["Tier-specific timeouts"]
  C --> E["6MB hard limit"]
```



<details> <summary><h3> File Walkthrough</h3></summary>

<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>cool-toes-impress.md</strong><dd><code>Add changeset
for functions documentation update</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

.changeset/cool-toes-impress.md

<ul><li>Added changeset file for documentation update<br> <li> Specified
patch version bump for '@nhost/docs'<br> <li> Described fix for
functions response payload limit</ul>


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>overview.mdx</strong><dd><code>Update Functions limits
documentation with payload limit</code>&nbsp; </dd></summary>
<hr>

docs/products/functions/overview.mdx

<ul><li>Added new "Response Payload" subsection under "Limits"<br> <li>
Introduced 6MB hard limit for response payloads<br> <li> Restructured
"Limits" section with "Execution Timeout" subsection</ul>


</details>


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

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

</details>

___
2025-08-11 09:03:16 +02:00
David BM
5e9ddb41d2 fix (dashboard): show run service name in logs page (#3415) 2025-08-08 10:38:06 +02:00
robertkasza
00132bd961 fix (dashboard): Clear isSigningOut variable on Signin page (#3410)
### **PR Type**
Bug fix


___

### **Description**
- Clear isSigningOut variable on Signin page

- Add clearIsSigningOut function to AuthContext

- Implement clearIsSigningOut in AuthProvider

- Use clearIsSigningOut in signin page useEffect


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["AuthContext"] -- "Add clearIsSigningOut" --> B["AuthProvider"]
  B -- "Implement clearIsSigningOut" --> C["Signin Page"]
  C -- "Use clearIsSigningOut" --> D["Clear isSigningOut"]
```



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Debugging</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>AuthenticatedLayout.tsx</strong><dd><code>Add debug
logging in AuthenticatedLayout</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/components/layout/AuthenticatedLayout/AuthenticatedLayout.tsx

<ul><li>Added console.log for debugging isPlatform, isLoading, and
<br>isSigningOut states</ul>


</details>


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

</tr>
</table></td></tr><tr><td><strong>Bug fix</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>signin.tsx</strong><dd><code>Implement isSigningOut
state clearing on Signin page</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

dashboard/src/pages/signin.tsx

<ul><li>Import useAuth hook and useEffect<br> <li> Add useEffect to
clear isSigningOut state on component mount<br> <li> Destructure
clearIsSigningOut from useAuth</ul>


</details>


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

</tr>
</table></td></tr><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>AuthContext.ts</strong><dd><code>Add clearIsSigningOut
to AuthContext</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

dashboard/src/providers/Auth/AuthContext.ts

<ul><li>Add clearIsSigningOut function to AuthContextType<br> <li>
Include clearIsSigningOut in default AuthContext value</ul>


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>AuthProvider.tsx</strong><dd><code>Implement
clearIsSigningOut in AuthProvider</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

dashboard/src/providers/Auth/AuthProvider.tsx

<ul><li>Implement clearIsSigningOut function in AuthProvider<br> <li>
Add clearIsSigningOut to the context value object</ul>


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>clever-dots-complain.md</strong><dd><code>Add changeset
for isSigningOut fix</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

.changeset/clever-dots-complain.md

<ul><li>Add changeset file for patch update to @nhost/dashboard<br> <li>
Describe the fix for clearing isSigningOut variable on Signin page</ul>


</details>


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

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

</details>

___
2025-08-06 15:06:13 +02:00
robertkasza
57b26152e4 chore (dashboard): refactor redirect behaviour (#3403)
### **PR Type**
Enhancement, Bug fix


___

### **Description**
- Refactor redirect behavior in dashboard

- Implement OrganizationGuard for project access control

- Add ProjectLayoutContent for improved layout management

- Update tests for new components and hooks

- Fix minor issues in existing components


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["AuthenticatedLayout"] --> B["OrganizationGuard"]
  B --> C["ProjectLayoutContent"]
  C --> D["Project-specific components"]
  E["useNotFoundRedirect"] --> F["404 Redirect"]
  G["useProjectWithState"] --> H["Project Data"]
```



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody></tr></tbody></table>

</details>

___
2025-08-05 08:40:37 +02:00
David BM
5565451f18 fix (dashboard): support page, can scroll all the way down in Chrome for iOS (#3408)
### **PR Type**
Bug fix


___

### **Description**
- Fixed scrolling issue on support page for Chrome iOS

- Changed container height from 'h-screen' to 'h-full'

- Added changeset for version tracking


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["Support Page"] -- "Height Change" --> B["Full Scrolling"]
  C["Changeset"] -- "Version Update" --> D["@nhost/dashboard"]
```



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Bug
fix</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>index.tsx</strong><dd><code>Adjust support page
container height for better scrolling</code></dd></summary>
<hr>

dashboard/src/pages/support/index.tsx

<ul><li>Changed container height from 'h-screen' to 'h-full'<br> <li>
Allows full scrolling on Chrome for iOS</ul>


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>stupid-phones-act.md</strong><dd><code>Add changeset
for version tracking</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>

.changeset/stupid-phones-act.md

<ul><li>Added new changeset file<br> <li> Specifies minor version bump
for '@nhost/dashboard'<br> <li> Describes the fix for support page
scrolling</ul>


</details>


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

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

</details>

___
2025-08-01 09:21:34 +02:00
Nuno Pato
4b18e02ad2 fix: dashboard: don't upgrade to starter (#3407)
### **PR Type**
Enhancement


___

### **Description**
- Disable upgrade to Starter plan

- Add visual cues for disabled Starter plan

- Improve user interface for plan selection

- Enhance accessibility and user experience


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["Plan Selection"] --> B["Identify Starter Plan"]
  B --> C["Disable Starter Option"]
  C --> D["Visual Feedback"]
  D --> E["Improved UX"]
```



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>SubscriptionPlan.tsx</strong><dd><code>Disable and
style Starter plan in subscription selection</code>&nbsp;
</dd></summary>
<hr>


dashboard/src/features/orgs/components/billing/components/SubscriptionPlan/SubscriptionPlan.tsx

<ul><li>Added logic to identify Starter plan<br> <li> Disabled radio
button for Starter plan<br> <li> Applied opacity and cursor styles to
Starter plan<br> <li> Refactored plan mapping for better
readability</ul>


</details>


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

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

</details>

___
2025-07-31 14:19:41 +00:00
robertkasza
181c0ab19d fix (dashboard): Fix upgrade project e2e tests (#3406)
### **PR Type**
Bug fix, Tests


___

### **Description**
- Fix upgrade project e2e tests in dashboard

- Add organization type selection in upgrade process

- Update header class in AuthenticatedLayout component

- Include changeset for patch update


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["E2E Test"] -- "Add org type selection" --> B["Upgrade Process"]
  C["AuthenticatedLayout"] -- "Update header class" --> D["UI Improvement"]
  E["Changeset"] -- "Document patch" --> F["Version Control"]
```



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Tests</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>upgrade-project.test.ts</strong><dd><code>Add
organization type selection in upgrade test</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

dashboard/e2e/upgrade-project/upgrade-project.test.ts

<ul><li>Add steps to select organization type<br> <li> Choose 'Personal
Project' as the organization type<br> <li> Improve test flow for project
upgrade process</ul>


</details>


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

</tr>
</table></td></tr><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>AuthenticatedLayout.tsx</strong><dd><code>Modify Header
className in AuthenticatedLayout</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/components/layout/AuthenticatedLayout/AuthenticatedLayout.tsx

- Update Header className to include 'hello_there'


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>big-bananas-roll.md</strong><dd><code>Add changeset for
dashboard patch update</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></summary>
<hr>

.changeset/big-bananas-roll.md

<ul><li>Add changeset file for patch update<br> <li> Document fix for
upgrade project e2e tests</ul>


</details>


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

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

</details>

___
2025-07-31 10:58:04 +02:00
robertkasza
939a158917 chore (dashboard): re-enable upgrade project e2e tests (#3401)
### **PR Type**
Enhancement, Tests


___

### **Description**
- Re-enable upgrade project e2e tests for dashboard

- Remove temporary comment disabling the tests

- Adjust CI workflow to include upgrade tests


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["Disabled Tests"] -- "Re-enable" --> B["Upgrade Project E2E Tests"]
  B -- "Include in" --> C["CI Workflow"]
```



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>ci.yaml</strong><dd><code>Re-enable Dashboard upgrade
project e2e tests in CI</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

.github/workflows/ci.yaml

<ul><li>Removed comments disabling upgrade project e2e tests<br> <li>
Re-enabled the "Run Upgrade project Dashboard e2e tests" step<br> <li>
Kept the timeout and filter conditions unchanged</ul>


</details>


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

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

</details>

___
2025-07-30 15:27:43 +02:00
robertkasza
9c0a118721 chore (dashboard): Add RetryLink to ApolloClient (#3400)
### **User description**
The default config for the RetryLink:
```
new RetryLink({
  delay: {
    initial: 300,
    max: Infinity,
    jitter: true
  },
  attempts: {
    max: 5,
    retryIf: (error, _operation) => !!error
  }
});
```

Source:
https://www.apollographql.com/docs/react/api/link/apollo-link-retry


___

### **PR Type**
Enhancement


___

### **Description**
- Added RetryLink to ApolloClient for improved network resilience

- Implemented in dashboard's createApolloClient function

- RetryLink added to Apollo link chain

- Updated changeset for @nhost/dashboard patch


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["ApolloClient"] --> B["Link Chain"]
  B --> C["RetryLink"]
  C --> D["SplitLink"]
  D --> E["WSLink/HTTPLink"]
```



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>createApolloClient.ts</strong><dd><code>Integrate
RetryLink into ApolloClient configuration</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

dashboard/src/providers/Apollo/createApolloClient.ts

<ul><li>Imported RetryLink from '@apollo/client/link/retry'<br> <li>
Created new RetryLink instance<br> <li> Added RetryLink to the Apollo
link chain</ul>


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>rude-days-punch.md</strong><dd><code>Add changeset for
RetryLink implementation</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

.changeset/rude-days-punch.md

<ul><li>Added new changeset file for @nhost/dashboard patch<br> <li>
Described the addition of RetryLink to ApolloClient</ul>


</details>


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

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

</details>

___
2025-07-30 13:42:08 +02:00
Nuno Pato
129ec1edfc feat: dashboard: new onboarding (#3398)
### **PR Type**
Enhancement


___

### **Description**
- New onboarding flow onboarding flow implemented

- Sign-up and sign-in pages redesigned

- Organization creation process updated

- Project creation step added to onboarding


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["Sign Up"] --> B["Create Organization"]
  B --> C["Choose Plan"]
  C --> D["Create Project"]
  D --> E["Dashboard"]
  F["Sign In"] --> G["New Design"]
```



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody></tr></tbody></table>

</details>

___

---------

Co-authored-by: robertkasza <robert.kasza@bishop-co.com>
Co-authored-by: David BM <correodelnino@gmail.com>
2025-07-30 10:07:09 +00:00
David Barroso
40439b9987 chore (docs): updated postgres extension and added new custom claims default option (#3404)
### **PR Type**
Enhancement, Documentation


___

### **Description**
- Updated Postgres extensions list and versions

- Added new pg_search extension documentation

- Included custom claims default option

- Minor configuration and formatting improvements


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["Postgres Extensions"] --> B["Update List"]
  A --> C["Add pg_search"]
  D["Auth Configuration"] --> E["Add Default Claim"]
  F["Documentation"] --> G["Improve Formatting"]
```



<details> <summary><h3> File Walkthrough</h3></summary>

<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>short-jars-report.md</strong><dd><code>Add changeset
for version update and feature description</code>&nbsp; </dd></summary>
<hr>

.changeset/short-jars-report.md

<ul><li>Added new changeset file for version bump<br> <li> Described
changes to Postgres extension and custom claims</ul>


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>extensions.mdx</strong><dd><code>Update Postgres
extensions list and add pg_search documentation</code></dd></summary>
<hr>

docs/products/database/extensions.mdx

<ul><li>Updated Postgres extensions list with new versions<br> <li>
Improved table formatting for better readability<br> <li> Added
documentation for new pg_search extension<br> <li> Updated TimescaleDB
version and removed duplicate code</ul>


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3404/files#diff-6bab5da4b9a2b7c2ff6ae4ba02a390b3e676e42daef3326ae4d11f15c2010682">+90/-69</a>&nbsp;
</td>

</tr>
</table></td></tr><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>configuring-postgres.mdx</strong><dd><code>Add
trackIoTiming configuration option</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

docs/products/database/configuring-postgres.mdx

- Added `trackIoTiming = 'on'` to Postgres configuration


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>permissions.mdx</strong><dd><code>Add default value for
custom claim in auth configuration</code>&nbsp; </dd></summary>
<hr>

docs/products/graphql/permissions.mdx

- Added default value for custom claim 'organization-id'


</details>


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

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

</details>

___
2025-07-30 10:42:49 +02:00
robertkasza
cffa161da7 fix (dashboard): disable settings in the header when self-hosting (#3402)
### **PR Type**
Bug fix


___

### **Description**
- Disable settings in header for self-hosted environments

- Implement `useSettingsDisabled` hook for conditional rendering

- Update project pages array with new disabled logic

- Add changeset for patch version bump


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["useSettingsDisabled Hook"] --> B["ProjectPagesComboBox"]
  B --> C["Settings Option"]
  C --> D{"isSettingsDisabled?"}
  D -->|Yes| E["Disabled"]
  D -->|No| F["Enabled"]
```



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>ProjectPagesComboBox.tsx</strong><dd><code>Implement
settings disabling logic in ProjectPagesComboBox</code></dd></summary>
<hr>

dashboard/src/components/layout/Header/ProjectPagesComboBox.tsx

<ul><li>Import <code>useSettingsDisabled</code> hook<br> <li> Add
<code>isSettingsDisabled</code> state<br> <li> Update
<code>Settings</code> option in <code>projectPages</code> array<br> <li>
Add <code>isSettingsDisabled</code> to dependency array</ul>


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>strange-lamps-compare.md</strong><dd><code>Add
changeset for dashboard patch update</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

.changeset/strange-lamps-compare.md

<ul><li>Add changeset file for patch version bump<br> <li> Include fix
description for dashboard</ul>


</details>


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

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

</details>

___
2025-07-25 15:21:58 +02:00
robertkasza
4ffff86752 fix (dashboard): disable settings when there is no config server env variable present (#3394)
### **PR Type**
Bug fix, Enhancement


___

### **Description**
- Disable settings when no config server variable

- Improve platform-specific page handling

- Enhance error handling and loading states

- Refactor environment variable checks


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["Environment Check"] --> B["Settings Visibility"]
  A --> C["Platform-specific Pages"]
  D["Error Handling"] --> E["Loading States"]
  F["Code Refactoring"]
```



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody></tr></tbody></table>

</details>

___

---------

Co-authored-by: David Barroso <dbarrosop@dravetech.com>
2025-07-25 13:05:04 +02:00
Gayathri-K-Binoy
f9e170e958 chore (docs): fix typos (#3396) 2025-07-25 10:46:53 +02:00
robertkasza
b8cb491ab1 fix: update dependencies to fix vulnerabilities (#3399)
### **PR Type**
Enhancement, Bug fix


___

### **Description**
- Update dependencies to address vulnerabilities

- Improve DTS plugin configuration in Vite

- Update Next.js and GraphQL Codegen CLI

- Add resolutions for security patches


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["Security Updates"] --> B["Dependency Upgrades"]
  B --> C["Next.js 14.2.30"]
  B --> D["GraphQL Codegen CLI 5.0.7"]
  A --> E["Vite DTS Plugin 4.5.4"]
  E --> F["Improved DTS Configuration"]
  A --> G["Additional Resolutions"]
```



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody></tr></tbody></table>

</details>

___
2025-07-23 13:55:15 +02:00
David BM
59249e5161 fix (dashboard): elevate permissions in password reset (#3392)
### **PR Type**
Bug fix, Enhancement


___

### **Description**
- Refactored password reset to use elevated permissions hook

- Improved error and success handling in password reset flow

- Added a changeset documenting the permission elevation fix

- Removed direct toast usage from password reset logic


___

### **Changes diagram**

```mermaid
flowchart LR
  A["Reset Password Page"] -- "calls" --> B["useActionWithElevatedPermissions"]
  B -- "handles" --> C["Password Change Action"]
  C -- "on success" --> D["Redirect to Home"]
  C -- "shows" --> E["Success/Error Message"]
```


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>reset.tsx</strong><dd><code>Refactor password reset to
use elevated permissions hook</code>&nbsp; </dd></summary>
<hr>

dashboard/src/pages/password/reset.tsx

<li>Replaced direct password change logic with
<br><code>useActionWithElevatedPermissions</code> hook<br> <li>
Centralized success and error handling via the hook<br> <li> Removed
direct toast notifications from the component<br> <li> Streamlined
password reset submission logic


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>lemon-papayas-act.md</strong><dd><code>Add changeset
for password reset permission fix</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

.changeset/lemon-papayas-act.md

<li>Added a changeset documenting the permission elevation fix in
password <br>reset


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3392/files#diff-bae78ce46846e38b416ebbc4b599670fbe5384c8c850b9d97b3a8924f2d60327">+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-07-16 14:36:28 +02:00
robertkasza
df6b85e98c fix (dashboard): fix password reset redirect url (#3391)
### **PR Type**
Bug fix, Enhancement


___

### **Description**
- Fixed password reset redirect to use absolute URL.

- Removed duplicate sign-up tabs and extra legal text.

- Added direct sign-in prompt for existing users.

- Added changeset entry for the patch update.


___

### **Changes diagram**

```mermaid
flowchart LR
  A["Password reset redirect (relative)"] -- "Changed to absolute URL" --> B["Password reset redirect (absolute)"]
  C["Sign-up page with tabs and legal text"] -- "Removed tabs & extra legal text" --> D["Sign-up page with sign-in prompt"]
  E["No changeset for fix"] -- "Added changeset entry" --> F["Patch changeset for dashboard"]
```


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Bug
fix</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>new.tsx</strong><dd><code>Use absolute URL for password
reset redirect</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

dashboard/src/pages/password/new.tsx

<li>Changed password reset redirect to use absolute URL.<br> <li>
Ensures correct redirect after password reset email.


</details>


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

</tr>
</table></td></tr><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>signup.tsx</strong><dd><code>Streamlined sign-up page
and added sign-in prompt</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></summary>
<hr>

dashboard/src/pages/signup.tsx

<li>Removed <code>SignUpTabs</code> and duplicate legal text.<br> <li>
Added prompt for existing users to sign in.<br> <li> Simplified and
clarified sign-up page UI.


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>serious-eagles-rule.md</strong><dd><code>Added
changeset for password reset redirect fix</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

.changeset/serious-eagles-rule.md

<li>Added changeset entry for password reset redirect fix.<br> <li>
Documents patch update for dashboard package.


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3391/files#diff-058395bb4a26b44e46054945b2710688aebefcb9ad898396af1cac658e20b049">+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-07-16 14:03:32 +02:00
robertkasza
85316e822f fix (dashboard): Remove second loading indicator on projects page (#3380)
### **PR Type**
Bug fix


___

### **Description**
- Removed redundant loading indicator from projects page

- Refactored `ProjectsGrid` to accept projects as props

- Updated data fetching to use `useGetProjectsQuery` by org slug

- Cleaned up unused queries and code for project listing


___

### **Changes diagram**

```mermaid
flowchart LR
  A["ProjectsGrid fetches projects internally"] -- "Old" --> B["ProjectsGrid receives projects as props"]
  C["Redundant loading indicator in ProjectsGrid"] -- "Removed" --> D["Single loading indicator in OrgProjects"]
  E["useGetOrganizationProjectsQuery (by orgId)"] -- "Removed" --> F["useGetProjectsQuery (by orgSlug)"]
```


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Miscellaneous</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>AuthenticatedLayout.tsx</strong><dd><code>Clean up
commented authentication check code</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>


dashboard/src/components/layout/AuthenticatedLayout/AuthenticatedLayout.tsx

- Removed commented-out code related to authentication check


</details>


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

</tr>
</table></td></tr><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>projects-grid.tsx</strong><dd><code>Refactor
ProjectsGrid to accept projects as props</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/features/orgs/components/projects/projects-grid/projects-grid.tsx

<li>Refactored <code>ProjectsGrid</code> to accept <code>projects</code>
as a prop<br> <li> Removed internal data fetching and loading/error
handling<br> <li> Cleaned up unused imports and variables


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>index.tsx</strong><dd><code>Centralize project data
fetching and loading indicator</code>&nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

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

<li>Moved project data fetching to page level using
<code>useGetProjectsQuery</code><br> <li> Passed projects to
<code>ProjectsGrid</code> as props<br> <li> Unified loading indicator to
a single location<br> <li> Switched layout to
<code>AuthenticatedLayout</code>


</details>


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

</tr>
</table></td></tr><tr><td><strong>Dependencies</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>graphql.ts</strong><dd><code>Remove deprecated
GetOrganizationProjectsQuery code</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></summary>
<hr>

dashboard/src/utils/__generated__/graphql.ts

<li>Removed all code related to
<code>GetOrganizationProjectsQuery</code><br> <li> Cleaned up unused
query types and hooks


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>getOrganizationProjects.gql</strong><dd><code>Remove
unused getOrganizationProjects GraphQL query</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

dashboard/src/gql/organizations/getOrganizationProjects.gql

- Deleted unused GraphQL query for organization projects by orgId


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>tame-suits-rest.md</strong><dd><code>Add changeset for
dashboard loading indicator fix</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

.changeset/tame-suits-rest.md

- Added changeset entry for dashboard patch fix


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3380/files#diff-e294197b031340c88e9faf8c8a3f2fa3e8795927376dce8e5e15458f55b64301">+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-07-14 10:36:17 +02:00
Nuno Pato
f7d7080dad chore: dashboard: add gtag (#3388)
### **PR Type**
Enhancement


___

### **Description**
- Integrates Google Tag Manager (gtag) into the signup page

- Dynamically injects Google Ads script with error handling

- Cleans up injected script on component unmount

- Adds a changeset entry for the dashboard package


___

### **Changes diagram**

```mermaid
flowchart LR
  SignUpPage["SignUpPage component"]
  useEffect["useEffect hook"]
  Script["Inject Google Ads script"]
  gtag["Initialize gtag & dataLayer"]
  Cleanup["Remove script on unmount"]

  SignUpPage -- "mounts" --> useEffect
  useEffect -- "sets up" --> gtag
  useEffect -- "injects" --> Script
  useEffect -- "cleans up" --> Cleanup
```


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>signup.tsx</strong><dd><code>Integrate Google Tag
Manager script in signup page</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></summary>
<hr>

dashboard/src/pages/signup.tsx

<li>Adds useEffect to inject Google Ads gtag script<br> <li> Initializes
global gtag and dataLayer if not present<br> <li> Handles script
loading, error, and cleanup on unmount


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>thin-steaks-poke.md</strong><dd><code>Add changeset for
dashboard gtag enhancement</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

.changeset/thin-steaks-poke.md

- Adds a changeset entry for the dashboard package update


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3388/files#diff-57d0a66dc101feb0260a2285ccf8dacb4d90fc478d721b4a4432f169ce11270b">+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-07-11 13:13:13 +00:00
robertkasza
ec24567d83 fix (dashboard): Add content-type header (#3385)
### **PR Type**
Bug fix


___

### **Description**
- Add `Content-Type: application/json` header to GitHub app installation
request

- Ensure correct content type for POST request in dashboard

- Add changeset entry documenting the bug fix

- Improve API compatibility for GitHub app installation endpoint


___

### **Changes diagram**

```mermaid
flowchart LR
  A["GitHub App Installation Request"] -- "Add Content-Type header" --> B["API Endpoint"]
  B -- "Processes JSON body correctly" --> C["Improved Compatibility"]
```


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Bug
fix</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>index.tsx</strong><dd><code>Add Content-Type header to
GitHub app installation POST request</code></dd></summary>
<hr>

dashboard/src/pages/github-app-installation/index.tsx

<li>Add <code>Content-Type: application/json</code> header to POST
request<br> <li> Ensure API receives correct content type for JSON body


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3385/files#diff-617a35daae6c458b9fe6374fe3d72a1f0c17f1975d2180ebed76d6945f8ced3c">+3/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>spicy-camels-work.md</strong><dd><code>Add changeset
entry for Content-Type header fix</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

.changeset/spicy-camels-work.md

- Add changeset entry describing the bug fix for dashboard


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3385/files#diff-ed215958071054c894c74606f2d96e18e5cc478183f88bebee13bce9e186e975">+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-07-03 19:15:32 +02:00
robertkasza
56c87dad64 fix (dashboard): Use the correct http method when connecting to new github installation (#3384)
### **PR Type**
Bug fix


___

### **Description**
- Fixes HTTP method to 'POST' for GitHub app installation API call

- Adds a changeset entry documenting the bug fix


___

### **Changes diagram**

```mermaid
flowchart LR
  A["GitHub App Installation API Call"] -- "method: GET (incorrect)" --> B["Error/Failure"]
  A -- "method: POST (correct)" --> C["Successful Installation"]
```


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Bug
fix</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>index.tsx</strong><dd><code>Use POST method for GitHub
app installation API call</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

dashboard/src/pages/github-app-installation/index.tsx

<li>Sets HTTP method to 'POST' in fetch call for GitHub app
installation<br> <li> Ensures correct API interaction when connecting
new GitHub <br>installation


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>big-students-crash.md</strong><dd><code>Add changeset
entry for GitHub installation bug fix</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></summary>
<hr>

.changeset/big-students-crash.md

- Adds a patch changeset describing the HTTP method bug fix


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3384/files#diff-114feb4f179f3533e5546f1cdaddfeb232268b6147c41edfa2f1f387a9320085">+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-07-03 18:16:10 +02:00
robertkasza
47ab341ce4 fix (dashboard): Fix announcement layout when title is too short (#3382)
### **User description**
Before:

![image](https://github.com/user-attachments/assets/d8f0404b-fafe-4d30-bb19-f3eeedda31b8)

After:


![image](https://github.com/user-attachments/assets/10dd9986-b461-4466-ae2f-d169f663146b)


___

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


___

### **Description**
- Fixed announcement layout for short titles in AnnouncementsTray.

- Updated announcement list to use hardcoded sample data.

- Improved flexbox styling for announcement items.

- Added a changeset entry for the patch release.


___

### **Changes diagram**

```mermaid
flowchart LR
  AnnouncementsTray["AnnouncementsTray.tsx"]
  Styling["Flexbox layout fix"]
  SampleData["Hardcoded announcements data"]
  Changeset[".changeset/wet-sheep-bake.md"]

  AnnouncementsTray -- "uses" --> SampleData
  AnnouncementsTray -- "applies" --> Styling
  AnnouncementsTray -- "documented in" --> Changeset
```


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>AnnouncementsTray.tsx</strong><dd><code>Fix
announcement layout and use sample data in
AnnouncementsTray</code></dd></summary>
<hr>


dashboard/src/features/orgs/components/members/components/AnnouncementsTray/AnnouncementsTray.tsx

<li>Replaced dynamic announcement fetching with hardcoded sample
data.<br> <li> Fixed flexbox layout for announcement items to handle
short titles.<br> <li> Improved visual alignment and spacing in the
announcement list.


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>wet-sheep-bake.md</strong><dd><code>Add changeset for
announcement layout fix</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

.changeset/wet-sheep-bake.md

- Added a changeset entry describing the announcement layout fix.


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3382/files#diff-45895b0cd41c7cf29b27780adee81b07c63884cfe2bc7d9fb589e1017bbba61e">+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-07-03 16:38:04 +02:00
github-actions[bot]
5fed49e05b chore: update versions (#3370)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @nhost/hasura-storage-js@2.8.0

### Minor Changes

-   aee9a80: chore: update typescript version to the latest

## @nhost/nhost-js@3.3.0

### Minor Changes

-   aee9a80: chore: update typescript version to the latest

### Patch Changes

-   Updated dependencies [aee9a80]
    -   @nhost/hasura-storage-js@2.8.0

## @nhost/apollo@9.0.0

### Patch Changes

-   Updated dependencies [aee9a80]
    -   @nhost/nhost-js@3.3.0

## @nhost/react-apollo@18.0.1

### Patch Changes

-   @nhost/apollo@9.0.0
-   @nhost/react@3.11.1

## @nhost/react-urql@15.0.1

### Patch Changes

-   @nhost/react@3.11.1

## @nhost/nextjs@2.2.9

### Patch Changes

-   @nhost/react@3.11.1

## @nhost/react@3.11.1

### Patch Changes

-   Updated dependencies [aee9a80]
    -   @nhost/nhost-js@3.3.0

## @nhost/vue@2.9.7

### Patch Changes

-   Updated dependencies [aee9a80]
    -   @nhost/nhost-js@3.3.0

## @nhost/dashboard@2.33.0

### Minor Changes

-   aee9a80: chore: update typescript version to the latest
-   5ef3f76: chore (dashboard): Use the new SDK in the Dashboard

### Patch Changes

- 9ed8ce8: fix (dashboard): Request new Mfa ticket after an invalid totp
when signing in
- fd3b5c7: fix (dashboard): Limit new project's name to a maximum of 32
charachters in E2E tests

## @nhost/docs@2.33.0

### Minor Changes

-   4ca9641: feat: added cloud development documentation

## @nhost-examples/cli@0.3.23

### Patch Changes

-   Updated dependencies [aee9a80]
    -   @nhost/nhost-js@3.3.0

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

### Patch Changes

-   @nhost/react@3.11.1
-   @nhost/react-apollo@18.0.1

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

### Patch Changes

-   @nhost/react@3.11.1

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

### Patch Changes

-   @nhost/react@3.11.1
-   @nhost/react-urql@15.0.1

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

### Patch Changes

-   Updated dependencies [aee9a80]
    -   @nhost/nhost-js@3.3.0

## @nhost-examples/nextjs@0.4.9

### Patch Changes

-   @nhost/react@3.11.1
-   @nhost/react-apollo@18.0.1
-   @nhost/nextjs@2.2.9

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

### Patch Changes

-   Updated dependencies [aee9a80]
    -   @nhost/nhost-js@3.3.0

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

### Patch Changes

-   Updated dependencies [aee9a80]
    -   @nhost/nhost-js@3.3.0

## @nhost-examples/sveltekit@0.8.2

### Patch Changes

-   Updated dependencies [aee9a80]
    -   @nhost/nhost-js@3.3.0

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

### Patch Changes

-   @nhost/react@3.11.1
-   @nhost/react-apollo@18.0.1

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

### Patch Changes

-   @nhost/react@3.11.1

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

### Patch Changes

-   @nhost/react@3.11.1
-   @nhost/react-apollo@18.0.1

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

### Patch Changes

-   Updated dependencies [aee9a80]
    -   @nhost/nhost-js@3.3.0
    -   @nhost/apollo@9.0.0
    -   @nhost/vue@2.9.7

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

### Patch Changes

-   @nhost/apollo@9.0.0
-   @nhost/vue@2.9.7

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-07-01 13:00:12 +02:00
robertkasza
aee9a80ac8 chore: update typescript to latest version (#3376)
### **PR Type**
Enhancement, Other


___

### **Description**
- Update TypeScript to version 5.8.3

- Upgrade react-merge-refs to version 3.0.2

- Refactor import syntax for mergeRefs

- Update tsconfig settings for modern JavaScript


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><details><summary>11
files</summary><table>
<tr>
<td><strong>ControlledAutocomplete.tsx</strong><dd><code>Update import
syntax for mergeRefs</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></td>
<td><a
href="https://github.com/nhost/nhost/pull/3376/files#diff-e1bbef866e556facc768a4239b443e193f460321689e368fcaae31c1a7c90478">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>ControlledCheckbox.tsx</strong><dd><code>Update import and
type reference for mergeRefs</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3376/files#diff-6f7d29735900a65f96663da4719bf151c5c98224c0a4e39d84b9e5e1db6b8c42">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>ControlledSelect.tsx</strong><dd><code>Update import and
type reference for mergeRefs</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3376/files#diff-4dda68ad8ea568203b515c9cb81eabd05109f55b10e96712924744aba8c22468">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>ControlledSwitch.tsx</strong><dd><code>Update import syntax
for mergeRefs</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></td>
<td><a
href="https://github.com/nhost/nhost/pull/3376/files#diff-173b17a003d4d330b2a7157258d0d34cbbbac6ae10840245294f22a8e6ef89ed">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>Checkbox.tsx</strong><dd><code>Update ForwardedRef type for
Checkbox component</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3376/files#diff-16e6ada0fb8f9c0ecaa00fcfc61c166d0c4c051efe5345d58ee5e4ab618ca0c5">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>Input.tsx</strong><dd><code>Update import syntax for
mergeRefs</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></td>
<td><a
href="https://github.com/nhost/nhost/pull/3376/files#diff-16643cae2ae39d51faa2ed4d7e045f4ec2af31ec5f91768cff742e0364400cb1">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>Radio.tsx</strong><dd><code>Update ForwardedRef type for
Radio component</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/3376/files#diff-cab2e6a6d80963fb89d93b52ac228ab8f2e2d9d60d3d2567547da562e922ac63">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>LogsServiceFilter.tsx</strong><dd><code>Update ForwardedRef
type for LogsServiceFilter</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3376/files#diff-a590a7298a9f040df9f26c4eb37d10fc36f47c32996f71aec47796f08c44e892">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>ReferencedSchemaSelect.tsx</strong><dd><code>Update
ForwardedRef type for ReferencedSchemaSelect</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3376/files#diff-450038e1607012a27e047ef0fa3e7c3ba58a4be7750940aa21c7166713b15c76">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>DataGrid.tsx</strong><dd><code>Update import syntax for
mergeRefs</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></td>
<td><a
href="https://github.com/nhost/nhost/pull/3376/files#diff-3bc6476aed14d8e4f26134fa452d22c41b6d3ecb0989871a8a99230a82496474">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>DataGridBooleanCell.tsx</strong><dd><code>Update
useDataGridCell generic type</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3376/files#diff-b700eacab9c73b147e248ce58d47a208c1e499124a20444efd73db7ecb68505f">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

</table></details></td></tr><tr><td><strong>Tests</strong></td><td><details><summary>1
files</summary><table>
<tr>
<td><strong>getAllocatedResources.test.ts</strong><dd><code>Remove
replicas property from test cases</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3376/files#diff-c7db4fcf0770eb6e4eba76db64b1c705404538a3c204ea212028cad591c6d85a">+0/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></details></td></tr><tr><td><strong>Configuration
changes</strong></td><td><details><summary>4 files</summary><table>
<tr>
<td><strong>tsconfig.base.json</strong><dd><code>Update TypeScript
compiler options for ES2022</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3376/files#diff-1542b47836923af953e9f14d4db6843171edb79232ba834276394b4ed3035c63">+4/-15</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>tsconfig.json</strong><dd><code>Update TypeScript target and
adjust paths</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3376/files#diff-9c3967d850eef2a3a17b5169df09de68ecb0f24ec46f0a9dd1b3ca7c6da7a384">+9/-4</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>tsconfig.json</strong><dd><code>Add typeRoots to compiler
options</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; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3376/files#diff-aa2c7a9ede2c1897e087efac48742cf228b8af42e73dec31ec6403461b98c63a">+6/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>tsconfig.json</strong><dd><code>Add typeRoots to compiler
options</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; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3376/files#diff-6b59df76b8f353267e50f13e5fdd23ff7490a417bdc9b7e9f4e94aaafa448dcd">+7/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

</table></details></td></tr><tr><td><strong>Dependencies</strong></td><td><details><summary>2
files</summary><table>
<tr>
<td><strong>package.json</strong><dd><code>Upgrade react-merge-refs to
version 3.0.2</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3376/files#diff-2d8d55c799cd71f1b35e831f075f8178ed1734c4820a2ad548b4dd24d6938d7c">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>package.json</strong><dd><code>Upgrade TypeScript to version
5.8.3</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3376/files#diff-7ae45ad102eab3b6d7e7896acd08c427a9b25b346470d7bc6507b6481575d519">+2/-2</a>&nbsp;
&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-07-01 11:07:17 +02:00
robertkasza
5ef3f76ea0 chore (dashboard): use new sdk on the dashboard (#3374)
### **PR Type**
Enhancement, Bug fix


___

### **Description**
- Migrate from @nhost/nextjs to @nhost/nhost-js-beta

- Update authentication flow and components

- Refactor Apollo client and GraphQL operations

- Implement new session management and storage


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Error
handling</strong></td><td><details><summary>1 files</summary><table>
<tr>
<td><strong>MfaOtpForm.tsx</strong><dd><code>Refactor MFA OTP form error
handling</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-88ee3610a0658d5eead85db025a5e91e74a4d2f2a836adf7eb44ff80888a613b">+11/-9</a>&nbsp;
&nbsp; </td>

</tr>

</table></details></td></tr><tr><td><strong>Enhancement</strong></td><td><details><summary>66
files</summary><table>
<tr>
<td><strong>AccountMenu.tsx</strong><dd><code>Update account menu to use
new SDK hooks</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-57e70c7e6a22a5ab5271b2f36a54eabf544d9f62cd18dae83e2e89b125e77e0c">+10/-10</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>AuthenticatedLayout.tsx</strong><dd><code>Refactor
authenticated layout with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-2d69ccffd267658f76d77a864cdece93fc222e08f6025955795fc6f4697f60e7">+15/-13</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>MobileNav.tsx</strong><dd><code>Update mobile navigation to
use new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-88408885daaec8805bd085b53462c9f2d95db32f7e523912837a8167211b4fb2">+14/-8</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>UnauthenticatedLayout.tsx</strong><dd><code>Refactor
unauthenticated layout with new SDK</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/3374/files#diff-54ee5ad9c01e99ffb05218020a6b97d091cd97cc53ad27e950480a3e675f2220">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>ErrorToast.tsx</strong><dd><code>Update error toast to use
new SDK hooks</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-189ba99303a20e964b5e3f3d6f1cf95c6376780a59604d1dee98aa84d9a2a9dc">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>DisableMfaButton.tsx</strong><dd><code>Refactor MFA disable
button with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-8548174093cd8b3bcd754b630c0bcc946e7cdc80176f8e0f0540fd60c9e47486">+17/-18</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>MfaQRCodeAndTOTPSecret.tsx</strong><dd><code>Update MFA
enable process with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-91870bba41e6e807ced8d185a9d61282540ca82741a938b12f20c4f452bdabf8">+30/-29</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>useMfaEnabled.ts</strong><dd><code>Refactor MFA enabled hook
with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-31d2af339a8dd32beff8cce79962fa0dd23b6c89687b21aa75663ebeccb0b154">+3/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>CreatePATForm.tsx</strong><dd><code>Update PAT creation form
with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-75aecb06ebb3e3cd0de6bf253af6966e245e46e9b739314d49073ba2c80a3a90">+6/-6</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>DeleteAccount.tsx</strong><dd><code>Refactor account
deletion with new SDK hooks</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/3374/files#diff-3d84927ffa4b91d986ff6c6f601b3476503220e1c1d8cde25ebf72c8d0ed6b9e">+4/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>DisplayNameSetting.tsx</strong><dd><code>Update display name
setting with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-a1daec18d5c3196aee5b2c5303db5654724f8d37cfa427594951a4d02fbe32db">+4/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>EmailSetting.tsx</strong><dd><code>Refactor email setting
with new SDK hooks</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-98bdf4ebec67ab2b4cd475c9df16a39a66505da961a8448eb5e41a33544dcb38">+4/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>useOnChangePasswordHandler.ts</strong><dd><code>Update
password change handler with new SDK</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/3374/files#diff-be0c02de792e4ba1b71258eb3992bbc531bc37658cbad0e01e2db4419a9285f1">+4/-4</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>useOnAddNewSecurityKeyHandler.ts</strong><dd><code>Refactor
security key addition with new SDK</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/3374/files#diff-3514a6d1514269a83f37fc25e9cb24add9d5d74f9cf3341293c0e0f2a4c2e286">+10/-2</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>useRemoveSecurityKey.ts</strong><dd><code>Update security
key removal with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-5683e00a14f39018d8fe58a3116c2a8ea6d2f2a83abb2177bbf0ee8ddf0f97b5">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>SocialProvidersSettings.tsx</strong><dd><code>Refactor
social providers settings with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-82d7c0c9eb3a23586998b6eadff9e56b123b14d03179212ca82439d3bdcd6e96">+14/-5</a>&nbsp;
&nbsp; </td>

</tr>

<tr>

<td><strong>useActionWithElevatedPermissions.ts</strong><dd><code>Update
elevated permissions hook with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-3390879c4a0cd70aa1db6672a1607c5c2444c0bf653b711d73eda8ee466aa61a">+10/-16</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>useElevatedPermissions.ts</strong><dd><code>Refactor
elevated permissions hook with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-c1e4f573300c771149cc2e59918c9acf2ae5f8a6680800a899707c70800ba144">+11/-10</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>useGetSecurityKeys.ts</strong><dd><code>Update security keys
fetching with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-1f9fed870cab61f15e304342e4913edab0f5537eeb6230070de4b4f7173fa138">+3/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>useGithubAuthentication.ts</strong><dd><code>Refactor GitHub
authentication with new SDK</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/3374/files#diff-fad4875e0f07391dadcfc7e2dd481cafd5172dbb740c47e56fa75beb271618e1">+16/-8</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>SignInWithSecurityKey.tsx</strong><dd><code>Update security
key sign-in with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-dc892fd3d9fd3cc7efca35c813cea43c63aa691b1d55d376ac69a2d75065bde9">+9/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>VerifyEmailDialog.tsx</strong><dd><code>Refactor email
verification dialog for security key</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-24699641924d25d9b2d72b7df5da44d837e1c1e5c77b9f4b00f7c07d12c72c42">+4/-10</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>useSignInWithSecurityKey.ts</strong><dd><code>Update
security key sign-in hook with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-14ce9eae9e1ec03512bdd55198fbce47a81ce8ce769d002164926d2cc76e91aa">+34/-21</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>MfaSignInOtpForm.tsx</strong><dd><code>Refactor MFA OTP form
for sign-in</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; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-91eba232beb0543b1e972ed9a21a0be797ed94b720487834bb3316a5dbd732f5">+1/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>SignInWithEmailAndPassword.tsx</strong><dd><code>Update
email/password sign-in with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-a2b70644663baf4f6f2cdffd846d4d743a5ca1f2a64c4b278b6f04c6c5c92161">+34/-12</a>&nbsp;
</td>

</tr>

<tr>

<td><strong>SignInWithEmailAndPasswordForm.tsx</strong><dd><code>Refactor
email/password sign-in form with loading state</code>&nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-a07fd6bd20c97d0c9c875e690cd3a80068fc58f74d3579feb210e189d32f5031">+5/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>

<td><strong>useOnSignInWithEmailAndPasswordHandler.ts</strong><dd><code>Update
email/password sign-in handler with new SDK</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-1a253bfc02c3267ab1c6b58c07aa06142b7e711d613b672c8420ff2861b12d27">+35/-37</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>useRequestNewMfaTicket.ts</strong><dd><code>Refactor MFA
ticket request with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-64a3a91cf75c8faf5bf6a9fdd23978659d68888744a92f82602b1a2f7290c1f6">+12/-11</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>useOnSignUpWithPasswordHandler.ts</strong><dd><code>Update
email/password sign-up handler with new SDK</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-d1a80c5b1076129735ffff9ea879ca8c8fe88e548d06e98a1fb6bfd7147dae01">+14/-19</a>&nbsp;
</td>

</tr>

<tr>

<td><strong>useSignupWithSecurityKeyHandler.ts</strong><dd><code>Refactor
security key sign-up with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-cef4f710ea89c67e27e9fe77db2d2ebc6d774657e0671b21b7353f3e927126bd">+24/-17</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>CreateOrgFormDialog.tsx</strong><dd><code>Update
organization creation dialog with new SDK</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-9a1ed9e851328393b81356d80ade3509016aa55c254ed1f4deb692b0bd96f02e">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>TransferProjectForm.tsx</strong><dd><code>Refactor project
transfer form with new SDK</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/3374/files#diff-3324c79d8b4d48777467132ba0f13a95d4b0f1a9fbb4df9fd7f67735ac40cbbd">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>Soc2Download.tsx</strong><dd><code>Update SOC2 report
download with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-3768eb3fc718d4780028c34b5c76388e8d93cbbac94868f82c1a262fb9cc1100">+12/-19</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>AnnouncementsTray.tsx</strong><dd><code>Refactor
announcements tray with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-88fdcce3e90fa9e4d172858ae702855f86e6ece724ba443d8a6ed918999a1630">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>NotificationsTray.tsx</strong><dd><code>Update notifications
tray with new SDK hooks</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/3374/files#diff-8b559ee1d3176203e8a4e1588924d57944d09d792117ed578b27cd5401ee5d4f">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>OrgMember.tsx</strong><dd><code>Refactor organization member
component with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-a50b1baab968a7d3bd1459ba01107a13bd25e5077b6ad49a0d7e9dd88992276a">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>useFinishOrgCreation.ts</strong><dd><code>Update
organization creation finish hook with new SDK</code>&nbsp; &nbsp;
&nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-3b8bf7608ab36d8ab0df895e400f0d2d9e29fad2055b40b33d8d9912a27c99c3">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>useIsOrgAdmin.ts</strong><dd><code>Refactor organization
admin check with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-216a850dad38e829d0a8892c34d87426cd68f10c92f4c647673667dbbd11464d">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>MessageBox.tsx</strong><dd><code>Update dev assistant
message box with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-d4dd97b5a55f8246836226333d35a1c18c2907e47bdd2654707ed43ac54f2fb8">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>ApplicationInfo.tsx</strong><dd><code>Refactor application
info component with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-7372ad22d70c3c354d8e0dd442eb7e49f70f65a386b934b6eee7f8c4b89c3a3f">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>ApplicationPausedBanner.tsx</strong><dd><code>Update paused
application banner with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-fa94285530f7118d9f27a2d9088f5cf6ba71879d14957d91eb01dba16b6b6f1c">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>RemoveApplicationModal.tsx</strong><dd><code>Refactor
application removal modal with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-e454a42c12dcbfcfaa463ab3421037408634e3a539f460525c79d68adfc118ab">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>useAppPausedReason.ts</strong><dd><code>Update app paused
reason hook with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-51d220574b3da84f08d2cb134682172ed11b908c4d855ccc8d9de30805921a00">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>useCheckProvisioning.ts</strong><dd><code>Refactor
provisioning check hook with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-e1758bb8d3381f814d6619dc33eee8b36e39d2fcb6486d5c8cc3c46bbe62c555">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>useIsCurrentUserOwner.ts</strong><dd><code>Update current
user ownership check with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-3941cc4f23c66f12e94850e88e05ca142a627ab2d9ec797ff757dab679c58c0f">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>useProjectRedirectWhenReady.ts</strong><dd><code>Refactor
project redirect hook with new SDK</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/3374/files#diff-a234bc908266de3091b23b5134a01fd769f96759eb52aa108d2ad4b796b0303f">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>ResetDatabasePasswordSettings.tsx</strong><dd><code>Update
database password reset with new SDK</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/3374/files#diff-46fc60a26a2de3efb98e9778b1c6e82d62823ae5c7534037eb120728cba26288">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>DeploymentListItem.tsx</strong><dd><code>Refactor deployment
list item with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-2a548c457ff2ab8fc1bee326a6a3b5eae9d0d6eb18f5ae95bbdb437c3f6b0a73">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>

<td><strong>SystemEnvironmentVariableSettings.tsx</strong><dd><code>Update
system environment variables with new SDK</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-b952daa2a34e49a14c5a471477fa2d50583091e420d88a3b941503b092d18e5c">+7/-4</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>BaseDirectorySettings.tsx</strong><dd><code>Refactor base
directory settings with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-50bcccdf949a19ce69fa86acdd63b5291fa2beaba07191a62c87d40ea5b94e88">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>DeploymentBranchSettings.tsx</strong><dd><code>Update
deployment branch settings with new SDK</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-d8fc80cc734f593c686f873536856bf9103efb1115ca865709bbeb7bd940895e">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>useAppClient.ts</strong><dd><code>Refactor app client hook
with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-0aa83222c0e0eac6f0058070de2b199e5e78514cbba405eb98d3693329a93e65">+13/-6</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>useCurrentOrg.tsx</strong><dd><code>Update current
organization hook with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-97e1dbde4beece374834d5e81dd56fddeb5f1756a3358f6afecf88df93f6b0b0">+60/-3</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>useOrgs.ts</strong><dd><code>Refactor organizations hook
with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-995629b13bac07ec5c0e79caa8f5f8df19fc842d1b8cfe8fd2b1fcd9448868c4">+5/-6</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>useProject.ts</strong><dd><code>Update project hook with new
SDK</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></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-ef96f340af7a87a1fc60c42d8f4de846a2a54fde830a9461c64cfbc99dc11128">+8/-10</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>useProjectLogs.ts</strong><dd><code>Update project logs hook
with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-10efc67700b3f024dd03442eacd339802e951696d04caa76bd5a864bd5c7c83f">+2/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>useProjectWithState.ts</strong><dd><code>Refactor project
with state hook using new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-4fa0e580d9f12e35ff5d2751597bf443bd055cd1c854cf6b356110724d424188">+7/-7</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>DataGridPreviewCell.tsx</strong><dd><code>Update data grid
preview cell with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-d7bffe5896d2c9bac505fa9675790c59549d4fb35a2ad0cce903cc0aa31a8321">+7/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>FilesDataGrid.tsx</strong><dd><code>Refactor files data grid
with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-18c8df727e1a4fc6a94d03bd4a3a7a8cb3ad44d754803c4c7988c1c00a4b7caf">+20/-15</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>FilesDataGridControls.tsx</strong><dd><code>Update files
data grid controls with new SDK</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/3374/files#diff-b85b40168e9c149331a68cb1a0cbec570c75233fa34385945e094b8f4c032974">+15/-30</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>useAccessToken.ts</strong><dd><code>Add new hook for
accessing token with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-1e7322930841a7ee092650eedafab9b83a8eb2d376aa299f3dfd790304a7ad21">+9/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>useDecodedAccessToken.ts</strong><dd><code>Add new hook for
decoding access token</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-ff3f112dfd0dae55404d17d972f5309d9a8cf0859222061e1c6f10e52c442390">+28/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>useElevateEmail.ts</strong><dd><code>Add new hook for email
elevation with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-b38d4c8f500fe9f40d4649e78907fc2f8691bd950b377e85be9142226b2b3460">+26/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>useHasuraClaims.ts</strong><dd><code>Add new hook for Hasura
claims with new SDK</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/3374/files#diff-f5352373468a509527f74db8d16a632905284009ed386ea50cd9fb7f42817431">+11/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>useUserData.ts</strong><dd><code>Add new hook for user data
with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-3e3f3684aba10abe1d06d0be625a8077efe2e7d6a17b79d5ecddd43cfc190224">+12/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>index.ts</strong><dd><code>Remove old remote application
GraphQL client hook</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-d2d725306920bf5413fc010843e4ca13570b225febb200330e8c6902ae0b085c">+0/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

</table></details></td></tr><tr><td><strong>Tests</strong></td><td><details><summary>1
files</summary><table>
<tr>
<td><strong>useProjectLogs.test.ts</strong><dd><code>Refactor project
logs test with new SDK</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3374/files#diff-13d900aa08d06962a09628136b893801ad62a96c3ff89d380c5c4b7ae92d891e">+19/-31</a>&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-06-30 14:31:29 +02:00
David Barroso
4ca9641304 feat (docs): added cloud development documentation (#3377) 2025-06-25 23:24:10 +02:00
robertkasza
fd3b5c77e4 fix (dashboard): Limit new project name to a max of 32 chars (#3371)
### **PR Type**
Bug fix, Tests


___

### **Description**
- Limit new project name to 32 characters in E2E tests

- Update project creation test in upgrade-project.test.ts

- Add changeset for @nhost/dashboard patch


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Bug
fix</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>upgrade-project.test.ts</strong><dd><code>Limit project
name length in E2E test</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/e2e/upgrade-project/upgrade-project.test.ts

<li>Modify project name generation to limit to 32 characters<br> <li>
Use <code>slice(0, 32)</code> on faker-generated project name


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>weak-bottles-stare.md</strong><dd><code>Add changeset
for project name length fix</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></summary>
<hr>

.changeset/weak-bottles-stare.md

<li>Add new changeset file for @nhost/dashboard patch<br> <li> Document
fix for limiting project name to 32 characters


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3371/files#diff-352316104f52e31fc130d1016f300d58c243319c6e6e434c9bc6912402117d6a">+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-06-18 15:50:56 +02:00
robertkasza
9ed8ce8a5e fix (dashboard): request new mfa ticket after error when signing in (#3369)
### **PR Type**
Bug fix


___

### **Description**
- Request new MFA ticket after invalid TOTP

- Improve error handling in MFA flow

- Add comprehensive tests for MfaOtpForm

- Refactor SignInWithEmailAndPassword component


___



### **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>1
files</summary><table>
<tr>
<td><strong>MfaOtpForm.test.tsx</strong><dd><code>Add comprehensive
tests for MfaOtpForm component</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3369/files#diff-0a0a9d4aa607a60fb4f38712686101d583426536ff6c177ea625cf8ce1946971">+519/-0</a>&nbsp;
</td>

</tr>

</table></details></td></tr><tr><td><strong>Enhancement</strong></td><td><details><summary>5
files</summary><table>
<tr>
<td><strong>MfaOtpForm.tsx</strong><dd><code>Implement MFA ticket
renewal and improve error handling</code>&nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3369/files#diff-88ee3610a0658d5eead85db025a5e91e74a4d2f2a836adf7eb44ff80888a613b">+39/-12</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>MfaSignInOtpForm.tsx</strong><dd><code>Add
requestNewMfaTicket prop to MfaSignInOtpForm</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3369/files#diff-91eba232beb0543b1e972ed9a21a0be797ed94b720487834bb3316a5dbd732f5">+7/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>SignInWithEmailAndPassword.tsx</strong><dd><code>Implement
requestNewMfaTicket function and pass to
MfaSignInOtpForm</code></dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3369/files#diff-a2b70644663baf4f6f2cdffd846d4d743a5ca1f2a64c4b278b6f04c6c5c92161">+20/-4</a>&nbsp;
&nbsp; </td>

</tr>

<tr>

<td><strong>useOnSignInWithEmailAndPasswordHandler.ts</strong><dd><code>Add
emailPasswordRef to store credentials for MFA renewal</code></dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3369/files#diff-1a253bfc02c3267ab1c6b58c07aa06142b7e711d613b672c8420ff2861b12d27">+19/-2</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>useRequestNewMfaTicket.ts</strong><dd><code>Create new hook
for requesting new MFA ticket</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3369/files#diff-64a3a91cf75c8faf5bf6a9fdd23978659d68888744a92f82602b1a2f7290c1f6">+28/-0</a>&nbsp;
&nbsp; </td>

</tr>
</table></details></td></tr><tr><td><strong>Bug
fix</strong></td><td><details><summary>1 files</summary><table>
<tr>
<td><strong>email.tsx</strong><dd><code>Fix page title for sign-in
page</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3369/files#diff-b5d7db4460066bc114cb766771612d6f908bd6e440f40de98e4ac311a26b50cd">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

</table></details></td></tr><tr><td><strong>Documentation</strong></td><td><details><summary>1
files</summary><table>
<tr>
<td><strong>lovely-days-whisper.md</strong><dd><code>Add changeset for
MFA ticket renewal fix</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3369/files#diff-1d7e7e258210abb910bb9c392731a3195ffca03024082c4b357e61c475dd3e3f">+5/-0</a>&nbsp;
&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-06-18 14:02:18 +02:00
Ivan Kuznetsov
e7762cb2b5 fix (examples/nextjs-server-components): added missing await (#3364) 2025-06-17 11:53:38 +02:00
gssakash-nhost
e353d99de8 feat (examples/react-apollo): add more social providers (#3339)
### **User description**
___

### **PR Type**
Enhancement


___

### **Description**
- **Added OAuth Integrations**  
Enabled OAuth for Spotify, Twitch, GitLab, Bitbucket, WorkOS, Discord,
AzureAD, Facebook, Strava, Windows Live, and Twitter.
- **Enhanced UI**  
  Added login buttons for each provider.
- **Updated Configuration**  
Configured OAuth settings in `nhost.toml` and updated the authentication
version as necessary.
- **Included Example Credentials**  
  Added client credentials to `.secrets.example` for easy setup.

___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>oauth-links.tsx</strong><dd><code>Add Spotify OAuth
button to login options</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

examples/react-apollo/src/components/auth/oauth-links.tsx

<li>Imported Spotify icon from react-simple-icons<br> <li> Added Spotify
to useProviderLink hook<br> <li> Implemented Spotify login button with
styling


</details>


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

</tr>
</table></td></tr><tr><td><strong>Configuration
changes</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>nhost.toml</strong><dd><code>Enable Spotify OAuth in
e2e test project</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

dashboard/e2e/e2e-tests-project/nhost/nhost.toml

- Enabled Spotify OAuth method


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>.secrets.example</strong><dd><code>Add Spotify
credentials to secrets example</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

examples/react-apollo/.secrets.example

- Added placeholders for Spotify client ID and secret


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>nhost.toml</strong><dd><code>Configure Spotify OAuth in
example project</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

examples/react-apollo/nhost/nhost.toml

<li>Enabled Spotify OAuth method<br> <li> Added configuration for
Spotify client ID and secret


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3339/files#diff-268d6c8dddd6990d60d62c1c923955c4e0e7549a80f0f5856192f889378416a0">+3/-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>

---------

Co-authored-by: David Barroso <dbarrosop@dravetech.com>
2025-06-13 11:06:43 +02:00
David Barroso
c4d289a4d5 chore (docs): added limits section (#3367)
### **PR Type**
Documentation, Enhancement


___

### **Description**
- Added new 'Limits' section to Functions overview

- Detailed function execution timeout limits by project tier

- Included custom timeout option for Enterprise tier


___



### **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>overview.mdx</strong><dd><code>Add Function Execution
Timeout Limits Section</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

docs/products/functions/overview.mdx

<li>Added new 'Limits' section after deployment information<br> <li>
Listed function execution timeout limits for different project tiers<br>
<li> Included Starter, Pro, Teams, and Enterprise tier limits<br> <li>
Mentioned custom timeout values for Enterprise tier


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3367/files#diff-c1e4e354976e7a602620f2540bb357b7d4d73853f8310342a75e1e14d4fd35f3">+9/-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-06-12 14:24:32 +02:00
github-actions[bot]
e2065e22df chore: update versions (#3360)
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.32.0

### Minor Changes

-   736862c: fix: update link to base directory docs in git settings
-   ea99fb3: chore: dashboard: improve messaging when git connected

### Patch Changes

-   d738884: chore (dashboard): Add link about antivirus integration

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-06-10 14:17:38 +02:00
robertkasza
d738884d7d chore (dashboard): Add link about antivirus integration (#3363)
### **PR Type**
Enhancement, Documentation


___

### **Description**
- Add antivirus integration documentation link

- Update HasuraStorageAVSettings component

- Create changeset for dashboard patch


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>HasuraStorageAVSettings.tsx</strong><dd><code>Add
antivirus documentation link to settings component</code>&nbsp; &nbsp;
&nbsp; </dd></summary>
<hr>


dashboard/src/features/orgs/projects/storage/settings/components/StorageAVSettings/HasuraStorageAVSettings.tsx

- Add `docsLink` prop to component with antivirus documentation URL


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>pink-grapes-cheat.md</strong><dd><code>Add changeset
for dashboard antivirus link update</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

.changeset/pink-grapes-cheat.md

<li>Create new changeset file for dashboard patch<br> <li> Add
description for antivirus integration link addition


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3363/files#diff-08b9cb5cc1ddca46a96721dbb3e6982d1833985dc4342ec17b9c1e7dfefa7cb4">+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-06-10 13:46:09 +02:00
robertkasza
b50404566f feat (dashboard): Add logs view to deployment page (#3352)
### **PR Type**
Enhancement, Documentation


___

### **Description**
- Add logs view to deployment page

- Refactor logs components for reusability

- Improve log filtering and service selection

- Update GraphQL queries and fragments


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><details><summary>22
files</summary><table>
<tr>
<td><strong>LogsRegexFilter.tsx</strong><dd><code>Add reusable
LogsRegexFilter component</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3352/files#diff-349fe23e29895116a6e03cd9277c455860af99f3690cc267b2cc7a07628c2530">+87/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>index.ts</strong><dd><code>Export LogsRegexFilter
component</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></td>
<td><a
href="https://github.com/nhost/nhost/pull/3352/files#diff-7fa93132c67731a94b80233a459cab4e83f6c9f3f5adaa21661876bc4c4240bd">+1/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>LogsServiceFilter.tsx</strong><dd><code>Add reusable
LogsServiceFilter component</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3352/files#diff-a590a7298a9f040df9f26c4eb37d10fc36f47c32996f71aec47796f08c44e892">+69/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>index.ts</strong><dd><code>Export LogsServiceFilter
component</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></td>
<td><a
href="https://github.com/nhost/nhost/pull/3352/files#diff-e75bdc4d69b5725a63a6867b58a41fe4a9892d20c528f91382342959954e6ec7">+1/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>DeploymentDetails.tsx</strong><dd><code>Create
DeploymentDetails component with logs view</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3352/files#diff-e95736b80d6545cd9bab82a81263adef8e9c39f8428eae50420e4b65339b774b">+161/-0</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>DeploymentInfo.tsx</strong><dd><code>Add DeploymentInfo
component for log timestamps</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3352/files#diff-37a0e29e73146c3434fe95b0aa93b93f51db32211b2f2646e7248f7ac2dce1a6">+38/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>DeploymentServiceLogs.tsx</strong><dd><code>Implement
DeploymentServiceLogs component</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3352/files#diff-333a9783713e9a4bad1b5327e117cbe69148091abe8b9038d36132b5f4635bbe">+59/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>DeploymentServiceLogsHeader.tsx</strong><dd><code>Create
DeploymentServiceLogsHeader component</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/3352/files#diff-4f102c06ed32bb3d8245e415e76b0b14d2d4ae3abca6e234edf69278325c7a95">+81/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>index.tsx</strong><dd><code>Export DeploymentServiceLogs
component</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3352/files#diff-acd5fadae2f4f5f8a9de9717237d93ada3da2c3502bda78cfab123b9b8b4e8f3">+1/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>index.ts</strong><dd><code>Export useDeployment
hook</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3352/files#diff-d45a44082ae4d2d5148c908d077ff69b69cf6ebcd8389e21f5381842cd1896f5">+1/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>useDeployment.ts</strong><dd><code>Implement useDeployment
hook</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3352/files#diff-e733d29eeab1252ca05a48aa009938205b5f9b0b5e3f90535b6159c1e7ec9137">+59/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>index.ts</strong><dd><code>Export useProjectLogs
hook</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3352/files#diff-ae67977c734fbd0f10114658db5b715c09eb8cfe5ae720a96ae7692905e9071e">+2/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>useProjectLogs.ts</strong><dd><code>Implement useProjectLogs
hook</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3352/files#diff-10efc67700b3f024dd03442eacd339802e951696d04caa76bd5a864bd5c7c83f">+122/-0</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>LogsBody.tsx</strong><dd><code>Update LogsBody
component</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3352/files#diff-b628e511a7fb9b237ac691b27ab9585eed0d0803144cde66c3af7fa6f9a2dc40">+49/-31</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>LogsHeader.tsx</strong><dd><code>Refactor LogsHeader
component</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3352/files#diff-ebb3285aa776c9c5ea8b72672c4aafd55994c6c694998bbf56ca9c56d1e77664">+12/-125</a></td>

</tr>

<tr>
<td><strong>LogsServiceFilter.tsx</strong><dd><code>Remove
LogsServiceFilter component</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></td>
<td><a
href="https://github.com/nhost/nhost/pull/3352/files#diff-52634b3870eb08646192600c3ec6bb2737750327dcfa5c08435d99a108fb057c">+0/-29</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>LogsRangeSelector.tsx</strong><dd><code>Update
LogsRangeSelector component</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></td>
<td><a
href="https://github.com/nhost/nhost/pull/3352/files#diff-46dd7c795a79e4b443213ed10089651423d13e5c776ca72e3a95ae5e0f7f63c8">+14/-11</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>services.ts</strong><dd><code>Add custom templates fetcher
service</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3352/files#diff-8fcdaed33322718091b613ae22c65cc3eb61972904b5af46866b160c9bbbe48c">+2/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>[deploymentId].tsx</strong><dd><code>Update deployment
details page</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3352/files#diff-fbf95e7970ecb8157795fe4d1803c6913b1ba78183fa8a9b0ca9b9e4e9eccba2">+3/-144</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>logs.tsx</strong><dd><code>Refactor logs page to use new
hooks</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3352/files#diff-77489a68a7526d74f06d59019ad68c44728b7620637308d70fba38d6649b73fa">+9/-119</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>graphql.ts</strong><dd><code>Update generated GraphQL
types</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3352/files#diff-fbd5db84b560b1c91675004448c6c7fa0dcbfb28b9eb05d53b03e6cb7b83ebac">+75/-23</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>deployments.graphql</strong><dd><code>Update GraphQL queries
and fragments</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3352/files#diff-c8c4668b1999c73e78eb706631ce9d0e0e41debf66e616350436af4ae3095b76">+31/-22</a>&nbsp;
</td>

</tr>

</table></details></td></tr><tr><td><strong>Tests</strong></td><td><details><summary>3
files</summary><table>
<tr>
<td><strong>useDeployment.test.ts</strong><dd><code>Add tests for
useDeployment hook</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></td>
<td><a
href="https://github.com/nhost/nhost/pull/3352/files#diff-37c7c86c6c93931c8794f241db0605267d1a051786972c1ab763ca0fe94f2b2b">+183/-0</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>updateQuery.test.ts</strong><dd><code>Add tests for
updateQuery function</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></td>
<td><a
href="https://github.com/nhost/nhost/pull/3352/files#diff-9eeaaad41f9097bab3be3769f17e4de74c642d5a2313899df3663e1bd3856b30">+324/-0</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>useProjectLogs.test.ts</strong><dd><code>Add tests for
useProjectLogs hook</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; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3352/files#diff-13d900aa08d06962a09628136b893801ad62a96c3ff89d380c5c4b7ae92d891e">+328/-0</a>&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-06-10 12:01:45 +02:00
Emory Mercera
8caf3daa54 Improve sentence flow of paragraph. (#3359)
Improve sentence flow of paragraph.
2025-06-10 11:08:27 +02:00
Calvin
8a07613cbe fix(examples/docker-compose): fix postgres persistent data storage path (#3346) 2025-06-10 11:08:21 +02:00
David BM
736862c9cc fix (dashboard): update link to base directory docs in git settings (#3358)
### **PR Type**
Bug fix


___

### **Description**
- Update link to base directory docs in git settings

- Correct URL for base directory documentation


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Bug
fix</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>BaseDirectorySettings.tsx</strong><dd><code>Update Base
Directory Documentation Link</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/features/orgs/projects/git/settings/components/BaseDirectorySettings/BaseDirectorySettings.tsx

<li>Updated <code>docsLink</code> prop with correct URL for base
directory <br>documentation


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>rich-cups-nail.md</strong><dd><code>Add Changeset for
Documentation Link Update</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

.changeset/rich-cups-nail.md

<li>Added changeset file for minor version bump<br> <li> Described fix
for updating base directory docs link


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3358/files#diff-d085c64fa4e5869bd8d8aa20ef902840240daf6463c463f5a2ae9001932e961b">+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-06-06 16:12:41 +02:00
Nuno Pato
ea99fb31d7 chore: dashboard: improve messaging then git connected (#3348)
### **PR Type**
Enhancement, Documentation


___

### **Description**
- Improved GitHub connection messaging in SettingsLayout

- Updated DataBrowserSidebar for GitHub-connected projects

- Added 'graphite' to READ_ONLY_SCHEMAS list

- Created changeset for dashboard version bump


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>SettingsLayout.tsx</strong><dd><code>Redesign GitHub
connection alert in SettingsLayout</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

dashboard/src/features/orgs/layout/SettingsLayout/SettingsLayout.tsx

<li>Redesigned GitHub connection alert<br> <li> Changed alert severity
from warning to info<br> <li> Improved text content and styling<br> <li>
Added link to configuration overlays documentation


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3348/files#diff-aa21cda513a125d8cefc5e7b5e1c755128aa904657350abf0ce1cde21e27ca75">+36/-30</a>&nbsp;
</td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>DataBrowserSidebar.tsx</strong><dd><code>Update GitHub
connection message in DataBrowserSidebar</code>&nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>


dashboard/src/features/orgs/projects/database/dataGrid/components/DataBrowserSidebar/DataBrowserSidebar.tsx

<li>Updated GitHub connection message in DataBrowserSidebar<br> <li>
Simplified text and added InfoIcon<br> <li> Improved layout and styling
of the message


</details>


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

</tr>
</table></td></tr><tr><td><strong>Configuration
changes</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>common.ts</strong><dd><code>Add 'graphite' to
READ_ONLY_SCHEMAS constant</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

dashboard/src/utils/constants/common/common.ts

- Added 'graphite' to READ_ONLY_SCHEMAS list


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>rich-pillows-teach.md</strong><dd><code>Add changeset
for dashboard version bump</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></summary>
<hr>

.changeset/rich-pillows-teach.md

<li>Created changeset file for minor version bump<br> <li> Added
description of changes for @nhost/dashboard


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3348/files#diff-80c4d9304d4ac2cca6acd40a4909dd85be2d333b64c3a8a25d84bfa6201d9122">+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>

---------

Co-authored-by: robertkasza <167509084+robertkasza@users.noreply.github.com>
2025-06-05 21:01:23 +00:00
github-actions[bot]
70433187cc chore: update versions (#3355)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


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

### Minor Changes

-   39b10a2: feat (dashboard): Add multi-factor authentication

## @nhost/react@3.11.0

### Minor Changes

-   39b10a2: feat (dashboard): Add multi-factor authentication
-   4b84780: feat (dashboard): Add Webauthn to dashboard

### Patch Changes

-   @nhost/nhost-js@3.2.9

## @nhost/apollo@8.0.9

### Patch Changes

-   @nhost/nhost-js@3.2.9

## @nhost/react-apollo@18.0.0

### Patch Changes

-   Updated dependencies [39b10a2]
-   Updated dependencies [4b84780]
    -   @nhost/react@3.11.0
    -   @nhost/apollo@8.0.9

## @nhost/react-urql@15.0.0

### Patch Changes

-   Updated dependencies [39b10a2]
-   Updated dependencies [4b84780]
    -   @nhost/react@3.11.0

## @nhost/nextjs@2.2.8

### Patch Changes

-   Updated dependencies [39b10a2]
-   Updated dependencies [4b84780]
    -   @nhost/react@3.11.0

## @nhost/nhost-js@3.2.9

### Patch Changes

-   Updated dependencies [39b10a2]
    -   @nhost/hasura-auth-js@2.12.0

## @nhost/vue@2.9.6

### Patch Changes

-   @nhost/nhost-js@3.2.9

## @nhost/dashboard@2.31.0

### Minor Changes

-   39b10a2: feat (dashboard): Add multi-factor authentication
-   4b84780: feat (dashboard): Add Webauthn to dashboard

### Patch Changes

-   61eb6cd: fix (dashboard): Fix update project e2e test
    -   @nhost/react-apollo@18.0.0
    -   @nhost/nextjs@2.2.8

## @nhost-examples/cli@0.3.22

### Patch Changes

-   @nhost/nhost-js@3.2.9

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

### Patch Changes

-   Updated dependencies [39b10a2]
-   Updated dependencies [4b84780]
    -   @nhost/react@3.11.0
    -   @nhost/react-apollo@18.0.0

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

### Patch Changes

-   Updated dependencies [39b10a2]
-   Updated dependencies [4b84780]
    -   @nhost/react@3.11.0

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

### Patch Changes

-   Updated dependencies [39b10a2]
-   Updated dependencies [4b84780]
    -   @nhost/react@3.11.0
    -   @nhost/react-urql@15.0.0

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

### Patch Changes

-   @nhost/nhost-js@3.2.9

## @nhost-examples/nextjs@0.4.8

### Patch Changes

-   Updated dependencies [39b10a2]
-   Updated dependencies [4b84780]
    -   @nhost/react@3.11.0
    -   @nhost/react-apollo@18.0.0
    -   @nhost/nextjs@2.2.8

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

### Patch Changes

-   @nhost/nhost-js@3.2.9

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

### Patch Changes

-   @nhost/nhost-js@3.2.9

## @nhost-examples/sveltekit@0.8.1

### Patch Changes

-   @nhost/nhost-js@3.2.9

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

### Patch Changes

-   Updated dependencies [39b10a2]
-   Updated dependencies [4b84780]
    -   @nhost/react@3.11.0
    -   @nhost/react-apollo@18.0.0

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

### Patch Changes

-   Updated dependencies [39b10a2]
-   Updated dependencies [4b84780]
    -   @nhost/react@3.11.0

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

### Patch Changes

-   Updated dependencies [39b10a2]
-   Updated dependencies [4b84780]
    -   @nhost/react@3.11.0
    -   @nhost/react-apollo@18.0.0

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

### Patch Changes

-   @nhost/nhost-js@3.2.9
-   @nhost/apollo@8.0.9
-   @nhost/vue@2.9.6

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

### Patch Changes

-   @nhost/apollo@8.0.9
-   @nhost/vue@2.9.6

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-06-05 12:39:48 +02:00
robertkasza
39b10a2e9f feat (dashboard): Add mfa (#3342)
### **PR Type**
Enhancement


___

### **Description**
- Add multi-factor authentication (MFA) to dashboard

- Implement MFA OTP form and QR code generation

- Create MFA settings and activation components

- Update sign-in process to support MFA


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><details><summary>19
files</summary><table>
<tr>
<td><strong>MfaOtpForm.tsx</strong><dd><code>Create reusable MFA OTP
form component</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3342/files#diff-88ee3610a0658d5eead85db025a5e91e74a4d2f2a836adf7eb44ff80888a613b">+61/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>index.ts</strong><dd><code>Export MfaOtpForm
component</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3342/files#diff-9c1deb50c3a92ca5494be705635984a97e1b41b07cd0847168a4eeddf0e375d0">+1/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>AccountMfaSettings.tsx</strong><dd><code>Implement MFA
settings component</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></td>
<td><a
href="https://github.com/nhost/nhost/pull/3342/files#diff-4eb33e0f23780eaf93fd7d86850b263d83b05dc2d7a3f6ed9e30d1ca811f17af">+32/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>GenerateMfaQRCodeButton.tsx</strong><dd><code>Create button
to generate MFA QR code</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3342/files#diff-7310648a5e879bb76ba6c3136fe555ed3bbdacddc33eef4ce8fc9c21a547ec82">+50/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>MfaQRCode.tsx</strong><dd><code>Implement MFA QR code
generation component</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3342/files#diff-0c60d61f12b47e421c67c389c66399da76af4b32241610fe94c6635353e57da2">+49/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>useActivateMfa.ts</strong><dd><code>Create hook for MFA
activation</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3342/files#diff-0ae70fc9df5a3a6828f7a266db8036107ce9ea705cd318d3a1c4b7304d8522ba">+46/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>useMfaEnabled.ts</strong><dd><code>Create hook to check MFA
status</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3342/files#diff-31d2af339a8dd32beff8cce79962fa0dd23b6c89687b21aa75663ebeccb0b154">+17/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>index.ts</strong><dd><code>Export AccountMfaSettings
component</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3342/files#diff-8c530fc016dd3569f2b7ec7e9085b99c99922ed077357bec562b8c9acaead24a">+1/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>SecurityKeyList.tsx</strong><dd><code>Update import path for
useGetSecurityKeys</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3342/files#diff-966a157d381be33bc876e76b28f804e80cae6edb1aa088e78f883063966be3ba">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>useOnAddNewSecurityKeyHandler.ts</strong><dd><code>Update
import paths for hooks</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3342/files#diff-3514a6d1514269a83f37fc25e9cb24add9d5d74f9cf3341293c0e0f2a4c2e286">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>useRemoveSecurityKey.ts</strong><dd><code>Update import
paths for hooks</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3342/files#diff-5683e00a14f39018d8fe58a3116c2a8ea6d2f2a83abb2177bbf0ee8ddf0f97b5">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>useElevatedPermissions.ts</strong><dd><code>Create hook for
elevated permissions</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3342/files#diff-c1e4f573300c771149cc2e59918c9acf2ae5f8a6680800a899707c70800ba144">[link]</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>useGetSecurityKeys.ts</strong><dd><code>Create hook to fetch
security keys</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></td>
<td><a
href="https://github.com/nhost/nhost/pull/3342/files#diff-1f9fed870cab61f15e304342e4913edab0f5537eeb6230070de4b4f7173fa138">[link]</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>MfaSignInOtpForm.tsx</strong><dd><code>Create MFA sign-in
OTP form component</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3342/files#diff-91eba232beb0543b1e972ed9a21a0be797ed94b720487834bb3316a5dbd732f5">+26/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>SignInWithEmailAndPassword.tsx</strong><dd><code>Update
sign-in component to support MFA</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3342/files#diff-a2b70644663baf4f6f2cdffd846d4d743a5ca1f2a64c4b278b6f04c6c5c92161">+16/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>

<td><strong>SignInWithEmailAndPasswordForm.tsx</strong><dd><code>Implement
sign-in form with MFA support</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3342/files#diff-a07fd6bd20c97d0c9c875e690cd3a80068fc58f74d3579feb210e189d32f5031">+91/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>

<td><strong>useOnSignInWithEmailAndPasswordHandler.ts</strong><dd><code>Create
hook for sign-in with MFA</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></td>
<td><a
href="https://github.com/nhost/nhost/pull/3342/files#diff-1a253bfc02c3267ab1c6b58c07aa06142b7e711d613b672c8420ff2861b12d27">+56/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>

<td><strong>useSignInWithEmailAndPasswordForm.ts</strong><dd><code>Create
hook for sign-in form validation</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3342/files#diff-b908e474c0fb54db9c922d9fef7cf1ef6c4ccb0dd7519da0c45a18e5bb26ed40">+30/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>index.ts</strong><dd><code>Export SignInWithEmailAndPassword
component</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/3342/files#diff-d3fd195b5ca8ece9eac446129e8501793e5bd6e5c167ed36c8c6d0adc1723fda">+1/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></details></td></tr><tr><td><strong>Additional
files</strong></td><td><details><summary>8 files</summary><table>
<tr>
  <td><strong>mighty-onions-crash.md</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3342/files#diff-834d585225de297c20c9e325a231c6d3a72227fc1d8cc84b0c1f8fe0dbb1c523">+7/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>getActiveMfaType.gql</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3342/files#diff-ac5aa6c409363b550d15aace147448c5e267a3cf0fb7f86faf5060f8cbe35302">+5/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>index.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3342/files#diff-61a48d15d3a2e29160a6d91cd01501ac94cf9f70995c6a84fbb6d6e2c2d4fca1">+4/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>email.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3342/files#diff-b5d7db4460066bc114cb766771612d6f908bd6e440f40de98e4ac311a26b50cd">+16/-152</a></td>

</tr>

<tr>
  <td><strong>graphql.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3342/files#diff-fbd5db84b560b1c91675004448c6c7fa0dcbfb28b9eb05d53b03e6cb7b83ebac">+80/-35</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>enable-mfa.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3342/files#diff-8ed0174991b707a5c54f54ec881656403b4409cd0e3d7004045a80dbeb7b4444">+1/-4</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3342/files#diff-1cee8646d2cfba37d6ce6a6e9a8d16f8caba0b99fc3a1ad0cb997ed8c7384d2e">+7/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>useSignInEmailPassword.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3342/files#diff-107884d4022cd6c01459f001fa97d2b2ce11566a2c88c8deaec4727c1af44aba">+6/-8</a>&nbsp;
&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-06-05 11:38:49 +02:00
robertkasza
4b8478004e feat (dashboard): Add Webauthn to dashboard (#3320) 2025-06-05 10:28:42 +02:00
robertkasza
61eb6cdc2d fix (dashboard): fix e2e test (#3354)
### **PR Type**
Bug fix, Tests


___

### **Description**
- Refactored e2e test for project upgrade

- Removed unnecessary 'await' keywords

- Added step to save payment information

- Commented out local dashboard image build and tests


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>upgrade-project.test.ts</strong><dd><code>Refactor and
enhance upgrade project e2e test</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

dashboard/e2e/upgrade-project/upgrade-project.test.ts

<li>Removed redundant 'await' keywords<br> <li> Added step to save
payment information<br> <li> Simplified assertions and variable
assignments<br> <li> Minor code cleanup and formatting


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3354/files#diff-8bafbe707eb1dff0c5ae24d6b0a514ff6e80889237de6c89ec330a93be138a12">+18/-16</a>&nbsp;
</td>

</tr>
</table></td></tr><tr><td><strong>Configuration
changes</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>ci.yaml</strong><dd><code>Modify CI workflow to focus
on specific tests</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

.github/workflows/ci.yaml

<li>Commented out local dashboard image build step<br> <li> Removed
Nhost CLI installation and local tests<br> <li> Disabled general e2e
tests run


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3354/files#diff-944291df2c9c06359d37cc8833d182d705c9e8c3108e7cfe132d61a06e9133dd">+21/-21</a>&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-06-05 09:17:46 +02:00
github-actions[bot]
14187d381f chore: update versions (#3332)
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.30.0

### Minor Changes

-   f6947a2: fix: fetch job-backup services logs using Live filter
- 44a3e6b: fix: collapsed main navigation sidebar overlaps mobile navbar
-   99b78f1: feat: dashboard: add download button for soc2 report
-   9acae7d: fix: e2e tests, stop on error when refreshing metadata

### Patch Changes

- 31e636a: fix (dashboard): Use the correct payload to reset metadata
before the e2e tests

## @nhost/docs@2.32.0

### Minor Changes

-   df51c3e: fix: added installation instructions for the CLI

### Patch Changes

-   4d835c4: fix: remove nodejs18
-   2aa81a6: fix (docs): fix audit

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

### Minor Changes

-   6ee2d1f: fix: proper use of onError in middleware

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-06-03 18:33:21 +00:00
Nuno Pato
99b78f147e feat: dashboard: add download button for soc2 report (#3349)
### **PR Type**
Enhancement


___

### **Description**
- Add SOC2 report download button for eligible organizations

- Implement Soc2Download component with error handling

- Update settings page to include Soc2Download component

- Add environment variable for SOC2 report file ID


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>Soc2Download.tsx</strong><dd><code>Implement
Soc2Download Component</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>


dashboard/src/features/orgs/components/general/components/Soc2Download/Soc2Download.tsx

<li>Create Soc2Download component with download functionality<br> <li>
Implement eligibility check for Team and Enterprise plans<br> <li> Add
error handling and user feedback for download process<br> <li> Design UI
for SOC2 report download section


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3349/files#diff-3768eb3fc718d4780028c34b5c76388e8d93cbbac94868f82c1a262fb9cc1100">+88/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>index.ts</strong><dd><code>Export Soc2Download
Component</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>


dashboard/src/features/orgs/components/general/components/Soc2Download/index.ts

- Export Soc2Download component as default


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>settings.tsx</strong><dd><code>Add Soc2Download to
Settings Page</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; </dd></summary>
<hr>

dashboard/src/pages/orgs/[orgSlug]/settings.tsx

<li>Import Soc2Download component<br> <li> Add Soc2Download component to
OrgSettings page


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>spicy-walls-joke.md</strong><dd><code>Add Changeset for
SOC2 Download Feature</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></summary>
<hr>

.changeset/spicy-walls-joke.md

<li>Add changeset for minor version bump<br> <li> Describe feature
addition for SOC2 report download


</details>


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

</tr>
</table></td></tr><tr><td><strong>Configuration
changes</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>.env.example</strong><dd><code>Add SOC2 Report File ID
Environment Variable</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

dashboard/.env.example

- Add NEXT_PUBLIC_SOC2_REPORT_FILE_ID environment variable


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3349/files#diff-b47cf46119af2f0298d96e5657e53e57161833e8b02d87526ac5c1ed9393d477">+3/-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-06-03 15:04:05 +00:00
robertkasza
2aa81a6cb9 fix (docs): fix audit (#3351)
### **PR Type**
Bug fix, Documentation


___

### **Description**
- Update audit-ci.jsonc to allow CVE-2025-48068 for 'next'

- Add new security patches in package.json

- Create changeset for @nhost/docs patch

- Improve documentation and audit compliance


___



### **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>yellow-drinks-sort.md</strong><dd><code>Add changeset
for @nhost/docs patch</code>&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/yellow-drinks-sort.md

<li>Add new changeset file for @nhost/docs<br> <li> Specify patch
version update<br> <li> Include fix message for documentation audit


</details>


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

</tr>
</table></td></tr><tr><td><strong>Configuration
changes</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>audit-ci.jsonc</strong><dd><code>Update audit-ci.jsonc
allowlist for security exception</code>&nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

audit-ci.jsonc

- Add allowlist entry for CVE-2025-48068 in 'next' path


</details>


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

</tr>
</table></td></tr><tr><td><strong>Dependencies</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>package.json</strong><dd><code>Update package.json with
new security patches</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

package.json

<li>Add new security patches for undici and tar-fs<br> <li> Update
existing security patch versions<br> <li> Adjust formatting for
consistency


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3351/files#diff-7ae45ad102eab3b6d7e7896acd08c427a9b25b346470d7bc6507b6481575d519">+4/-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-06-03 16:01:52 +02:00
David BM
a1edaf18ea fix: update requirements in DEVELOPERS.md (#3345)
### **User description**
Update requirements for development to Node.js 20


___

### **PR Type**
Documentation


___

### **Description**
- Update Node.js requirement to v20 or later

- Remove mention of Node.js v16 support

- Simplify Node.js version requirement section


___



### **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>DEVELOPERS.md</strong><dd><code>Update Node.js version
requirement</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>

DEVELOPERS.md

<li>Updated Node.js requirement to v20 or later<br> <li> Removed mention
of Node.js v16 support<br> <li> Simplified Node.js version requirement
section


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3345/files#diff-bd017515eb79a7fb7569b1d15e8963ea380123d4fdf779978dd4b3ab7500fd10">+1/-3</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>

Co-authored-by: David Barroso Murcia <davidbm@air-m4.local>
2025-05-22 12:14:15 +02:00
David Barroso
4d835c4b9c fix (docs): remove nodejs18 (#3343)
### **PR Type**
Documentation


___

### **Description**
- Remove Node.js 18 runtime from supported versions

- Update documentation to reflect current runtimes

- Remove Node.js 18 configuration example

- Add changeset for patch update to @nhost/docs


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>brave-garlics-act.md</strong><dd><code>Add changeset
for removing Node.js 18</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

.changeset/brave-garlics-act.md

<li>Add new changeset file for @nhost/docs patch update<br> <li>
Describe fix to remove Node.js 18


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>runtimes.mdx</strong><dd><code>Update runtimes
documentation to remove Node.js 18</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

docs/products/functions/runtimes.mdx

<li>Remove Node.js 18 from list of supported runtimes<br> <li> Delete
Node.js 18 configuration example<br> <li> Update supported versions to
Node.js 20 and 22


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3343/files#diff-41cc586838cadca39a91bf32878fb7cc5473d5815dec595547a4089684b5d489">+0/-9</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-05-20 22:19:18 +02:00
David BM
44a3e6bd41 fix (dashboard): collapsed main navigation sidebar overlaps mobile navbar (#3341) 2025-05-20 22:05:58 +02:00
Dimitri POSTOLOV
6ee2d1f5bf fix (examples/nextjs-server-components): proper use of onError in middleware (#3330)
onError should be returned since it can contain `NextResponse.redirect`
like in the example
e87505c564/examples/quickstarts/nextjs-server-components/src/middleware.ts (L5-L7)

---------

Co-authored-by: David Barroso <dbarrosop@dravetech.com>
2025-05-19 11:21:06 +02:00
Calvin
df51c3e64e fix (docs): added installation instructions for the CLI (#3329)
Co-authored-by: David Barroso <dbarrosop@dravetech.com>
2025-05-16 09:01:45 +02:00
David BM
9acae7d1c4 fix (dashboard ci): stop playwright e2e tests run after first failure (#3334)
### **PR Type**
Bug fix, Enhancement


___

### **Description**
- Reload metadata for Graphite's remote schemas in e2e tests

- Add 'reload_remote_schemas' parameter to metadata reload

- Include Changeset for version tracking


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>refresh-metadata.setup.ts</strong><dd><code>Add
Graphite remote schema to metadata reload</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

dashboard/e2e/setup/refresh-metadata.setup.ts

<li>Add 'reload_remote_schemas' parameter with value ['graphite']<br>
<li> Include Graphite remote schema in metadata reload


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>wild-stingrays-help.md</strong><dd><code>Add changeset
for dashboard version update</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

.changeset/wild-stingrays-help.md

<li>Create new changeset file<br> <li> Specify minor version bump for
'@nhost/dashboard'<br> <li> Add description of the fix


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3334/files#diff-b5a0c57a4f2bd08515f9feef3c38804e7f948ffb4b76418f6549131f61cf20fd">+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-05-15 18:03:29 +02:00
David BM
f6947a2194 fix (dashboard): logs page, fetch job-backup services logs using Live filter (#3333)
### **User description**
Adds `job-backup.+` regex pattern to the service filter in the logs
subscription, to match any job-backup services


___

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


___

### **Description**
- Fix logs fetching for job-backup services

- Implement regex pattern for job-backup service filter

- Improve live log subscription functionality

- Add changeset for version tracking


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>logs.tsx</strong><dd><code>Improve log fetching for
job-backup services</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

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

<li>Modify service filter in logs subscription<br> <li> Implement regex
pattern 'job-backup.+' for job-backup services<br> <li> Enhance
conditional logic for service filtering


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>hungry-waves-destroy.md</strong><dd><code>Add changeset
for version tracking</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>

.changeset/hungry-waves-destroy.md

<li>Add new changeset file<br> <li> Specify minor version bump for
@nhost/dashboard<br> <li> Document fix for job-backup services logs
fetching


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3333/files#diff-45dd073b01febac00c055bb63f51182ff043ee7a5df2c12058232caf2d2a31ca">+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-05-14 13:55:11 +02:00
robertkasza
31e636a9c8 fix (dashboard): Use the correct payload to reset metadata before e2 tests (#3331)
### **PR Type**
Bug fix, Tests


___

### **Description**
- Fix metadata reset payload in e2e tests

- Improve error handling and logging for metadata consistency

- Add changeset for patch version bump


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Bug
fix</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>refresh-metadata.setup.ts</strong><dd><code>Refactor
metadata reset and improve consistency checks</code>&nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

dashboard/e2e/setup/refresh-metadata.setup.ts

<li>Updated payload for metadata reset (removed
<code>reload_remote_schemas</code>, set <br><code>reload_sources</code>
to false)<br> <li> Enhanced error handling and logging for metadata
consistency<br> <li> Added detailed console logging for inconsistent
metadata


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>lemon-flies-live.md</strong><dd><code>Add changeset for
dashboard patch update</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></summary>
<hr>

.changeset/lemon-flies-live.md

<li>Added changeset file for patch version bump<br> <li> Described fix
for metadata reset in e2e tests


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3331/files#diff-25789650a83994d924e29e67aafc8011da8f98e2178211207de1ef049d53e4f6">+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-05-13 13:18:29 +02:00
github-actions[bot]
0fdff345ac chore: update versions (#3327)
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.29.0

### Minor Changes

-   c97b43f: fix: update vite to address vulnerability audit
-   a0931e2: fix: improve logs time range and filter selection
- c0635ae: feat (dashboard): Add information about that free
organization cannot be upgraded.
- e87505c: fix: can downsize postgres storage capacity using local
dashboard

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

### Minor Changes

-   c97b43f: fix: update vite to address vulnerability audit

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

### Minor Changes

-   c97b43f: fix: update vite to address vulnerability audit

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

### Minor Changes

-   c97b43f: fix: update vite to address vulnerability audit

## @nhost-examples/sveltekit@0.8.0

### Minor Changes

-   c97b43f: fix: update vite to address vulnerability audit

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

### Minor Changes

-   c97b43f: fix: update vite to address vulnerability audit

### Patch Changes

-   97db637: fix: fix settings

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

### Minor Changes

-   c97b43f: fix: update vite to address vulnerability audit

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

### Minor Changes

-   c97b43f: fix: update vite to address vulnerability audit

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

### Minor Changes

-   c97b43f: fix: update vite to address vulnerability audit

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-05-12 20:05:18 +00:00
David Barroso
97db63791b fix (examples/react-apollo): fix settings (#3301)
### **PR Type**
Enhancement, Configuration changes


___

### **Description**
- Update auth settings in nhost.toml

- Remove rate limiting configurations

- Remove SMTP provider settings

- Add changeset for patch 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>lazy-years-kneel.md</strong><dd><code>Add changeset for
patch version bump</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>

.changeset/lazy-years-kneel.md

<li>Add new changeset file for patch version bump<br> <li> Specify
'@nhost-examples/react-apollo' package<br> <li> Include fix description


</details>


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

</tr>
</table></td></tr><tr><td><strong>Configuration
changes</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>nhost.toml</strong><dd><code>Update Nhost configuration
settings</code>&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>

examples/react-apollo/nhost/nhost.toml

<li>Change auth.elevatedPrivileges.mode to 'recommended'<br> <li> Remove
auth.rateLimit configurations<br> <li> Remove provider.smtp settings<br>
<li> Update allowed URLs for auth redirections


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3301/files#diff-268d6c8dddd6990d60d62c1c923955c4e0e7549a80f0f5856192f889378416a0">+1/-30</a>&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-05-12 19:30:59 +02:00
David BM
a0931e282f fix (dashboard): logs persist time range selector, fix validation (#3300)
### **User description**
Resolves #3154


___

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


___

### **Description**
- Fix logs search functionality with selected service filter

- Implement persistent time range selector

- Add interval-based date range selection

- Improve form validation and submission logic


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>LogsDatePicker.tsx</strong><dd><code>Enhance
LogsDatePicker with form context integration</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/features/orgs/projects/logs/components/LogsDatePicker/LogsDatePicker.tsx

<li>Import LogsFilterFormValues type and useFormContext hook<br> <li>
Add setValue function from form context<br> <li> Implement
handleDateChange to update selected date and reset interval<br> <li>
Update DatePicker onChange to use new handleDateChange function


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3300/files#diff-0768cb2a5cee4ab57a64580c34213950a042a9893b5da51b8886e166cb7a9060">+9/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>LogsHeader.tsx</strong><dd><code>Improve LogsHeader
with interval support and form handling</code></dd></summary>
<hr>


dashboard/src/features/orgs/projects/logs/components/LogsHeader/LogsHeader.tsx

<li>Add interval to validation schema and form default values<br> <li>
Implement interval-based date recalculation in handleSubmit<br> <li>
Update form mode to 'onChange' for real-time validation<br> <li> Modify
useEffect to trigger submission on service change


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>LogsRangeSelector.tsx</strong><dd><code>Enhance
LogsRangeSelector with interval selection and UI
updates</code></dd></summary>
<hr>


dashboard/src/features/orgs/projects/logs/components/LogsRangeSelector/LogsRangeSelector.tsx

<li>Add interval handling in LogsToDatePickerLiveButton<br> <li>
Implement interval setting in handleIntervalChange function<br> <li>
Update Button variant based on selected interval<br> <li> Add interval
to useWatch hook for reactive updates


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3300/files#diff-46dd7c795a79e4b443213ed10089651423d13e5c776ca72e3a95ae5e0f7f63c8">+9/-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-05-12 18:31:58 +02:00
David BM
e87505c564 fix (dashboard): downsize postgres using local dashboard (#3292)
### **User description**
Fixes #3265


___

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


___

### **Description**
- Fix PostgreSQL version parsing for empty strings

- Enable downsizing Postgres in local dashboard

- Improve handling of free project and platform checks

- Update refetch queries with optional chaining


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Bug
fix</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>useGetPostgresVersion.ts</strong><dd><code>Fix
PostgreSQL version parsing for empty strings</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/features/orgs/projects/database/common/hooks/useGetPostgresVersion/useGetPostgresVersion.ts

<li>Add fallback to empty string for <code>version</code> in
<br><code>splitPostgresMajorMinorVersions</code>


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>index.tsx</strong><dd><code>Update refetch queries with
optional chaining</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>


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

- Add optional chaining for `userData.id` in refetch queries


</details>


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

</tr>
</table></td></tr><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>DatabaseStorageCapacity.tsx</strong><dd><code>Improve
database storage capacity handling and UI</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/features/orgs/projects/database/settings/components/DatabaseStorageCapacity/DatabaseStorageCapacity.tsx

<li>Add <code>isEmptyValue</code> check for <code>org</code> object<br>
<li> Introduce <code>shouldShowUpdateCapacityWarning</code> variable<br>
<li> Modify <code>submitDisabled</code> logic for non-platform
environments<br> <li> Update conditional rendering of
<code>DatabaseStorageCapacityWarning</code>


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3292/files#diff-097a59d13b44816051386182a444eadfe2dcacd69b88c121af6733d7eca3ee43">+16/-3</a>&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-05-08 14:02:09 +02:00
robertkasza
c0635ae1c7 feat (dashboard): Add information about that free organization cannot be upgraded (#3316)
### **PR Type**
Enhancement


___

### **Description**
- Add info about free org upgrade limitations

- Introduce new 'NewOrgButton' component

- Update UI for subscription plan section

- Improve text link component functionality


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>InfoAlert.tsx</strong><dd><code>Enhance AlertTitle
styling</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

dashboard/src/features/orgs/components/InfoAlert/InfoAlert.tsx

- Added 'font-semibold' class to AlertTitle


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>SubscriptionPlan.tsx</strong><dd><code>Update
subscription plan UI and add free org info</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/features/orgs/components/billing/components/SubscriptionPlan/SubscriptionPlan.tsx

<li>Added InfoAlert for free organizations<br> <li> Introduced
NewOrgButton component<br> <li> Updated layout and styling of
subscription plan section<br> <li> Replaced Link component with TextLink


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>TextLink.tsx</strong><dd><code>Enhance TextLink
component with optional icon</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>


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

<li>Added optional icon to TextLink component<br> <li> Introduced
withIcon prop for flexibility


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>good-frogs-share.md</strong><dd><code>Add changeset for
dashboard feature</code>&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/good-frogs-share.md

- Added changeset file for version bump


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3316/files#diff-ff1c12916da9254a5d59fef39d5220a0ccdd20a7e66e1436a860da9a014d31ee">+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-05-07 13:31:01 +02:00
robertkasza
d2a9a9ae1d fix: update labeler config (#3328)
### **PR Type**
Enhancement


___

### **Description**
- Update labeler configuration for all categories

- Standardize format using 'any' key for all rules

- Remove redundant 'any' key for documentation category

- Maintain existing category definitions and file patterns


___



### **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>labeler.yml</strong><dd><code>Standardize and simplify
labeler configuration</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

.github/labeler.yml

<li>Standardized all rules using 'any' key<br> <li> Removed redundant
'any' key for documentation<br> <li> Maintained existing category
definitions and file patterns<br> <li> Simplified overall configuration
structure


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3328/files#diff-a22c263686553013feaeb0677d26eeb0b8778a756c4311c1fce13384258026aa">+8/-9</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-05-07 10:00:34 +02:00
David BM
c97b43f149 fix (ci): update vite to solve vulnerability audit (#3323)
### **PR Type**
Bug fix, Enhancement


___

### **Description**
- Update Vite to address vulnerability audit

- Upgrade Vite in multiple project dependencies

- Update package overrides for security

- Add changeset for minor version bumps


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Documentation</strong></td><td><details><summary>1
files</summary><table>
<tr>
<td><strong>chatty-kids-exist.md</strong><dd><code>Add changeset for
minor version updates</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3323/files#diff-22d27113acb695bcdab878d71e0e553a23f87070faeb4672ce09bf2108c56064">+13/-0</a>&nbsp;
&nbsp; </td>

</tr>

</table></details></td></tr><tr><td><strong>Dependencies</strong></td><td><details><summary>10
files</summary><table>
<tr>
<td><strong>package.json</strong><dd><code>Update Vite to
v5.4.19</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3323/files#diff-2d8d55c799cd71f1b35e831f075f8178ed1734c4820a2ad548b4dd24d6938d7c">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>package.json</strong><dd><code>Update Vite to
v5.4.19</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3323/files#diff-83675898dc6ed88838763232d022f6e100e07d71681cc8a1f02aee99ee3f229b">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>package.json</strong><dd><code>Update Vite to
v5.4.19</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3323/files#diff-9fb3a23f389ab1d192d7e018d2acbe512bd8792278662101401caa98692735db">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>package.json</strong><dd><code>Update Vite to
v5.4.19</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3323/files#diff-cb7094614884e8cd2c8fb67dadedb1887c46c31b888840def0b7042273bfbb28">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>package.json</strong><dd><code>Update Vite to
v6.2.7</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3323/files#diff-6288951fff74ec246c9cc023b7b7e3e9aad31423891bc4ea25b5d84a5f5b061f">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>package.json</strong><dd><code>Update Vite to
v5.4.19</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3323/files#diff-d95dc3391741287366ea2e61f70e9ccc64452e0d22b1db91d6bf524f5aa4331c">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>package.json</strong><dd><code>Update Vite to
v5.4.19</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3323/files#diff-8a3e5ed0f618f15211c31f700e0da998e2eae58f60353624b7a7e637bd63b153">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>package.json</strong><dd><code>Update Vite to
v5.4.19</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3323/files#diff-fc4298d3512fdd9a3d871f9f182fe871c8beccd1580f864a271ddfb32005feef">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>package.json</strong><dd><code>Update Vite to
v5.4.19</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3323/files#diff-85166d1137e29a5275f991e1e94a0c9d5b83ac7504463ba76f9187b2b750c895">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>package.json</strong><dd><code>Update Vite and adjust
overrides</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></td>
<td><a
href="https://github.com/nhost/nhost/pull/3323/files#diff-7ae45ad102eab3b6d7e7896acd08c427a9b25b346470d7bc6507b6481575d519">+4/-4</a>&nbsp;
&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>

---------

Co-authored-by: robertkasza <robert.kasza@bishop-co.com>
2025-05-06 14:39:39 +02:00
github-actions[bot]
2026bb7a9c chore: update versions (#3298)
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/apollo@8.0.8

### Patch Changes

-   @nhost/nhost-js@3.2.8

## @nhost/react-apollo@17.0.4

### Patch Changes

-   @nhost/apollo@8.0.8
-   @nhost/react@3.10.4

## @nhost/react-urql@14.0.4

### Patch Changes

-   @nhost/react@3.10.4

## @nhost/hasura-auth-js@2.11.1

### Patch Changes

- 5ff4dd6: fix (hasura-auth-js|hasura-storage-js): update e2e config for
packages

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

### Patch Changes

- 5ff4dd6: fix (hasura-auth-js|hasura-storage-js): update e2e config for
packages

## @nhost/nextjs@2.2.7

### Patch Changes

-   d9eb906: fix: update vite and nextjs because of vulnerability
    -   @nhost/react@3.10.4

## @nhost/nhost-js@3.2.8

### Patch Changes

-   Updated dependencies [5ff4dd6]
    -   @nhost/hasura-storage-js@2.7.1
    -   @nhost/hasura-auth-js@2.11.1

## @nhost/react@3.10.4

### Patch Changes

-   @nhost/nhost-js@3.2.8

## @nhost/vue@2.9.5

### Patch Changes

-   @nhost/nhost-js@3.2.8

## @nhost/dashboard@2.28.0

### Minor Changes

-   8552678: feat: dashboard: add additional events to segment
-   0bf2808: chore: refresh metadata before end-to-end tests
-   72a365c: fix: correct graphql page roles dropdown's source
-   cef6471: fix: dashboard: add anonid to user's metadata

### Patch Changes

-   d9eb906: fix: update vite and nextjs because of vulnerability
-   233232b: feat (dashboard): improve Upgrade project dialog
-   Updated dependencies [d9eb906]
    -   @nhost/nextjs@2.2.7
    -   @nhost/react-apollo@17.0.4

## @nhost/docs@2.31.0

### Minor Changes

-   b302dbd: feat: added sveltekit quickstart

### Patch Changes

-   5e96230: fix: fixing mintlify breaking our docs

## @nhost-examples/cli@0.3.21

### Patch Changes

-   @nhost/nhost-js@3.2.8

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

### Patch Changes

-   d9eb906: fix: update vite and nextjs because of vulnerability
    -   @nhost/react@3.10.4
    -   @nhost/react-apollo@17.0.4

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

### Patch Changes

-   d9eb906: fix: update vite and nextjs because of vulnerability
    -   @nhost/react@3.10.4

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

### Patch Changes

-   d9eb906: fix: update vite and nextjs because of vulnerability
    -   @nhost/react@3.10.4
    -   @nhost/react-urql@14.0.4

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

### Patch Changes

-   @nhost/nhost-js@3.2.8

## @nhost-examples/nextjs@0.4.7

### Patch Changes

-   fad7f64: chore: fix typo
-   d9eb906: fix: update vite and nextjs because of vulnerability
-   Updated dependencies [d9eb906]
    -   @nhost/nextjs@2.2.7
    -   @nhost/react@3.10.4
    -   @nhost/react-apollo@17.0.4

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

### Patch Changes

-   @nhost/nhost-js@3.2.8

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

### Patch Changes

-   d9eb906: fix: update vite and nextjs because of vulnerability
    -   @nhost/nhost-js@3.2.8

## @nhost-examples/sveltekit@0.7.1

### Patch Changes

-   f8243f9: chore (examples/svelte): update @sveltejs/kit
-   d9eb906: fix: update vite and nextjs because of vulnerability
    -   @nhost/nhost-js@3.2.8

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

### Patch Changes

-   d9eb906: fix: update vite and nextjs because of vulnerability
- efd68c3: chore (react-apollo): use preview build instead of local dev
server for e2e tests
    -   @nhost/react@3.10.4
    -   @nhost/react-apollo@17.0.4

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

### Patch Changes

-   d9eb906: fix: update vite and nextjs because of vulnerability
    -   @nhost/react@3.10.4

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

### Patch Changes

-   @nhost/react@3.10.4
-   @nhost/react-apollo@17.0.4

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

### Patch Changes

-   d9eb906: fix: update vite and nextjs because of vulnerability
    -   @nhost/nhost-js@3.2.8
    -   @nhost/apollo@8.0.8
    -   @nhost/vue@2.9.5

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

### Patch Changes

-   d9eb906: fix: update vite and nextjs because of vulnerability
    -   @nhost/apollo@8.0.8
    -   @nhost/vue@2.9.5

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-04-28 13:56:36 +00:00
David Barroso
1bc1e30f5e chore (ci): send message to discord (#3317)
### **PR Type**
Enhancement


___

### **Description**
- Add Discord notifications for dashboard deployment status

- Implement success and failure notifications separately

- Include deployment details in Discord messages

- Use tsickert/discord-webhook action for notifications


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>deploy-dashboard.yaml</strong><dd><code>Implement
Discord notifications for deployment status</code>&nbsp; &nbsp; &nbsp;
&nbsp; </dd></summary>
<hr>

.github/workflows/deploy-dashboard.yaml

<li>Added success notification step using Discord webhook<br> <li> Added
failure notification step using Discord webhook<br> <li> Both
notifications include deployment status, trigger user, and git
<br>ref<br> <li> Used different embed colors for success (green) and
failure (red)


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3317/files#diff-634642357deb8c43286f58a5b454c8f10aeab2fb9937c9cb0c4300ac84dc00cf">+28/-0</a>&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-04-28 14:37:33 +02:00
Nuno Pato
85526782f2 feat: dashboard: add additional segment events (#3313)
### **PR Type**
Enhancement


___

### **Description**
- Added Segment analytics tracking for key actions

- Implemented event tracking for project upgrades

- Added tracking for organization invites

- Included analytics for GitHub project connections

- Implemented tracking for new project creation


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>UpgradeProjectDialogContent.tsx</strong><dd><code>Add
Segment tracking for project upgrades</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/features/orgs/components/common/TransferOrUpgradeProjectDialog/UpgradeProjectDialogContent.tsx

<li>Imported useCurrentOrg and analytics<br> <li> Added Segment tracking
for 'Project Upgraded' event<br> <li> Included detailed project and
organization data in the event


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>PendingInvites.tsx</strong><dd><code>Implement Segment
tracking for organization invites</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/features/orgs/components/members/components/PendingInvites/PendingInvites.tsx

<li>Imported analytics from Segment<br> <li> Added tracking for
'Organization Invite Sent' event<br> <li> Included organization and
invitee details in the event


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>EditRepositorySettingsModal.tsx</strong><dd><code>Add
Segment tracking for GitHub project connections</code>&nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/features/orgs/projects/git/common/components/EditRepositorySettingsModal/EditRepositorySettingsModal.tsx

<li>Imported analytics from Segment<br> <li> Added tracking for 'Project
Connected to GitHub' event<br> <li> Included project and repository
details in the event


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>new.tsx</strong><dd><code>Implement Segment tracking
for new project creation</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

dashboard/src/pages/orgs/[orgSlug]/projects/new.tsx

<li>Imported analytics from Segment<br> <li> Added tracking for 'Project
Created' event<br> <li> Included project, organization, and region
details in the event


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>hungry-terms-retire.md</strong><dd><code>Add changeset
for Segment analytics feature</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

.changeset/hungry-terms-retire.md

<li>Added changeset file for minor version bump<br> <li> Described
feature addition of Segment events


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3313/files#diff-3accee3677ac6171593ed474c4c867ce1d27b490b69c9fd738f1cff121791ba9">+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-04-28 11:14:51 +00:00
Russians tortured my 18yo friend Ivan bc of ukr flag in mobile phone
fad7f640de fix (examples/nextjs): typo (#3309)
Co-authored-by: David Barroso <dbarrosop@dravetech.com>
2025-04-28 09:58:08 +02:00
robertkasza
5ff4dd6e40 fix (packages): update storage/auth e2e config (#3306)
### **PR Type**
Enhancement, Tests


___

### **Description**
- Update e2e configuration for hasura-auth-js and hasura-storage-js

- Modify CI workflow for package-specific Nhost CLI shutdown

- Adjust test scripts in package.json files

- Add changeset for patch updates


___



### **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>fluffy-shoes-cross.md</strong><dd><code>Add changeset
for auth and storage package updates</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

.changeset/fluffy-shoes-cross.md

<li>Add new changeset file for patch updates<br> <li> Specify changes
for @nhost/hasura-storage-js and @nhost/hasura-auth-js


</details>


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

</tr>
</table></td></tr><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>ci.yaml</strong><dd><code>Update CI workflow for
package-specific Nhost CLI shutdown</code></dd></summary>
<hr>

.github/workflows/ci.yaml

<li>Add new step to stop Nhost CLI for specific packages<br> <li> Ensure
Nhost CLI stops even if previous steps fail


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3306/files#diff-944291df2c9c06359d37cc8833d182d705c9e8c3108e7cfe132d61a06e9133dd">+6/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></td></tr><tr><td><strong>Tests</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>package.json</strong><dd><code>Modify test scripts for
hasura-auth-js package</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

packages/hasura-auth-js/package.json

<li>Update ci:test script to use vite.config.e2e.json<br> <li> Remove
Nhost CLI shutdown from ci:test script


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>package.json</strong><dd><code>Update test script for
hasura-storage-js package</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

packages/hasura-storage-js/package.json

- Remove Nhost CLI shutdown from ci:test script


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3306/files#diff-eca15b254298d1b63d7c80b470d31e046d63ae93b1f09eb6dc3959e3a326560d">+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-04-25 18:21:09 +02:00
David BM
0bf28085b7 chore (dashboard CI): refresh hasura metadata before e2e tests (#3314) 2025-04-25 17:40:29 +02:00
Alexander Mart
b302dbd27d docs: add sveltekit quickstart (#3302)
Co-authored-by: David Barroso <dbarrosop@dravetech.com>
Co-authored-by: Nuno Pato <nunopato@gmail.com>
2025-04-24 14:04:48 +02:00
David BM
72a365c5fc fix (dashboard): correct graphql role dropdown source (#3291) 2025-04-21 18:19:09 +02:00
David Barroso
d11363a74c chore (observability): make alerts less sensitive (#3310)
### **PR Type**
Enhancement


___

### **Description**
- Increase alert sensitivity time from 5m to 15m

- Change NoData state to Alerting for most rules

- Modify execErrState to Alerting or OK

- Adjust noDataState for specific alert rules


___



### **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>rules_nhost.yaml</strong><dd><code>Adjust alert
sensitivity and error handling configurations</code></dd></summary>
<hr>

observability/grafana/rules_nhost.yaml

<li>Increased 'for' duration from 5m to 15m for multiple alerts<br> <li>
Changed 'noDataState' from NoData to Alerting for most rules<br> <li>
Modified 'execErrState' to Alerting or OK depending on the rule<br> <li>
Adjusted 'noDataState' for specific alert rules (e.g., OK to Alerting)


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3310/files#diff-27165812186176e21d13a35136e43511b837700a599d3a00c61a1f6b36c55af2">+13/-13</a>&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-04-20 13:59:31 +02:00
David BM
1bc2fabe59 chore (CI): skip CI runs on documentation change (#3307)
### **User description**
Skips CI running if we only changed under `docs/`


___

### **PR Type**
Enhancement


___

### **Description**
- Skip CI runs for changes in 'docs/' directory

- Update CI workflow configuration in GitHub Actions


___



### **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>ci.yaml</strong><dd><code>Update CI workflow to ignore
documentation changes</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></summary>
<hr>

.github/workflows/ci.yaml

<li>Add 'docs/**' to paths-ignore for push and pull_request events<br>
<li> Prevent CI from running on documentation-only changes


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3307/files#diff-944291df2c9c06359d37cc8833d182d705c9e8c3108e7cfe132d61a06e9133dd">+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-04-16 15:35:41 +02:00
robertkasza
f8243f9434 chore (examples/svelte): update @sveltejs/kit (#3305)
### **PR Type**
Enhancement, Documentation


___

### **Description**
- Update @sveltejs/kit to version 2.20.6

- Add changeset for @nhost-examples/sveltekit patch

- Update package resolutions for 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>neat-eggs-chew.md</strong><dd><code>Add changeset for
sveltekit example update</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

.changeset/neat-eggs-chew.md

<li>Add new changeset file for @nhost-examples/sveltekit<br> <li>
Specify patch update for the package<br> <li> Include description of the
change


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3305/files#diff-f07ba45e000aecdb0b0c45fbc4a50ccc0749e7755fdd86d630b9025cdde187ee">+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>Update @sveltejs/kit
dependency version</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></summary>
<hr>

examples/quickstarts/sveltekit/package.json

- Update @sveltejs/kit from 2.11.1 to 2.20.6


</details>


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

</tr>
</table></td></tr><tr><td><strong>Configuration
changes</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>package.json</strong><dd><code>Add security resolution
for @sveltejs/kit</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

package.json

- Add resolution for @sveltejs/kit >= 2.20.6


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3305/files#diff-7ae45ad102eab3b6d7e7896acd08c427a9b25b346470d7bc6507b6481575d519">+2/-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-04-16 12:48:40 +02:00
robertkasza
d9eb90604d fix: update vite and nextjs because of vulnerability (#3303)
### **PR Type**
Bug fix


___

### **Description**
- Update Vite and Next.js versions for security

- Add new version constraints for Vite and Next.js

- Create changeset for patch updates to multiple packages


___



### **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>neat-mugs-bake.md</strong><dd><code>Add changeset for
Vite and Next.js updates</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

.changeset/neat-mugs-bake.md

<li>Add new changeset file for patch updates<br> <li> List affected
packages including dashboard and examples<br> <li> Describe fix as
updating Vite and Next.js


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3303/files#diff-6ec609b553758bab0278f440f07a0af9e742df25dbdc038b6212bb683f88eb59">+13/-0</a>&nbsp;
&nbsp; </td>

</tr>
</table></td></tr><tr><td><strong>Dependencies</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>package.json</strong><dd><code>Update dependency
version constraints</code>&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 new version constraint for Next.js (>=14.2.26)<br> <li> Update
Vite version constraints (>=5.4.18 and >=6.2.6)<br> <li> Remove outdated
Vite version constraint


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3303/files#diff-7ae45ad102eab3b6d7e7896acd08c427a9b25b346470d7bc6507b6481575d519">+4/-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-04-16 09:17:12 +02:00
Nuno Pato
cef647194d fix: dashboard: add anonid to user's metadata (#3282)
### **PR Type**
Enhancement


___

### **Description**
- Add anonymous ID to user metadata during signup

- Integrate Segment analytics for anonymous ID retrieval

- Update GitHub sign-in to include anonymous ID

- Add changeset for version bump and changelog


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>signup.tsx</strong><dd><code>Integrate anonymous ID in
signup process</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

dashboard/src/pages/signup.tsx

<li>Import Segment analytics<br> <li> Add state for anonymous ID<br>
<li> Fetch anonymous ID on component mount<br> <li> Include anonymous ID
in email and GitHub signup


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>tall-eggs-battle.md</strong><dd><code>Add changeset for
dashboard 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; </dd></summary>
<hr>

.changeset/tall-eggs-battle.md

<li>Add changeset file for version bump<br> <li> Describe change as
adding anonid to user's metadata


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3282/files#diff-26ba0d1f688299d031611809f726356bdec0104a9264ec7dcca0757985023a58">+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-04-10 14:29:56 +00:00
robertkasza
efd68c3f92 chore (react-apollo): run e2e on preview instead of dev server (#3295)
### **PR Type**
Enhancement


___

### **Description**
- Run e2e tests on preview build instead of dev server

- Update Playwright configuration for better test reliability

- Add new script for building and previewing in one step

- Improve clean and install process with new script


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>playwright.config.ts</strong><dd><code>Update
Playwright config for preview build and improved
tracing</code></dd></summary>
<hr>

examples/react-apollo/playwright.config.ts

<li>Changed webServer command from 'pnpm dev' to 'pnpm
build:preview'<br> <li> Updated trace option from 'on-first-retry' to
'retain-on-failure'


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>package.json</strong><dd><code>Add build:preview script
and specify preview port</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></summary>
<hr>

examples/react-apollo/package.json

<li>Added port 3000 to preview script<br> <li> Introduced new
'build:preview' script combining build and preview


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>package.json</strong><dd><code>Add clean:install script
for project maintenance</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

package.json

- Added new 'clean:install' script for cleaning and reinstalling


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3295/files#diff-7ae45ad102eab3b6d7e7896acd08c427a9b25b346470d7bc6507b6481575d519">+1/-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-04-10 15:51:05 +02:00
robertkasza
233232b06f feat (dashboard): improve upgrade project (#3257)
### **PR Type**
Enhancement, Tests


___

### **Description**
- Introduced `TransferOrUpgradeProjectDialog` to unify transfer and
upgrade dialogs.

- Enhanced project upgrade flow with new components and logic.

- Added comprehensive tests for the new upgrade and transfer
functionalities.

- Replaced `TransferProjectDialog` with `TransferOrUpgradeProjectDialog`
across the codebase.


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Miscellaneous</strong></td><td><details><summary>2
files</summary><table>
<tr>
<td><strong>SelectOrgAndProject.tsx</strong><dd><code>Removed unused
import statement.</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></td>
<td><a
href="https://github.com/nhost/nhost/pull/3257/files#diff-7d86c6e5bc51696bf1aa421c920e01a1447699456c37b025bdc407050c7b5613">+0/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>OverviewTopBar.tsx</strong><dd><code>Updated import for
`UpgradeProjectDialog`.</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3257/files#diff-560ae107ed8e458fa4b4a226b9f5c24e24b042b5f9bcea9317c78e75929faa4b">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

</table></details></td></tr><tr><td><strong>Enhancement</strong></td><td><details><summary>16
files</summary><table>
<tr>
<td><strong>UpgradeToProBanner.tsx</strong><dd><code>Updated to use
`TransferOrUpgradeProjectDialog`.</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3257/files#diff-f38fc14d24ec6ee22f9a100cc473c641dcdc66284d41d030c456bf505094ed9d">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>StripeEmbeddedForm.tsx</strong><dd><code>Wrapped
`EmbeddedCheckoutProvider` with a scrollable container.</code></dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3257/files#diff-d8e63f9bdc9c2c672a4caabd406bf77bec4e4988e716d2b9e101182a863eb495">+10/-8</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>TransferProject.tsx</strong><dd><code>Replaced
<code>TransferProjectDialog</code> with
<code>TransferOrUpgradeProjectDialog</code>.</code></dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3257/files#diff-bb5ac90e4fcb5841e3fef912beec1b1dbe83b273eea7a9e39fb258ff0361e7e3">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>FinishOrgCreationProcess.tsx</strong><dd><code>Refactored to
use <code>useFinishOrgCreation</code> hook for dynamic status
<br>handling.</code></dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3257/files#diff-7602855e6aaab1dd3810c866acbedd5b9eb22c271806969eb9a3435f1c76ca8d">+13/-5</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>FinishOrgCreation.tsx</strong><dd><code>Simplified
`FinishOrgCreation` component logic.</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3257/files#diff-9e3ccc4f3c0168746e53b68211d07391593712d5d74847861248cfa7da31dd7d">+4/-5</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>

<td><strong>TransferOrUpgradeProjectDialog.tsx</strong><dd><code>Introduced
`TransferOrUpgradeProjectDialog` component.</code>&nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3257/files#diff-06d6ae707f06c0db49a8930a8756195899ece09f08affa44aeadedce4b208948">+105/-0</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>TransferProjectDialogContent.tsx</strong><dd><code>Added
`TransferProjectDialogContent` for transfer logic.</code>&nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3257/files#diff-3f66f2e8af0175d1c3f9d4940b8dc965fefa18967c8f4977739ac73000708763">+100/-0</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>TransferProjectForm.tsx</strong><dd><code>Added
`TransferProjectForm` for organization selection and
transfer.</code></dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3257/files#diff-3324c79d8b4d48777467132ba0f13a95d4b0f1a9fbb4df9fd7f67735ac40cbbd">+186/-0</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>UpgradeProjectDialogContent.tsx</strong><dd><code>Added
`UpgradeProjectDialogContent` for project upgrade flow.</code></dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3257/files#diff-ced98d2b8b0e83e41fd9bd569a6dd3fb5c4013861d3352628e63abe0c285d2ba">+96/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>index.ts</strong><dd><code>Exported
`TransferOrUpgradeProjectDialog`.</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3257/files#diff-bd61908ca8ab41f1a88cdcc3bafe4264b1e8120d7f65ff64f158631dd4e65a58">+1/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>NotificationsTray.tsx</strong><dd><code>Added router
readiness check in `NotificationsTray`.</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3257/files#diff-8b559ee1d3176203e8a4e1588924d57944d09d792117ed578b27cd5401ee5d4f">+3/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>useFinishOrgCreation.ts</strong><dd><code>Added router
readiness check to `useFinishOrgCreation`.</code>&nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3257/files#diff-3b8bf7608ab36d8ab0df895e400f0d2d9e29fad2055b40b33d8d9912a27c99c3">+1/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>ApplicationPaused.tsx</strong><dd><code>Replaced
<code>TransferProjectDialog</code> with
<code>TransferOrUpgradeProjectDialog</code>.</code></dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3257/files#diff-14afdf5ac20f058c26563a6992a3751f11cf173eec27206001262b5d1b3b979f">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>UpgradeNotification.tsx</strong><dd><code>Updated to use
`TransferOrUpgradeProjectDialog`.</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3257/files#diff-f712e65a6e88f2731fc5597117f716594311087f8090e3e8f5f76e1a67c95188">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>UpgradeProjectDialog.tsx</strong><dd><code>Updated to use
`TransferOrUpgradeProjectDialog` for upgrades.</code></dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3257/files#diff-7bfab4ad088dbc503c1304f5620e22e02f70602bf14ba6b495969b882b2eb30e">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>verify.tsx</strong><dd><code>Refactored to use
`FinishOrgCreationProcess` with hooks.</code>&nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3257/files#diff-5fa0ea2519bed6649a8aa98826526945868bd7a925c5ce5edb3fd14e81273947">+1/-5</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

</table></details></td></tr><tr><td><strong>Tests</strong></td><td><details><summary>2
files</summary><table>
<tr>

<td><strong>TransferOrUpgradeProjectDialog.test.tsx</strong><dd><code>Added
tests for `TransferOrUpgradeProjectDialog`.</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3257/files#diff-1b274953c536fcd901f72765ab134a34641442655988bde5595f63265a9e7ce9">+155/-12</a></td>

</tr>

<tr>
<td><strong>NotificationsTray.test.tsx</strong><dd><code>Added tests for
router readiness in `NotificationsTray`.</code>&nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3257/files#diff-727f6debec6a102557407e55c56363e0c75486e30a732158f85c81ada892f77c">+39/-4</a>&nbsp;
&nbsp; </td>

</tr>

</table></details></td></tr><tr><td><strong>Cleanup</strong></td><td><details><summary>2
files</summary><table>
<tr>
<td><strong>TransferProjectDialog.tsx</strong><dd><code>Removed
deprecated `TransferProjectDialog`.</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/3257/files#diff-b68d4641a67e07a8bf8c14e1f705059c564e1bca53e591783581af27a488d86e">+0/-306</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>index.ts</strong><dd><code>Removed export for deprecated
`TransferProjectDialog`.</code>&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3257/files#diff-ed023a2c08c77e3693789305cf9b9f2cd871090acf7b0775c7d7434903710c42">+0/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

</table></details></td></tr><tr><td><strong>Documentation</strong></td><td><details><summary>1
files</summary><table>
<tr>
<td><strong>tame-planes-sleep.md</strong><dd><code>Added changeset for
project upgrade dialog improvements.</code>&nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3257/files#diff-c83c4e28de9a00c1ee2cb4ad9867d2c42415c01c80e990205c351e6f5c8a6f83">+5/-0</a>&nbsp;
&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-04-10 15:15:25 +02:00
David Barroso
5e962300f6 fix (docs): fixing mintlify breaking our docs (#3297) 2025-04-10 13:23:31 +02:00
Nuno Pato
048b3389e6 chore: docs: add segment analytics (#3294)
### **PR Type**
Enhancement


___

### **Description**
- Added Segment analytics integration to documentation

- Configured Segment key in docs.json file


___



### **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>docs.json</strong><dd><code>Configure Segment analytics
in docs.json</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

docs/docs.json

<li>Added 'integrations' object with Segment configuration<br> <li>
Included Segment API key for analytics tracking


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3294/files#diff-873ce17c654718debe2fe308a2f2279bde8663686423c51f97fab2dd0722b8d9">+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-04-08 12:17:05 +00:00
github-actions[bot]
be8cd6c3a6 chore: update versions (#3277)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


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

### Minor Changes

-   d26b6b8: fix: update broadcasted session directly

## @nhost/apollo@8.0.7

### Patch Changes

-   @nhost/nhost-js@3.2.7

## @nhost/react-apollo@17.0.3

### Patch Changes

-   @nhost/apollo@8.0.7
-   @nhost/react@3.10.3

## @nhost/react-urql@14.0.3

### Patch Changes

-   @nhost/react@3.10.3

## @nhost/nextjs@2.2.6

### Patch Changes

-   @nhost/react@3.10.3

## @nhost/nhost-js@3.2.7

### Patch Changes

-   Updated dependencies [d26b6b8]
    -   @nhost/hasura-auth-js@2.11.0

## @nhost/react@3.10.3

### Patch Changes

-   @nhost/nhost-js@3.2.7

## @nhost/vue@2.9.4

### Patch Changes

-   @nhost/nhost-js@3.2.7

## @nhost/dashboard@2.27.0

### Minor Changes

- 013e1c1: fix: update vite and image-size dependencies to address
security audit vulnerabilities
- 4fd176b: chore: re-add user event ci tests, updated sveltekit example
tests to e2e suite

### Patch Changes

-   a1333df: fix: update vite because of vulnerability
- 0420e4f: fix (dashboard): Display the selected date's month in the
datetime picker component
    -   @nhost/react-apollo@17.0.3
    -   @nhost/nextjs@2.2.6

## @nhost/docs@2.30.0

### Minor Changes

-   38e7e9d: fix: remove community as it isn't ready

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

### Minor Changes

- 013e1c1: fix: update vite and image-size dependencies to address
security audit vulnerabilities

### Patch Changes

-   a1333df: fix: update vite because of vulnerability
    -   @nhost/react@3.10.3
    -   @nhost/react-apollo@17.0.3

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

### Minor Changes

- 013e1c1: fix: update vite and image-size dependencies to address
security audit vulnerabilities

### Patch Changes

-   a1333df: fix: update vite because of vulnerability
    -   @nhost/react@3.10.3

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

### Minor Changes

- 013e1c1: fix: update vite and image-size dependencies to address
security audit vulnerabilities

### Patch Changes

-   a1333df: fix: update vite because of vulnerability
    -   @nhost/react@3.10.3
    -   @nhost/react-urql@14.0.3

## @nhost-examples/sveltekit@0.7.0

### Minor Changes

- 013e1c1: fix: update vite and image-size dependencies to address
security audit vulnerabilities
- 4fd176b: chore: re-add user event ci tests, updated sveltekit example
tests to e2e suite

### Patch Changes

-   b89500d: fix: use nhost-js version from the workspace
-   a1333df: fix: update vite because of vulnerability
    -   @nhost/nhost-js@3.2.7

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

### Minor Changes

- 013e1c1: fix: update vite and image-size dependencies to address
security audit vulnerabilities
-   25f07a3: fix: update versions

### Patch Changes

-   a1333df: fix: update vite because of vulnerability
    -   @nhost/react@3.10.3
    -   @nhost/react-apollo@17.0.3

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

### Minor Changes

- 013e1c1: fix: update vite and image-size dependencies to address
security audit vulnerabilities

### Patch Changes

-   a1333df: fix: update vite because of vulnerability
    -   @nhost/react@3.10.3

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

### Minor Changes

- 013e1c1: fix: update vite and image-size dependencies to address
security audit vulnerabilities

### Patch Changes

-   a1333df: fix: update vite because of vulnerability
    -   @nhost/nhost-js@3.2.7
    -   @nhost/apollo@8.0.7
    -   @nhost/vue@2.9.4

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

### Minor Changes

- 013e1c1: fix: update vite and image-size dependencies to address
security audit vulnerabilities

### Patch Changes

-   a1333df: fix: update vite because of vulnerability
    -   @nhost/apollo@8.0.7
    -   @nhost/vue@2.9.4

## @nhost-examples/cli@0.3.20

### Patch Changes

-   @nhost/nhost-js@3.2.7

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

### Patch Changes

-   @nhost/nhost-js@3.2.7

## @nhost-examples/nextjs@0.4.6

### Patch Changes

-   @nhost/react@3.10.3
-   @nhost/react-apollo@17.0.3
-   @nhost/nextjs@2.2.6

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

### Patch Changes

-   @nhost/nhost-js@3.2.7

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

### Patch Changes

-   @nhost/nhost-js@3.2.7

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

### Patch Changes

-   @nhost/react@3.10.3
-   @nhost/react-apollo@17.0.3

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-04-08 13:52:27 +02:00
David Barroso
b89500d175 chore (workspaces): fixes to the workspace (#3287)
### **PR Type**
Enhancement, Bug fix


___

### **Description**
- Update @nhost/nhost-js dependency to use workspace version

- Modify pnpm-workspace.yaml to include more examples

- Exclude specific templates from workspace

- Add changeset for @nhost-examples/sveltekit patch


___



### **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>late-ghosts-taste.md</strong><dd><code>Add changeset
for SvelteKit example patch</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></summary>
<hr>

.changeset/late-ghosts-taste.md

<li>Add new changeset file for @nhost-examples/sveltekit<br> <li>
Specify patch update for using nhost-js from workspace


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3287/files#diff-1578fc8821e79f4e226a9d0f78fb415e5b6cbd0a71f41e4f15ec6b91f2cc4842">+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>Update nhost-js
dependency to workspace version</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

examples/quickstarts/sveltekit/package.json

- Update @nhost/nhost-js dependency to use workspace version


</details>


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

</tr>
</table></td></tr><tr><td><strong>Configuration
changes</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>pnpm-workspace.yaml</strong><dd><code>Refine workspace
package inclusions and exclusions</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

pnpm-workspace.yaml

<li>Change 'examples/*' to 'examples/**' for broader inclusion<br> <li>
Exclude CRA and React Native templates from workspace


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3287/files#diff-18ae0a0fab29a7db7aded913fd05f30a2c8f6c104fadae86c9d217091709794c">+3/-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>

Co-authored-by: robertkasza <167509084+robertkasza@users.noreply.github.com>
2025-04-08 12:13:59 +02:00
David BM
013e1c1d70 fix (ci lint): update vite and image-size dependencies to address security audit vulnerabilities (#3293)
### **User description**
Addresses advisories:
https://github.com/advisories/GHSA-m5qc-5hw7-8vg7
https://github.com/advisories/GHSA-xcj6-pq6g-qj4x


___

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


___

### **Description**
- Update Vite to address security vulnerabilities

- Update image-size dependency for security

- Add changeset for version bumps

- Update package resolutions for security fixes


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Documentation</strong></td><td><details><summary>1
files</summary><table>
<tr>
<td><strong>flat-suits-join.md</strong><dd><code>Add changeset for
version bumps</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3293/files#diff-985f5074afc6182f003fda21514c3398427504e76a81e28b730920c5cf2b420e">+13/-0</a>&nbsp;
&nbsp; </td>

</tr>

</table></details></td></tr><tr><td><strong>Dependencies</strong></td><td><details><summary>10
files</summary><table>
<tr>
<td><strong>package.json</strong><dd><code>Update Vite dependency
version</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3293/files#diff-2d8d55c799cd71f1b35e831f075f8178ed1734c4820a2ad548b4dd24d6938d7c">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>package.json</strong><dd><code>Update Vite dependency
version</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3293/files#diff-83675898dc6ed88838763232d022f6e100e07d71681cc8a1f02aee99ee3f229b">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>package.json</strong><dd><code>Update Vite dependency
version</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3293/files#diff-9fb3a23f389ab1d192d7e018d2acbe512bd8792278662101401caa98692735db">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>package.json</strong><dd><code>Update Vite dependency
version</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3293/files#diff-cb7094614884e8cd2c8fb67dadedb1887c46c31b888840def0b7042273bfbb28">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>package.json</strong><dd><code>Update Vite dependency
version</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3293/files#diff-6288951fff74ec246c9cc023b7b7e3e9aad31423891bc4ea25b5d84a5f5b061f">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>package.json</strong><dd><code>Update Vite dependency
version</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3293/files#diff-d95dc3391741287366ea2e61f70e9ccc64452e0d22b1db91d6bf524f5aa4331c">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>package.json</strong><dd><code>Update Vite dependency
version</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3293/files#diff-8a3e5ed0f618f15211c31f700e0da998e2eae58f60353624b7a7e637bd63b153">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>package.json</strong><dd><code>Update Vite dependency
version</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3293/files#diff-fc4298d3512fdd9a3d871f9f182fe871c8beccd1580f864a271ddfb32005feef">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>package.json</strong><dd><code>Update Vite dependency
version</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3293/files#diff-85166d1137e29a5275f991e1e94a0c9d5b83ac7504463ba76f9187b2b750c895">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>package.json</strong><dd><code>Update Vite and image-size
dependencies</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3293/files#diff-7ae45ad102eab3b6d7e7896acd08c427a9b25b346470d7bc6507b6481575d519">+6/-6</a>&nbsp;
&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>

---------

Co-authored-by: robertkasza <167509084+robertkasza@users.noreply.github.com>
2025-04-08 09:45:49 +02:00
David BM
4fd176bce2 chore (ci): re-add user event tests (#3288)
### **PR Type**
Tests, Enhancement


___

### **Description**
- Reintroduce user event tests in CI

- Update SvelteKit example tests to e2e suite

- Refactor TestUserEvent class for improved testing

- Add new tests for database and backup features


___



### **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>7
files</summary><table>
<tr>
<td><strong>DateTimePicker.test.tsx</strong><dd><code>Add comprehensive
tests for DateTimePicker component</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3288/files#diff-c7076012eb33d6f60049710638b5ad19c2f310b8c250c79f1905be7e0a30b00a">+177/-0</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>TimePicker.test.tsx</strong><dd><code>Update TimePicker
tests to use TestUserEvent</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/3288/files#diff-784f69003ebbc9e39837b920007cef14125a5fc48bb9114226820bcb2b0827b0">+6/-7</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>TransferProjectDialog.test.tsx</strong><dd><code>Add tests
for TransferProjectDialog component</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3288/files#diff-d4ebdb8af76a7c9e73606708718c3448445545259ad553d73b6d322408e3eb8c">+234/-0</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>ImportBackupTabContent.test.tsx</strong><dd><code>Add tests
for ImportBackupTabContent component</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3288/files#diff-753e5e6735a2d612b6ccc6617c053017ba591a763182fa28a8fc302731c3f347">+267/-0</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>DatabasePiTRSettings.test.tsx</strong><dd><code>Add tests
for DatabasePiTRSettings component</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/3288/files#diff-85d1f82a571b56469eab40dcc164fdd1e107fba79611ddd5cca7c191fe5117b4">+188/-0</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>ResourcesForm.test.tsx</strong><dd><code>Update
ResourcesForm tests to use TestUserEvent</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3288/files#diff-8828db70c080be6fc19f88059b08587584f1c23c9159092d6b186ca82a1943aa">+60/-55</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>resourceSettingsQuery.ts</strong><dd><code>Update
resourcesAvailableQuery mock data</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3288/files#diff-49b3a2a24ead48f97ace0b90f1ecaf4d4edbdef17109e29f5101016515e5946a">+12/-0</a>&nbsp;
&nbsp; </td>

</tr>

</table></details></td></tr><tr><td><strong>Enhancement</strong></td><td><details><summary>2
files</summary><table>
<tr>
<td><strong>testUtils.tsx</strong><dd><code>Refactor TestUserEvent class
and remove utility functions</code></dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3288/files#diff-78f29250407edf853a353b48242d3cee59aa5724f38a60bb23bebdfc1ea2f9b5">+35/-18</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>package.json</strong><dd><code>Update SvelteKit example test
script to e2e</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/3288/files#diff-6288951fff74ec246c9cc023b7b7e3e9aad31423891bc4ea25b5d84a5f5b061f">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

</table></details></td></tr><tr><td><strong>Documentation</strong></td><td><details><summary>1
files</summary><table>
<tr>
<td><strong>nasty-cherries-cover.md</strong><dd><code>Add changeset for
user event CI tests</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3288/files#diff-653e520d91e00e8c62155076a5acfb2a606381f63c4c87b42ac70d23e7c97a01">+6/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></details></td></tr><tr><td><strong>Additional
files</strong></td><td><details><summary>1 files</summary><table>
<tr>
  <td><strong>PointInTimeBackupInfo.test.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3288/files#diff-3980415ca79bf039abb469281fff9b1dc1de0a1ef52b4044d8c6f529538b6edf">+356/-0</a>&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-04-07 17:15:33 +02:00
David Barroso
d26b6b848d chore (auth-js): add missing changeset (#3286)
### **PR Type**
Enhancement


___

### **Description**
- Update broadcasted session directly in @nhost/hasura-auth-js


___



### **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>honest-countries-melt.md</strong><dd><code>Add
changeset for session broadcast update</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></summary>
<hr>

.changeset/honest-countries-melt.md

<li>Added changeset file for @nhost/hasura-auth-js<br> <li> Specified
minor version bump<br> <li> Described fix for updating broadcasted
session directly


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3286/files#diff-a9bbe8d89f97fb5a46896d2cf1e4fd059d55360261ce3bc37b34fd54bd246076">+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-04-04 13:28:23 +02:00
David Barroso
3df7ca2a33 fix (hasura-auth-js): update broadcasted session directly (#3284)
### **PR Type**
Enhancement, Bug fix


___

### **Description**
- Update broadcasted session with full data

- Improve cross-tab synchronization in Hasura Auth JS

- Enhance session update mechanism for better reliability

- Fix potential issues with token comparison and updates


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>internal-client.ts</strong><dd><code>Improve cross-tab
session synchronization</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

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

<li>Changed 'broadcast_token' to 'broadcast_session'<br> <li> Updated
session data handling in message listener<br> <li> Implemented direct
SESSION_UPDATE event with full session data<br> <li> Added null check
for context in token comparison


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>machine.ts</strong><dd><code>Enhance session
broadcasting with comprehensive data</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></summary>
<hr>

packages/hasura-auth-js/src/machines/authentication/machine.ts

<li>Updated broadcastToken function to send full session data<br> <li>
Changed message type from 'broadcast_token' to 'broadcast_session'<br>
<li> Added accessToken, user, expiresAt, and expiresInSeconds to payload


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3284/files#diff-a8fdfee087ad5a72ea0a64667e2a0c7f25baa84eaaf73ebfee3f5a5a1b7584d1">+7/-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-04-04 13:16:36 +02:00
David Barroso
38e7e9deee chore (docs): remove community as it isn't ready (#3280)
### **PR Type**
Documentation


___

### **Description**
- Remove community section from documentation

- Delete Code of Conduct and Getting Involved pages

- Update docs.json to reflect removed community content


___



### **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>friendly-chairs-argue.md</strong><dd><code>Add
changeset for community section removal</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></summary>
<hr>

.changeset/friendly-chairs-argue.md

<li>Add changeset file for minor version bump<br> <li> Include fix note
about removing community section


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>coc.mdx</strong><dd><code>Remove Code of Conduct
page</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></summary>
<hr>

docs/community/coc.mdx

- Delete entire Code of Conduct page


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>getting-involved.mdx</strong><dd><code>Remove Getting
Involved page</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></summary>
<hr>

docs/community/getting-involved.mdx

- Delete entire Getting Involved page


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>docs.json</strong><dd><code>Update docs.json to remove
community section</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

docs/docs.json

- Remove "Community" tab and its associated pages


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3280/files#diff-873ce17c654718debe2fe308a2f2279bde8663686423c51f97fab2dd0722b8d9">+0/-5</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-04-04 08:49:03 +02:00
David Barroso
25f07a3763 chore (examples/react-apollo): update versions (#3281)
### **PR Type**
Enhancement


___

### **Description**
- Update Hasura, Auth, Postgres, and Storage versions

- Upgrade Node.js version for functions to 22

- Bump @nhost-examples/react-apollo package version


___



### **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>spicy-sloths-cover.md</strong><dd><code>Add changeset
for React Apollo example version update</code>&nbsp; &nbsp; &nbsp;
&nbsp; </dd></summary>
<hr>

.changeset/spicy-sloths-cover.md

<li>Add changeset for @nhost-examples/react-apollo minor version
bump<br> <li> Include fix note for version updates


</details>


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

</tr>
</table></td></tr><tr><td><strong>Configuration
changes</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>nhost.toml</strong><dd><code>Update core component
versions in nhost.toml</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

examples/react-apollo/nhost/nhost.toml

<li>Update Hasura version to v2.46.0-ce<br> <li> Upgrade Node.js version
for functions to 22<br> <li> Update Auth version to 0.38.0<br> <li>
Update Postgres version to 16.6-20250311-1<br> <li> Update Storage
version to 0.7.1


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3281/files#diff-268d6c8dddd6990d60d62c1c923955c4e0e7549a80f0f5856192f889378416a0">+6/-6</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-04-04 08:48:46 +02:00
David BM
38c3db4a9e fix (ci): dashboard unittests (#3285)
### **PR Type**
Tests


___

### **Description**
- Remove userEvent-based tests

- Delete unused test files

- Update ResourcesForm test to use userEvent


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Tests</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>DateTimePicker.test.tsx</strong><dd><code>Remove
DateTimePicker test file</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

dashboard/src/components/common/DateTimePicker/DateTimePicker.test.tsx

- Removed entire test file


</details>


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

</tr>

<tr>
  <td>
    <details>

<summary><strong>TransferProjectDialog.test.tsx</strong><dd><code>Remove
TransferProjectDialog test file</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/features/orgs/components/common/TransferProjectDialog/TransferProjectDialog.test.tsx

- Removed entire test file


</details>


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

</tr>

<tr>
  <td>
    <details>

<summary><strong>ImportBackupTabContent.test.tsx</strong><dd><code>Remove
ImportBackupTabContent test file</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/features/orgs/projects/backups/components/ImportBackupTabContent/ImportBackupTabContent.test.tsx

- Removed entire test file


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3285/files#diff-753e5e6735a2d612b6ccc6617c053017ba591a763182fa28a8fc302731c3f347">+0/-267</a>&nbsp;
</td>

</tr>

<tr>
  <td>
    <details>

<summary><strong>PointInTimeBackupInfo.test.tsx</strong><dd><code>Remove
PointInTimeBackupInfo test file</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/features/orgs/projects/backups/components/common/PointInTimeBackupInfo/PointInTimeBackupInfo.test.tsx

- Removed entire test file


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3285/files#diff-3980415ca79bf039abb469281fff9b1dc1de0a1ef52b4044d8c6f529538b6edf">+0/-357</a>&nbsp;
</td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>DatabasePiTRSettings.test.tsx</strong><dd><code>Remove
DatabasePiTRSettings test file</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/features/orgs/projects/database/settings/components/DatabasePiTRSettings/DatabasePiTRSettings.test.tsx

- Removed entire test file


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3285/files#diff-85d1f82a571b56469eab40dcc164fdd1e107fba79611ddd5cca7c191fe5117b4">+0/-189</a>&nbsp;
</td>

</tr>
</table></td></tr><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>ResourcesForm.test.tsx</strong><dd><code>Update
ResourcesForm tests to use userEvent</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>


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

<li>Imported userEvent from '@testing-library/user-event'<br> <li>
Updated tests to use userEvent instead of custom click functions<br>
<li> Moved vCPU and Memory ratio validation test


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3285/files#diff-8828db70c080be6fc19f88059b08587584f1c23c9159092d6b186ca82a1943aa">+52/-48</a>&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-04-03 16:43:00 +02:00
robertkasza
a1333df2a1 fix: update vite because of vulnerability (#3283)
### **PR Type**
Bug fix, Enhancement


___

### **Description**
- Update Vite to address security vulnerability

- Upgrade dependencies in Vue examples

- Add 'type: module' to Vue quickstart package

- Update resolutions for Vite versions


___



### **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>stale-horses-run.md</strong><dd><code>Add changeset for
Vite vulnerability fix</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></summary>
<hr>

.changeset/stale-horses-run.md

<li>Add new changeset file<br> <li> List affected packages for patch
update<br> <li> Describe fix for Vite vulnerability


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3283/files#diff-79e66d2654e3803067439855123d20d162193a019ecf68b5b45ee1d0e344949d">+13/-0</a>&nbsp;
&nbsp; </td>

</tr>
</table></td></tr><tr><td><strong>Dependencies</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>package.json</strong><dd><code>Update sass dependency
in Vue Apollo example</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

examples/vue-apollo/package.json

- Update sass dependency from 1.32.0 to 1.86.1


</details>


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

</tr>
</table></td></tr><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>package.json</strong><dd><code>Update package
configuration and dependencies in Vue quickstart</code></dd></summary>
<hr>

examples/vue-quickstart/package.json

<li>Add "type": "module" to package.json<br> <li> Update @unocss/reset
from 0.33.5 to 66.1.0-beta.8<br> <li> Update unocss from 0.33.5 to
66.1.0-beta.8


</details>


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

</tr>
</table></td></tr><tr><td><strong>Bug fix</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>package.json</strong><dd><code>Add Vite version
resolutions to address vulnerabilities</code>&nbsp; &nbsp;
</dd></summary>
<hr>

package.json

- Add resolutions for Vite versions 5.4.16 and 6.2.4


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3283/files#diff-7ae45ad102eab3b6d7e7896acd08c427a9b25b346470d7bc6507b6481575d519">+3/-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-04-02 17:23:26 +02:00
robertkasza
0420e4fda4 fix (dashboard): display the selected date's month in the datetime picker component (#3276)
### **PR Type**
Bug fix


___

### **Description**
- Fix datetime picker to display selected date's month

- Add defaultMonth prop to Calendar component

- 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>Bug
fix</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>calendar.tsx</strong><dd><code>Set default month in
Calendar component</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></summary>
<hr>

dashboard/src/components/ui/v3/calendar.tsx

- Added `defaultMonth={props.selected}` to Calendar component


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>stupid-sloths-poke.md</strong><dd><code>Add changeset
for dashboard package update</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

.changeset/stupid-sloths-poke.md

<li>Added changeset file for @nhost/dashboard package<br> <li> Described
fix for datetime picker component


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3276/files#diff-4f6398b11015521b2039034f4ae61cd1ac5870421f1a52ddbf11f209aa141230">+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-04-01 14:42:08 +02:00
github-actions[bot]
97f6642c43 chore: update versions (#3256)
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.26.0

### Minor Changes

-   7b9cdf1: chore: remove legacy workspaces
-   1c4f321: fix: update vite to fix audit vulnerabilities

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

### Minor Changes

-   1c4f321: fix: update vite to fix audit vulnerabilities

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

### Minor Changes

-   1c4f321: fix: update vite to fix audit vulnerabilities

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

### Minor Changes

-   1c4f321: fix: update vite to fix audit vulnerabilities

## @nhost-examples/sveltekit@0.6.0

### Minor Changes

-   1c4f321: fix: update vite to fix audit vulnerabilities

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

### Minor Changes

-   1c4f321: fix: update vite to fix audit vulnerabilities

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

### Minor Changes

-   1c4f321: fix: update vite to fix audit vulnerabilities

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

### Minor Changes

-   1c4f321: fix: update vite to fix audit vulnerabilities

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

### Minor Changes

-   1c4f321: fix: update vite to fix audit vulnerabilities

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-04-01 09:50:28 +02:00
David Barroso
69c1ffa766 feat (docs): overhaul structure (#3254)
### **PR Type**
Enhancement, Documentation


___

### **Description**
- Restructured docs navigation and content

- Updated links and paths throughout docs

- Refreshed images and examples in guides

- Added new content for AI, Auth, and Run


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><details><summary>15
files</summary><table>
<tr>
<td><strong>docs.json</strong><dd><code>Restructure navigation and add
new sections</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/3254/files#diff-873ce17c654718debe2fe308a2f2279bde8663686423c51f97fab2dd0722b8d9">+616/-0</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>welcome.mdx</strong><dd><code>Add new welcome page with
getting started links</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-b35cb8e6a6201730c2d95103d1275186d72e727686bfd6470256c0c30137a761">+65/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>overview.mdx</strong><dd><code>Add new getting started
overview page</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-8c9b35da559a5de5fe14ee078573e8d487453e26ed760c03ffd7f0ad476ca24d">+88/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>overview.mdx</strong><dd><code>Add new products overview
page</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-745a45fa3dbe67784dd921e50865c7ef33fdc6488cff1ccc75d9db524799d8b3">+81/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>overview.mdx</strong><dd><code>Add new platform overview
page</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-63ed954170e482e58b02938bcf8ab3c5b9b76b1a37b23b521cd88de2685ab566">+46/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>overview.mdx</strong><dd><code>Update AI overview with new
content and links</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-e36c2139a3deb3ca81742e73df8ce981aa4502fcb3713832636088eda8f120fd">+10/-10</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>overview.mdx</strong><dd><code>Add new Auth overview
page</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-fcb8a858a73ee17bb801d63453716d58b940d7b1e51f48c5fb184e34971866f2">+49/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>overview.mdx</strong><dd><code>Update Database overview with
new content</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-542ffbd4d75869cef7479dbc59a2c7c67272879b4f219488193794567b545351">+8/-9</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>overview.mdx</strong><dd><code>Update Run overview with new
content and links</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-ca49842af7e87c264e3ce8c19f4df657890fa0965cc188dbffafcd6ced1c526c">+11/-11</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>overview.mdx</strong><dd><code>Add new Cloud overview
page</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-32f53230fbf8b84f6a60dbf37568f8a4ea4bcab6f2e00e4357cd3b7f4c50cb55">+70/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>style.css</strong><dd><code>Add new styles for welcome
page</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-4dde236d1a1b6f7a24be281ce9e8212368612d66a631fa592bfe18653f57c601">+80/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>echo.ts</strong><dd><code>Add echo function
example</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-95b428813572cd2a2abcaf0c6e243622d757860c22f170c82126e5d2cbb269f0">+13/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>email-confirm-change.tsx</strong><dd><code>Add email confirm
change template</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; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-34aea348d369ef146295ec5c36c6df0fde8262277b93b98d7d9f4633092dc195">+129/-0</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>signin-passwordless.tsx</strong><dd><code>Add signin
passwordless email template</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-2d67959219d5979cf79921d4e8a86e16cceb46cd1e909a1783b68d27a85a0998">+127/-0</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>email-verify.tsx</strong><dd><code>Add email verify
template</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-139c6d5e04e5f6d2ce2c8e08a513a9830752fd9baff2aab415c9e34b0cee9918">+127/-0</a>&nbsp;
</td>

</tr>
</table></details></td></tr><tr><td><strong>Configuration
changes</strong></td><td><details><summary>2 files</summary><table>
<tr>
<td><strong>docker-compose.yaml</strong><dd><code>Update Docker Compose
configuration</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-47a924f5ea105a2a42b2c421901d43cf1f834a94be0c2f2f868d29dd8990b060">+481/-174</a></td>

</tr>

<tr>
<td><strong>.env.example</strong><dd><code>Update environment variables
example</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-08ca7f9ad9d499c71a30703d1bb00c4c599646480cfcc311972bfaa654530c45">+13/-25</a>&nbsp;
</td>

</tr>

</table></details></td></tr><tr><td><strong>Documentation</strong></td><td><details><summary>2
files</summary><table>
<tr>
<td><strong>README.md</strong><dd><code>Update Docker Compose example
README</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-34955300bc0ac9daa466c28e7aa59683b9b0c89e16344cf0544772acfb971b8f">+184/-23</a></td>

</tr>

<tr>
<td><strong>README.md</strong><dd><code>Update main README with new doc
links</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5">+14/-14</a>&nbsp;
</td>

</tr>
</table></details></td></tr><tr><td><strong>Additional
files</strong></td><td><details><summary>101 files</summary><table>
<tr>
  <td><strong>CONTRIBUTING.md</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-eca12c0a30e25b4b46522ebf89465a03ba72a03f540796c979137931d8f92055">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>DEVELOPERS.md</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-bd017515eb79a7fb7569b1d15e8963ea380123d4fdf779978dd4b3ab7500fd10">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>README.md</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-c15729e6c35a283a4b0eda60a991303b6c36c03903ba42dbf832bb8d0daa1a1a">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>AuthenticatedLayout.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-2d69ccffd267658f76d77a864cdece93fc222e08f6025955795fc6f4697f60e7">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>docs.json</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-ba8b2e40409d3782ac444d6c60d7f478772311cb211acd1c24c791937e47f1c6">+7/-7</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>SubscriptionPlan.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-2a5f070869055286b669e382b18d656935752803b9a1ef13390ac028c2a48ac4">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>SettingsLayout.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-aa21cda513a125d8cefc5e7b5e1c755128aa904657350abf0ce1cde21e27ca75">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>AllowedEmailSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-f4b2730b26266319aa6e705012da5bd20774881bc473411bd8b1619bbd0646d1">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>AllowedRedirectURLsSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-5c4c3714c99421265e1c35dd4300423407f758555eab0622d1f3bf12e7eb13ce">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>AppleProviderSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-2e75c4eada80cf228714593e2cd315108b5d10ff7f20bd91e8bc884f571f6f85">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>BlockedEmailSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-3a99b1db51b5654043151df4d77ad1ec369dd6d475e3261f80bb52e55dd81296">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>ClientURLSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-fd60e1f63909e5cf5a57ca7cb9eb5c8577683b638e94185cc840ce8fc6ad0d39">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>DisableNewUsersSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-60f6b3603e0467216d9633f4f92879a37416e202b18f0a4da0171332492fb6cf">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>DisableSignUpsSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-13b3734c8b8aed2e159affbfc9997846e85e2096e739479c72a09e9101d31faf">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>DiscordProviderSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-640c83d25085fd13cac559d4b567e2b14f0ef77e003d3b0a6fd4c35b2b5177f9">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>EmailAndPasswordSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-b4c8b368defc138ebbf777af773d0a98d00f7130e4f795b0fd83cf934bbf9a4a">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>FacebookProviderSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-5103b8085b43ba8f884429a70076ac8707a1510f06d62b5bf5bd08380ef4385c">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>GitHubProviderSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-438abe40d1c5ea84110c526038042a65d4c960a87f0371c23fc5d493350c5bd7">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>GoogleProviderSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-3c17bcfb21f6d2066f4727df5d059cfe871a5e1cf5efede5fcdf97d86ce17dbd">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>GravatarSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-e6d30e32ab062fd6060282190a4b28d86cd7aaf1a08fe3090056759ea43cfc02">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>LinkedInProviderSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-1efc0012f8c04ff4d54a29d20c0bc81422bcb5d689f4141c52179d7e8c054a7f">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>MFASettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-edb42fdfa300aae0bea103b9b4cc379e3d5c49ed00646a30673473660982904f">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>MagicLinkSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-d698ac461b405af3109f38cf74a81eb919193c28a62fa8abda7f62ba573a38e8">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>SMSSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-beffd7762c6b4f12ba0edd9e524fe07c33062f5d8c12d3783ae2bb42e1380f64">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>SpotifyProviderSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-93ba8b83aa965db9730f5f4aef9da2db8279a924a3812fc9e6f880173fa4235c">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>TwitchProviderSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-0f30d19f5b40424b59a85450a33f870a1a3e7b844e36e2ff7a92ce6c35a441c1">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>WebAuthnSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-d34c84f3b66fa2b843540e1829d3c827e38c46d5e663b8dcad11dac964a34080">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>WorkOsProviderSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-f0cd2c2e6badf59f882d564bf06617345cb4243bc699af4d02420ec2aefb166e">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>PointInTimeBackupInfo.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-35be453f6605231bcee5b7f7f78564eb7aa2be723f5169509f9dddfe84477fe6">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>DatabasePiTRSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-7a638c446af8419249770dc8da1ea522f950163b1d0045020927216c38db8cec">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>EnvironmentVariableSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-621bb42cb9fe0a763d30e738ab075af2784e8538e5ed7ac6ff1aa132d1a38042">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>SystemEnvironmentVariableSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-b952daa2a34e49a14c5a471477fa2d50583091e420d88a3b941503b092d18e5c">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>EditRepositoryAndBranchSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-e19e36c0830816cdd4d73cd058b91295bbfcbe65c37c36fa9a87e9c1f2e3b7ef">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>BaseDirectorySettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-50bcccdf949a19ce69fa86acdd63b5291fa2beaba07191a62c87d40ea5b94e88">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>DeploymentBranchSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-d8fc80cc734f593c686f873536856bf9103efb1115ca865709bbeb7bd940895e">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>GitConnectionSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-9e7a97afc3500aa2f4b28bdf4acb135925d92a6a595e16a3808b0b90ecc6be58">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>JWTSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-4bc7ce8b3f6e45940e5137c199d24b7a62cf3f804bf9c51b34a5f1168567ef25">+4/-4</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>ContactPointsSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-50a024995bad7b420fd717104a1584009e9fa44c508889dd125155f33d99f48e">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>MetricsSMTPSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-db01779fdfdece601aa83a1a2c256e65514602344a8556afd5832d32e465bc65">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>MetricsSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-957bb404fee8d18aa45af9e878837d311b69d9805ac16fe8d2c0e9d3b431e906">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>features.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-036778e07a1cdf33b7d90d8110f75338f8cd6870cc68bb75cff0c880318cd92d">+4/-4</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>frameworks.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-3833ff9ca6b5f1020384672b9de38149de400c57beaeb65ea255475ba8ce7da3">+3/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>PermissionVariableSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-ffbd1a0083e64318b68922362b6392090e24facc2a6476dc31e54e988a7599f6">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>ResourcesFormFooter.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-035d56050da913a9ab98c730bb88b34c734149053674204b86bd798d79f81371">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>ServiceResourcesFormFragment.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-9b9bf7e4f4e4dd34502e1b636c9f9aabbb20defe43595a79aa7e3f7d89750029">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>RoleSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-4cd13b62487b2de616d26d895ce4bb3afc7380abf9f3831ef2b949d073802a1f">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>ComputeFormSection.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-b5600bae05b535d54dc04b2a847b6402b10575efd87a0e7098796f0f9ae96d51">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>HealthCheckFormSection.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-9287c48c51c8a48a4b4aedcdc195cd9c8c79d3b3e2072765608081bc341f7fba">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>ImageField.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-6f618d85f2ca9a85b2a754f45e7b7e7803317be7e5dfd0e05bbee87c5bd1f116">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>PortsFormSection.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-75c4254c31fe6addb187b5d122dd1fa171c1a8875c0152a6c1b2a05257c61d4c">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>custom-domains.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-e35b13396a4aa0b96e35dd7a0b1a27d188c0d45fe20cbda99e2fd59b83da5574">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>rate-limiting.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-f31e44eb689a0e65e60f6eb2701f7adf283582fa5014c8727dc4922ecbd8c657">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>snippet-example.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-5fdce31e426151efa036ecdc78f6842c3bcd644a3d7658b1c753ee80c55d3cc8">+0/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>coc.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-dc80329f722e73bc46ee76902de782b4f696a4be0224658cbbb0a70127cb7627">+128/-0</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>getting-involved.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-4c15a93e9b63664bed77a875378d805efc8dc787bc0e1d6a6f413a376c5e6983">+57/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>commands.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-2053eb5138f4c468b9aa94e6fd7302ad2f577839be107741f265ae1b2d9bfcaa">+0/-158</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>getting-started.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-05cc8d760dce63f257bee91e9c0293424a63e0ed210d26c7bca78bc3a3d5d763">+0/-87</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>overview.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-dfcca51e047037e649bbf76e68ab3aa9161a85c1bd25cf385acc5e764bea0cd3">+0/-32</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>nextjs.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-291e724f8e8aadb8d126a30590af172b9b82fe187407c83cfc0673d76efd1188">+3/-7</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>react.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-fdf7ec55eee7c46bd8f83f8bf10066a136d21181bd6a04d513ae4c3bfaec1dc5">+7/-21</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>reactnative.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-bac475908ec022811c05fccec3d0eae805b25419b65a5d2537d70c606415d586">+14/-28</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>vue.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-1fee09fc68c4d33cea15dcb726c3e3671fdfbfc605a1751337f685f3cf851ca5">+3/-7</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>nextjs.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-a5210d45e7d33a57d43078dbe2a2ccbf0667b157291fd92c3986092d7d33ab9c">+10/-11</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>react.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-6f5adda9f7b29d98c68cab6ec754c0bac501666a49dd635ee830789e2c812b68">+9/-9</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>vue.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-f6c4215fa6909fd3accebe0691a7364d17befb8ef90da5a4aeaee83d598c0540">+9/-9</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>overview.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-3ca431109466557ec1ba7fbd4cb01fa0ad6316e3a9a2fe9c4a849b2760cc7613">+0/-115</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>overview.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-2a040923190b20dd4aa651b3cae8a7be263e7c5d014a71e9f27d628fa7404c08">[link]</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>getting-started.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-f5ce74103419f39f4217dd75f3e89517779c94615558ae726ae1b4519328a939">+0/-35</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>diagrams.txt</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-5f90e86736e92ab8b695c8cad8bd1d65d2be49609da7e693957bad0e238e563e">[link]</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>overview.mermaidjs</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-e68718f71eddf030085b739d48f6067bbb15f2421256ff27620d00f022b0c710">[link]</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>sequence.mermaid</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-cec810243251bf77934d8689d65f3e7d33f7632decf51e5eb7115b17042c11d9">[link]</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>introduction.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-0166b0574213b999964155797259928739a25e0a09d0442bdd14ff8307dcca30">+0/-85</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>mint.json</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-c91a604899dfef4b2494c317f4fd39a7f22b79986095f580399347293d534deb">+0/-560</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>package.json</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-adfa337ce44dc2902621da20152a048dac41878cf3716dfc4cc56d03aa212a56">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>configuration-overlays.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-f94c8434a3810529922d6b73ebd5f348e4f978b973e2959de0c0e45889b914d9">+7/-7</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>local-development.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-29e98b0241b9335e8929e64440664e4be275f3a3965a88d22a3eb80b5034fca1">+4/-4</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>migrate-config.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-0e2b5b8948935d313421790d173d10bb5c1242166f97d87fbf35d2a010d643f1">[link]</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>multiple-projects.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-b756a0fa80d9cdbefb538f676c90521bcff5e730498cde0430bfe789475c4e2f">[link]</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>overview.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-18be817b7d51e5caba56718075ae087777f3e3811987257d48949ada0fe96da8">+46/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>seeds.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-94215e4f4b5a3df8c20f0102f5755ecb55b5155d6ddbae30844666e477b496ab">[link]</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>subdomain.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-3300c8ab184167028e82d2e66932958ac55ebe94fba7d1aa2e45e8180178ea0e">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>billing.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-5a3b0998ad9e2f09c66255dff3651de3c6d7999e8e9c84169481e5e8af95935d">[link]</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>compute-resources.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-e2c40097d219e905b83f9e5ea40b19f6b927f846d7834b37a2dbe93dea3f5299">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>custom-domains.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-6004c16e12e623eda4d50a3b2e4f8ecbf5c2e1bbc9e5a91a62232e3a35f76a9d">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>environment-variables.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-49e8324f160e8fbe2cfea76adb45de7bbc3da6ca3d64d3a786a0f188c8bec9dc">[link]</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>git.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-d427ee2887e5cae303ce21a0b08300a82955c0f7f231ecea2ee198b69b0feb8d">+52/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>logs.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-d04ffc497f0eac2496c6bb7d4dfbb49853f35ba380dd45baf2d3239f8a42d569">[link]</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>metrics.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-14a13543059bf5d4903769ef3e6a90bb63af5cacc6105a35689ff75936421ea2">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>rate-limits.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-16b5125772f57a495889904938e950431b7b03a886e32241a162554b952db0c1">[link]</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>secrets.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-4c49bd272574c88f0d475d349c782c4ea24ba5cef97127106ebddde5befe7f4e">[link]</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>service-replicas.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-9188cea8fe3017f7732d5c9ed6600ef0147da8e960cff24ac4c6e156b53c4be1">[link]</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>subdomain.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-6d4add19495d7514bbaf0d67d9e60cf83b10ca4de6012aaf39dc0e39f3086bc6">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>tls.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-ca2d4657dffa3ca239e06eef76855154feb9b155317c67ff182d79f81aeaa236">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>deployments.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-6fa07c021c9566a75e9aca5efbf0f4708bd9862bb5484bf95cc25ce00f30e853">+0/-38</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>community.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-4f14893ed8d4ebde9be284bec0c27adc760452f8939246a6a65361bfd70760b8">+13/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>dedicated.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-78f989a9a039240f69408cb775632f7494754276051eae98af420dadf096c8cd">+18/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>overview.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-7cc9f04b4559ab62c5104791051ff7d7ad8dea108f1720eb260aa8e68475b0ee">+40/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>support.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-2aa4bcb1194ac3857cbb1846e43db4f1a5ebd0d9302e02308ce1502fb8c0a763">+17/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>product.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-3a7c615149cb270f3f59493a817306f87f8771114d1272de085359996e64bef2">+0/-56</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>authentication.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-1d91de2bc59159b3d47e86967f6ea82c608a10eb277d3fc0b5734f6f19305089">+0/-66</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>Additional files not shown</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-2f328e4cd8dbe3ad193e49d92bcf045f47a6b72b1e9487d366f6b8288589b4ca"></a></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>

---------

Co-authored-by: Sumit Saurabh <62152915+sumitsaurabh927@users.noreply.github.com>
Co-authored-by: Nuno Pato <nunopato@gmail.com>
2025-04-01 09:34:27 +02:00
David BM
8ea263ec75 chore: clean workspaces code (#3241)
### **PR Type**
Enhancement


___

### **Description**
- Migrate from workspaces to organizations

- Update GraphQL queries and mutations

- Refactor components for organization structure

- Adjust routing and navigation for orgs


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><details><summary>16
files</summary><table>
<tr>
<td><strong>graphql.ts</strong><dd><code>Update GraphQL types and
queries for organization structure</code></dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-fbd5db84b560b1c91675004448c6c7fa0dcbfb28b9eb05d53b03e6cb7b83ebac">+84/-1054</a></td>

</tr>

<tr>
<td><strong>MobileNav.tsx</strong><dd><code>Simplify MobileNav component
and update navigation</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-88408885daaec8805bd085b53462c9f2d95db32f7e523912837a8167211b4fb2">+11/-126</a></td>

</tr>

<tr>
<td><strong>ticket.tsx</strong><dd><code>Update support ticket form for
organization structure</code>&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-a66cba186d2014b03f1a0e005147ae7b48e88933700fe065d235cd819a949a97">+28/-84</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>ApplicationUnknown.tsx</strong><dd><code>Refactor
ApplicationUnknown component for new structure</code>&nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-d1d7044dd66488c5bc787a89612754b283eedb404d4d6abcface2fa533d5c9d3">+17/-21</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>DeleteAccount.tsx</strong><dd><code>Update imports and
remove workspace references</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-3d84927ffa4b91d986ff6c6f601b3476503220e1c1d8cde25ebf72c8d0ed6b9e">+2/-26</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>run-one-click-install.tsx</strong><dd><code>Refactor
one-click install for organization structure</code>&nbsp; &nbsp; &nbsp;
&nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-00e84c02bfc3c34019e15f820b23e332eeb1933a745be330c3644cb0f63c92b5">+5/-9</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>RemoveApplicationModal.tsx</strong><dd><code>Update mutation
refetch query for organization structure</code>&nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-e454a42c12dcbfcfaa463ab3421037408634e3a539f460525c79d68adfc118ab">+7/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>ApplicationInfo.tsx</strong><dd><code>Update mutation
refetch query in ApplicationInfo</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-7372ad22d70c3c354d8e0dd442eb7e49f70f65a386b934b6eee7f8c4b89c3a3f">+8/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>useProjectRedirectWhenReady.ts</strong><dd><code>Update
refetch query for organization structure</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-a234bc908266de3091b23b5134a01fd769f96759eb52aa108d2ad4b796b0303f">+2/-6</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>

<td><strong>DatabaseMigrateVersionConfirmationDialog.tsx</strong><dd><code>Remove
workspace refetch query in migration dialog</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-89e193ec45127a72f9491ad89eed5eda5939936686f88aadb48cfac350462271">+1/-5</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>new.tsx</strong><dd><code>Update new project page for
organization structure</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-ef97470126e3edc146dda51337aaec556387e2f8a37afa70810d1dc94958f4fd">+3/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>BreadcrumbNav.tsx</strong><dd><code>Remove workspace
references from BreadcrumbNav</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-2a69d273b2a9e8695d46f6c73dcbb6e161d3bb85f52deb65930018b17b148b3e">+3/-4</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>BaseDirectorySettings.tsx</strong><dd><code>Update refetch
query for organization structure</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-50bcccdf949a19ce69fa86acdd63b5291fa2beaba07191a62c87d40ea5b94e88">+4/-4</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>DeploymentBranchSettings.tsx</strong><dd><code>Update
refetch query for organization structure</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-d8fc80cc734f593c686f873536856bf9103efb1115ca865709bbeb7bd940895e">+4/-4</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>DeploymentListItem.tsx</strong><dd><code>Update refetch
query for organization structure</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-2a548c457ff2ab8fc1bee326a6a3b5eae9d0d6eb18f5ae95bbdb437c3f6b0a73">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>index.tsx</strong><dd><code>Update mutations to refetch
organization data</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-b4185be97a505e25badcdefe31ea86fa9d69f72264c4bb35eae17fba936a3d47">+4/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

</table></details></td></tr><tr><td><strong>Tests</strong></td><td><details><summary>2
files</summary><table>
<tr>
<td><strong>mocks.ts</strong><dd><code>Update mock data for organization
structure</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/3241/files#diff-d1ef12c0f15123bb4e23a0c513fc3d9b5c16af421c71c2909fde3717e09a9d89">+10/-27</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>testUtils.tsx</strong><dd><code>Add new test utilities for
GraphQL mocking</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-78f29250407edf853a353b48242d3cee59aa5724f38a60bb23bebdfc1ea2f9b5">+50/-0</a>&nbsp;
&nbsp; </td>

</tr>

</table></details></td></tr><tr><td><strong>Documentation</strong></td><td><details><summary>1
files</summary><table>
<tr>
<td><strong>useNotFoundRedirect.ts</strong><dd><code>Update comment to
reflect organization structure</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-262687fd80c4510f966a57885b1cc42a6297fd89ab49f6ff49b0df59670027f1">+1/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></details></td></tr><tr><td><strong>Additional
files</strong></td><td><details><summary>77 files</summary><table>
<tr>
  <td><strong>env.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-a1581a28a990763a0fada80d8a3030b70a702d744e98303887f390ac5ae24139">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>ContactUs.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-7137edfa9862e14ab2ca4660c679fb62f83990e161267d0dd7deb2977d117ea3">+0/-102</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-7968eed227f9c5da437b28062300b7076b1c124a3e3a335b29d91610c321954b">+0/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>InviteNotification.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-9209cf2ec7253c2a3ea03496f2e213b9f6ebf569264394ccd4c5cf5deef1f0b5">+0/-200</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-d4130a4e4d35e0d48479ae89c72650e23cb7a0389224f932efe59722e3a47d93">+0/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>TimePicker.test.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-784f69003ebbc9e39837b920007cef14125a5fc48bb9114226820bcb2b0827b0">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>AuthenticatedLayout.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-2d69ccffd267658f76d77a864cdece93fc222e08f6025955795fc6f4697f60e7">+0/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>OrgsComboBox.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-0736dac185f4ed134d5b53be292c9a2ee4f6df65e965b801a2dbbc8a184b3687">+2/-9</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>PinnedMainNav.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-0fbc67c16a16e263b51e46ada3fbaccc041074f31f541bf663ae3b4b5f2a2a17">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>DisplayNameSetting.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-a1daec18d5c3196aee5b2c5303db5654724f8d37cfa427594951a4d02fbe32db">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>EmailSetting.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-98bdf4ebec67ab2b4cd475c9df16a39a66505da961a8448eb5e41a33544dcb38">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>PATSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-880f5f139ed8c495239dbffee77691f761a004dbc5ce8456a95a259f79fb4136">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>PasswordSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-3b25d2f3c57a61224551f9eafaf53f22a70c5767b22ff5b7e2ae85b9c5705dfe">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>CreateOrgFormDialog.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-9a1ed9e851328393b81356d80ade3509016aa55c254ed1f4deb692b0bd96f02e">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>TransferProjectDialog.test.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-d4ebdb8af76a7c9e73606708718c3448445545259ad553d73b6d322408e3eb8c">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>NotificationsTray.test.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-727f6debec6a102557407e55c56363e0c75486e30a732158f85c81ada892f77c">+2/-4</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>ErrorToast.test.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-4a05f3b37769de69682260045f29c254b3ad6ef05f059e2b0f77cf9bd68e9bdf">+0/-85</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>ErrorToast.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-0095b510fd0557ef1d286cebd9fa102d24e1b0ff4d67148575d158e938304656">+0/-170</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-c16e96ee3476ef73bbc643d7c2399ad9ae8d0cff77a8e554a79c78eea26252ab">+0/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>useFinishOrgCreation.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-3b8bf7608ab36d8ab0df895e400f0d2d9e29fad2055b40b33d8d9912a27c99c3">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>useRestoreApplicationDatabasePiTR.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-dd5774f502b63d2d443069bedb4c9531a77794a95aaa5c07287093695a4dc60a">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>DeleteAssistantModal.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-81fc3c54dbde20f2535b00a52fc28e11ffd80fbcc90c0c34b1b82ff937cce215">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>DisableAIServiceConfirmationDialog.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-ae59e5250d9ec095cf3b141efa9734f239aff11c959de9795a94eddd426b1804">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>CreateUserForm.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-4e59f7d98f7ab979d2273d8685649f1c39165b2e33b47887645f0dda07edf306">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>PointInTimeBackupInfo.test.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-3980415ca79bf039abb469281fff9b1dc1de0a1ef52b4044d8c6f529538b6edf">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>AppLoader.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-fdef910b2c808595c77cb3c0ae573db3ff57cdb4a8161db2e36e86ec548b9b6f">+10/-20</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>ApplicationErrored.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-77c5a4128ffd614f299c867e5e3508430946f8f40d4ef5825f57874371fb1101">+0/-272</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-dbaba110b63f272983b09a1a453c0b69577136e7f0f2ff49c4cee6cf78f4325e">+0/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

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

</tr>

<tr>
  <td><strong>DeleteServiceModal.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-509d84f75908da0f25dce5f49a6103f3a938c9dd7106b66739ca3758bb83686f">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>useCheckProvisioning.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-e1758bb8d3381f814d6619dc33eee8b36e39d2fcb6486d5c8cc3c46bbe62c555">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>useIsCurrentUserOwner.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-3941cc4f23c66f12e94850e88e05ca142a627ab2d9ec797ff757dab679c58c0f">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-5a21e22b6c3f0b8f3abd13a4f78cd918662785eee6253480fa0116d11e9c6957">+0/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>useNavigationVisible.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-3a395e5461f6112ecf12f399ef008999133a1b3a9d9b267b2ea7f7d5d39d1fe0">+0/-63</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-4f8060ca9eb12226bfb857e06e67f5f3fb583622d878a243e300c9529275c032">+0/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>useProjectRoutes.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-ffb341175a52f91f88ce6906c93ff747944ffd3ed9ff9ed27f0894e88e778b66">+0/-160</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>RolePermissionEditorForm.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-c7cc670c499aaa76537a1ac3848721988fa0196d4cca8f6b5376b4a14f01341d">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>DatabasePiTRSettings.test.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-85d1f82a571b56469eab40dcc164fdd1e107fba79611ddd5cca7c191fe5117b4">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>DatabaseServiceVersionSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-a982b817513fc173371f7468ad642f99ee0c914e5990a48992fc1fa5e230765f">+1/-5</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>OverviewDeployments.test.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-a9440d76cf165e4df8e9db020ee2ab3896281633dbe5ba3691e775d57188bc80">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>ResourcesForm.test.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-8828db70c080be6fc19f88059b08587584f1c23c9159092d6b186ca82a1943aa">+1/-5</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>ServiceForm.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-a02746694d45a84390d09b49a1b3eec85c25a8bd9a70b4834ee5af1ba82cb88e">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>execPromiseWithErrorToast.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-adc371e89102ef58f14269197d4ce970117519df44ad77174ed6c32128a67079">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>getAllWorkspacesAndProjects.gql</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-d932cf46bd3efabd2e4240961ce868bfe056319507e0f0738476d2300520df46">+0/-5</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>getAppPlansAndGlobalPlans.graphql</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-390440124963f8917a01146b85220aaa57a1979f1d0efa5d460b8979121be089">+0/-39</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>getApplicationPlan.graphql</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-cd0b842260639b906128451c479685925192415ae366c3a584f897022f715ccb">+0/-14</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>getWorkspaceAndProject.graphql</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-6b457c9426ff027a373b6366fa518466e1bbe31aedd19ae0d5a5ac000defebff">+0/-5</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>getWorkspacesAppPlansAndGlobalPlans.graphql</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-98bf824b6937b6b6ec16d4c75194876ecdb2ad9e9a4d5bb3681458214007fd02">+0/-39</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>insertApp.graphql</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-1b04d1a9b24bd1348f12f9f89330e38aa4e64fa9d34f3635a02f23c5bbc767d1">+0/-12</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>prefetchNewApp.graphql</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-da7b539d835be3df6211788845bfccf4a45259516af11bcae8840f7ac6c2eb9d">+0/-12</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>organization.gql</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-7a8445445910a3f718136846bcdd03a504adaa0ece372e1cee99855abc26f1a0">+27/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>workspace.gql</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-503e0160f94a01ed2ac4026bb30e5c3524d54eadba1edb986a8b5e5518112577">+0/-18</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>getAllOrganizationsAndProjects.gql</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-11d0c4e299315719cac8553bfe6a245fcab0d592611f262b8975066b968799a5">+5/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>deletePaymentMethod.graphql</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-ed0ca3304c58b0867a3dacc4262b9f3dbe1720f6bbbc4f6b70c630231d3fa842">+0/-5</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>getPaymentMethods.graphql</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-05e6800ddfae03eec9b811bedb49e519a9683009eef7db1276d483d8810016b2">+0/-27</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>insertPaymentMethod.graphql</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-580f9ca3fbdc0b48c66b5c358045a24e890c5d53e6ed2ae9818d7775f2564269">+0/-16</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>setNewDefaultPaymentMethod.graphql</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-fa1366610e5485ac4e423267434c0d9147dc76db7f0842ac2f9d5c32f57e8e22">+0/-17</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>deleteWorkspaceMemberInvite.graphql</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-85b6d2a6825ba54b85b5cb065705eeb0d65a488fbea853cd46e60208f2d17146">+0/-5</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>getWorkspaceMemberInvitesToManage.graphql</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-8e97084848d9462ae3a1751d5e5468c5a9772df56d790b4c29a80c89776070a0">+0/-14</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>insertWorkspaceMemberInvite.graphql</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-7a86261ddc3fcb4863c2fdf607eb73292f0c6175f4fe74303b5f3325279852da">+0/-7</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>updateWorkspaceMemberInvite.graphql</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-b36ab22e1cc92da61d8499dffa16a96e54e353f839b026acc9a08d29b2ebba1e">+0/-11</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>deleteWorkspaceMember.graphql</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-7a1add8ebc3e12adf78aa481062a207af509d82170a383d0995eb46a1151e4de">+0/-5</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>getWorkspaceMembers.graphql</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-584c1f1108054fd783fd7f12a9a746a1c69345d0a6c1d2bfb6f6cf57ce423065">+0/-31</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>updateWorkspaceMember.graphql</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-ad799e00a2ca484fbe7aa9b1e1f6e0519a989ebf1478506f1c4a516052bd70a6">+0/-8</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>deleteWorkspace.gql</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-9c3cea5f88a37ea264617a5cc4e992f2b49c3817a31786a238fef9ec4cf6ad95">+0/-5</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>insertWorkspace.gql</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-ffcac8e9d094021d7ec386ced82f1a36b366e86b39acaf389c570bc21b92be1c">+0/-6</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>updateWorkspace.gql</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-d8cf2dd0d7e221dc8d5f787a1db06492cb56919725fc2211f47c399ddc1b0f19">+0/-16</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>[...slug].tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-56e5a4a71eca9397303199bc4f5595a08ec3ce62a2499f8c079d53c71e9cd8f1">+0/-158</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>plansQuery.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-22d9c2d45021b1b76fc284ef1baa41474357ea0ef8c2cdedd06d7bcac3e32629">+0/-16</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>prefetchNewAppQuery.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-0a3a444a14b5f5495ef86c90f200a3a672732770e90d4b7206468e2ac265d9fe">+0/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>mocks.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-39b16c295568f731fa43aa5a9d642b75fc70f4c0a8e281d701c59da01ec2121e">+0/-124</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>testUtils.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-6ebbd73e167641a1706f1b8d30b00569336d10f3c2ab7626d81e639015383e5e">+0/-164</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>application.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-380f35753fb3e224792c12d28bc7505ea961ea3f7efd578d1647f76af15afe9f">+0/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>graphite.graphql.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-0b7f0e87bb1506853e3ff0227d39085c67994427b818b1b05bb3df5a94539ffb">+5769/-25931</a></td>

</tr>

<tr>
  <td><strong>execPromiseWithErrorToast.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-1470fd6a1f6e5557aae2940678106477b11e8a9c8ebf37fc2fa38c0d24a9118e">+0/-62</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-992ff318b1e702f9ad368ce2e529f0ea57cc6711edf892815a0ed246173001b5">+0/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>tailwind.config.js</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3241/files#diff-0421515d64f36bf18988a5e62f6b406277d9a63b6991a8b3f4c9e976836449c8">+8/-9</a>&nbsp;
&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-27 16:25:39 +01:00
David BM
7b9cdf1f5f chore (dashboard): remove unused legacy workspaces code (#3209)
### **PR Type**
Enhancement, Bug fix


___

### **Description**
- Removed legacy workspace-related code and dependencies.

- Refactored and relocated utility functions and hooks for better
organization.

- Added new GraphQL enum value `Pitr` for billing report resource types.

- Improved type safety and validation in service resource forms.


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><details><summary>13
files</summary><table>
<tr>
<td><strong>graphql.ts</strong><dd><code>Added `Pitr` enum and
refactored GraphQL queries.</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-fbd5db84b560b1c91675004448c6c7fa0dcbfb28b9eb05d53b03e6cb7b83ebac">+177/-175</a></td>

</tr>

<tr>
<td><strong>ServiceResourcesFormFragment.tsx</strong><dd><code>Improved
type safety and validation for service resources.</code></dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-9b9bf7e4f4e4dd34502e1b636c9f9aabbb20defe43595a79aa7e3f7d89750029">+46/-12</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>getPreviousApplicationState.ts</strong><dd><code>Added
utility to determine previous application state.</code>&nbsp; &nbsp;
&nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-cdc095ecffb5d21ca54d8537f3d2359bb64c5a0ade4ee94ae9d842ea7342f3f0">[link]</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>ServiceForm.tsx</strong><dd><code>Updated imports and logic
for service form components.</code>&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-a02746694d45a84390d09b49a1b3eec85c25a8bd9a70b4834ee5af1ba82cb88e">+4/-4</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>useProjectRoutes.tsx</strong><dd><code>Refactored project
routes hook to remove workspace dependency.</code></dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-ffb341175a52f91f88ce6906c93ff747944ffd3ed9ff9ed27f0894e88e778b66">+5/-7</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>

<td><strong>ResourcesConfirmationDialog.tsx</strong><dd><code>Simplified
resource confirmation dialog logic.</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-31f0a9eb5e1c1199ad462b7e1a9886cf4941676dc2506661c3d304aa5cf1716a">+6/-8</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>

<td><strong>usePreviousApplicationStates.ts</strong><dd><code>Refactored
hook to use updated project state logic.</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-e0bdede95ef9307a61f227b0f6a7dd3be67470e4a58ff139bb5b569f5bef2680">+6/-6</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>AuthenticatedLayout.tsx</strong><dd><code>Updated layout to
use refactored hooks.</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-2d69ccffd267658f76d77a864cdece93fc222e08f6025955795fc6f4697f60e7">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>PortsFormSection.tsx</strong><dd><code>Updated imports and
types for ports form section.</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-75c4254c31fe6addb187b5d122dd1fa171c1a8875c0152a6c1b2a05257c61d4c">+3/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>ApplicationUnknown.tsx</strong><dd><code>Updated imports for
application unknown component.</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-d1d7044dd66488c5bc787a89612754b283eedb404d4d6abcface2fa533d5c9d3">+4/-4</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>ApplicationErrored.tsx</strong><dd><code>Updated imports and
logic for application errored component.</code></dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-77c5a4128ffd614f299c867e5e3508430946f8f40d4ef5825f57874371fb1101">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>ServicesList.tsx</strong><dd><code>Updated imports and types
for services list.</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/3209/files#diff-643c818a248c42950336289392ac97ed9ef5c670ff8e47b80588b9802844d28a">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>useHostName.ts</strong><dd><code>Added new hook to retrieve
host name.</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-89b0d30fdcc12b0b3ea97e76676101c2a535ec0817ef106e26f74736d190d1b0">[link]</a>&nbsp;
&nbsp; </td>

</tr>
</table></details></td></tr><tr><td><strong>Bug
fix</strong></td><td><details><summary>7 files</summary><table>
<tr>
<td><strong>OrgsComboBox.tsx</strong><dd><code>Removed workspace-related
logic from organization combo box.</code></dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-0736dac185f4ed134d5b53be292c9a2ee4f6df65e965b801a2dbbc8a184b3687">+3/-57</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>Header.tsx</strong><dd><code>Simplified logic for opening
Dev Assistant.</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/3209/files#diff-edac1cd4478dc0ad12911ea2e486f40e49f6dc64eaf8e72084225d1f4e8725af">+6/-18</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>useNotFoundRedirect.ts</strong><dd><code>Removed
workspace-related checks in not-found redirect logic.</code></dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-262687fd80c4510f966a57885b1cc42a6297fd89ab49f6ff49b0df59670027f1">+1/-14</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>index.tsx</strong><dd><code>Simplified navigation logic by
removing workspace handling.</code></dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-4eefa54204aa396da4d4d2f1d633d42d1b8ef86987f6e8c9b63d81df1ea6a273">+3/-21</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>run-one-click-install.tsx</strong><dd><code>Removed
workspace-related project filtering.</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/3209/files#diff-00e84c02bfc3c34019e15f820b23e332eeb1933a745be330c3644cb0f63c92b5">+3/-17</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>useNavigationVisible.ts</strong><dd><code>Updated navigation
visibility logic to remove workspace dependency.</code></dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-3a395e5461f6112ecf12f399ef008999133a1b3a9d9b267b2ea7f7d5d39d1fe0">+8/-8</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>ErrorToast.tsx</strong><dd><code>Updated error toast to use
project context.</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/3209/files#diff-189ba99303a20e964b5e3f3d6f1cf95c6376780a59604d1dee98aa84d9a2a9dc">+3/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></details></td></tr><tr><td><strong>Additional
files</strong></td><td><details><summary>101 files</summary><table>
<tr>
  <td><strong>brave-fishes-tap.md</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-d01ffdb9103e911bc83d52df72b16006ca7d8af6c0ac8ca5504f022c0c3cbd0b">+5/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>package.json</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-2d8d55c799cd71f1b35e831f075f8178ed1734c4820a2ad548b4dd24d6938d7c">+0/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>InviteNotification.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-9209cf2ec7253c2a3ea03496f2e213b9f6ebf569264394ccd4c5cf5deef1f0b5">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>TimePickerInput.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-970eb8f755f27a1e13f0d24230c403ffd1e5ad7829e14b67690373bcdade1277">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>DataGrid.test.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-9cec5ba99b1f62307ecdd1444d14288bef737bac6d3eff1c02ddc2f89e9f9061">+0/-67</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>DataGrid.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-28be1550256357ac5d3668065e1e3a496e6896ac12121dba4dd0c98948c3d2f6">+0/-185</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-9458085c38927aa3e04af020d769fc21a2b9b38dd190da9258a557d720c20f7c">+0/-4</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>useDataGrid.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-0af098dd11eddfb502643d4a17599d3f96f70dda9d0dd76be58eb651e6ab3e08">+0/-110</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>DataGridBody.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-bd9e62c9a14fac478b95684e09943ad95493e3cd0f517d3b2bcf27d90a8b6b7c">+0/-315</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-095354baa6f9bcf08084323308fb51d62cdf1993fa2922f5b6008173654ff94c">+0/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>DataGridBooleanCell.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-912f222369372de8803ab4ea2ab8310d2ea12f98f08e9e4ae76ce90b99e9e718">+0/-121</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-6aaf85dd782c1bd3f87baa67daa100ae57b06680b536ae261be81a9ae9f3225f">+0/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>DataGridCell.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-30b7b50f3aaa8f1da1709951acc8338ca283830474e9d701e5a4650540ea6f8a">+0/-381</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>DataGridCellProvider.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-c996a77e36cee151e515fd26d540a3e661c76e41f1cceb7de6f52bd51d5849b5">+0/-238</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-085c66def9eb67fc7c2a44f3421206a58c4ec60127e463251a2632061fbe8ea8">+0/-5</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>useDataGridCell.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-cb0b09edfdc285173765bcbb7c4822083286dee9be4de07fbafe802a72d997c2">+0/-10</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>DataGridConfigContext.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-f6e013fae040f331dba8a8cfd69ecd9629e609299ca2613de378deef3e2b0a70">+0/-6</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>DataGridConfigProvider.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-a285c2ab50379b3e50ae912427b3bbf1748534fb688c23e0e9b3e9d63e3670a5">+0/-16</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-b495c649d04122385810916ab7e9cea8a36b3a2c636c376b44172a70804cf7a5">+0/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>useDataGridConfig.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-1ad1e4d3198ad963ac96fecbdd83f4061ed3133cf16ace8f7f936bf7721365ab">+0/-15</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>DataGridDateCell.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-fff3b2aebb93d3d3a351d7d4ccbc43d376b09ec623c1535c94509f4f35ae2da4">+0/-166</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-fbbdbffeef2e43799d1108293e0e37d7f2949540b4c9ab542beb340a6a84c115">+0/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>DataGridFrame.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-8d8bcaeea226957a5ef1a58038b02c161950da8a2f7af5ee95c657775a204705">+0/-29</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-b4c9a950b5dcf474d3d8110544e8a049ff2c0d496aced6c82f7fd77c438c7e67">+0/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>DataGridHeader.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-02b826079155107d8958b4c673ab2b16853a96e46ef6f57cd832eadfdc2092c8">+0/-233</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-4fd4f6e3ee3ef5c4821bd8fa47ac59c2c6a8ca90dde1765ca8dde1a0689474f8">+0/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>DataGridNumericCell.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-e43c9c46c38fcdb978debf6164c8961acb5205ee6d152176b63d8dd2af413aa0">+0/-110</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-4497697c15accb04a0115741740c32a7bdef1590b395f3158b1099a627d501ce">+0/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>DataGridPagination.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-70ecfb728f6db3744bb35fcf537f70b20fea7688a00d302db0c624ffc0a043f0">+0/-91</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-eb674985acf19a5b7e619edd684c7760a617dc50fde1e9d746b1e261e092ea97">+0/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>DataGridPreviewCell.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-a4b0178eb28a1feaec9a72ad10c12283920cebbbfb0191c60b2535cb9ae028c6">+0/-410</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-845756895046979c2172565ff6d7e02340b93ac9e4499f930df626a0f5097880">+0/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>DataGridTextCell.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-74741563ec9d20b8894db4b3e653d1b345de156cd7dea1aded30ae9f78c3a7d3">+0/-243</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-53ad1b029b8643989c03e80ec5bb988c9eea2cf0ca595df2bd9eeb173f035f9f">+0/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>AILayout.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-06c432465b00d94c1f3fc8021951bb4d25f4e38195a6b1d90bb728f9105ae632">+0/-46</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-d97b390020ef14021a1ae3e1643b3a4f329b13a8a68aa5353a8a3ab64e824f91">+0/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>AISidebar.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-29134460a234b6ae943e6c6d8d65ac8f9d66bf4e3403b045b94662b0f57a964a">+0/-143</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-b3af150842887ad9d9107eb9c70330ab8ae5b4b04932a1c3f671547c4e99301c">+0/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>Breadcrumbs.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-faf66535b1957a4f15804af0dd708fd0a64847ae31d782db949ce0c6597e3683">+0/-78</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-2cad195ac8af2b5acd41032c9ecbec8b476c9c348f08aa305ef0a3e81098a29d">+0/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>DesktopNav.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-547854a882b4681187d3e8beae5d8512fb3c49cef3017ac891f57b4f04e87fc2">+0/-90</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-2f102e83204acf8d7bb8133d7366e65a168c77e212fbade105f67845d53e4622">+0/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>BreadcrumbComboBox.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-1d14ffa8e3a2bbaf9d8bfd4f215670cc62ce74558420619b98dd563a82f5ddb2">+0/-109</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>MainNav.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-8a552e1cae4ec4725740e006ec406aa60057db39c9580a31d938709d17d4b2c3">+0/-12</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>PinnedMainNav.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-0fbc67c16a16e263b51e46ada3fbaccc041074f31f541bf663ae3b4b5f2a2a17">+0/-12</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>TreeNavStateContext.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-a3558f36294f2b09b28b3a7704b443f2f2c92c33a0d376f986ca4b365907e7a9">+0/-13</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>WorkspacesNavTree.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-f16c5269315ce432f3fadd7e5b6c67b5677c2565e86d8e992d7336c139240423">+0/-495</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>MobileNav.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-88408885daaec8805bd085b53462c9f2d95db32f7e523912837a8167211b4fb2">+3/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>OrgProjectLayout.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-a123a6ce5d250edcfad8d67346a1e7ee5bb31f2416f8434c406f8c08e6d1c810">+0/-123</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-18c0d591ef16e8caecd0f371f139647bc68a958f300296cd5077e91f5a5efa73">+0/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>ProjectLayout.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-8caf89cbfa2eaba06d159548c1a77cd21b0da6553922bb5198bf8fb0f1d15512">+0/-114</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-8514a657bfc9d16c0c3d0cfc7df589876c15389cb9937fc15e46944e625413e6">+0/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>SettingsLayout.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-5d2869e956e78a19f2c099eb43ed3edca826c599ea327e790ec09f2c07f92026">+0/-69</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-e0760e0de853e7e172f98c8c2932124d9a6bdd644d1751dffefaa39a13f313a3">+0/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>SettingsSidebar.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-228be719ea3624edbfd2af99af3c076cebb3d0732026987306aa1032a795ba00">+0/-266</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-398edb964d1a53e31ed4afedda4f85455f37180b8bfa3b4164d848e9f8e25438">+0/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>UnauthenticatedLayout.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-54ee5ad9c01e99ffb05218020a6b97d091cd97cc53ad27e950480a3e675f2220">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>StateBadge.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-0785b6d6a702605f6410d8c76a303ed8bcaf33449f12b0cf6324f0250e94562d">+0/-58</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-d9c38a018643979391b0c0baea0e859dfb19eba0f06dcaa7198a789dcab24df8">+0/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>spinner.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-0404df81ce8503d881cd2f3f1ac59865aafd65f559e6a335cd79e2c49fe31476">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>AssistantForm.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-f6015289d06f2d4d6b495549c0c54db2fb5833bac4ea659877b3e2c32668c758">+0/-309</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>ArgumentsFormSection.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-c0cbe9d5ad0a46c4cd994015d5b27452b484182bc59f9524e585389c784c6fad">+0/-165</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-9a27cce2e15cc8f73013ea09de29d18b077b3dca6b70cbbb6f65868cc6e4f35a">+0/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>GraphqlDataSourcesFormSection.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-4a435a4417301fe788a7556a19e81b78fce505dc1c5fa6dcd7866ab4882e16b0">+0/-123</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-a47e5e39caca5b4d48ebb44351bf53a131d3bbda63842702998eaf10758457bd">+0/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>WebhooksDataSourcesFormSection.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-351156304a9a0e733ed3021f8403d66e0c90d982f0473ecdde18fbdb7cda62b6">+0/-123</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-ba756f916fe87414836dede20a92c9d6b92dd45e637a3b4997dda4a53afb6561">+0/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-7a8d3a1c1699597e56716689080a27d87fa8e324b8d9630e376f6b7ac4e7b103">+0/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>AssistantsList.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-1a59975c1b045c82661af32381c5ba707d6148d3cbf32d2058cd1608a498bcf7">+0/-158</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-8cc30611ef5cd09068b1b6e72dec22807667298bb00b3d03dd857ac4e18ae693">+0/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>AutoEmbeddingsForm.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-652aaf2408d7a565c133280378b00f1f915b95f6e11a02c3284b3de1e3f0563e">+0/-333</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-9b82349addb66b827deffab33b2278cc9d1592d73a7f3b5403388eb361f59e26">+0/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>AutoEmbeddingsList.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-2d5ad51ee4b313417bf25812aea7a7b2194d8b36ec7b21f2715c591f3a650979">+0/-172</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-071889af96589df81d86bd8f56518ac55414b56710c12e04422259f8f28417b1">+0/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>DeleteAssistantModal.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-936ee6ffc853afdfbe613d8f0691b0717b893867ef68a515772c1d1c2b34dbe2">+0/-101</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-416db234a1b6459a1aa10d159372597b06b57bd97bed9517447c328969cffcb7">+0/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>DeleteAutoEmbeddingsModal.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-cc09a2e76a36bd3d3a72662fc74dcd8567c72a60f65babe0f9d4cd24dc1049f5">+0/-126</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-3c86ad5feb48d5736588598c0d4f6f2a2e96316f2088db653cd3008694410580">+0/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>DevAssistant.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-a70be4ce82cafa2a5cd0c587a5c927c1e21ebfe9aeebe0db45c91a7fdbfad216">+0/-235</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>LoadingAssistantMessage.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-7d85aea7bef56f2cd60bedcf0bceeea2d0a286ffaf41dae46e1a09ee3517d339">+0/-28</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-52e76ab9735b31f4a23067fb232087a07f366785bd9ed770a405cb53d7814ac6">+0/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>MessageBox.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-4e2c9825294e6e1d27a82ca6275724223a438975b4c27bd2c4285c4b44192562">+0/-98</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-51ba9e75ccb25006d10dbdd1dc837f717ad35405a3f1cb7268e7e9c3efc8a0f5">+0/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>MessagesList.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-ce3eee6db2c6205688e9e18e14bdf69ac086a9bb14b9ca700d363255bfd6285d">+0/-36</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-0c1c5112ef0ff550e50083472c4664cd65ba358e40488475e6dfde20513c72b5">+0/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-3ed20f43facb55a7acaaf127c3ec63647b04b6b035be34ba61407b0f361099ae">+0/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-4d7e6c292d1217979f4119a3e981807d6bbd9a106d1e2e4c5129df2cdc38b9bf">+0/-5</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>messages.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-d87f7975332092d0bb875f789ce3e06fef19d675a540805c520bb1d796fe2efc">+0/-23</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>projectMessages.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-29ee83e06b8c27fa0b56d3827e82241c59441b33107805c133e44866331aed4a">+0/-20</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>session.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-9f3f7f1876efbbff1133c150dd39505154d8d1e9d0d123e199f251258ad3a178">+0/-10</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>AISettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-caaa010fadfdc403e470035e2dbbd950c163d59f8192bfbccbf0d1dd159a57a5">+0/-496</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>DisableAIServiceConfirmationDialog.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-be999162874fbadbc93ca1bcabd881931c2673863e36c2e7b427f11fb7908879">+0/-110</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-2fdab42f10d8c17e14864ea2ee736126e009985998cf4ec07a45f22d34deee82">+0/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-c44601df3a538664a1d7bfbf27552fe36246ac69f27d4c35c9ede34f624a222a">+0/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>getAISettings.gql</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-3bf40707417defbba9ec9de149f7f322ad11869ea89cb136b5b4fcffe74f3610">+0/-24</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-7e62ae21154e773aa7527bea511ff1a517139bade8f36feb177a0da185778a50">+0/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>isPostgresVersionValidForAI.test.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-b3649eb91d332adb390bf040e9eef975190a5080e6792076449a38296c9741ac">+0/-22</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>isPostgresVersionValidForAI.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-0f2b72f23874eaccaed79c80ffa750fdf0094940adfa733e8961322556195bfe">+0/-18</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>AllowedEmailSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-33d6bf857db317c4533a74e8cfc36642892a30510f04425aa20a4f9e858814c3">+0/-197</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>index.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-47c1d040f85882e659b4c936649cecf98ff50a5d87a075bba66250d9a84e6d89">+0/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>Additional files not shown</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3209/files#diff-2f328e4cd8dbe3ad193e49d92bcf045f47a6b72b1e9487d366f6b8288589b4ca"></a></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-27 14:56:39 +01:00
David BM
1c4f321f64 fix (ci): update vite to fix vulnerabilities audit (#3255)
Updated Vite minor versions across projects to address security advisory
vulnerability
https://github.com/advisories/GHSA-x574-m823-4x7w

### **PR Type**
Enhancement, Other


___

### **Description**
- Updated `vite` dependency across multiple projects to address
vulnerabilities.

- Added a changeset file documenting the `vite` update.

- Incremented minor versions for affected packages in the changeset.


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Other</strong></td><td><details><summary>1
files</summary><table>
<tr>
<td><strong>little-peaches-bathe.md</strong><dd><code>Added changeset
for `vite` update and version bumps</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3255/files#diff-1517254487ebcd9cd74441ddbed15984d623cbb85119925248e57242614a47d5">+13/-0</a>&nbsp;
&nbsp; </td>

</tr>

</table></details></td></tr><tr><td><strong>Enhancement</strong></td><td><details><summary>10
files</summary><table>
<tr>
<td><strong>package.json</strong><dd><code>Updated `vite` dependency to
version 5.4.15</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/3255/files#diff-2d8d55c799cd71f1b35e831f075f8178ed1734c4820a2ad548b4dd24d6938d7c">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>package.json</strong><dd><code>Updated `vite` dependency to
version 5.4.15</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/3255/files#diff-83675898dc6ed88838763232d022f6e100e07d71681cc8a1f02aee99ee3f229b">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>package.json</strong><dd><code>Updated `vite` dependency to
version 5.4.15</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/3255/files#diff-9fb3a23f389ab1d192d7e018d2acbe512bd8792278662101401caa98692735db">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>package.json</strong><dd><code>Updated `vite` dependency to
version 5.4.15</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/3255/files#diff-cb7094614884e8cd2c8fb67dadedb1887c46c31b888840def0b7042273bfbb28">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>package.json</strong><dd><code>Updated `vite` dependency to
version 6.0.12</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/3255/files#diff-6288951fff74ec246c9cc023b7b7e3e9aad31423891bc4ea25b5d84a5f5b061f">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>package.json</strong><dd><code>Updated `vite` dependency to
version 5.4.15</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/3255/files#diff-d95dc3391741287366ea2e61f70e9ccc64452e0d22b1db91d6bf524f5aa4331c">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>package.json</strong><dd><code>Updated `vite` dependency to
version 5.4.15</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/3255/files#diff-8a3e5ed0f618f15211c31f700e0da998e2eae58f60353624b7a7e637bd63b153">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>package.json</strong><dd><code>Updated `vite` dependency to
version 5.4.15</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/3255/files#diff-fc4298d3512fdd9a3d871f9f182fe871c8beccd1580f864a271ddfb32005feef">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>package.json</strong><dd><code>Updated `vite` dependency to
version 5.4.15</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/3255/files#diff-85166d1137e29a5275f991e1e94a0c9d5b83ac7504463ba76f9187b2b750c895">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>package.json</strong><dd><code>Updated `vite` dependency to
version 5.4.15</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/3255/files#diff-7ae45ad102eab3b6d7e7896acd08c427a9b25b346470d7bc6507b6481575d519">+1/-1</a>&nbsp;
&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-26 13:15:04 +01:00
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
2079 changed files with 31168 additions and 105139 deletions

View File

@@ -1,5 +0,0 @@
---
'@nhost/dashboard': minor
---
feat: add empty string as default value for text in databases

View File

@@ -1,5 +0,0 @@
---
'@nhost/dashboard': minor
---
fix: update babel dependencies to address security audit vulnerabilities

19
.github/labeler.yml vendored
View File

@@ -1,24 +1,25 @@
dashboard: dashboard:
- dashboard/**/* - any:
- changed-files:
- any-glob-to-any-file: ['dashboard/**/*']
documentation: documentation:
- any: - any: ['docs/**/*']
- docs/**/*
examples: examples:
- examples/**/* - any: ['examples/**/*']
sdk: sdk:
- packages/**/* - any: ['packages/**/*']
integrations: integrations:
- integrations/**/* - any: ['integrations/**/*']
react: react:
- '{packages,examples,integrations}/*react*/**/*' - any: ['{packages,examples,integrations}/*react*/**/*']
nextjs: nextjs:
- '{packages,examples}/*next*/**/*' - any: ['{packages,examples}/*next*/**/*']
vue: vue:
- '{packages,examples,integrations}/*vue*/**/*' - any: ['{packages,examples,integrations}/*vue*/**/*']

View File

@@ -7,19 +7,20 @@ on:
- 'assets/**' - 'assets/**'
- '**.md' - '**.md'
- 'LICENSE' - 'LICENSE'
- 'docs/**'
pull_request: pull_request:
types: [opened, synchronize] types: [opened, synchronize]
paths-ignore: paths-ignore:
- 'assets/**' - 'assets/**'
- '**.md' - '**.md'
- 'LICENSE' - 'LICENSE'
- 'docs/**'
env: env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: nhost TURBO_TEAM: nhost
NEXT_PUBLIC_ENV: dev NEXT_PUBLIC_ENV: dev
NEXT_TELEMETRY_DISABLED: 1 NEXT_TELEMETRY_DISABLED: 1
NHOST_TEST_DASHBOARD_URL: ${{ vars.NHOST_TEST_DASHBOARD_URL }} NHOST_TEST_DASHBOARD_URL: ${{ vars.NHOST_TEST_DASHBOARD_URL }}
NHOST_TEST_WORKSPACE_NAME: ${{ vars.NHOST_TEST_WORKSPACE_NAME }}
NHOST_TEST_PROJECT_NAME: ${{ vars.NHOST_TEST_PROJECT_NAME }} NHOST_TEST_PROJECT_NAME: ${{ vars.NHOST_TEST_PROJECT_NAME }}
NHOST_TEST_ORGANIZATION_NAME: ${{ vars.NHOST_TEST_ORGANIZATION_NAME }} NHOST_TEST_ORGANIZATION_NAME: ${{ vars.NHOST_TEST_ORGANIZATION_NAME }}
NHOST_TEST_ORGANIZATION_SLUG: ${{ vars.NHOST_TEST_ORGANIZATION_SLUG }} NHOST_TEST_ORGANIZATION_SLUG: ${{ vars.NHOST_TEST_ORGANIZATION_SLUG }}
@@ -28,12 +29,13 @@ env:
NHOST_PRO_TEST_PROJECT_NAME: ${{ vars.NHOST_PRO_TEST_PROJECT_NAME }} NHOST_PRO_TEST_PROJECT_NAME: ${{ vars.NHOST_PRO_TEST_PROJECT_NAME }}
NHOST_TEST_USER_EMAIL: ${{ secrets.NHOST_TEST_USER_EMAIL }} NHOST_TEST_USER_EMAIL: ${{ secrets.NHOST_TEST_USER_EMAIL }}
NHOST_TEST_USER_PASSWORD: ${{ secrets.NHOST_TEST_USER_PASSWORD }} NHOST_TEST_USER_PASSWORD: ${{ secrets.NHOST_TEST_USER_PASSWORD }}
NHOST_TEST_PROJECT_ADMIN_SECRET: ${{ secrets.NHOST_TEST_PROJECT_ADMIN_SECRET }} NHOST_TEST_PROJECT_ADMIN_SECRET: '${{ secrets.NHOST_TEST_PROJECT_ADMIN_SECRET }}'
NHOST_TEST_FREE_USER_EMAILS: ${{ secrets.NHOST_TEST_FREE_USER_EMAILS }}
jobs: jobs:
build: build:
name: Build @nhost packages name: Build @nhost packages
runs-on: ubuntu-latest runs-on: blacksmith-2vcpu-ubuntu-2404
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:
@@ -73,7 +75,7 @@ jobs:
unit: unit:
name: Unit tests name: Unit tests
needs: build needs: build
runs-on: ubuntu-latest runs-on: blacksmith-2vcpu-ubuntu-2404
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
# * Install Node and dependencies. Package dependencies won't be downloaded again as they have been cached by the `build` job. # * Install Node and dependencies. Package dependencies won't be downloaded again as they have been cached by the `build` job.
@@ -98,7 +100,7 @@ jobs:
lint: lint:
name: Lint name: Lint
needs: build needs: build
runs-on: ubuntu-latest runs-on: blacksmith-2vcpu-ubuntu-2404
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
# * Install Node and dependencies. Package dependencies won't be downloaded again as they have been cached by the `build` job. # * Install Node and dependencies. Package dependencies won't be downloaded again as they have been cached by the `build` job.
@@ -125,7 +127,7 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
package: ${{ fromJson(needs.build.outputs.matrix) }} package: ${{ fromJson(needs.build.outputs.matrix) }}
runs-on: ubuntu-latest runs-on: blacksmith-2vcpu-ubuntu-2404
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
# * Install Node and dependencies. Package dependencies won't be downloaded again as they have been cached by the `build` job. # * Install Node and dependencies. Package dependencies won't be downloaded again as they have been cached by the `build` job.
@@ -170,6 +172,10 @@ jobs:
- name: Set Dashboard Preview URL - name: Set Dashboard Preview URL
if: steps.fetch-dashboard-preview-url.outputs.preview_url != '' if: steps.fetch-dashboard-preview-url.outputs.preview_url != ''
run: echo "NHOST_TEST_DASHBOARD_URL=https://${{ steps.fetch-dashboard-preview-url.outputs.preview_url }}" >> $GITHUB_ENV run: echo "NHOST_TEST_DASHBOARD_URL=https://${{ steps.fetch-dashboard-preview-url.outputs.preview_url }}" >> $GITHUB_ENV
- name: Run Onboarding Dashboard e2e tests
if: matrix.package.path == 'dashboard'
timeout-minutes: 10
run: pnpm --filter="${{ matrix.package.name }}" run e2e:onboarding
# * Run the `ci` script of the current package of the matrix. Dependencies build is cached by Turborepo # * Run the `ci` script of the current package of the matrix. Dependencies build is cached by Turborepo
- name: Run e2e tests - name: Run e2e tests
timeout-minutes: 20 timeout-minutes: 20
@@ -178,23 +184,31 @@ jobs:
- name: Run Local Dashboard e2e tests - name: Run Local Dashboard e2e tests
if: matrix.package.path == 'dashboard' if: matrix.package.path == 'dashboard'
timeout-minutes: 5 timeout-minutes: 5
run: | run: pnpm --filter="${{ matrix.package.name }}" run e2e:local
pnpm --filter="${{ matrix.package.name }}" run e2e-local
- name: Stop Nhost CLI - name: Stop Nhost CLI
if: matrix.package.path == 'dashboard' if: matrix.package.path == 'dashboard'
working-directory: ./nhost-test-project working-directory: ./nhost-test-project
run: nhost down run: nhost down
- id: file-name - name: Stop Nhost CLI for packages
if: ${{ failure() }} if: always() && (matrix.package.path == 'packages/hasura-auth-js' || matrix.package.path == 'packages/hasura-storage-js')
name: Transform package name into a valid file name working-directory: ./${{ matrix.package.path }}
run: nhost down
- name: Encrypt Playwright report
if: ${{ failure() && hashFiles('dashboard/playwright-report/**') != ''}}
run: | run: |
PACKAGE_FILE_NAME=$(echo "${{ matrix.package.name }}" | sed 's/@//g; s/\//-/g') tar -czf dashboard/playwright-report.tar.gz dashboard/playwright-report/
echo "fileName=$PACKAGE_FILE_NAME" >> $GITHUB_OUTPUT openssl enc -aes-256-cbc -salt -pbkdf2 -iter 100000 \
# * Run this step only if the previous step failed, and Playwright generated a report -in dashboard/playwright-report.tar.gz \
- name: Upload Playwright Report -out playwright-report.tar.gz.enc \
if: ${{ failure() && hashFiles(format('{0}/playwright-report/**', matrix.package.path)) != ''}} -k "${{ secrets.PLAYWRIGHT_REPORT_ENCRYPTION_KEY }}"
rm dashboard/playwright-report.tar.gz
- name: Upload encrypted Playwright report
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
if: ${{ failure() && hashFiles('dashboard/playwright-report/**') != ''}}
with: with:
name: playwright-${{ steps.file-name.outputs.fileName }} name: encrypted-playwright-report-${{ github.run_id }}
path: ${{format('{0}/playwright-report/**', matrix.package.path)}} path: playwright-report.tar.gz.enc
retention-days: 1

View File

@@ -56,3 +56,31 @@ jobs:
vercel pull --environment=production --token=${{ secrets.DASHBOARD_VERCEL_DEPLOY_TOKEN }} vercel pull --environment=production --token=${{ secrets.DASHBOARD_VERCEL_DEPLOY_TOKEN }}
vercel build --prod --token=${{ secrets.DASHBOARD_VERCEL_DEPLOY_TOKEN }} vercel build --prod --token=${{ secrets.DASHBOARD_VERCEL_DEPLOY_TOKEN }}
vercel deploy --prebuilt --prod --token=${{ secrets.DASHBOARD_VERCEL_DEPLOY_TOKEN }} vercel deploy --prebuilt --prod --token=${{ secrets.DASHBOARD_VERCEL_DEPLOY_TOKEN }}
- name: Send Discord notification (success)
if: success()
uses: tsickert/discord-webhook@v7.0.0
with:
webhook-url: ${{ secrets.DISCORD_WEBHOOK_PRODUCTION }}
embed-title: "Dashboard Deployment"
embed-description: |
**Status**: success
**Triggered by**: ${{ github.actor }}
**Inputs**:
- Git Ref: ${{ inputs.git_ref }}
embed-color: '5763719'
- name: Send Discord notification (failure)
if: failure()
uses: tsickert/discord-webhook@v7.0.0
with:
webhook-url: ${{ secrets.DISCORD_WEBHOOK_PRODUCTION }}
embed-title: "Dashboard Deployment"
embed-description: |
**Status**: failure
**Triggered by**: ${{ github.actor }}
**Inputs**:
- Git Ref: ${{ inputs.git_ref }}
embed-color: '15548997'

View File

@@ -3,13 +3,12 @@ on:
- pull_request_target - pull_request_target
jobs: jobs:
triage: labeler:
permissions: permissions:
contents: read contents: read
pull-requests: write pull-requests: write
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/labeler@v4 - uses: actions/labeler@v5
with: with:
repo-token: '${{ secrets.GH_PAT }}' repo-token: ${{ secrets.GH_PAT }}
sync-labels: ''

View File

@@ -31,7 +31,7 @@ PRs to our libraries are always welcome and can be a quick way to get your fix o
- Only fix/add the functionality in question **OR** address wide-spread whitespace/style issues, not both. - Only fix/add the functionality in question **OR** address wide-spread whitespace/style issues, not both.
- Add unit or integration tests for fixed or changed functionality (if a test suite exists). - Add unit or integration tests for fixed or changed functionality (if a test suite exists).
- Address a single concern in the least number of changed lines as possible. - Address a single concern in the least number of changed lines as possible.
- Include documentation in the repo or on our [docs site](https://docs.nhost.io/get-started). - Include documentation in the repo or on our [docs site](https://docs.nhost.io).
- Be accompanied by a complete Pull Request template (loaded automatically when a PR is created). - Be accompanied by a complete Pull Request template (loaded automatically when a PR is created).
For changes that address core functionality or require breaking changes (e.g., a major release), it's best to open an Issue to discuss your proposal first. This is not required but can save time creating and reviewing changes. For changes that address core functionality or require breaking changes (e.g., a major release), it's best to open an Issue to discuss your proposal first. This is not required but can save time creating and reviewing changes.

View File

@@ -2,9 +2,7 @@
## Requirements ## Requirements
### Node.js v18 ### Node.js v20 or later
_⚠️ Node.js v16 is also supported for the time being but support will be dropped in the near future_.
### [pnpm](https://pnpm.io/) package manager ### [pnpm](https://pnpm.io/) package manager
@@ -14,10 +12,10 @@ The easiest way to install `pnpm` if it's not installed on your machine yet is t
$ npm install -g pnpm $ npm install -g pnpm
``` ```
### [Nhost CLI](https://docs.nhost.io/cli) ### [Nhost CLI](https://docs.nhost.io/platform/cli/local-development)
- The CLI is primarily used for running the E2E tests - The CLI is primarily used for running the E2E tests
- Please refer to the [installation guide](https://docs.nhost.io/get-started/cli-workflow/install-cli) if you have not installed it yet - Please refer to the [installation guide](https://docs.nhost.io/platform/cli/local-development) if you have not installed it yet
## File Structure ## File Structure

View File

@@ -4,7 +4,7 @@
# Nhost # Nhost
<a href="https://docs.nhost.io/introduction#quick-start-guides">Quickstart</a> <a href="https://docs.nhost.io/getting-started/overview">Quickstart</a>
<span>&nbsp;&nbsp;•&nbsp;&nbsp;</span> <span>&nbsp;&nbsp;•&nbsp;&nbsp;</span>
<a href="http://nhost.io/">Website</a> <a href="http://nhost.io/">Website</a>
<span>&nbsp;&nbsp;•&nbsp;&nbsp;</span> <span>&nbsp;&nbsp;•&nbsp;&nbsp;</span>
@@ -36,7 +36,7 @@ Nhost consists of open source software:
- Authentication: [Hasura Auth](https://github.com/nhost/hasura-auth/) - Authentication: [Hasura Auth](https://github.com/nhost/hasura-auth/)
- Storage: [Hasura Storage](https://github.com/nhost/hasura-storage) - Storage: [Hasura Storage](https://github.com/nhost/hasura-storage)
- Serverless Functions: Node.js (JavaScript and TypeScript) - Serverless Functions: Node.js (JavaScript and TypeScript)
- [Nhost CLI](https://docs.nhost.io/development/cli/overview) for local development - [Nhost CLI](https://docs.nhost.io/platform/cli/local-development) for local development
## Architecture of Nhost ## Architecture of Nhost
@@ -61,9 +61,9 @@ Visit [https://docs.nhost.io](http://docs.nhost.io) for the complete documentati
Since Nhost is 100% open source, you can self-host the whole Nhost stack. Check out the example [docker-compose file](https://github.com/nhost/nhost/tree/main/examples/docker-compose) to self-host Nhost. Since Nhost is 100% open source, you can self-host the whole Nhost stack. Check out the example [docker-compose file](https://github.com/nhost/nhost/tree/main/examples/docker-compose) to self-host Nhost.
## Sign In and Make a Graphql Request ## Sign In and Make a GraphQL Request
Install the `@nhost/nhost-js` package and start build your app: Install the `@nhost/nhost-js` package and start building your app:
```jsx ```jsx
import { NhostClient } from '@nhost/nhost-js' import { NhostClient } from '@nhost/nhost-js'
@@ -89,25 +89,25 @@ await nhost.graphql.request(`{
Nhost is frontend agnostic, which means Nhost works with all frontend frameworks. Nhost is frontend agnostic, which means Nhost works with all frontend frameworks.
<div align="center"> <div align="center">
<a href="https://docs.nhost.io/guides/quickstarts/nextjs"><img src="assets/nextjs.svg"/></a> <a href="https://docs.nhost.io/getting-started/quickstart/nextjs"><img src="assets/nextjs.svg"/></a>
<a href="https://docs.nhost.io/reference/javascript"><img src="assets/nuxtjs.svg"/></a> <a href="https://docs.nhost.io/reference/javascript/nhost-js/nhost-client"><img src="assets/nuxtjs.svg"/></a>
<a href="https://docs.nhost.io/guides/quickstarts/react"><img src="assets/react.svg"/></a> <a href="https://docs.nhost.io/getting-started/quickstart/react"><img src="assets/react.svg"/></a>
<a href="https://docs.nhost.io/reference/javascript"><img src="assets/react-native.svg"/></a> <a href="https://docs.nhost.io/getting-started/quickstart/reactnative"><img src="assets/react-native.svg"/></a>
<a href="https://docs.nhost.io/reference/javascript"><img src="assets/svelte.svg"/></a> <a href="https://docs.nhost.io/reference/javascript/nhost-js/nhost-client"><img src="assets/svelte.svg"/></a>
<a href="https://docs.nhost.io/guides/quickstarts/vue"><img src="assets/vuejs.svg"/></a> <a href="https://docs.nhost.io/getting-started/quickstart/vue"><img src="assets/vuejs.svg"/></a>
</div> </div>
# Resources # Resources
- Start developing locally with the [Nhost CLI](https://docs.nhost.io/cli) - Start developing locally with the [Nhost CLI](https://docs.nhost.io/platform/cli/local-development)
## Nhost Clients ## Nhost Clients
- [JavaScript/TypeScript](https://docs.nhost.io/reference/javascript) - [JavaScript/TypeScript](https://docs.nhost.io/reference/javascript/nhost-js/nhost-client)
- [Dart and Flutter](https://github.com/nhost/nhost-dart) - [Dart and Flutter](https://github.com/nhost/nhost-dart)
- [React](https://docs.nhost.io/reference/react) - [React](https://docs.nhost.io/reference/react/nhost-client)
- [Next.js](https://docs.nhost.io/reference/nextjs) - [Next.js](https://docs.nhost.io/reference/nextjs/nhost-client)
- [Vue](https://docs.nhost.io/reference/vue) - [Vue](https://docs.nhost.io/reference/vue/nhost-client)
## Integrations ## Integrations
@@ -140,7 +140,7 @@ This repository, and most of our other open source projects, are licensed under
Here are some ways of contributing to making Nhost better: Here are some ways of contributing to making Nhost better:
- **[Try out Nhost](https://docs.nhost.io/introduction)**, and think of ways to make the service better. Let us know here on GitHub. - **[Try out Nhost](https://docs.nhost.io)**, and think of ways to make the service better. Let us know here on GitHub.
- Join our [Discord](https://discord.com/invite/9V7Qb2U) and connect with other members to share and learn from. - Join our [Discord](https://discord.com/invite/9V7Qb2U) and connect with other members to share and learn from.
- Send a pull request to any of our [open source repositories](https://github.com/nhost) on Github. Check our [contribution guide](https://github.com/nhost/nhost/blob/main/CONTRIBUTING.md) and our [developers guide](https://github.com/nhost/nhost/blob/main/DEVELOPERS.md) for more details about how to contribute. We're looking forward to your contribution! - Send a pull request to any of our [open source repositories](https://github.com/nhost) on Github. Check our [contribution guide](https://github.com/nhost/nhost/blob/main/CONTRIBUTING.md) and our [developers guide](https://github.com/nhost/nhost/blob/main/DEVELOPERS.md) for more details about how to contribute. We're looking forward to your contribution!

View File

@@ -2,5 +2,5 @@
// $schema provides code completion hints to IDEs. // $schema provides code completion hints to IDEs.
"$schema": "https://github.com/IBM/audit-ci/raw/main/docs/schema.json", "$schema": "https://github.com/IBM/audit-ci/raw/main/docs/schema.json",
"moderate": true, "moderate": true,
"allowlist": ["vue-template-compiler"] "allowlist": ["vue-template-compiler", { "id": "CVE-2025-48068", "path": "next" }]
} }

0
config/.husky/pre-commit Normal file → Executable file
View File

View File

@@ -11,20 +11,9 @@
"allowSyntheticDefaultImports": true, "allowSyntheticDefaultImports": true,
"skipLibCheck": true, "skipLibCheck": true,
"moduleResolution": "node", "moduleResolution": "node",
"target": "ES6", "target": "ESNext",
"module": "CommonJS", "module": "CommonJS",
"lib": [ "lib": ["ES2022", "DOM", "DOM.Iterable"],
"es5",
"dom",
"es2015.promise",
"es2015.symbol",
"es2015.iterable",
"es2015.collection",
"es2015.symbol.wellknown",
"es2015.core",
"es2017.object",
"es2017.string"
],
"resolveJsonModule": true, "resolveJsonModule": true,
"esModuleInterop": true, "esModuleInterop": true,
"sourceMap": true, "sourceMap": true,
@@ -79,4 +68,4 @@
"**/*/__tests__", "**/*/__tests__",
"**/*/__mocks__" "**/*/__mocks__"
] ]
} }

View File

@@ -25,4 +25,6 @@ NEXT_PUBLIC_ZENDESK_USER_EMAIL=
CODEGEN_GRAPHQL_URL=https://local.graphql.local.nhost.run/v1 CODEGEN_GRAPHQL_URL=https://local.graphql.local.nhost.run/v1
CODEGEN_HASURA_ADMIN_SECRET=nhost-admin-secret CODEGEN_HASURA_ADMIN_SECRET=nhost-admin-secret
NEXT_PUBLIC_TURNSTILE_SITE_KEY=FIXME NEXT_PUBLIC_TURNSTILE_SITE_KEY=FIXME
NEXT_PUBLIC_SOC2_REPORT_FILE_ID=

View File

@@ -76,6 +76,13 @@ module.exports = {
], ],
}, },
], ],
'jsx-a11y/label-has-associated-control': [
2,
{
controlComponents: ['Input'],
depth: 3,
},
],
}, },
overrides: [ overrides: [
{ {

View File

@@ -1,8 +1,9 @@
import { NhostProvider } from '@/providers/nhost';
import '@fontsource/inter'; import '@fontsource/inter';
import '@fontsource/inter/500.css'; import '@fontsource/inter/500.css';
import '@fontsource/inter/700.css'; import '@fontsource/inter/700.css';
import { CssBaseline, ThemeProvider } from '@mui/material'; import { CssBaseline, ThemeProvider } from '@mui/material';
import { NhostClient, NhostProvider } from '@nhost/nextjs'; import { createClient } from '@nhost/nhost-js-beta';
import { NhostApolloProvider } from '@nhost/react-apollo'; import { NhostApolloProvider } from '@nhost/react-apollo';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { Buffer } from 'buffer'; import { Buffer } from 'buffer';
@@ -58,7 +59,9 @@ export const decorators = [
</NhostApolloProvider> </NhostApolloProvider>
), ),
(Story) => ( (Story) => (
<NhostProvider nhost={new NhostClient({ subdomain: 'local' })}> <NhostProvider
nhost={createClient({ subdomain: 'local', region: 'local' })}
>
<Story /> <Story />
</NhostProvider> </NhostProvider>
), ),

View File

@@ -1,5 +1,178 @@
# @nhost/dashboard # @nhost/dashboard
## 2.36.0
### Minor Changes
- a30da08: feat (dashboard): add custom types to column types
### Patch Changes
- 73a7ba8: fix (dashboard): Show errors in row permission rule form
- 397bfc9: fix (dashboard): Parse foreign key relations correctly
- 2f4b376: fix (dashboard): allow permission variables with in operator
- 88836f3: fix (dashboard): use correct fallback endpoint for migration in the CLI
- ba3c49e: fix (dashboard): Show nested relationships in row permissions
- 92e71a6: fix: minor fixes to csp
- 81716d9: fix (dashboard): Show validation error on save when editing database columns
## 2.35.0
### Minor Changes
- 7633d04: feat (dashbord): Allow composite primary keys
- c4f383f: fix: dashboard: don't allow for upgrading to starter
- 4c6400f: fix: handle redirect to verify email page if sign in with github
- 7f0db21: feat: added entraid support
- 412692c: chore (dashboard): Turn on strictNullChecks config
### Patch Changes
- 1708578: fix (dashboard): Update navbar after org and project operations
- 34ede5c: fix: enable csp again
- 96228df: chore (dashboard): update nhost-js to the latest version
- d8c5117: fix (dashboard): Allow creating tables without primary key
- 89f6fe6: chore (docker-example): update dashboard image version
- e8a3789: fix (dashboard): scroll to active element in navbar when navigating
## 2.34.0
### Minor Changes
- 7eb9539: feat (dashboard): Allow upgrading free organizations
- 129ec1e: feat: dashboard: new onboarding
- 59249e5: fix: elevate permissions in password reset
- 5e9ddb4: fix: show Run service name in logs page
- 4ffff86: fix (dashboard): Disable settings pages when config server env variable is not set
- b8cb491: fix: update dependencies to fix vulnerabilities
- 5565451: fix: support page, can scroll all the way down in Chrome for iOS
- f7d7080: chore: dashboard: add gtag
### Patch Changes
- 181c0ab: fix (dashboard): Fix upgrade project e2e tests
- 56c87da: fix (dashboard): Use the correct http method when conneting to new github
- 00132bd: fix (dashboard): Clear isSigningOut variable on Signin page
- 66e0cc8: fix (dashboard): Check if user is logged in before redirecting
- 9c0a118: chore (dashboard): Add RetryLink to ApolloClient
- df6b85e: fix (dashboard): fix password reset redirect url
- ec24567: fix (dashboard): Add content-type header
- 57b2615: chore (dashboard): refactor redirect behaviour
- cffa161: fix (dashboard): disable settings in the header when self-hosting
- 85316e8: fix (dashboard): Remove second loading indicator on projects page
- 47ab341: fix (dashboard): Fix announcement layout when title is too short
## 2.33.0
### Minor Changes
- aee9a80: chore: update typescript version to the latest
- 5ef3f76: chore (dashboard): Use the new SDK in the Dashboard
### Patch Changes
- 9ed8ce8: fix (dashboard): Request new Mfa ticket after an invalid totp when signing in
- fd3b5c7: fix (dashboard): Limit new project's name to a maximum of 32 charachters in E2E tests
## 2.32.0
### Minor Changes
- 736862c: fix: update link to base directory docs in git settings
- ea99fb3: chore: dashboard: improve messaging when git connected
### Patch Changes
- d738884: chore (dashboard): Add link about antivirus integration
## 2.31.0
### Minor Changes
- 39b10a2: feat (dashboard): Add multi-factor authentication
- 4b84780: feat (dashboard): Add Webauthn to dashboard
### Patch Changes
- 61eb6cd: fix (dashboard): Fix update project e2e test
- @nhost/react-apollo@18.0.0
- @nhost/nextjs@2.2.8
## 2.30.0
### Minor Changes
- f6947a2: fix: fetch job-backup services logs using Live filter
- 44a3e6b: fix: collapsed main navigation sidebar overlaps mobile navbar
- 99b78f1: feat: dashboard: add download button for soc2 report
- 9acae7d: fix: e2e tests, stop on error when refreshing metadata
### Patch Changes
- 31e636a: fix (dashboard): Use the correct payload to reset metadata before the e2e tests
## 2.29.0
### Minor Changes
- c97b43f: fix: update vite to address vulnerability audit
- a0931e2: fix: improve logs time range and filter selection
- c0635ae: feat (dashboard): Add information about that free organization cannot be upgraded.
- e87505c: fix: can downsize postgres storage capacity using local dashboard
## 2.28.0
### Minor Changes
- 8552678: feat: dashboard: add additional events to segment
- 0bf2808: chore: refresh metadata before end-to-end tests
- 72a365c: fix: correct graphql page roles dropdown's source
- cef6471: fix: dashboard: add anonid to user's metadata
### Patch Changes
- d9eb906: fix: update vite and nextjs because of vulnerability
- 233232b: feat (dashboard): improve Upgrade project dialog
- Updated dependencies [d9eb906]
- @nhost/nextjs@2.2.7
- @nhost/react-apollo@17.0.4
## 2.27.0
### Minor Changes
- 013e1c1: fix: update vite and image-size dependencies to address security audit vulnerabilities
- 4fd176b: chore: re-add user event ci tests, updated sveltekit example tests to e2e suite
### Patch Changes
- a1333df: fix: update vite because of vulnerability
- 0420e4f: fix (dashboard): Display the selected date's month in the datetime picker component
- @nhost/react-apollo@17.0.3
- @nhost/nextjs@2.2.6
## 2.26.0
### Minor Changes
- 7b9cdf1: chore: remove legacy workspaces
- 1c4f321: fix: update vite to fix audit vulnerabilities
## 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 ## 2.17.0
### Minor Changes ### Minor Changes

View File

@@ -38,7 +38,7 @@ These files are added to `.gitignore`, so you don't need to worry about committi
### Enable Local Development ### Enable Local Development
You can connect the Nhost Dashboard to your **locally running** Nhost backend in a few steps. Make sure you have the [Nhost CLI installed](https://docs.nhost.io/platform/cli#installation). You can connect the Nhost Dashboard to your **locally running** Nhost backend in a few steps. Make sure you have the [Nhost CLI installed](https://docs.nhost.io/platform/cli/local-development).
First, you need to run the following command to start your backend locally: First, you need to run the following command to start your backend locally:
@@ -149,8 +149,11 @@ Next, you need to create a project. Create a `.env.test` file with the following
NHOST_TEST_DASHBOARD_URL=<test_dashboard_url> NHOST_TEST_DASHBOARD_URL=<test_dashboard_url>
NHOST_TEST_USER_EMAIL=<test_user_email> NHOST_TEST_USER_EMAIL=<test_user_email>
NHOST_TEST_USER_PASSWORD=<test_user_password> NHOST_TEST_USER_PASSWORD=<test_user_password>
NHOST_TEST_WORKSPACE_NAME=<test_workspace_name> NHOST_TEST_ORGANIZATION_NAME=<test_organization_name>
NHOST_TEST_ORGANIZATION_SLUG=<test_organization_slug>
NHOST_TEST_PERSONAL_ORG_SLUG=<test_personal_org_slug>
NHOST_TEST_PROJECT_NAME=<test_project_name> NHOST_TEST_PROJECT_NAME=<test_project_name>
NHOST_TEST_PROJECT_SUBDOMAIN=<test_project_subdomain>
NHOST_TEST_PROJECT_ADMIN_SECRET=<test_project_admin_secret> NHOST_TEST_PROJECT_ADMIN_SECRET=<test_project_admin_secret>
``` ```
@@ -159,11 +162,14 @@ NHOST_TEST_PROJECT_ADMIN_SECRET=<test_project_admin_secret>
- `NHOST_TEST_DASHBOARD_URL`: The URL to run the tests against (e.g: http://localhost:3000 or https://staging.app.nhost.io) - `NHOST_TEST_DASHBOARD_URL`: The URL to run the tests against (e.g: http://localhost:3000 or https://staging.app.nhost.io)
- `NHOST_TEST_USER_EMAIL`: Email address of the test user that owns the test project - `NHOST_TEST_USER_EMAIL`: Email address of the test user that owns the test project
- `NHOST_TEST_USER_PASSWORD`: Password of the test user that owns the test project - `NHOST_TEST_USER_PASSWORD`: Password of the test user that owns the test project
- `NHOST_TEST_WORKSPACE_NAME`: Name of the workspace that contains the test project - `NHOST_TEST_ORGANIZATION_NAME`: Name of the organization that contains the test project
- `NHOST_TEST_ORGANIZATION_SLUG`: Slug of the organization that contains the test project
- `NHOST_TEST_PERSONAL_ORG_SLUG`: Slug of the personal organization that contains the test project
- `NHOST_TEST_PROJECT_NAME`: Name of the test project - `NHOST_TEST_PROJECT_NAME`: Name of the test project
- `NHOST_TEST_PROJECT_SUBDOMAIN`: Subdomain of the test project
- `NHOST_TEST_PROJECT_ADMIN_SECRET`: Admin secret of the test project - `NHOST_TEST_PROJECT_ADMIN_SECRET`: Admin secret of the test project
Make sure to copy the workspace and project information from the [Nhost Dashboard](https://app.nhost.io/). Make sure to copy the organization and project information from the [Nhost Dashboard](https://app.nhost.io/).
End-to-end tests are written using [Playwright](https://playwright.dev/). To run the tests, run the following command: End-to-end tests are written using [Playwright](https://playwright.dev/). To run the tests, run the following command:

View File

@@ -21,6 +21,6 @@ find dashboard -type f -exec sed -i "s~__NEXT_PUBLIC_NHOST_STORAGE_URL__~${NEXT_
find dashboard -type f -exec sed -i "s~__NEXT_PUBLIC_NHOST_HASURA_CONSOLE_URL__~${NEXT_PUBLIC_NHOST_HASURA_CONSOLE_URL}~g" {} + find dashboard -type f -exec sed -i "s~__NEXT_PUBLIC_NHOST_HASURA_CONSOLE_URL__~${NEXT_PUBLIC_NHOST_HASURA_CONSOLE_URL}~g" {} +
find dashboard -type f -exec sed -i "s~__NEXT_PUBLIC_NHOST_HASURA_MIGRATIONS_API_URL__~${NEXT_PUBLIC_NHOST_HASURA_MIGRATIONS_API_URL}~g" {} + find dashboard -type f -exec sed -i "s~__NEXT_PUBLIC_NHOST_HASURA_MIGRATIONS_API_URL__~${NEXT_PUBLIC_NHOST_HASURA_MIGRATIONS_API_URL}~g" {} +
find dashboard -type f -exec sed -i "s~__NEXT_PUBLIC_NHOST_HASURA_API_URL__~${NEXT_PUBLIC_NHOST_HASURA_API_URL}~g" {} + find dashboard -type f -exec sed -i "s~__NEXT_PUBLIC_NHOST_HASURA_API_URL__~${NEXT_PUBLIC_NHOST_HASURA_API_URL}~g" {} +
find dashboard -type f -exec sed -i "s~__NEXT_PUBLIC_NHOST_CONFIGSERVER_URL__~${NEXT_PUBLIC_NHOST_CONFIGSERVER_URL}~g" {} + find dashboard -type f -exec sed -i "s~__NEXT_PUBLIC_NHOST_CONFIGSERVER_URL__~${NEXT_PUBLIC_NHOST_CONFIGSERVER_URL:-""}~g" {} +
exec "$@" exec "$@"

View File

@@ -1,22 +1,10 @@
import { expect, test } from '@/e2e/fixtures/auth-hook';
import { faker } from '@faker-js/faker'; import { faker } from '@faker-js/faker';
import type { Page } from '@playwright/test';
import { expect, test } from '@playwright/test';
let page: Page; test('should be able to create then delete a personal access token', async ({
authenticatedNhostPage: 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 () => {
await page.waitForTimeout(1000); await page.waitForTimeout(1000);
await page.getByRole('banner').getByRole('button').last().click(); await page.getByRole('banner').getByRole('button').last().click();
await page.getByRole('link', { name: /account settings/i }).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 { TEST_ORGANIZATION_SLUG, TEST_PROJECT_SUBDOMAIN } from '@/e2e/env';
import { expect, test } from '@/e2e/fixtures/auth-hook';
import { navigateToProject } from '@/e2e/utils'; 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({ await navigateToProject({
page, page,
orgSlug: TEST_ORGANIZATION_SLUG, orgSlug: TEST_ORGANIZATION_SLUG,
@@ -23,11 +14,9 @@ test.beforeEach(async () => {
await page.waitForURL(AIRoute); await page.waitForURL(AIRoute);
}); });
test.afterAll(async () => { test('should create and delete an Assistant', async ({
await page.close(); authenticatedNhostPage: page,
}); }) => {
test('should create and delete an Assistant', async () => {
await page.getByRole('link', { name: 'Assistants' }).click(); await page.getByRole('link', { name: 'Assistants' }).click();
await expect(page.getByText(/no assistants are configured/i)).toBeVisible(); 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 { TEST_ORGANIZATION_SLUG, TEST_PROJECT_SUBDOMAIN } from '@/e2e/env';
import { navigateToProject } from '@/e2e/utils'; import { navigateToProject } from '@/e2e/utils';
import type { Page } from '@playwright/test';
import { expect, test } 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 () => {
await page.goto('/');
test.beforeEach(async ({ authenticatedNhostPage: page }) => {
await navigateToProject({ await navigateToProject({
page, page,
orgSlug: TEST_ORGANIZATION_SLUG, orgSlug: TEST_ORGANIZATION_SLUG,
@@ -23,11 +15,9 @@ test.beforeEach(async () => {
await page.waitForURL(AIRoute); await page.waitForURL(AIRoute);
}); });
test.afterAll(async () => { test('should create and delete an Auto-Embeddings', async ({
await page.close(); authenticatedNhostPage: page,
}); }) => {
test('should create and delete an Auto-Embeddings', async () => {
await page.getByRole('button', { name: 'Add a new Auto-Embeddings' }).click(); await page.getByRole('button', { name: 'Add a new Auto-Embeddings' }).click();
await page.getByLabel('Name').fill('test'); await page.getByLabel('Name').fill('test');

View File

@@ -1,17 +1,21 @@
import { TEST_ORGANIZATION_SLUG, TEST_PROJECT_SUBDOMAIN } from '@/e2e/env'; import { expect, test } from '@/e2e/fixtures/auth-hook';
import { createUser, generateTestEmail } from '@/e2e/utils'; import { createUser, generateTestEmail, gotoAuthURL } from '@/e2e/utils';
import { faker } from '@faker-js/faker'; import { faker } from '@faker-js/faker';
import test, { expect } from '@playwright/test';
test('should be able to ban and unban a user', async ({ page }) => { test.beforeEach(async ({ authenticatedNhostPage: page }) => {
const authUrl = `/orgs/${TEST_ORGANIZATION_SLUG}/projects/${TEST_PROJECT_SUBDOMAIN}/users`; await gotoAuthURL(page);
await page.goto(authUrl); });
await page.waitForURL(authUrl, { waitUntil: 'networkidle' });
test('should be able to ban and unban a user', async ({
authenticatedNhostPage: page,
}) => {
const email = generateTestEmail(); const email = generateTestEmail();
const password = faker.internet.password(); const password = faker.internet.password();
await createUser({ page, email, password }); await createUser({ page, email, password });
await page.waitForSelector(
'div:has-text("User has been created successfully.")',
);
await page await page
.getByRole('button', { name: `View ${email}`, exact: true }) .getByRole('button', { name: `View ${email}`, exact: true })

View File

@@ -1,37 +1,28 @@
import { TEST_ORGANIZATION_SLUG, TEST_PROJECT_SUBDOMAIN } from '@/e2e/env'; import { expect, test } from '@/e2e/fixtures/auth-hook';
import { createUser, generateTestEmail } from '@/e2e/utils'; import { createUser, generateTestEmail, gotoAuthURL } from '@/e2e/utils';
import { faker } from '@faker-js/faker'; import { faker } from '@faker-js/faker';
import type { Page } from '@playwright/test';
import test, { expect } from '@playwright/test';
let page: Page; test.beforeEach(async ({ authenticatedNhostPage: page }) => {
await gotoAuthURL(page);
test.beforeAll(async ({ browser }) => {
page = await browser.newPage();
}); });
test.beforeEach(async () => { test('should create a user', async ({ authenticatedNhostPage: page }) => {
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 () => {
const email = generateTestEmail(); const email = generateTestEmail();
const password = faker.internet.password(); const password = faker.internet.password();
await createUser({ page, email, password }); await createUser({ page, email, password });
await page.waitForSelector(
'div:has-text("User has been created successfully.")',
);
await expect( await expect(
page.getByRole('button', { name: `View ${email}`, exact: true }), page.getByRole('button', { name: `View ${email}`, exact: true }),
).toBeVisible(); ).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 email = generateTestEmail();
const password = faker.internet.password(); const password = faker.internet.password();

View File

@@ -1,30 +1,22 @@
import { TEST_ORGANIZATION_SLUG, TEST_PROJECT_SUBDOMAIN } from '@/e2e/env'; import { createUser, generateTestEmail, gotoAuthURL } from '@/e2e/utils';
import { createUser, generateTestEmail } from '@/e2e/utils';
import { faker } from '@faker-js/faker'; 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 }) => { test.beforeEach(async ({ authenticatedNhostPage: page }) => {
page = await browser.newPage(); await gotoAuthURL(page);
}); });
test.beforeEach(async () => { test('should be able to delete a user', async ({
const authUrl = `/orgs/${TEST_ORGANIZATION_SLUG}/projects/${TEST_PROJECT_SUBDOMAIN}/users`; authenticatedNhostPage: page,
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 () => {
const email = generateTestEmail(); const email = generateTestEmail();
const password = faker.internet.password(); const password = faker.internet.password();
await createUser({ page, email, password }); await createUser({ page, email, password });
await page.waitForSelector(
'div:has-text("User has been created successfully.")',
);
await expect( await expect(
page.getByRole('button', { name: `View ${email}`, exact: true }), page.getByRole('button', { name: `View ${email}`, exact: true }),
@@ -50,14 +42,21 @@ test('should be able to delete a user', async () => {
await expect( await expect(
page.getByRole('button', { name: `View ${email}`, exact: true }), page.getByRole('button', { name: `View ${email}`, exact: true }),
).not.toBeVisible(); ).not.toBeVisible();
await expect(page.getByText('User deleted successfully.')).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 email = generateTestEmail();
const password = faker.internet.password(); const password = faker.internet.password();
await createUser({ page, email, password }); await createUser({ page, email, password });
await page.waitForSelector(
'div:has-text("User has been created successfully.")',
);
await page await page
.getByRole('button', { name: `View ${email}`, exact: true }) .getByRole('button', { name: `View ${email}`, exact: true })
.click(); .click();
@@ -77,4 +76,5 @@ test('should be able to delete a user from the details page', async () => {
await expect( await expect(
page.getByRole('button', { name: `View ${email}`, exact: true }), page.getByRole('button', { name: `View ${email}`, exact: true }),
).not.toBeVisible(); ).not.toBeVisible();
await expect(page.getByText('User deleted successfully.')).toBeVisible();
}); });

View File

@@ -1,30 +1,21 @@
import { TEST_ORGANIZATION_SLUG, TEST_PROJECT_SUBDOMAIN } from '@/e2e/env'; import { expect, test } from '@/e2e/fixtures/auth-hook';
import { createUser, generateTestEmail } from '@/e2e/utils'; import { createUser, generateTestEmail, gotoAuthURL } from '@/e2e/utils';
import { faker } from '@faker-js/faker'; import { faker } from '@faker-js/faker';
import type { Page } from '@playwright/test';
import test, { expect } from '@playwright/test';
let page: Page; test.beforeEach(async ({ authenticatedNhostPage: page }) => {
await gotoAuthURL(page);
test.beforeAll(async ({ browser }) => {
page = await browser.newPage();
}); });
test.beforeEach(async () => { test('should be able to edit user roles from the details page', async ({
const authUrl = `/orgs/${TEST_ORGANIZATION_SLUG}/projects/${TEST_PROJECT_SUBDOMAIN}/users`; authenticatedNhostPage: page,
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 () => {
const email = generateTestEmail(); const email = generateTestEmail();
const password = faker.internet.password(); const password = faker.internet.password();
await createUser({ page, email, password }); await createUser({ page, email, password });
await page.waitForSelector(
'div:has-text("User has been created successfully.")',
);
await page await page
.getByRole('button', { name: `View ${email}`, exact: true }) .getByRole('button', { name: `View ${email}`, exact: true })

View File

@@ -1,31 +1,23 @@
import { TEST_ORGANIZATION_SLUG, TEST_PROJECT_SUBDOMAIN } from '@/e2e/env'; import { expect, test } from '@/e2e/fixtures/auth-hook';
import { createUser, generateTestEmail } from '@/e2e/utils'; import { createUser, generateTestEmail, gotoAuthURL } from '@/e2e/utils';
import { faker } from '@faker-js/faker'; import { faker } from '@faker-js/faker';
import type { Page } from '@playwright/test';
import { expect, test } from '@playwright/test';
let page: Page; test.beforeEach(async ({ authenticatedNhostPage: page }) => {
await gotoAuthURL(page);
test.beforeAll(async ({ browser }) => {
page = await browser.newPage();
}); });
test.beforeEach(async () => { test('should be able to verify the email of a user', async ({
const authUrl = `/orgs/${TEST_ORGANIZATION_SLUG}/projects/${TEST_PROJECT_SUBDOMAIN}/users`; authenticatedNhostPage: page,
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 () => {
const email = generateTestEmail(); const email = generateTestEmail();
const password = faker.internet.password(); const password = faker.internet.password();
await createUser({ page, email, password }); await createUser({ page, email, password });
await page.waitForSelector(
'div:has-text("User has been created successfully.")',
);
await page await page
.getByRole('button', { name: `View ${email}`, exact: true }) .getByRole('button', { name: `View ${email}`, exact: true })
.click(); .click();
@@ -50,7 +42,9 @@ test('should be able to verify the email of a user', async () => {
).toBeChecked(); ).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 email = generateTestEmail();
const password = faker.internet.password(); const password = faker.internet.password();
const phoneNumber = faker.phone.number(); const phoneNumber = faker.phone.number();

View File

@@ -1,35 +1,18 @@
import { TEST_ORGANIZATION_SLUG, TEST_PROJECT_SUBDOMAIN } from '@/e2e/env'; 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 { faker } from '@faker-js/faker';
import type { Page } from '@playwright/test';
import { expect, test } from '@playwright/test';
import { snakeCase } from 'snake-case'; import { snakeCase } from 'snake-case';
let page: Page; test.beforeEach(async ({ authenticatedNhostPage: 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,
});
const databaseRoute = `/orgs/${TEST_ORGANIZATION_SLUG}/projects/${TEST_PROJECT_SUBDOMAIN}/database/browser/default`; const databaseRoute = `/orgs/${TEST_ORGANIZATION_SLUG}/projects/${TEST_PROJECT_SUBDOMAIN}/database/browser/default`;
await page.goto(databaseRoute); await page.goto(databaseRoute);
await page.waitForURL(databaseRoute); await page.waitForURL(databaseRoute);
}); });
test.afterAll(async () => { test('should create a simple table', async ({
await page.close(); authenticatedNhostPage: page,
}); }) => {
test('should create a simple table', async () => {
await page.getByRole('button', { name: /new table/i }).click(); await page.getByRole('button', { name: /new table/i }).click();
await expect(page.getByText(/create a new table/i)).toBeVisible(); await expect(page.getByText(/create a new table/i)).toBeVisible();
@@ -38,7 +21,7 @@ test('should create a simple table', async () => {
await prepareTable({ await prepareTable({
page, page,
name: tableName, name: tableName,
primaryKey: 'id', primaryKeys: ['id'],
columns: [ columns: [
{ name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' }, { name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'title', type: 'text' }, { name: 'title', type: 'text' },
@@ -57,7 +40,9 @@ test('should create a simple table', async () => {
).toBeVisible(); ).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 page.getByRole('button', { name: /new table/i }).click();
await expect(page.getByText(/create a new table/i)).toBeVisible(); await expect(page.getByText(/create a new table/i)).toBeVisible();
@@ -66,7 +51,7 @@ test('should create a table with unique constraints', async () => {
await prepareTable({ await prepareTable({
page, page,
name: tableName, name: tableName,
primaryKey: 'id', primaryKeys: ['id'],
columns: [ columns: [
{ name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' }, { name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'title', type: 'text', unique: true }, { name: 'title', type: 'text', unique: true },
@@ -86,7 +71,9 @@ test('should create a table with unique constraints', async () => {
).toBeVisible(); ).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 page.getByRole('button', { name: /new table/i }).click();
await expect(page.getByText(/create a new table/i)).toBeVisible(); await expect(page.getByText(/create a new table/i)).toBeVisible();
@@ -95,7 +82,7 @@ test('should create a table with nullable columns', async () => {
await prepareTable({ await prepareTable({
page, page,
name: tableName, name: tableName,
primaryKey: 'id', primaryKeys: ['id'],
columns: [ columns: [
{ name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' }, { name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'title', type: 'text', nullable: true }, { name: 'title', type: 'text', nullable: true },
@@ -115,7 +102,9 @@ test('should create a table with nullable columns', async () => {
).toBeVisible(); ).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 page.getByRole('button', { name: /new table/i }).click();
await expect(page.getByText(/create a new table/i)).toBeVisible(); await expect(page.getByText(/create a new table/i)).toBeVisible();
@@ -124,7 +113,7 @@ test('should create a table with an identity column', async () => {
await prepareTable({ await prepareTable({
page, page,
name: tableName, name: tableName,
primaryKey: 'id', primaryKeys: ['id'],
columns: [ columns: [
{ name: 'id', type: 'int4' }, { name: 'id', type: 'int4' },
{ name: 'title', type: 'text', nullable: true }, { name: 'title', type: 'text', nullable: true },
@@ -148,7 +137,9 @@ test('should create a table with an identity column', async () => {
).toBeVisible(); ).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 page.getByRole('button', { name: /new table/i }).click();
await expect(page.getByText(/create a new table/i)).toBeVisible(); await expect(page.getByText(/create a new table/i)).toBeVisible();
@@ -157,7 +148,7 @@ test('should create table with foreign key constraint', async () => {
await prepareTable({ await prepareTable({
page, page,
name: firstTableName, name: firstTableName,
primaryKey: 'id', primaryKeys: ['id'],
columns: [ columns: [
{ name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' }, { name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'name', type: 'text' }, { name: 'name', type: 'text' },
@@ -179,7 +170,7 @@ test('should create table with foreign key constraint', async () => {
await prepareTable({ await prepareTable({
page, page,
name: secondTableName, name: secondTableName,
primaryKey: 'id', primaryKeys: ['id'],
columns: [ columns: [
{ name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' }, { name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'title', type: 'text' }, { name: 'title', type: 'text' },
@@ -205,6 +196,10 @@ test('should create table with foreign key constraint', async () => {
await page.getByRole('button', { name: /add/i }).click(); await page.getByRole('button', { name: /add/i }).click();
await expect(
page.getByTestId('foreignKeyFormSubmitButton'),
).not.toBeVisible();
await expect( await expect(
page.getByText(`public.${firstTableName}.id`, { exact: true }), page.getByText(`public.${firstTableName}.id`, { exact: true }),
).toBeVisible(); ).toBeVisible();
@@ -221,7 +216,9 @@ test('should create table with foreign key constraint', async () => {
).toBeVisible(); ).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 page.getByRole('button', { name: /new table/i }).click();
await expect(page.getByText(/create a new table/i)).toBeVisible(); await expect(page.getByText(/create a new table/i)).toBeVisible();
@@ -230,7 +227,7 @@ test('should not be able to create a table with a name that already exists', asy
await prepareTable({ await prepareTable({
page, page,
name: tableName, name: tableName,
primaryKey: 'id', primaryKeys: ['id'],
columns: [ columns: [
{ name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' }, { name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'name', type: 'text' }, { name: 'name', type: 'text' },
@@ -250,7 +247,7 @@ test('should not be able to create a table with a name that already exists', asy
await prepareTable({ await prepareTable({
page, page,
name: tableName, name: tableName,
primaryKey: 'id', primaryKeys: ['id'],
columns: [ columns: [
{ name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' }, { name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'title', type: 'text' }, { name: 'title', type: 'text' },
@@ -265,3 +262,33 @@ test('should not be able to create a table with a name that already exists', asy
page.getByText(/error: a table with this name already exists/i), page.getByText(/error: a table with this name already exists/i),
).toBeVisible(); ).toBeVisible();
}); });
test('should be able to create a table with a composite key', async ({
authenticatedNhostPage: page,
}) => {
await page.getByRole('button', { name: /new table/i }).click();
await expect(page.getByText(/create a new table/i)).toBeVisible();
const tableName = snakeCase(faker.lorem.words(3));
await prepareTable({
page,
name: tableName,
primaryKeys: ['id', 'second_id'],
columns: [
{ name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'second_id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'name', type: 'text' },
],
});
await page.getByRole('button', { name: /create/i }).click();
await page.waitForURL(
`/orgs/${TEST_ORGANIZATION_SLUG}/projects/${TEST_PROJECT_SUBDOMAIN}/database/browser/default/public/${tableName}`,
);
await expect(
page.getByRole('link', { name: tableName, exact: true }),
).toBeVisible();
});

View File

@@ -1,35 +1,17 @@
import { TEST_ORGANIZATION_SLUG, TEST_PROJECT_SUBDOMAIN } from '@/e2e/env'; 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 { 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'; import { snakeCase } from 'snake-case';
let page: Page; test.beforeEach(async ({ authenticatedNhostPage: 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,
});
const databaseRoute = `/orgs/${TEST_ORGANIZATION_SLUG}/projects/${TEST_PROJECT_SUBDOMAIN}/database/browser/default`; const databaseRoute = `/orgs/${TEST_ORGANIZATION_SLUG}/projects/${TEST_PROJECT_SUBDOMAIN}/database/browser/default`;
await page.goto(databaseRoute); await page.goto(databaseRoute);
await page.waitForURL(databaseRoute); await page.waitForURL(databaseRoute);
}); });
test.afterAll(async () => { test('should delete a table', async ({ authenticatedNhostPage: page }) => {
await page.close();
});
test('should delete a table', async () => {
const tableName = snakeCase(faker.lorem.words(3)); const tableName = snakeCase(faker.lorem.words(3));
await page.getByRole('button', { name: /new table/i }).click(); await page.getByRole('button', { name: /new table/i }).click();
@@ -37,7 +19,7 @@ test('should delete a table', async () => {
await prepareTable({ await prepareTable({
page, page,
name: tableName, name: tableName,
primaryKey: 'id', primaryKeys: ['id'],
columns: [ columns: [
{ name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' }, { name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'title', type: 'text' }, { name: 'title', type: 'text' },
@@ -65,7 +47,9 @@ test('should delete a table', async () => {
).not.toBeVisible(); ).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); test.setTimeout(60000);
await page.getByRole('button', { name: /new table/i }).click(); await page.getByRole('button', { name: /new table/i }).click();
await expect(page.getByText(/create a new table/i)).toBeVisible(); await expect(page.getByText(/create a new table/i)).toBeVisible();
@@ -75,7 +59,7 @@ test('should not be able to delete a table if other tables have foreign keys ref
await prepareTable({ await prepareTable({
page, page,
name: firstTableName, name: firstTableName,
primaryKey: 'id', primaryKeys: ['id'],
columns: [ columns: [
{ name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' }, { name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'name', type: 'text' }, { name: 'name', type: 'text' },
@@ -97,7 +81,7 @@ test('should not be able to delete a table if other tables have foreign keys ref
await prepareTable({ await prepareTable({
page, page,
name: secondTableName, name: secondTableName,
primaryKey: 'id', primaryKeys: ['id'],
columns: [ columns: [
{ name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' }, { name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'title', type: 'text' }, { name: 'title', type: 'text' },

View File

@@ -1,39 +1,18 @@
import { TEST_ORGANIZATION_SLUG, TEST_PROJECT_SUBDOMAIN } from '@/e2e/env'; import { TEST_ORGANIZATION_SLUG, TEST_PROJECT_SUBDOMAIN } from '@/e2e/env';
import { import { expect, test } from '@/e2e/fixtures/auth-hook';
clickPermissionButton, import { clickPermissionButton, prepareTable } from '@/e2e/utils';
navigateToProject,
prepareTable,
} from '@/e2e/utils';
import { faker } from '@faker-js/faker'; import { faker } from '@faker-js/faker';
import type { Page } from '@playwright/test';
import { expect, test } from '@playwright/test';
import { snakeCase } from 'snake-case'; import { snakeCase } from 'snake-case';
let page: Page; test.beforeEach(async ({ authenticatedNhostPage: 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,
});
const databaseRoute = `/orgs/${TEST_ORGANIZATION_SLUG}/projects/${TEST_PROJECT_SUBDOMAIN}/database/browser/default`; const databaseRoute = `/orgs/${TEST_ORGANIZATION_SLUG}/projects/${TEST_PROJECT_SUBDOMAIN}/database/browser/default`;
await page.goto(databaseRoute); await page.goto(databaseRoute);
await page.waitForURL(databaseRoute); await page.waitForURL(databaseRoute);
}); });
test.afterAll(async () => { test('should create a table with role permissions to select row', async ({
await page.close(); authenticatedNhostPage: page,
}); }) => {
test('should create a table with role permissions to select row', async () => {
await page.getByRole('button', { name: /new table/i }).click(); await page.getByRole('button', { name: /new table/i }).click();
await expect(page.getByText(/create a new table/i)).toBeVisible(); await expect(page.getByText(/create a new table/i)).toBeVisible();
@@ -42,7 +21,7 @@ test('should create a table with role permissions to select row', async () => {
await prepareTable({ await prepareTable({
page, page,
name: tableName, name: tableName,
primaryKey: 'id', primaryKeys: ['id'],
columns: [ columns: [
{ name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' }, { name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'title', type: 'text' }, { name: 'title', type: 'text' },
@@ -79,7 +58,9 @@ test('should create a table with role permissions to select row', async () => {
).toBeVisible(); ).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 page.getByRole('button', { name: /new table/i }).click();
await expect(page.getByText(/create a new table/i)).toBeVisible(); await expect(page.getByText(/create a new table/i)).toBeVisible();
@@ -88,7 +69,7 @@ test('should create a table with role permissions and a custom check to select r
await prepareTable({ await prepareTable({
page, page,
name: tableName, name: tableName,
primaryKey: 'id', primaryKeys: ['id'],
columns: [ columns: [
{ name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' }, { name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'title', type: 'text' }, { name: 'title', type: 'text' },

View File

@@ -1,42 +1,46 @@
/** /**
* URL of the dashboard to test against. * URL of the dashboard to test against.
*/ */
export const TEST_DASHBOARD_URL = process.env.NHOST_TEST_DASHBOARD_URL; export const TEST_DASHBOARD_URL = process.env.NHOST_TEST_DASHBOARD_URL!;
/** /**
* Name of the workspace to test against. * Name of the organization to test against.
*/ */
export const TEST_ORGANIZATION_NAME = process.env.NHOST_TEST_ORGANIZATION_NAME; export const TEST_ORGANIZATION_NAME = process.env.NHOST_TEST_ORGANIZATION_NAME!;
/** /**
* Slug of the organization to test against. * Slug of the organization to test against.
*/ */
export const TEST_ORGANIZATION_SLUG = process.env.NHOST_TEST_ORGANIZATION_SLUG; export const TEST_ORGANIZATION_SLUG = process.env.NHOST_TEST_ORGANIZATION_SLUG!;
/** /**
* Name of the project to test against. * Name of the project to test against.
*/ */
export const TEST_PROJECT_NAME = process.env.NHOST_TEST_PROJECT_NAME; export const TEST_PROJECT_NAME = process.env.NHOST_TEST_PROJECT_NAME!;
/** /**
* Subdomain of the project to test against. * Subdomain of the project to test against.
*/ */
export const TEST_PROJECT_SUBDOMAIN = process.env.NHOST_TEST_PROJECT_SUBDOMAIN; export const TEST_PROJECT_SUBDOMAIN = process.env.NHOST_TEST_PROJECT_SUBDOMAIN!;
/** /**
* Hasura admin secret of the test project to use. * Hasura admin secret of the test project to use.
*/ */
export const TEST_PROJECT_ADMIN_SECRET = export const TEST_PROJECT_ADMIN_SECRET =
process.env.NHOST_TEST_PROJECT_ADMIN_SECRET; process.env.NHOST_TEST_PROJECT_ADMIN_SECRET!;
/** /**
* Email of the test account to use. * Email of the test account to use.
*/ */
export const TEST_USER_EMAIL = process.env.NHOST_TEST_USER_EMAIL; export const TEST_USER_EMAIL = process.env.NHOST_TEST_USER_EMAIL!;
/** /**
* Password of the test account to use. * Password of the test account to use.
*/ */
export const TEST_USER_PASSWORD = process.env.NHOST_TEST_USER_PASSWORD; export const TEST_USER_PASSWORD = process.env.NHOST_TEST_USER_PASSWORD!;
export const TEST_PERSONAL_ORG_SLUG = process.env.NHOST_TEST_PERSONAL_ORG_SLUG; export const TEST_PERSONAL_ORG_SLUG = process.env.NHOST_TEST_PERSONAL_ORG_SLUG!;
const freeUserEmails = process.env.NHOST_TEST_FREE_USER_EMAILS!;
export const TEST_FREE_USER_EMAILS: string[] = JSON.parse(freeUserEmails);

View File

@@ -0,0 +1,23 @@
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: 'load' },
);
await use(page);
// update the context to get the new refresh token
await page.waitForLoadState('load');
await page.context().storageState({ path: AUTH_CONTEXT });
await page.close();
},
});
export { expect } from '@playwright/test';

View File

@@ -0,0 +1,223 @@
import { expect, test } from '@/e2e/fixtures/auth-hook';
import {
getCardExpiration,
getOrgSlugFromUrl,
getProjectSlugFromUrl,
gotoUrl,
loginWithFreeUser,
setFreeUserStarterOrgSlug,
setNewProjectName,
setNewProjectSlug,
} from '@/e2e/utils';
import { faker } from '@faker-js/faker';
import type { Page } from '@playwright/test';
let page: Page;
test.beforeAll(async ({ browser }) => {
page = await browser.newPage();
await loginWithFreeUser(page);
});
test('user should be able to finish onboarding', async () => {
await gotoUrl(page, `/onboarding`);
expect(page.getByText('Welcome to Nhost!')).toBeVisible();
const organizationName = faker.lorem.words(3).slice(0, 32);
await page.getByLabel('Organization Name').fill(organizationName);
await page.getByText('Select organization type', { exact: true }).click();
await page.getByText('Personal Project').nth(1).click();
await page.getByText('Pro', { exact: true }).click();
await page.getByText('Create Organization').click();
const stripeFrame = page
.frameLocator('iframe[name="embedded-checkout"]')
.first();
stripeFrame.getByText('Subscribe to Nhost');
await stripeFrame.getByLabel('Email').fill(faker.internet.email());
await stripeFrame
.getByPlaceholder('1234 1234 1234 1234')
.fill('4242424242424242');
await stripeFrame.getByPlaceholder('MM / YY').fill(getCardExpiration());
await stripeFrame.getByPlaceholder('CVC').fill('123');
await stripeFrame
.getByPlaceholder('Full name on card')
.fill('EndyTo EndyTest');
await stripeFrame.locator('#billingCountry').scrollIntoViewIfNeeded();
// Need to comment out for testing outside US START
// await stripeFrame.getByPlaceholder('Address', { exact: true }).click();
// stripeFrame.locator('span:has-text("Enter address manually")');
// await stripeFrame.getByText('Enter address manually').click();
// await stripeFrame
// .getByPlaceholder('Address line 1', { exact: true })
// .fill('123 Main Street');
// await stripeFrame
// .getByPlaceholder('City', { exact: true })
// .fill('Springfield');
// await stripeFrame.getByPlaceholder('ZIP', { exact: true }).fill('62701');
// await stripeFrame.locator('#enableStripePass').click({ force: true });
// Need to comment out for testing outside US END
stripeFrame
.getByTestId('hosted-payment-submit-button')
.scrollIntoViewIfNeeded();
await stripeFrame
.getByTestId('hosted-payment-submit-button')
.click({ force: true });
expect(
page.getByText('Processing new organization request').first(),
).toBeVisible();
await page.waitForSelector(
'div:has-text("Organization created successfully. Redirecting...")',
);
expect(page.getByText('Create Your First Project')).toBeVisible();
const projectName = faker.lorem.words(3).slice(0, 32);
await page.getByLabel('Project Name').fill(projectName);
await page.getByText('Create Project', { exact: true }).click();
expect(page.getByText('Creating your project...')).toBeVisible();
expect(page.getByText('Project created successfully!')).toBeVisible();
expect(page.getByText('Internal info')).toBeVisible();
await page.waitForSelector('h3:has-text("Project Health")', {
timeout: 180000,
});
const newProjectSlug = getProjectSlugFromUrl(page.url());
setNewProjectSlug(newProjectSlug);
setNewProjectName(organizationName);
const newOrgSlug = getOrgSlugFromUrl(page.url());
setFreeUserStarterOrgSlug(newOrgSlug);
});
test('should delete the new organization', async () => {
const newOrgSlug = getOrgSlugFromUrl(page.url());
await gotoUrl(page, `/orgs/${newOrgSlug}/projects`);
await page.getByRole('link', { name: 'Settings' }).click();
await page.waitForSelector('h3:has-text("Delete Organization")');
await page.getByRole('button', { name: 'Delete' }).click();
await page.waitForSelector('h2:has-text("Delete Organization")');
expect(page.getByTestId('deleteOrgButton')).toBeDisabled();
await page.getByLabel("I'm sure I want to delete this Organization").click();
expect(page.getByTestId('deleteOrgButton')).toBeDisabled();
await page.getByLabel('I understand this action cannot be undone').click();
expect(page.getByTestId('deleteOrgButton')).not.toBeDisabled();
await page.getByTestId('deleteOrgButton').click();
await page.waitForSelector('div:has-text("Deleting the organization")');
await page.waitForSelector(
'div:has-text("Successfully deleted the organization")',
);
await page.waitForSelector('h2:has-text("Welcome to Nhost!")');
});
test('should be able to upgrade an organization', async () => {
await gotoUrl(page, `/onboarding`);
expect(page.getByText('Welcome to Nhost!')).toBeVisible();
const organizationName = faker.lorem.words(3).slice(0, 32);
await page.getByLabel('Organization Name').fill(organizationName);
await page.getByText('Select organization type', { exact: true }).click();
await page.getByText('Personal Project').nth(1).click();
await page.getByText('Create Organization').click();
await page.waitForSelector(
'div:has-text("Organization created successfully!")',
);
await page.getByText('Select organization', { exact: true }).click();
await page.getByLabel('Organizations').getByText(organizationName).click();
await page.waitForSelector('h2:has-text("Welcome to Nhost!")');
await page.getByRole('link', { name: 'Billing' }).click();
await page.waitForSelector('h4:has-text("Subscription plan")');
expect(page.getByText('Upgrade')).toBeEnabled();
await page.getByText('Upgrade').click();
await page.waitForSelector('h2:has-text("Upgrade Organization")');
await page.getByText('Pro', { exact: true }).click();
await page.getByTestId('upgradeOrgSubmitButton').click();
await page.waitForSelector('button[data-testid="upgradeOrgSubmitButton"]', {
state: 'hidden',
});
const stripeFrame = page
.frameLocator('iframe[name="embedded-checkout"]')
.first();
stripeFrame
.locator('div[data-testid="product-summary"]')
.waitFor({ state: 'visible' });
await stripeFrame.getByLabel('Email').fill(faker.internet.email());
await stripeFrame
.getByPlaceholder('1234 1234 1234 1234')
.fill('4242424242424242');
await stripeFrame.getByPlaceholder('MM / YY').fill(getCardExpiration());
await stripeFrame.getByPlaceholder('CVC').fill('123');
await stripeFrame
.getByPlaceholder('Full name on card')
.fill('EndyTo EndyTest');
await stripeFrame.locator('#billingCountry').scrollIntoViewIfNeeded();
// Need to comment out for testing outside US START
// await stripeFrame.getByPlaceholder('Address', { exact: true }).click();
// stripeFrame.locator('span:has-text("Enter address manually")');
// await stripeFrame.getByText('Enter address manually').click();
// await stripeFrame
// .getByPlaceholder('Address line 1', { exact: true })
// .fill('123 Main Street');
// await stripeFrame
// .getByPlaceholder('City', { exact: true })
// .fill('Springfield');
// await stripeFrame.getByPlaceholder('ZIP', { exact: true }).fill('62701');
// await stripeFrame.locator('#enableStripePass').click({ force: true });
// Need to comment out for testing outside US END
stripeFrame
.getByTestId('hosted-payment-submit-button')
.scrollIntoViewIfNeeded();
await stripeFrame
.getByTestId('hosted-payment-submit-button')
.click({ force: true });
await page.waitForSelector('div:has-text("Upgrading organization")');
await page.waitForSelector(
'div:has-text("Organization has been upgraded successfully.")',
);
await page.waitForSelector('span:has-text("Spending Notifications")');
await page.getByRole('link', { name: 'Settings' }).click();
await page.waitForSelector('h3:has-text("Delete Organization")');
await page.getByRole('button', { name: 'Delete' }).click();
await page.waitForSelector('h2:has-text("Delete Organization")');
expect(page.getByTestId('deleteOrgButton')).toBeDisabled();
await page.getByLabel("I'm sure I want to delete this Organization").click();
expect(page.getByTestId('deleteOrgButton')).toBeDisabled();
await page.getByLabel('I understand this action cannot be undone').click();
expect(page.getByTestId('deleteOrgButton')).not.toBeDisabled();
await page.getByTestId('deleteOrgButton').click();
await page.waitForSelector('div:has-text("Deleting the organization")');
await page.waitForSelector(
'div:has-text("Successfully deleted the organization")',
);
await page.waitForSelector('h2:has-text("Welcome to Nhost!")');
});

View File

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

View File

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

View File

@@ -18,7 +18,7 @@ setup('authenticate user', async ({ page }) => {
await page.waitForURL( await page.waitForURL(
`${TEST_DASHBOARD_URL}/orgs/${TEST_PERSONAL_ORG_SLUG}/projects`, `${TEST_DASHBOARD_URL}/orgs/${TEST_PERSONAL_ORG_SLUG}/projects`,
{ waitUntil: 'networkidle' }, { waitUntil: 'load' },
); );
await page.context().storageState({ path: 'e2e/.auth/user.json' }); await page.context().storageState({ path: 'e2e/.auth/user.json' });
}); });

View File

@@ -0,0 +1,55 @@
/* eslint-disable no-console */
import { TEST_PROJECT_ADMIN_SECRET, TEST_PROJECT_SUBDOMAIN } from '@/e2e/env';
import { test as setup } from '@playwright/test';
setup('refresh metadata', async () => {
try {
const response = await fetch(
`https://${TEST_PROJECT_SUBDOMAIN}.hasura.eu-central-1.staging.nhost.run/v1/metadata`,
{
method: 'POST',
headers: {
'x-hasura-admin-secret': TEST_PROJECT_ADMIN_SECRET,
},
body: JSON.stringify({
args: [
{
type: 'reload_metadata',
args: {
reload_sources: false,
},
},
{
args: {},
type: 'get_inconsistent_metadata',
},
],
source: 'default',
type: 'bulk',
}),
},
);
const body = await response.json();
if (!response.ok) {
const message = `[${body.code}]:${body.error}`;
throw new Error(message);
} else {
const isConsistent = body[0].is_consistent;
if (isConsistent) {
console.log('Metadata is consistent.');
} else {
console.error('Metadata is not consistent.');
console.error(body[0].inconsistent_objects);
throw new Error('Metadata is not consistent');
}
}
} catch (error) {
// Log safe error information
console.error(
'Failed to refresh metadata:',
error instanceof Error ? error.message : 'Unknown error',
);
throw new Error('Failed to refresh metadata');
}
});

View File

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

View File

@@ -1,5 +1,12 @@
import {
TEST_FREE_USER_EMAILS,
TEST_ORGANIZATION_SLUG,
TEST_PROJECT_SUBDOMAIN,
TEST_USER_PASSWORD,
} from '@/e2e/env';
import { faker } from '@faker-js/faker'; import { faker } from '@faker-js/faker';
import type { Page } from '@playwright/test'; import { type Page } from '@playwright/test';
import { add, format } from 'date-fns-v4';
/** /**
* Open a project by navigating to the project's overview page. * Open a project by navigating to the project's overview page.
@@ -21,7 +28,7 @@ export async function navigateToProject({
const projectUrl = `/orgs/${orgSlug}/projects/${projectSubdomain}`; const projectUrl = `/orgs/${orgSlug}/projects/${projectSubdomain}`;
try { try {
await page.goto(projectUrl, { waitUntil: 'networkidle' }); await page.goto(projectUrl, { waitUntil: 'load' });
await page.waitForURL(projectUrl, { timeout: 10000 }); await page.waitForURL(projectUrl, { timeout: 10000 });
} catch (error) { } catch (error) {
console.error(`Failed to navigate to project URL: ${projectUrl}`, error); console.error(`Failed to navigate to project URL: ${projectUrl}`, error);
@@ -39,12 +46,12 @@ export async function navigateToProject({
export async function prepareTable({ export async function prepareTable({
page, page,
name: tableName, name: tableName,
primaryKey, primaryKeys,
columns, columns,
}: { }: {
page: Page; page: Page;
name: string; name: string;
primaryKey: string; primaryKeys: string[];
columns: Array<{ columns: Array<{
name: string; name: string;
type: string; type: string;
@@ -53,7 +60,7 @@ export async function prepareTable({
defaultValue?: string; defaultValue?: string;
}>; }>;
}) { }) {
if (!columns.some(({ name }) => name === primaryKey)) { if (!columns.some(({ name }) => primaryKeys.includes(name))) {
throw new Error('Primary key must be one of the columns.'); throw new Error('Primary key must be one of the columns.');
} }
@@ -117,11 +124,13 @@ export async function prepareTable({
}, },
), ),
); );
// select the first column as primary key
// await page.getByRole('button', { name: /primary key/i }).click();
await page.getByLabel('Primary Key').click(); await page.getByLabel('Primary Key').click();
await page.getByRole('option', { name: primaryKey, exact: true }).click(); await Promise.all(
primaryKeys.map(async (primaryKey) => {
await page.getByRole('option', { name: primaryKey, exact: true }).click();
}),
);
await page.getByText('Create a New Table').click();
} }
/** /**
@@ -211,3 +220,95 @@ export async function clickPermissionButton({
.locator('button') .locator('button')
.click(); .click();
} }
export async function gotoAuthURL(page: Page) {
const authUrl = `/orgs/${TEST_ORGANIZATION_SLUG}/projects/${TEST_PROJECT_SUBDOMAIN}/users`;
await page.goto(authUrl);
await page.waitForURL(authUrl, { waitUntil: 'load' });
}
export async function gotoUrl(page: Page, url: string) {
await page.goto(url);
await page.waitForURL(url, { waitUntil: 'load' });
}
let newOrgSlug: string;
export function getNewOrgSlug() {
return newOrgSlug;
}
export function setNewOrgSlug(slug: string) {
newOrgSlug = slug;
}
let freeUserStarterOrgSlug: string;
export function getFreeUserStarterOrgSlug() {
return freeUserStarterOrgSlug;
}
export function setFreeUserStarterOrgSlug(slug: string) {
freeUserStarterOrgSlug = slug;
}
let newProjectSlug: string;
export function getNewProjectSlug() {
return newProjectSlug;
}
export function setNewProjectSlug(slug: string) {
newProjectSlug = slug;
}
export function getProjectSlugFromUrl(url: string) {
const [, projectSlug] = url.split('/projects/');
return projectSlug;
}
export function getOrgSlugFromUrl(url: string) {
const orgSlug = url.split('/orgs/')[1].split('/projects/')[0];
return orgSlug;
}
export function getCardExpiration() {
const now = add(new Date(), { years: 3 });
return format(now, 'MMyy');
}
let newProjectName: string;
export function getNewProjectName() {
return newProjectName;
}
export function setNewProjectName(name: string) {
newProjectName = name;
}
function getRandomUserIndex(): number {
return Math.floor(Math.random() * TEST_FREE_USER_EMAILS.length);
}
export async function loginWithFreeUser(page: Page) {
const userIndex = getRandomUserIndex();
const freeUserEmail = TEST_FREE_USER_EMAILS[userIndex];
// eslint-disable-next-line no-console
console.log(`Selected userIndex: ${userIndex}`);
await page.goto('/');
await page.waitForURL('/signin');
await page.getByRole('link', { name: /continue with email/i }).click();
await page.waitForURL('/signin/email');
await page.getByLabel('Email').fill(freeUserEmail);
await page.getByLabel('Password').fill(TEST_USER_PASSWORD);
await page.getByRole('button', { name: /sign in/i }).click();
await page.waitForSelector('h2:has-text("Welcome to Nhost!")', {
timeout: 20000,
});
}

View File

@@ -5,21 +5,24 @@ const withBundleAnalyzer = require('@next/bundle-analyzer')({
const { version } = require('./package.json'); const { version } = require('./package.json');
const cspHeader = ` const cspHeader = `
default-src 'self' *.nhost.run ws://*.nhost.run nhost.run ws://nhost.run; default-src 'self' *.nhost.run wss://*.nhost.run nhost.run wss://nhost.run;
script-src 'self' 'unsafe-eval' 'unsafe-inline' cdn.segment.com js.stripe.com; script-src 'self' 'unsafe-eval' cdn.segment.com js.stripe.com challenges.cloudflare.com googletagmanager.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; connect-src 'self' *.nhost.run wss://*.nhost.run nhost.run wss://nhost.run discord.com api.segment.io api.segment.com cdn.segment.com nhost.zendesk.com;
style-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';
img-src 'self' blob: data: avatars.githubusercontent.com s.gravatar.com *.nhost.run nhost.run; img-src 'self' blob: data: github.com avatars.githubusercontent.com s.gravatar.com *.nhost.run nhost.run;
font-src 'self' data:; font-src 'self' data:;
object-src 'none'; object-src 'none';
base-uri 'self'; base-uri 'self';
form-action 'self'; form-action 'self';
frame-ancestors 'none'; frame-ancestors 'none';
frame-src 'self' js.stripe.com; frame-src 'self' js.stripe.com challenges.cloudflare.com;
block-all-mixed-content; block-all-mixed-content;
upgrade-insecure-requests;
`; `;
if (process.env.NEXT_PUBLIC_ENV !== 'development') {
cspHeader.concat(` upgrade-insecure-requests;`);
}
module.exports = withBundleAnalyzer({ module.exports = withBundleAnalyzer({
reactStrictMode: false, reactStrictMode: false,
swcMinify: false, swcMinify: false,
@@ -38,10 +41,10 @@ module.exports = withBundleAnalyzer({
{ {
source: '/(.*)', source: '/(.*)',
headers: [ headers: [
// { {
// key: 'Content-Security-Policy', key: 'Content-Security-Policy',
// hgvalue: cspHeader.replace(/\s+/g, ' ').trim(), value: cspHeader.replace(/\s+/g, ' ').trim(),
// }, },
{ {
key: 'X-Frame-Options', key: 'X-Frame-Options',
value: 'DENY', value: 'DENY',

View File

@@ -1,6 +1,6 @@
{ {
"name": "@nhost/dashboard", "name": "@nhost/dashboard",
"version": "2.24.0", "version": "2.36.0",
"private": true, "private": true,
"scripts": { "scripts": {
"preinstall": "npx only-allow pnpm", "preinstall": "npx only-allow pnpm",
@@ -16,8 +16,10 @@
"storybook": "start-storybook -p 6006 -s public", "storybook": "start-storybook -p 6006 -s public",
"build-storybook": "build-storybook", "build-storybook": "build-storybook",
"install-browsers": "pnpm playwright install && pnpm playwright install-deps", "install-browsers": "pnpm playwright install && pnpm playwright install-deps",
"e2e": "pnpm install-browsers && pnpm playwright test --config=playwright.config.ts", "e2e:tests": "pnpm install-browsers && pnpm playwright test --config=playwright.config.ts -x",
"e2e-local": "pnpm install-browsers && pnpm playwright test --config=playwright.local.config.ts" "e2e": "pnpm e2e:tests --project=main",
"e2e:local": "pnpm e2e:tests --project=local",
"e2e:onboarding": "pnpm e2e:tests --project=onboarding"
}, },
"dependencies": { "dependencies": {
"@apollo/client": "^3.9.9", "@apollo/client": "^3.9.9",
@@ -37,29 +39,30 @@
"@heroicons/react": "^1.0.6", "@heroicons/react": "^1.0.6",
"@hookform/resolvers": "^3.9.0", "@hookform/resolvers": "^3.9.0",
"@iarna/toml": "^2.2.5", "@iarna/toml": "^2.2.5",
"@icons-pack/react-simple-icons": "^9.6.0",
"@marsidev/react-turnstile": "^1.0.2", "@marsidev/react-turnstile": "^1.0.2",
"@mui/base": "5.0.0-beta.31", "@mui/base": "5.0.0-beta.31",
"@mui/material": "^5.15.14", "@mui/material": "^5.15.14",
"@mui/system": "^5.15.14", "@mui/system": "^5.15.14",
"@mui/x-date-pickers": "^5.0.20", "@mui/x-date-pickers": "^5.0.20",
"@nhost/nextjs": "workspace:*", "@nhost/nhost-js-beta": "npm:@nhost/nhost-js@5.0.0-beta.9",
"@nhost/react-apollo": "workspace:*",
"@radix-ui/react-accordion": "^1.2.1", "@radix-ui/react-accordion": "^1.2.1",
"@radix-ui/react-alert-dialog": "^1.1.2", "@radix-ui/react-alert-dialog": "^1.1.2",
"@radix-ui/react-checkbox": "^1.1.2", "@radix-ui/react-checkbox": "^1.1.2",
"@radix-ui/react-dialog": "^1.1.1", "@radix-ui/react-dialog": "^1.1.3",
"@radix-ui/react-dropdown-menu": "^2.1.1", "@radix-ui/react-dropdown-menu": "^2.1.1",
"@radix-ui/react-hover-card": "^1.1.2", "@radix-ui/react-hover-card": "^1.1.2",
"@radix-ui/react-label": "^2.1.0", "@radix-ui/react-label": "^2.1.0",
"@radix-ui/react-popover": "^1.1.1", "@radix-ui/react-popover": "^1.1.3",
"@radix-ui/react-progress": "^1.1.0", "@radix-ui/react-progress": "^1.1.0",
"@radix-ui/react-radio-group": "^1.2.0", "@radix-ui/react-radio-group": "^1.2.0",
"@radix-ui/react-select": "^2.1.2", "@radix-ui/react-select": "^2.1.2",
"@radix-ui/react-separator": "^1.1.0", "@radix-ui/react-separator": "^1.1.0",
"@radix-ui/react-slot": "^1.1.0", "@radix-ui/react-slot": "^1.1.1",
"@radix-ui/react-tabs": "^1.1.3", "@radix-ui/react-tabs": "^1.1.3",
"@radix-ui/react-tooltip": "^1.1.2", "@radix-ui/react-tooltip": "^1.1.2",
"@segment/analytics-next": "^1.77.0", "@segment/analytics-next": "^1.77.0",
"@simplewebauthn/browser": "^9.0.1",
"@stripe/react-stripe-js": "^2.6.2", "@stripe/react-stripe-js": "^2.6.2",
"@stripe/stripe-js": "^1.54.2", "@stripe/stripe-js": "^1.54.2",
"@tailwindcss/forms": "^0.5.7", "@tailwindcss/forms": "^0.5.7",
@@ -85,9 +88,10 @@
"graphql-tag": "^2.12.6", "graphql-tag": "^2.12.6",
"graphql-ws": "^5.16.0", "graphql-ws": "^5.16.0",
"just-kebab-case": "^4.2.0", "just-kebab-case": "^4.2.0",
"jwt-decode": "^4.0.0",
"lodash.debounce": "^4.0.8", "lodash.debounce": "^4.0.8",
"lucide-react": "^0.416.0", "lucide-react": "^0.416.0",
"next": "^14.2.22", "next": "^14.2.31",
"next-nprogress-bar": "^2.3.13", "next-nprogress-bar": "^2.3.13",
"next-seo": "^6.5.0", "next-seo": "^6.5.0",
"next-themes": "^0.3.0", "next-themes": "^0.3.0",
@@ -95,8 +99,8 @@
"pluralize": "^8.0.0", "pluralize": "^8.0.0",
"react": "18.2.0", "react": "18.2.0",
"react-children-utilities": "^2.10.0", "react-children-utilities": "^2.10.0",
"react-complex-tree": "^2.4.5", "react-complex-tree": "^2.6.0",
"react-day-picker": "8.10.1", "react-day-picker": "9.6.3",
"react-dom": "18.2.0", "react-dom": "18.2.0",
"react-error-boundary": "^4.0.13", "react-error-boundary": "^4.0.13",
"react-hook-form": "^7.53.0", "react-hook-form": "^7.53.0",
@@ -105,18 +109,18 @@
"react-is": "18.2.0", "react-is": "18.2.0",
"react-loading-skeleton": "^2.2.0", "react-loading-skeleton": "^2.2.0",
"react-markdown": "^9.0.1", "react-markdown": "^9.0.1",
"react-merge-refs": "^1.1.0", "react-merge-refs": "^3.0.2",
"react-resizable-layout": "^0.7.2", "react-resizable-layout": "^0.7.2",
"react-table": "^7.8.0", "react-table": "^7.8.0",
"recoil": "^0.7.7", "recoil": "^0.7.7",
"recoil-persist": "^5.1.0", "recoil-persist": "^5.1.0",
"rehype-highlight": "^7.0.0", "rehype-highlight": "^7.0.0",
"remark-gfm": "^4.0.0", "remark-gfm": "^4.0.0",
"shell-quote": "^1.8.1",
"slugify": "^1.6.6", "slugify": "^1.6.6",
"stripe": "^10.17.0", "stripe": "^10.17.0",
"tailwind-merge": "^1.14.0", "tailwind-merge": "^1.14.0",
"tailwindcss-animate": "^1.0.7", "tailwindcss-animate": "^1.0.7",
"test@latest": "link:playwright/test@latest",
"timezones-list": "^3.1.0", "timezones-list": "^3.1.0",
"utility-types": "^3.11.0", "utility-types": "^3.11.0",
"uuid": "^9.0.1", "uuid": "^9.0.1",
@@ -157,7 +161,6 @@
"@types/react": "^18.2.73", "@types/react": "^18.2.73",
"@types/react-dom": "^18.2.23", "@types/react-dom": "^18.2.23",
"@types/react-table": "^7.7.20", "@types/react-table": "^7.7.20",
"@types/shell-quote": "^1.7.5",
"@types/testing-library__jest-dom": "^5.14.9", "@types/testing-library__jest-dom": "^5.14.9",
"@types/uuid": "^9.0.8", "@types/uuid": "^9.0.8",
"@types/validator": "^13.11.9", "@types/validator": "^13.11.9",
@@ -196,7 +199,7 @@
"tailwindcss": "^3.4.12", "tailwindcss": "^3.4.12",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
"tsconfig-paths-webpack-plugin": "^4.1.0", "tsconfig-paths-webpack-plugin": "^4.1.0",
"vite": "^5.4.12", "vite": "^5.4.20",
"vite-tsconfig-paths": "^4.3.2", "vite-tsconfig-paths": "^4.3.2",
"vitest": "^0.32.4" "vitest": "^0.32.4"
}, },

View File

@@ -6,7 +6,7 @@ dotenv.config({ path: path.resolve(__dirname, '.env.test') });
export default defineConfig({ export default defineConfig({
testDir: './e2e', testDir: './e2e',
timeout: 60 * 1000, timeout: 120 * 1000,
expect: { expect: {
timeout: 10000, timeout: 10000,
}, },
@@ -17,7 +17,7 @@ export default defineConfig({
reporter: 'html', reporter: 'html',
use: { use: {
actionTimeout: 0, actionTimeout: 0,
trace: 'on-first-retry', trace: 'retain-on-failure',
baseURL: process.env.NHOST_TEST_DASHBOARD_URL, baseURL: process.env.NHOST_TEST_DASHBOARD_URL,
launchOptions: { launchOptions: {
slowMo: 500, slowMo: 500,
@@ -34,13 +34,28 @@ export default defineConfig({
testMatch: ['**/teardown/*.teardown.ts'], testMatch: ['**/teardown/*.teardown.ts'],
}, },
{ {
name: 'chromium', name: 'main',
use: { use: {
...devices['Desktop Chrome'], ...devices['Desktop Chrome'],
storageState: 'e2e/.auth/user.json', storageState: 'e2e/.auth/user.json',
}, },
dependencies: ['setup'], dependencies: ['setup'],
grepInvert: [/Local Dashboard CLI e2e tests/], testIgnore: ['onboarding.test.ts', 'cli-local-dashboard.test.ts'],
},
{
name: 'local',
use: {
...devices['Desktop Chrome'],
baseURL: '', // Local dashboard URL
},
testMatch: 'cli-local-dashboard.test.ts',
},
{
name: 'onboarding',
testMatch: 'onboarding.test.ts',
use: {
...devices['Desktop Chrome'],
},
}, },
], ],
}); });

View File

@@ -1,31 +0,0 @@
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './e2e',
timeout: 30 * 1000,
expect: {
timeout: 5000,
},
fullyParallel: false,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: 1,
reporter: 'html',
use: {
actionTimeout: 0,
trace: 'on-first-retry',
baseURL: '', // Local dashboard URL
launchOptions: {
slowMo: 500,
},
},
projects: [
{
name: 'chromium',
use: {
...devices['Desktop Chrome'],
},
testMatch: ['**/e2e/cli-local-dashboard/**'],
},
],
});

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -0,0 +1,59 @@
import Image from 'next/image';
export function SignInRightColumn() {
return (
<div className="grid gap-6 font-[Inter]">
<div className="text-center">
<h2 className="mb-2 text-2xl font-semibold text-white">
Ship 10x faster
</h2>
<p className="text-sm text-[#A2B3BE]">
Skip months of backend setup and focus on building what matters
</p>
</div>
<div className="rounded-lg border border-white/10 bg-gradient-to-r from-[#0052CD]/10 to-[#FF02F5]/10 p-5">
<div className="flex items-start gap-4">
<div className="flex-shrink-0">
<Image
src="/assets/signup/CircleWavyCheck.svg"
width={20}
height={20}
alt="Check"
/>
</div>
<div>
<h3 className="mb-2 text-sm font-semibold text-white">
From idea to production
</h3>
<p className="text-xs text-[#A2B3BE]">
Everything you need to ship fast, without the setup complexity.
</p>
</div>
</div>
</div>
<div className="rounded-lg border border-white/10 bg-gradient-to-r from-[#0052CD]/10 to-[#FF02F5]/10 p-5">
<div className="flex items-start gap-4">
<div className="flex-shrink-0">
<Image
src="/assets/key.svg"
width={20}
height={20}
alt="Security"
/>
</div>
<div>
<h3 className="mb-2 text-sm font-semibold text-white">
Sleep easy at night
</h3>
<p className="text-xs text-[#A2B3BE]">
Rock-solid security so you can focus on building, not
vulnerabilities.
</p>
</div>
</div>
</div>
</div>
);
}

View File

@@ -1,102 +0,0 @@
import { Link } from '@/components/ui/v2/Link';
import { Text } from '@/components/ui/v2/Text';
import type { DetailedHTMLProps, HTMLProps } from 'react';
import { twMerge } from 'tailwind-merge';
export interface ContactUsProps
extends DetailedHTMLProps<HTMLProps<HTMLDivElement>, HTMLDivElement> {
isTeam?: boolean;
isOwner?: boolean;
}
export default function FeedbackForm({
className,
isTeam,
isOwner,
...props
}: ContactUsProps) {
return (
<div
className={twMerge(
'grid max-w-md grid-flow-row gap-2 px-5 py-4',
className,
)}
{...props}
>
<Text variant="h3" component="h2">
Contact us
</Text>
{isTeam && isOwner && (
<Text>
If this is a new Team project, or you need to manage members, reach
out to us on discord or via email at{' '}
<Link
href="mailto:support@nhost.io"
target="_blank"
rel="noopener noreferrer"
underline="hover"
>
support@nhost.io
</Link>{' '}
so we can have your dedicated channel set up.
</Text>
)}
{isTeam && !isOwner && (
<Text>
As part of a team plan you can reach out to us on the private channel
for this workspace. If you haven&apos;t been added to the channel, ask
the workspace owner to add you.
</Text>
)}
<Text>
To report issues with Nhost, please open a GitHub issue in the{' '}
<Link
href="https://github.com/nhost/nhost/issues/new"
target="_blank"
rel="noopener noreferrer"
underline="hover"
>
nhost/nhost
</Link>{' '}
repository.
</Text>
<Text>
For issues related to the CLI, please visit the{' '}
<Link
href="https://github.com/nhost/cli/issues/new"
target="_blank"
rel="noopener noreferrer"
underline="hover"
>
nhost/cli
</Link>{' '}
repository.
</Text>
<Text>
If you need assistance or have any questions, feel free to join us on{' '}
<Link
href="https://discord.com/invite/9V7Qb2U"
target="_blank"
rel="noopener noreferrer"
underline="hover"
>
Discord
</Link>
. Alternatively, if you prefer, you can also open a{' '}
<Link
href="https://github.com/nhost/nhost/discussions/new/choose"
target="_blank"
rel="noopener noreferrer"
underline="hover"
>
GitHub discussion
</Link>
.
</Text>
<Text>We&apos;re here to help, so don&apos;t hesitate to reach out!</Text>
</div>
);
}

View File

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

View File

@@ -0,0 +1,93 @@
import { Button } from '@/components/ui/v3/button';
import { useSSRLocalStorage } from '@/hooks/useSSRLocalStorage';
import { X } from 'lucide-react';
import NextLink from 'next/link';
import { useEffect, useState } from 'react';
interface CookieConsentProps {
onAccept: () => void;
}
export default function CookieConsent({ onAccept }: CookieConsentProps) {
const [consentGiven, setConsentGiven] = useSSRLocalStorage<boolean | null>(
'cookie-consent',
null,
);
const [showBanner, setShowBanner] = useState(false);
useEffect(() => {
if (consentGiven === null) {
setShowBanner(true);
} else if (consentGiven === true) {
onAccept();
}
}, [consentGiven, onAccept]);
const handleAccept = () => {
setConsentGiven(true);
setShowBanner(false);
onAccept();
};
const handleDecline = () => {
setConsentGiven(false);
setShowBanner(false);
};
const handleClose = () => {
handleDecline();
};
if (!showBanner) {
return null;
}
return (
<div className="fixed bottom-4 right-4 z-50 w-96">
<div className="rounded-lg border bg-black/95 p-6 shadow-lg backdrop-blur-sm">
<div className="flex items-start justify-between gap-4">
<div className="flex-1">
<h3 className="mb-3 text-sm font-semibold text-white">
We use cookies for payments and analytics to improve our services.
</h3>
<p className="mb-4 text-xs text-[#A2B3BE]">
<NextLink
href="https://nhost.io/legal/privacy-policy"
target="_blank"
rel="noopener noreferrer"
className="text-white underline hover:no-underline"
>
Learn more
</NextLink>
</p>
<div className="flex gap-2">
<Button
onClick={handleAccept}
size="sm"
className="bg-blue-600 px-3 py-1 text-xs text-white hover:bg-blue-700"
>
Accept all
</Button>
<Button
onClick={handleDecline}
variant="outline"
size="sm"
className="border-gray-600 px-3 py-1 text-xs text-white hover:bg-gray-800"
>
Essential only
</Button>
</div>
</div>
<button
onClick={handleClose}
type="button"
className="text-[#A2B3BE] hover:text-white"
aria-label="Close cookie banner"
>
<X size={16} />
</button>
</div>
</div>
</div>
);
}

View File

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

View File

@@ -0,0 +1,177 @@
import { isTZDate } from '@/components/common/TimePicker/time-picker-utils';
import { render, screen, TestUserEvent, waitFor } from '@/tests/testUtils';
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 = new TestUserEvent();
await user.click(await screen.findByTestId('dateTimePickerTrigger'));
expect(
await screen.findByRole('button', { name: 'Select' }),
).toBeInTheDocument();
expect(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(screen.getByText('13'));
const hoursInput = screen.getByLabelText('Hours');
await user.type(hoursInput, '11');
const minutesInput = screen.getByLabelText('Minutes');
await user.type(minutesInput, '12');
const secondsInput = screen.getByLabelText('Seconds');
await user.type(secondsInput, '13');
await user.click(screen.getByRole('button', { name: 'Select' }));
await waitFor(async () =>
expect(
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 = new TestUserEvent();
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(
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 = new TestUserEvent();
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(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(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(screen.getByText('March 2025')).toBeInTheDocument();
await user.click(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'; align?: 'start' | 'center' | 'end';
validateDateFn?: (date: Date) => string; validateDateFn?: (date: Date) => string;
} }
// in: UTC datetime
// out: UTC dateTime
function DateTimePicker({ function DateTimePicker({
dateTime, dateTime,
@@ -49,6 +47,10 @@ function DateTimePicker({
}); });
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [timezone, setTimezone] = useState(
() => defaultTimezone || guessTimezone(),
);
function emitNewDateTime() { function emitNewDateTime() {
onDateTimeChange(new Date(date.getTime()).toISOString()); onDateTimeChange(new Date(date.getTime()).toISOString());
} }
@@ -73,6 +75,7 @@ function DateTimePicker({
function handleTimezoneChange(newTimezone: string) { function handleTimezoneChange(newTimezone: string) {
const newDateWithTimezone = new TZDate(date.toISOString(), newTimezone); const newDateWithTimezone = new TZDate(date.toISOString(), newTimezone);
setTimezone(newTimezone);
setDate(newDateWithTimezone); setDate(newDateWithTimezone);
} }
@@ -80,6 +83,7 @@ function DateTimePicker({
if (!newOpenState) { if (!newOpenState) {
if (withTimezone) { if (withTimezone) {
const tz = defaultTimezone || guessTimezone(); const tz = defaultTimezone || guessTimezone();
setTimezone(tz);
setDate(new TZDate(dateTime, tz)); setDate(new TZDate(dateTime, tz));
} }
setDate(parseISO(dateTime)); setDate(parseISO(dateTime));
@@ -92,6 +96,8 @@ function DateTimePicker({
setOpen(false); setOpen(false);
} }
const selectedDateInUTC = new Date(date.getTime()).toISOString();
const dateString = formatDateFn?.(date) || format(date, 'PPP HH:mm:ss'); const dateString = formatDateFn?.(date) || format(date, 'PPP HH:mm:ss');
const errorText = validateDateFn?.(date); const errorText = validateDateFn?.(date);
@@ -101,6 +107,7 @@ function DateTimePicker({
<Popover open={open} onOpenChange={handleOpenChange}> <Popover open={open} onOpenChange={handleOpenChange}>
<PopoverTrigger asChild> <PopoverTrigger asChild>
<Button <Button
data-testid="dateTimePickerTrigger"
variant="outline" variant="outline"
className={cn( className={cn(
'w-full justify-between text-left font-normal', 'w-full justify-between text-left font-normal',
@@ -113,15 +120,17 @@ function DateTimePicker({
<CalendarIcon className="h-4 w-4" /> <CalendarIcon className="h-4 w-4" />
</Button> </Button>
</PopoverTrigger> </PopoverTrigger>
<PopoverContent className="w-auto p-0" align={align}> <PopoverContent className="w-auto p-0" align={align}>
<div className="flex"> <div className="flex">
<div className="flex"> <div className="flex">
<Calendar <Calendar
mode="single" mode="single"
selected={date} selected={date}
defaultMonth={date}
onSelect={(d) => handleSelect(d)} onSelect={(d) => handleSelect(d)}
initialFocus
disabled={isCalendarDayDisabled} disabled={isCalendarDayDisabled}
timeZone={timezone}
/> />
<div className="flex flex-col justify-between"> <div className="flex flex-col justify-between">
<div> <div>
@@ -131,7 +140,7 @@ function DateTimePicker({
{withTimezone && ( {withTimezone && (
<div className="border-t border-border p-3"> <div className="border-t border-border p-3">
<TimezoneSettings <TimezoneSettings
dateTime={dateTime} dateTime={selectedDateInUTC}
onTimezoneChange={handleTimezoneChange} onTimezoneChange={handleTimezoneChange}
/> />
</div> </div>

View File

@@ -18,16 +18,23 @@ function TimezoneSettings({ dateTime, onTimezoneChange }: Props) {
setTimezone(tz.value); setTimezone(tz.value);
onTimezoneChange?.(tz.value); onTimezoneChange?.(tz.value);
} }
const utcOffset = getUTCOffsetInHours(selectedTimezone, dateTime, 'OOOO'); const utcOffset = getUTCOffsetInHours(selectedTimezone, dateTime, 'OOOO');
return ( return (
<div className="flex w-full items-center justify-between"> <div className="flex w-full items-center justify-between">
Timezone: {utcOffset}{' '} <span>Timezone: {utcOffset}</span>
<TimezonePicker <TimezonePicker
dateTime={dateTime} dateTime={dateTime}
selectedTimezone={selectedTimezone} selectedTimezone={selectedTimezone}
onTimezoneSelect={handleTimezoneSelect} onTimezoneSelect={handleTimezoneSelect}
button={ 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" /> <Settings2 className="h-4 w-4 dark:text-foreground" />
</Button> </Button>
} }

View File

@@ -51,7 +51,7 @@ export interface DialogContextProps {
/** /**
* Call this function to open an alert dialog. * Call this function to open an alert dialog.
*/ */
openAlertDialog: <TPayload = string>(config?: DialogConfig<TPayload>) => void; openAlertDialog: <TPayload = string>(config: DialogConfig<TPayload>) => void;
/** /**
* Call this function to close the active dialog. * Call this function to close the active dialog.
*/ */

View File

@@ -23,6 +23,10 @@ import {
drawerReducer, drawerReducer,
} from './dialogReducers'; } from './dialogReducers';
function isBaseSyntheticEvent(event: any): event is BaseSyntheticEvent {
return event?.type !== undefined;
}
function DialogProvider({ children }: PropsWithChildren<unknown>) { function DialogProvider({ children }: PropsWithChildren<unknown>) {
const router = useRouter(); const router = useRouter();
@@ -87,7 +91,7 @@ function DialogProvider({ children }: PropsWithChildren<unknown>) {
drawerDispatch({ type: 'CLEAR_DRAWER_CONTENT' }); drawerDispatch({ type: 'CLEAR_DRAWER_CONTENT' });
}, []); }, []);
function openAlertDialog<TConfig = string>(config?: DialogConfig<TConfig>) { function openAlertDialog<TConfig = string>(config: DialogConfig<TConfig>) {
alertDialogDispatch({ type: 'OPEN_ALERT', payload: config }); alertDialogDispatch({ type: 'OPEN_ALERT', payload: config });
} }
@@ -122,8 +126,12 @@ function DialogProvider({ children }: PropsWithChildren<unknown>) {
); );
const closeDrawerWithDirtyGuard = useCallback( const closeDrawerWithDirtyGuard = useCallback(
(event?: BaseSyntheticEvent) => { (event?: any) => {
if (isDrawerDirty.current && event?.type !== 'submit') { if (
isDrawerDirty.current &&
isBaseSyntheticEvent(event) &&
event.type !== 'submit'
) {
setShowDirtyConfirmation(true); setShowDirtyConfirmation(true);
openDirtyConfirmation({ props: { onPrimaryAction: closeDrawer } }); openDirtyConfirmation({ props: { onPrimaryAction: closeDrawer } });
return; return;
@@ -135,8 +143,12 @@ function DialogProvider({ children }: PropsWithChildren<unknown>) {
); );
const closeDialogWithDirtyGuard = useCallback( const closeDialogWithDirtyGuard = useCallback(
(event?: BaseSyntheticEvent) => { (event?: any) => {
if (isDialogDirty.current && event?.type !== 'submit') { if (
isDialogDirty.current &&
isBaseSyntheticEvent(event) &&
event.type !== 'submit'
) {
setShowDirtyConfirmation(true); setShowDirtyConfirmation(true);
openDirtyConfirmation({ props: { onPrimaryAction: closeDialog } }); openDirtyConfirmation({ props: { onPrimaryAction: closeDialog } });
return; return;
@@ -250,7 +262,7 @@ function DialogProvider({ children }: PropsWithChildren<unknown>) {
<BaseDialog <BaseDialog
{...dialogProps} {...dialogProps}
title={dialogTitle} title={dialogTitle}
open={dialogOpen} open={!!dialogOpen}
onClose={closeDialogWithDirtyGuard} onClose={closeDialogWithDirtyGuard}
TransitionProps={{ onExited: clearDialogContent, unmountOnExit: false }} TransitionProps={{ onExited: clearDialogContent, unmountOnExit: false }}
PaperProps={{ PaperProps={{

View File

@@ -115,7 +115,7 @@ export function drawerReducer(
} }
export type AlertDialogAction = export type AlertDialogAction =
| { type: 'OPEN_ALERT'; payload?: DialogConfig } | { type: 'OPEN_ALERT'; payload: DialogConfig }
| { type: 'HIDE_ALERT' } | { type: 'HIDE_ALERT' }
| { type: 'CLEAR_ALERT_CONTENT' }; | { type: 'CLEAR_ALERT_CONTENT' };

View File

@@ -1,200 +0,0 @@
import { Box } from '@/components/ui/v2/Box';
import { Button } from '@/components/ui/v2/Button';
import { Text } from '@/components/ui/v2/Text';
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
import {
GetAllWorkspacesAndProjectsDocument,
GetWorkspaceMemberInvitesToManageDocument,
useGetWorkspaceMemberInvitesToManageQuery,
} from '@/generated/graphql';
import { useSubmitState } from '@/hooks/useSubmitState';
import { nhost } from '@/utils/nhost';
import { triggerToast } from '@/utils/toast';
import { useApolloClient } from '@apollo/client';
import { alpha } from '@mui/system';
import { useUserData } from '@nhost/nextjs';
import { useRouter } from 'next/router';
import { useEffect } from 'react';
export default function InviteNotification() {
const user = useUserData();
const isPlatform = useIsPlatform();
const client = useApolloClient();
const router = useRouter();
const { submitState, setSubmitState } = useSubmitState();
const { submitState: ignoreState, setSubmitState: setIgnoreState } =
useSubmitState();
// @FIX: We probably don't want to poll every ten seconds for possible invites. (We can change later depending on how it works in production.) Maybe just on the workspace page?
const {
data,
loading,
error,
refetch: refetchInvitations,
startPolling,
} = useGetWorkspaceMemberInvitesToManageQuery({
variables: {
userId: user?.id,
},
skip: !isPlatform || !user,
});
useEffect(() => {
startPolling(15000);
}, [startPolling]);
if (loading) {
return null;
}
if (error) {
// TODO: Throw error instead and wrap this component in an ErrorBoundary
// that would handle the error
return null;
}
if (!data || data.workspaceMemberInvites.length === 0) {
return null;
}
const handleInviteAccept = async (
_event: React.SyntheticEvent<HTMLButtonElement>,
invite: (typeof data.workspaceMemberInvites)[number],
) => {
setSubmitState({
error: null,
loading: true,
});
const { res, error: acceptError } = await nhost.functions.call(
'/accept-workspace-invite',
{
workspaceMemberInviteId: invite.id,
isAccepted: true,
},
);
if (res?.status !== 200) {
triggerToast('An error occurred when trying to accept the invitation.');
return setSubmitState({
error: new Error(acceptError.message),
loading: false,
});
}
await client.refetchQueries({
include: [
GetAllWorkspacesAndProjectsDocument,
GetWorkspaceMemberInvitesToManageDocument,
],
});
await router.push(`/${invite.workspace.slug}`);
await refetchInvitations();
triggerToast('Workspace invite accepted');
return setSubmitState({
error: null,
loading: false,
});
};
async function handleIgnoreInvitation(
inviteId: (typeof data.workspaceMemberInvites)[number]['id'],
) {
setIgnoreState({
loading: true,
error: null,
});
const { error: ignoreError } = await nhost.functions.call(
'/accept-workspace-invite',
{
workspaceMemberInviteId: inviteId,
isAccepted: false,
},
);
if (ignoreError) {
triggerToast('An error occurred when trying to ignore the invitation.');
setIgnoreState({
loading: false,
error: new Error(ignoreError.message),
});
return;
}
// just refetch all data
await client.refetchQueries({
include: [
GetAllWorkspacesAndProjectsDocument,
GetWorkspaceMemberInvitesToManageDocument,
],
});
setIgnoreState({
loading: false,
error: null,
});
}
return (
<Box
className="absolute right-10 z-50 mt-14 w-workspaceSidebar rounded-lg px-6 py-6 text-left"
sx={{
backgroundColor: (theme) =>
theme.palette.mode === 'dark' ? 'grey.200' : 'grey.700',
borderWidth: (theme) => (theme.palette.mode === 'dark' ? 1 : 0),
borderColor: (theme) =>
theme.palette.mode === 'dark' ? theme.palette.grey[400] : 'none',
}}
>
{data?.workspaceMemberInvites?.map(
(invite: (typeof data.workspaceMemberInvites)[number]) => (
<div key={invite.id} className="grid grid-flow-row gap-4 text-center">
<div className="grid grid-flow-row gap-1">
<Text variant="h3" component="h2" sx={{ color: 'common.white' }}>
You have been invited to
</Text>
<Text variant="h3" component="p" sx={{ color: 'common.white' }}>
{invite.workspace.name}
</Text>
</div>
<div className="grid grid-flow-row gap-2">
<Button
onClick={(e: React.SyntheticEvent<HTMLButtonElement>) =>
handleInviteAccept(e, invite)
}
loading={submitState.loading}
>
Accept Invite
</Button>
<Button
variant="outlined"
color="secondary"
sx={{
color: 'common.white',
'&:hover': {
backgroundColor: (theme) =>
alpha(theme.palette.common.white, 0.05),
},
'&:focus': {
backgroundColor: (theme) =>
alpha(theme.palette.common.white, 0.1),
},
}}
onClick={() => handleIgnoreInvitation(invite.id)}
loading={ignoreState.loading}
>
Ignore Invite
</Button>
</div>
</div>
),
)}
</Box>
);
}

View File

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

View File

@@ -0,0 +1,518 @@
import { render, screen, TestUserEvent, waitFor } from '@/tests/testUtils';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import MfaOtpForm from './MfaOtpForm';
const mocks = vi.hoisted(() => ({
toastError: vi.fn(),
}));
// Mock react-hot-toast
vi.mock('react-hot-toast', async () => {
const actualToast = await vi.importActual<any>('react-hot-toast');
return {
...actualToast,
default: {
...actualToast.default,
error: mocks.toastError,
},
};
});
// Mock the toast style props utility
vi.mock('@/utils/constants/settings', () => ({
getToastStyleProps: vi.fn(() => ({})),
}));
describe('MfaOtpForm', () => {
const mockSendMfaOtp = vi.fn();
const mockRequestNewMfaTicket = vi.fn();
const user = new TestUserEvent();
beforeEach(() => {
vi.clearAllMocks();
});
afterEach(() => {
vi.clearAllTimers();
});
const defaultProps = {
sendMfaOtp: mockSendMfaOtp,
loading: false,
requestNewMfaTicket: mockRequestNewMfaTicket,
} as any;
describe('Rendering and Initial State', () => {
it('renders with correct initial state', () => {
render(<MfaOtpForm {...defaultProps} />);
const input = screen.getByPlaceholderText('Enter TOTP');
const button = screen.getByRole('button', { name: 'Verify' });
expect(input).toBeInTheDocument();
expect(input).toHaveValue('');
expect(button).toBeInTheDocument();
expect(button).toBeDisabled();
});
it('focuses input on mount', () => {
render(<MfaOtpForm {...defaultProps} />);
const input = screen.getByPlaceholderText('Enter TOTP');
expect(input).toHaveFocus();
});
});
describe('Input Validation and Formatting', () => {
it('only accepts numeric characters', async () => {
render(<MfaOtpForm {...defaultProps} />);
const input = screen.getByPlaceholderText('Enter TOTP');
await user.type(input, 'abc123def456');
expect(input).toHaveValue('123456');
});
it('filters out non-numeric characters in real time', async () => {
render(<MfaOtpForm {...defaultProps} />);
const input = screen.getByPlaceholderText('Enter TOTP');
await user.type(input, '1a2b3c');
expect(input).toHaveValue('123');
});
it('button is disabled when input has fewer than 6 digits', async () => {
render(<MfaOtpForm {...defaultProps} />);
const input = screen.getByPlaceholderText('Enter TOTP');
const button = screen.getByRole('button', { name: 'Verify' });
await user.type(input, '12345');
expect(button).toBeDisabled();
});
it('button is enabled when input has exactly 6 digits', async () => {
render(<MfaOtpForm {...defaultProps} />);
const input = screen.getByPlaceholderText('Enter TOTP');
const button = screen.getByRole('button', { name: 'Verify' });
await user.type(input, '123456');
expect(button).toBeEnabled();
});
it('button is disabled when input has more than 6 digits', async () => {
render(<MfaOtpForm {...defaultProps} />);
const input = screen.getByPlaceholderText('Enter TOTP');
const button = screen.getByRole('button', { name: 'Verify' });
await user.type(input, '6123457');
expect(button).toBeDisabled();
});
});
describe('Loading States', () => {
it('disables input and button when loading prop is true', () => {
render(<MfaOtpForm {...defaultProps} loading />);
const input = screen.getByPlaceholderText('Enter TOTP');
const button = screen.getByRole('button');
expect(input).toBeDisabled();
expect(button).toBeDisabled();
expect(
screen.getByRole('button', { name: 'Verifying...' }),
).toBeInTheDocument();
});
it('input and button are disabled during submission', async () => {
// Mock sendMfaOtp to return a promise that we can control
const promise = new Promise(() => {}); // Never resolves
mockSendMfaOtp.mockReturnValue(promise);
render(<MfaOtpForm {...defaultProps} />);
const input = screen.getByPlaceholderText('Enter TOTP');
const button = screen.getByRole('button', { name: 'Verify' });
await user.type(input, '123456');
await user.click(button);
expect(input).toBeDisabled();
expect(button).toBeDisabled();
});
});
describe('Form Submission', () => {
it('triggers sendMfaOtp with correct code on button click', async () => {
mockSendMfaOtp.mockResolvedValue({ success: true });
render(<MfaOtpForm {...defaultProps} />);
const input = screen.getByPlaceholderText('Enter TOTP');
const button = screen.getByRole('button', { name: 'Verify' });
await user.type(input, '123456');
await user.click(button);
expect(mockSendMfaOtp).toHaveBeenCalledWith('123456');
expect(mockSendMfaOtp).toHaveBeenCalledTimes(1);
});
it('does not submit when input has fewer than 6 digits', async () => {
render(<MfaOtpForm {...defaultProps} />);
const input = screen.getByPlaceholderText('Enter TOTP');
const button = screen.getByRole('button', { name: 'Verify' });
await user.type(input, '12345');
await user.click(button);
expect(mockSendMfaOtp).not.toHaveBeenCalled();
});
it('does not submit multiple times when already submitting', async () => {
let resolvePromise: (value: any) => void;
const promise = new Promise((resolve) => {
resolvePromise = resolve;
});
mockSendMfaOtp.mockReturnValue(promise);
render(<MfaOtpForm {...defaultProps} />);
const input = screen.getByPlaceholderText('Enter TOTP');
const button = screen.getByRole('button', { name: 'Verify' });
await user.type(input, '123456');
await user.click(button);
await user.click(button); // Second click should be ignored
expect(mockSendMfaOtp).toHaveBeenCalledTimes(1);
// Resolve the promise to clean up
resolvePromise!({ success: true });
await waitFor(async () => {
await promise;
});
});
it('manages submission state properly', async () => {
let resolvePromise: (value: any) => void;
const promise = new Promise((resolve) => {
resolvePromise = resolve;
});
mockSendMfaOtp.mockReturnValue(promise);
render(<MfaOtpForm {...defaultProps} />);
const input = screen.getByPlaceholderText('Enter TOTP');
const button = screen.getByRole('button', { name: 'Verify' });
await user.type(input, '123456');
await user.click(button);
// During submission
expect(button).toBeDisabled();
expect(input).toBeDisabled();
// Resolve the promise
resolvePromise!({ success: true });
await waitFor(async () => {
await promise;
});
// After submission
await waitFor(() => {
expect(button).not.toBeDisabled();
expect(input).not.toBeDisabled();
});
});
});
describe('Error Handling', () => {
it('displays error toast when sendMfaOtp returns an error', async () => {
const errorMessage = 'Invalid TOTP code';
mockSendMfaOtp.mockRejectedValueOnce({ message: errorMessage });
render(<MfaOtpForm {...defaultProps} />);
const input = screen.getByPlaceholderText('Enter TOTP');
const button = screen.getByRole('button', { name: 'Verify' });
await user.type(input, '123456');
await user.click(button);
await waitFor(() => {
expect(mocks.toastError).toHaveBeenCalledWith(errorMessage, {});
});
});
it('shows generic error message when no specific error message is provided', async () => {
mockSendMfaOtp.mockRejectedValueOnce({});
render(<MfaOtpForm {...defaultProps} />);
const input = screen.getByPlaceholderText('Enter TOTP');
const button = screen.getByRole('button', { name: 'Verify' });
await user.type(input, '123456');
await user.click(button);
await waitFor(() => {
expect(mocks.toastError).toHaveBeenCalledWith(
'An error occurred. Please try again.',
{},
);
});
});
it('handles undefined error gracefully', async () => {
mockSendMfaOtp.mockResolvedValue({
error: undefined,
});
render(<MfaOtpForm {...defaultProps} />);
const input = screen.getByPlaceholderText('Enter TOTP');
const button = screen.getByRole('button', { name: 'Verify' });
await user.type(input, '123456');
await user.click(button);
// Should not throw an error
await waitFor(() => {
expect(mockSendMfaOtp).toHaveBeenCalled();
});
});
});
describe('MFA Ticket Renewal', () => {
it('calls requestNewMfaTicket when ticket is invalid', async () => {
// First call - set ticket as invalid
mockSendMfaOtp.mockRejectedValueOnce({ message: 'Invalid ticket' });
// Second call - should work
mockSendMfaOtp.mockResolvedValueOnce({ success: true });
render(<MfaOtpForm {...defaultProps} />);
const input = screen.getByPlaceholderText('Enter TOTP');
const button = screen.getByRole('button', { name: 'Verify' });
// First submission - creates error and marks ticket invalid
await user.type(input, '123456');
await user.click(button);
await waitFor(() => {
expect(mocks.toastError).toHaveBeenCalled();
});
// Clear input and try again
await user.clear(input);
await user.type(input, '654321');
await user.click(button);
await waitFor(() => {
expect(mockRequestNewMfaTicket).toHaveBeenCalled();
});
});
it('does not call requestNewMfaTicket on first submission', async () => {
mockSendMfaOtp.mockResolvedValue({ success: true });
render(<MfaOtpForm {...defaultProps} />);
const input = screen.getByPlaceholderText('Enter TOTP');
const button = screen.getByRole('button', { name: 'Verify' });
await user.type(input, '123456');
await user.click(button);
expect(mockRequestNewMfaTicket).not.toHaveBeenCalled();
});
it('works correctly when requestNewMfaTicket is not provided', async () => {
const propsWithoutTicketRenewal = {
sendMfaOtp: mockSendMfaOtp,
loading: false,
} as any;
mockSendMfaOtp.mockRejectedValueOnce({ message: 'Some error' });
render(<MfaOtpForm {...propsWithoutTicketRenewal} />);
const input = screen.getByPlaceholderText('Enter TOTP');
const button = screen.getByRole('button', { name: 'Verify' });
await user.type(input, '123456');
await user.click(button);
// Should not throw an error even without requestNewMfaTicket
await waitFor(() => {
expect(mocks.toastError).toHaveBeenCalled();
});
});
});
describe('User Interactions', () => {
it('updates input value correctly when typing', async () => {
render(<MfaOtpForm {...defaultProps} />);
const input = screen.getByPlaceholderText('Enter TOTP');
await user.type(input, '123');
expect(input).toHaveValue('123');
await user.type(input, '456');
expect(input).toHaveValue('123456');
});
it('can clear and retype input value', async () => {
render(<MfaOtpForm {...defaultProps} />);
const input = screen.getByPlaceholderText('Enter TOTP');
await user.type(input, '123456');
expect(input).toHaveValue('123456');
await user.clear(input);
expect(input).toHaveValue('');
await user.type(input, '654321');
expect(input).toHaveValue('654321');
});
it('button triggers submission with valid code', async () => {
mockSendMfaOtp.mockResolvedValue({ success: true });
render(<MfaOtpForm {...defaultProps} />);
const input = screen.getByPlaceholderText('Enter TOTP');
const button = screen.getByRole('button', { name: 'Verify' });
await user.type(input, '123456');
await user.click(button);
expect(mockSendMfaOtp).toHaveBeenCalledWith('123456');
});
it('submits form when pressing Enter key with valid code', async () => {
mockSendMfaOtp.mockResolvedValue({ success: true });
render(<MfaOtpForm {...defaultProps} />);
const input = screen.getByPlaceholderText('Enter TOTP');
await user.type(input, '123456');
await user.type(input, '{Enter}');
expect(mockSendMfaOtp).toHaveBeenCalledWith('123456');
expect(mockSendMfaOtp).toHaveBeenCalledTimes(1);
});
it('does not submit when pressing Enter with invalid code length', async () => {
render(<MfaOtpForm {...defaultProps} />);
const input = screen.getByPlaceholderText('Enter TOTP');
await user.type(input, '12345');
await user.type(input, '{Enter}');
expect(mockSendMfaOtp).not.toHaveBeenCalled();
});
it('does not submit when pressing Enter while loading', async () => {
render(<MfaOtpForm {...defaultProps} loading />);
const input = screen.getByPlaceholderText('Enter TOTP');
await user.type(input, '123456');
await user.type(input, '{Enter}');
expect(mockSendMfaOtp).not.toHaveBeenCalled();
});
it('does not submit multiple times when pressing Enter while submitting', async () => {
let resolvePromise: (value: any) => void;
const promise = new Promise((resolve) => {
resolvePromise = resolve;
});
mockSendMfaOtp.mockReturnValue(promise);
render(<MfaOtpForm {...defaultProps} />);
const input = screen.getByPlaceholderText('Enter TOTP');
await user.type(input, '123456');
await user.type(input, '{Enter}');
await user.type(input, '{Enter}'); // Second Enter should be ignored
expect(mockSendMfaOtp).toHaveBeenCalledTimes(1);
// Clean up
resolvePromise!({ success: true });
await waitFor(async () => {
await promise;
});
});
});
describe('Edge Cases', () => {
it('handles null error message gracefully', async () => {
mockSendMfaOtp.mockRejectedValueOnce({ message: null });
render(<MfaOtpForm {...defaultProps} />);
const input = screen.getByPlaceholderText('Enter TOTP');
const button = screen.getByRole('button', { name: 'Verify' });
await user.type(input, '123456');
await user.click(button);
await waitFor(() => {
expect(mocks.toastError).toHaveBeenCalledWith(
'An error occurred. Please try again.',
{},
);
});
});
it('prevents multiple rapid submissions', async () => {
let resolvePromise: (value: any) => void;
const promise = new Promise((resolve) => {
resolvePromise = resolve;
});
mockSendMfaOtp.mockReturnValue(promise);
render(<MfaOtpForm {...defaultProps} />);
const input = screen.getByPlaceholderText('Enter TOTP');
const button = screen.getByRole('button', { name: 'Verify' });
await user.type(input, '123456');
// Rapid clicks
await user.click(button);
await user.click(button);
await user.click(button);
expect(mockSendMfaOtp).toHaveBeenCalledTimes(1);
// Clean up
resolvePromise!({ success: true });
await waitFor(async () => {
await promise;
});
});
it('handles empty input correctly', async () => {
render(<MfaOtpForm {...defaultProps} />);
const button = screen.getByRole('button', { name: 'Verify' });
await user.click(button);
expect(mockSendMfaOtp).not.toHaveBeenCalled();
expect(button).toBeDisabled();
});
});
});

View File

@@ -0,0 +1,87 @@
import { Button } from '@/components/ui/v3/button';
import { Input } from '@/components/ui/v3/input';
import { getToastStyleProps } from '@/utils/constants/settings';
import {
useEffect,
useRef,
useState,
type ChangeEvent,
type KeyboardEvent,
} from 'react';
import toast from 'react-hot-toast';
interface Props {
sendMfaOtp: (code: string) => Promise<any>;
loading: boolean;
requestNewMfaTicket?: () => Promise<void>;
}
function MfaOtpForm({ sendMfaOtp, loading, requestNewMfaTicket }: Props) {
const [otpValue, setOtpValue] = useState<string>('');
const [isSubmitting, setIsSubmitting] = useState<boolean>(false);
const inputRef = useRef<HTMLInputElement | null>(null);
const isMfaTicketInvalid = useRef(false);
useEffect(() => {
if (inputRef.current) {
inputRef.current.focus();
}
}, []);
async function submitTOTP() {
if (otpValue.length === 6 && !isSubmitting) {
try {
setIsSubmitting(true);
if (requestNewMfaTicket && isMfaTicketInvalid.current) {
await requestNewMfaTicket();
}
await sendMfaOtp(otpValue);
} catch (error) {
isMfaTicketInvalid.current = true;
toast.error(
error?.message || 'An error occurred. Please try again.',
getToastStyleProps(),
);
setTimeout(() => {
inputRef.current?.focus();
}, 10);
} finally {
setIsSubmitting(false);
}
}
}
async function handleChange(event: ChangeEvent<HTMLInputElement>) {
const code = event.target.value.replace(/[^0-9]/g, '');
setOtpValue(code);
}
async function handleKeyDown(event: KeyboardEvent<HTMLInputElement>) {
if (event.key === 'Enter') {
submitTOTP();
}
}
const isInputDisabled = loading || isSubmitting;
const isButtonDisabled = isInputDisabled || otpValue.length !== 6;
return (
<div className="relative grid w-full grid-flow-row gap-4 bg-transparent">
<Input
ref={inputRef}
value={otpValue}
placeholder="Enter TOTP"
className="!bg-transparent"
disabled={isInputDisabled}
onChange={handleChange}
onKeyDown={handleKeyDown}
/>
<Button disabled={isButtonDisabled} onClick={submitTOTP}>
{loading ? 'Verifying...' : 'Verify'}
</Button>
</div>
);
}
export default MfaOtpForm;

View File

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

View File

@@ -1,11 +1,13 @@
import type { LinkProps } from '@/components/ui/v2/Link'; import type { LinkProps } from '@/components/ui/v2/Link';
import { Link } from '@/components/ui/v2/Link'; import { Link } from '@/components/ui/v2/Link';
import type { MakeRequired } from '@/types/common';
import NextLink from 'next/link'; import NextLink from 'next/link';
import type { ForwardedRef, PropsWithoutRef } from 'react'; import type { ForwardedRef, PropsWithoutRef } from 'react';
import { forwardRef } from 'react'; import { forwardRef } from 'react';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
export interface NavLinkProps extends PropsWithoutRef<LinkProps> { export interface NavLinkProps
extends MakeRequired<PropsWithoutRef<LinkProps>, 'href'> {
/** /**
* Determines whether or not the link should be disabled. * Determines whether or not the link should be disabled.
*/ */

View File

@@ -5,7 +5,7 @@ import { useIsCurrentUserOwner } from '@/features/orgs/projects/common/hooks/use
interface Props { interface Props {
buttonText?: string; buttonText?: string;
onClick?: () => void; onClick: () => void;
} }
function OpenTransferDialogButton({ buttonText, onClick }: Props) { function OpenTransferDialogButton({ buttonText, onClick }: Props) {

View File

@@ -19,7 +19,7 @@ export type PaginationProps = DetailedHTMLProps<
/** /**
* Number of total elements per page. * Number of total elements per page.
*/ */
elementsPerPage?: number; elementsPerPage: number;
/** /**
* Total number of elements. * Total number of elements.
*/ */

View File

@@ -7,7 +7,6 @@ import { List } from '@/components/ui/v2/List';
import { ListItem } from '@/components/ui/v2/ListItem'; import { ListItem } from '@/components/ui/v2/ListItem';
import { Text } from '@/components/ui/v2/Text'; import { Text } from '@/components/ui/v2/Text';
import { useOrgs } from '@/features/orgs/projects/hooks/useOrgs'; import { useOrgs } from '@/features/orgs/projects/hooks/useOrgs';
import {} from '@/utils/__generated__/graphql';
import { Divider } from '@mui/material'; import { Divider } from '@mui/material';
import debounce from 'lodash.debounce'; import debounce from 'lodash.debounce';
import Image from 'next/image'; import Image from 'next/image';

View File

@@ -1,7 +1,6 @@
import { render, screen } from '@/tests/orgs/testUtils'; import { render, screen, TestUserEvent } from '@/tests/testUtils';
import { guessTimezone } from '@/utils/timezoneUtils'; import { guessTimezone } from '@/utils/timezoneUtils';
import { TZDate } from '@date-fns/tz'; import { TZDate } from '@date-fns/tz';
import userEvent from '@testing-library/user-event';
import { parseISO } from 'date-fns'; import { parseISO } from 'date-fns';
import { format } from 'date-fns-v4'; import { format } from 'date-fns-v4';
import { useState } from 'react'; import { useState } from 'react';
@@ -36,7 +35,7 @@ describe('TimePicker', () => {
expect(await screen.getByText(/Time:/i)).toHaveTextContent( expect(await screen.getByText(/Time:/i)).toHaveTextContent(
'Time: 03:00:05', 'Time: 03:00:05',
); );
const user = userEvent.setup(); const user = new TestUserEvent();
const hoursInput = await screen.getByLabelText('Hours'); const hoursInput = await screen.getByLabelText('Hours');
await user.type(hoursInput, '18'); await user.type(hoursInput, '18');
expect(await screen.getByText(/Time:/i)).toHaveTextContent( expect(await screen.getByText(/Time:/i)).toHaveTextContent(
@@ -46,7 +45,7 @@ describe('TimePicker', () => {
test('only valid hours(0-23), minutes(0-59) and seconds(0-59) are allowed', async () => { test('only valid hours(0-23), minutes(0-59) and seconds(0-59) are allowed', async () => {
render(<TestComponent dateTime="2025-03-10T03:00:05" />); render(<TestComponent dateTime="2025-03-10T03:00:05" />);
const user = userEvent.setup(); const user = new TestUserEvent();
const hoursInput = await screen.getByLabelText('Hours'); const hoursInput = await screen.getByLabelText('Hours');
await user.type(hoursInput, '30'); await user.type(hoursInput, '30');
expect(await screen.getByText(/Time:/i)).toHaveTextContent( expect(await screen.getByText(/Time:/i)).toHaveTextContent(
@@ -61,7 +60,7 @@ describe('TimePicker', () => {
test('Updates only the minutes of the date object', async () => { test('Updates only the minutes of the date object', async () => {
render(<TestComponent dateTime="2025-03-10T03:00:05" />); render(<TestComponent dateTime="2025-03-10T03:00:05" />);
const user = userEvent.setup(); const user = new TestUserEvent();
const minutesInput = await screen.getByLabelText('Minutes'); const minutesInput = await screen.getByLabelText('Minutes');
await user.type(minutesInput, '44'); await user.type(minutesInput, '44');
expect(await screen.getByText(/Time:/i)).toHaveTextContent( expect(await screen.getByText(/Time:/i)).toHaveTextContent(
@@ -71,7 +70,7 @@ describe('TimePicker', () => {
test('Updates only the seconds of the date object', async () => { test('Updates only the seconds of the date object', async () => {
render(<TestComponent dateTime="2025-03-10T03:00:05" />); render(<TestComponent dateTime="2025-03-10T03:00:05" />);
const user = userEvent.setup(); const user = new TestUserEvent();
const secondsInput = await screen.getByLabelText('Seconds'); const secondsInput = await screen.getByLabelText('Seconds');
await user.type(secondsInput, '11'); await user.type(secondsInput, '11');
expect(await screen.getByText(/Time:/i)).toHaveTextContent( expect(await screen.getByText(/Time:/i)).toHaveTextContent(
@@ -84,7 +83,7 @@ describe('TimePicker', () => {
expect(await screen.getByText(/Date class:/i)).toHaveTextContent( expect(await screen.getByText(/Date class:/i)).toHaveTextContent(
'Date class: TZDate', 'Date class: TZDate',
); );
const user = userEvent.setup(); const user = new TestUserEvent();
const hoursInput = await screen.getByLabelText('Hours'); const hoursInput = await screen.getByLabelText('Hours');
await user.type(hoursInput, '18'); await user.type(hoursInput, '18');

View File

@@ -7,7 +7,7 @@ import { TimePickerInput } from './TimePickerInput';
interface TimePickerProps { interface TimePickerProps {
date: Date | undefined; date: Date | undefined;
setDate: (date: Date | undefined) => void; setDate: (date: Date) => void;
} }
function TimePicker({ date, setDate }: TimePickerProps) { function TimePicker({ date, setDate }: TimePickerProps) {

View File

@@ -3,19 +3,19 @@ import { Input } from '@/components/ui/v3/input';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import React from 'react'; import React from 'react';
import { import {
type Period,
type TimePickerType,
copyDate, copyDate,
getArrowByType, getArrowByType,
getDateByType, getDateByType,
setDateByType, setDateByType,
type Period,
type TimePickerType,
} from './time-picker-utils'; } from './time-picker-utils';
export interface TimePickerInputProps export interface TimePickerInputProps
extends React.InputHTMLAttributes<HTMLInputElement> { extends React.InputHTMLAttributes<HTMLInputElement> {
picker: TimePickerType; picker: TimePickerType;
date: Date | undefined; date: Date | undefined;
setDate: (date: Date | undefined) => void; setDate: (date: Date) => void;
period?: Period; period?: Period;
onRightFocus?: () => void; onRightFocus?: () => void;
onLeftFocus?: () => void; onLeftFocus?: () => void;

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; return date instanceof TZDate;
} }

View File

@@ -9,6 +9,26 @@ interface Props {
dateTime: string; 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({ function TimezonePicker({
selectedTimezone, selectedTimezone,
onTimezoneSelect, onTimezoneSelect,
@@ -16,9 +36,10 @@ function TimezonePicker({
dateTime, dateTime,
}: Props) { }: Props) {
const timezoneOptions = useMemo( const timezoneOptions = useMemo(
() => createTimezoneOptions(dateTime), () => getOrderedTimezones(dateTime, selectedTimezone),
[dateTime], [dateTime, selectedTimezone],
); );
return ( return (
<VirtualizedCombobox <VirtualizedCombobox
options={timezoneOptions} options={timezoneOptions}
@@ -27,6 +48,7 @@ function TimezonePicker({
searchPlaceholder="Search timezones..." searchPlaceholder="Search timezones..."
button={button} button={button}
side="right" side="right"
width="370px"
/> />
); );
} }

View File

@@ -8,7 +8,7 @@ export interface UIContextProps {
/** /**
* The date and time when maintenance mode will end. * The date and time when maintenance mode will end.
*/ */
maintenanceEndDate: Date; maintenanceEndDate: Date | null;
} }
const UIContext = createContext<UIContextProps>({ const UIContext = createContext<UIContextProps>({

View File

@@ -24,7 +24,7 @@ type Option = {
}; };
interface VirtualizedCommandProps<O extends Option> { interface VirtualizedCommandProps<O extends Option> {
height: string; height?: string;
options: O[]; options: O[];
placeholder: string; placeholder: string;
selectedOption: string; selectedOption: string;
@@ -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 ( return (
<Command shouldFilter={false} onKeyDown={handleKeyDown}> <Command
shouldFilter={false}
onKeyDown={handleKeyDown}
value={selectedOption}
>
<CommandInput onValueChange={handleSearch} placeholder={placeholder} /> <CommandInput onValueChange={handleSearch} placeholder={placeholder} />
<CommandList <CommandList
ref={parentRef} ref={parentRef}
@@ -145,7 +137,6 @@ function VirtualizedCommand<O extends Option>({
filteredOptions[virtualOption.index].key ?? filteredOptions[virtualOption.index].key ??
filteredOptions[virtualOption.index].value filteredOptions[virtualOption.index].value
} }
disabled={isKeyboardNavActive}
className={cn( className={cn(
'absolute left-0 top-0 w-full bg-transparent', 'absolute left-0 top-0 w-full bg-transparent',
focusedIndex === virtualOption.index && focusedIndex === virtualOption.index &&
@@ -190,7 +181,7 @@ interface VirtualizedComboboxProps<O extends Option> {
width?: string; width?: string;
height?: string; height?: string;
button?: React.JSX.Element; button?: React.JSX.Element;
onSelectOption?: (option: O) => void; onSelectOption: (option: O) => void;
selectedOption: string; selectedOption: string;
align?: 'start' | 'center' | 'end'; align?: 'start' | 'center' | 'end';
side?: 'right' | 'top' | 'bottom' | 'left'; side?: 'right' | 'top' | 'bottom' | 'left';
@@ -219,7 +210,7 @@ function VirtualizedCombobox<O extends Option>({
}} }}
> >
{selectedOption {selectedOption
? options.find((option) => option.value === selectedOption).value ? options.find((option) => option.value === selectedOption)!.value
: searchPlaceholder} : searchPlaceholder}
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" /> <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button> </Button>

View File

@@ -1,67 +0,0 @@
import { render, screen } from '@/tests/testUtils';
import type { Column } from 'react-table';
import { expect, test } from 'vitest';
import DataGrid from './DataGrid';
interface MockDataDetails {
id: number;
name: string;
}
const mockColumns: Column<MockDataDetails>[] = [
{ id: 'id', Header: 'ID', accessor: 'id' },
{ id: 'name', Header: 'Name', accessor: 'name' },
];
const mockData: MockDataDetails[] = [
{ id: 1, name: 'foo' },
{ id: 2, name: 'bar' },
];
test('should render an empty state if columns are not available', () => {
render(<DataGrid columns={[]} data={[]} />);
expect(screen.getByText(/columns not found/i)).toBeInTheDocument();
});
test('should render columns and empty state message if data is unavailable', () => {
render(<DataGrid columns={mockColumns} data={[]} />);
expect(screen.getByRole('table')).toBeInTheDocument();
expect(screen.getByRole('columnheader', { name: /id/i })).toBeInTheDocument();
expect(
screen.getByRole('columnheader', { name: /name/i }),
).toBeInTheDocument();
expect(screen.getByText(/no data is available/i)).toBeInTheDocument();
});
test('should render custom empty state message if data is unavailable', () => {
const customEmptyStateMessage = 'custom empty state message';
render(
<DataGrid
columns={mockColumns}
data={[]}
emptyStateMessage={customEmptyStateMessage}
/>,
);
expect(screen.getByText(customEmptyStateMessage)).toBeInTheDocument();
});
test('should display a loading indicator', async () => {
render(<DataGrid columns={mockColumns} data={[]} loading />);
// Activity indicator is not immediately displayed, so we need to wait
expect(await screen.findByRole('progressbar')).toBeInTheDocument();
});
test('should render data if provided', () => {
render(<DataGrid columns={mockColumns} data={mockData} />);
expect(screen.getAllByRole('row')).toHaveLength(2);
expect(screen.getByRole('cell', { name: /1/i })).toBeInTheDocument();
expect(screen.getByRole('cell', { name: /foo/i })).toBeInTheDocument();
});

View File

@@ -1,185 +0,0 @@
import type { UseDataGridOptions } from '@/components/dataGrid/DataGrid/useDataGrid';
import { DataGridBody } from '@/components/dataGrid/DataGridBody';
import { DataGridConfigProvider } from '@/components/dataGrid/DataGridConfigProvider';
import { DataGridFrame } from '@/components/dataGrid/DataGridFrame';
import type { DataGridHeaderProps } from '@/components/dataGrid/DataGridHeader';
import { DataGridHeader } from '@/components/dataGrid/DataGridHeader';
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
import { Box } from '@/components/ui/v2/Box';
import { DataBrowserEmptyState } from '@/features/database/dataGrid/components/DataBrowserEmptyState';
import type { DataBrowserGridColumn } from '@/features/database/dataGrid/types/dataBrowser';
import type { ForwardedRef } from 'react';
import { forwardRef, useEffect, useRef } from 'react';
import mergeRefs from 'react-merge-refs';
import type { Column, Row, SortingRule, TableOptions } from 'react-table';
import { twMerge } from 'tailwind-merge';
import useDataGrid from './useDataGrid';
export interface DataGridProps<TColumnData extends object>
extends Omit<UseDataGridOptions<TColumnData>, 'tableRef'> {
/**
* Available columns.
*/
columns: Column<TColumnData>[];
/**
* Data to be displayed in the table.
*/
data: any[];
/**
* Text to be displayed when no data is available in the data grid.
*
* @default null
*/
emptyStateMessage?: string;
/**
* Additional configuration options for the `react-table` hook.
*/
options?: Omit<TableOptions<TColumnData>, 'columns' | 'data'>;
/**
* Additional data grid controls. This component will be part of the Data Grid
* context, so it can use Data Grid configuration.
*/
controls?:
| React.ReactNode
| ((selectedFlatRows: Row<TColumnData>[]) => React.ReactNode);
/**
* Function to be called when columns are sorted in the table.
*/
onSort?: (args: SortingRule<TColumnData>[]) => void;
/**
* Function to be called when the user wants to insert a new row.
*/
onInsertRow?: VoidFunction;
/**
* Function to be called when the user wants to insert a new column.
*/
onInsertColumn?: VoidFunction;
/**
* Function to be called when the user wants to remove a column.
*/
onRemoveColumn?: (column: DataBrowserGridColumn<TColumnData>) => void;
/**
* Function to be called when the user wants to edit a column.
*/
onEditColumn?: (column: DataBrowserGridColumn<TColumnData>) => void;
/**
* Determines whether or not data is loading.
*/
loading?: boolean;
/**
* Class name to be applied to the data grid.
*/
className?: string;
/**
* Sort configuration.
*/
sortBy?: SortingRule<TColumnData>[];
/**
* Props to be passed to the `DataGridHeader` component.
*/
headerProps?: DataGridHeaderProps<TColumnData>;
}
function DataGrid<TColumnData extends object>(
{
columns,
data,
allowSelection,
allowSort,
allowResize,
emptyStateMessage,
options = {},
headerProps,
controls,
sortBy,
onSort,
onInsertRow,
onInsertColumn,
onEditColumn,
onRemoveColumn,
loading,
className,
}: DataGridProps<TColumnData>,
ref: ForwardedRef<HTMLDivElement>,
) {
const tableRef = useRef<HTMLDivElement>();
const { toggleAllRowsSelected, setSortBy, ...dataGridProps } =
useDataGrid<TColumnData>({
columns: columns || [],
data: data || [],
allowSelection,
allowSort,
allowResize,
...options,
});
useEffect(() => {
if (!sortBy && setSortBy) {
setSortBy([]);
}
}, [setSortBy, sortBy]);
useEffect(() => {
if (onSort && allowSort) {
onSort(dataGridProps.state.sortBy);
if (toggleAllRowsSelected) {
toggleAllRowsSelected(false);
}
}
}, [allowSort, dataGridProps.state.sortBy, onSort, toggleAllRowsSelected]);
return (
<DataGridConfigProvider
toggleAllRowsSelected={toggleAllRowsSelected}
setSortBy={setSortBy}
tableRef={tableRef}
{...dataGridProps}
>
<>
{controls}
{columns.length === 0 && !loading && (
<DataBrowserEmptyState
title="Columns not found"
description="Please create a column before adding data to the table."
/>
)}
{columns.length > 0 && (
<Box
ref={mergeRefs([ref, tableRef])}
sx={{ backgroundColor: 'background.default' }}
className={twMerge(
'overflow-x-auto',
!loading && 'h-full',
className,
)}
>
<DataGridFrame>
<DataGridHeader
onInsertColumn={onInsertColumn}
onEditColumn={onEditColumn}
onRemoveColumn={onRemoveColumn}
{...headerProps}
/>
<DataGridBody
emptyStateMessage={emptyStateMessage}
loading={loading}
onInsertRow={onInsertRow}
allowInsertColumn={Boolean(onRemoveColumn)}
/>
</DataGridFrame>
</Box>
)}
{loading && <ActivityIndicator delay={1000} className="my-4" />}
</>
</DataGridConfigProvider>
);
}
export default forwardRef(DataGrid) as <TColumnData extends object>(
props: DataGridProps<TColumnData> & { ref?: ForwardedRef<HTMLDivElement> },
) => ReturnType<typeof DataGrid>;

View File

@@ -1,4 +0,0 @@
export * from './DataGrid';
export { default as DataGrid } from './DataGrid';
export * from './useDataGrid';
export { default as useDataGrid } from './useDataGrid';

View File

@@ -1,110 +0,0 @@
import { Checkbox } from '@/components/ui/v2/Checkbox';
import type { MutableRefObject } from 'react';
import { useMemo } from 'react';
import type { PluginHook, TableInstance, TableOptions } from 'react-table';
import {
useBlockLayout,
useResizeColumns,
useRowSelect,
useSortBy,
useTable,
} from 'react-table';
export interface UseDataGridBaseOptions {
/**
* Determines whether data grid columns are selectable.
*
* @default false
*/
allowSelection?: boolean;
/**
* Determines whether data grid columns are sortable.
*
* @default false
*/
allowSort?: boolean;
/**
* Determine whether data grid columns are resizable.
*
* @default false
*/
allowResize?: boolean;
/**
* Reference to the data grid root element.
*/
tableRef?: MutableRefObject<HTMLDivElement>;
}
export type UseDataGridOptions<T extends object = {}> = TableOptions<T> &
UseDataGridBaseOptions;
export type UseDataGridReturn<T extends object = {}> = TableInstance<T> &
UseDataGridBaseOptions;
export default function useDataGrid<T extends object>(
{ allowSelection, allowSort, allowResize, ...options }: UseDataGridOptions<T>,
...plugins: PluginHook<T>[]
): UseDataGridReturn<T> {
const defaultColumn = useMemo(
() => ({
width: 32,
minWidth: 32,
Cell: ({ value }: { value: any }) => (
<span className="truncate">
{typeof value === 'object' ? JSON.stringify(value) : value}
</span>
),
}),
[],
);
const pluginHooks = [
useBlockLayout,
useResizeColumns,
useSortBy,
useRowSelect,
];
const tableData = useTable<T>(
{
defaultColumn,
...options,
},
...pluginHooks,
...plugins,
(hooks) =>
allowSelection
? hooks.visibleColumns.push((columns) => [
{
id: 'selection',
Header: ({ rows, getToggleAllRowsSelectedProps }: any) => (
<Checkbox
disabled={rows.length === 0}
{...getToggleAllRowsSelectedProps({ style: null })}
style={{
...getToggleAllRowsSelectedProps().style,
cursor: rows.length === 0 ? 'default' : 'pointer',
}}
/>
),
Cell: ({ row }: any) => {
const originalValue = row.original as any;
return (
<Checkbox
{...row.getToggleRowSelectedProps()}
// disable selection if row is just a upload preview
checked={originalValue.uploading ? false : row.isSelected}
disabled={originalValue.uploading}
/>
);
},
disableSortBy: true,
disableResizing: true,
},
...columns,
])
: hooks.visibleColumns,
);
return { ...tableData, allowSort, allowResize, allowSelection };
}

View File

@@ -1,315 +0,0 @@
import type { DataGridProps } from '@/components/dataGrid/DataGrid';
import { DataGridCell } from '@/components/dataGrid/DataGridCell';
import { useDataGridConfig } from '@/components/dataGrid/DataGridConfigProvider';
import type { BoxProps } from '@/components/ui/v2/Box';
import { Box } from '@/components/ui/v2/Box';
import { Button } from '@/components/ui/v2/Button';
import { PlusIcon } from '@/components/ui/v2/icons/PlusIcon';
import type { DataBrowserGridColumn } from '@/features/database/dataGrid/types/dataBrowser';
import type { DetailedHTMLProps, HTMLProps, KeyboardEvent } from 'react';
import { Fragment, useMemo, useRef } from 'react';
import type { Row } from 'react-table';
import { twMerge } from 'tailwind-merge';
export interface DataGridBodyProps<T extends object>
extends Omit<
DetailedHTMLProps<HTMLProps<HTMLDivElement>, HTMLDivElement>,
'children'
>,
Pick<DataGridProps<T>, 'onInsertRow' | 'emptyStateMessage' | 'loading'> {
/**
* Determines whether column insertion is allowed.
*/
allowInsertColumn?: boolean;
}
interface InsertPlaceholderTableRowProps extends BoxProps {
/**
* Function to be called when the user wants to insert a new row.
*/
onInsertRow: VoidFunction;
}
function InsertPlaceholderTableRow({
onInsertRow,
...props
}: InsertPlaceholderTableRowProps) {
return (
<Box className="h-12 border-b-1 border-r-1" {...props}>
<Button
onClick={onInsertRow}
variant="borderless"
color="secondary"
className="h-full w-full justify-start rounded-none px-2 py-3 text-xs font-normal hover:shadow-none focus:shadow-none focus:outline-none"
startIcon={
<PlusIcon className="h-4 w-4" sx={{ color: 'text.secondary' }} />
}
>
Insert New Row
</Button>
</Box>
);
}
// TODO: Get rid of Data Browser related code from here. This component should
// be generic and not depend on Data Browser related data types and logic.
export default function DataGridBody<T extends object>({
emptyStateMessage = 'No data is available',
loading,
onInsertRow,
allowInsertColumn,
...props
}: DataGridBodyProps<T>) {
const { getTableBodyProps, totalColumnsWidth, rows, prepareRow, columns } =
useDataGridConfig<T>();
const SELECTION_CELL_WIDTH = 32;
const ADD_COLUMN_CELL_WIDTH = 100;
const bodyRef = useRef<HTMLDivElement>();
const primaryAndUniqueKeys = useMemo(
() =>
columns
.filter(
(column: DataBrowserGridColumn<T>) =>
column.isPrimary || column.isUnique,
)
.map((column) => column.id),
[columns],
);
function handleKeyDown(event: KeyboardEvent<HTMLDivElement>, row: Row<T>) {
const { id: rowId } = row;
const cellId = document.activeElement.id;
const currentRow = bodyRef.current.children.namedItem(rowId);
if (event.key === 'ArrowUp') {
event.preventDefault();
if (!currentRow.previousElementSibling) {
return;
}
const cellInPreviousRow =
currentRow.previousElementSibling.children.namedItem(cellId);
if (cellInPreviousRow instanceof HTMLElement) {
cellInPreviousRow.scrollIntoView({
block: 'nearest',
});
cellInPreviousRow.focus();
}
}
if (event.key === 'ArrowDown') {
event.preventDefault();
if (!currentRow.nextElementSibling) {
return;
}
const cellInNextRow =
currentRow.nextElementSibling.children.namedItem(cellId);
if (cellInNextRow instanceof HTMLElement) {
cellInNextRow.scrollIntoView({ block: 'nearest' });
cellInNextRow.focus();
}
}
if (event.key === 'ArrowLeft' || (event.shiftKey && event.key === 'Tab')) {
let previousFocusableCellInRow: HTMLElement;
let previousFocusableCellInRowFound = false;
currentRow.childNodes.forEach((node) => {
if (node === currentRow.children.namedItem(cellId)) {
previousFocusableCellInRowFound = true;
}
if (
node instanceof HTMLElement &&
node.tabIndex > -1 &&
!previousFocusableCellInRowFound
) {
previousFocusableCellInRow = node;
}
});
if (previousFocusableCellInRow) {
event.preventDefault();
previousFocusableCellInRow.scrollIntoView({
block: 'nearest',
inline: 'center',
});
previousFocusableCellInRow.focus();
}
}
if (
event.key === 'ArrowRight' ||
(!event.shiftKey && event.key === 'Tab')
) {
let nextFocusableCellInRow: HTMLElement;
let nextFocusableCellInRowFound = false;
currentRow.childNodes.forEach((node) => {
if (
node instanceof HTMLElement &&
node.tabIndex > -1 &&
parseInt(node.id, 10) > parseInt(cellId, 10) &&
!nextFocusableCellInRowFound
) {
nextFocusableCellInRowFound = true;
nextFocusableCellInRow = node;
}
});
if (nextFocusableCellInRow) {
event.preventDefault();
nextFocusableCellInRow.scrollIntoView({
block: 'nearest',
inline: 'center',
});
nextFocusableCellInRow.focus();
}
}
}
const getBackgroundCellColor = (
row: Row<T>,
column: DataBrowserGridColumn<T>,
) => {
// Grey out files not uploaded
if (!row.values.isUploaded) {
return 'grey.200';
}
if (column.isDisabled) {
return 'grey.100';
}
return 'background.paper';
};
return (
<div {...getTableBodyProps()} ref={bodyRef} {...props}>
{rows.length === 0 && !loading && (
<div className="flex flex-nowrap pr-5">
{onInsertRow ? (
<InsertPlaceholderTableRow
style={{
width: allowInsertColumn
? totalColumnsWidth + ADD_COLUMN_CELL_WIDTH
: totalColumnsWidth - SELECTION_CELL_WIDTH,
}}
onInsertRow={onInsertRow}
/>
) : (
<Box
className="inline-flex h-12 items-center border-b-1 border-r-1 px-2 py-1.5 text-xs"
sx={{ color: 'text.secondary' }}
style={{
width: allowInsertColumn
? totalColumnsWidth + ADD_COLUMN_CELL_WIDTH
: totalColumnsWidth,
}}
>
{emptyStateMessage}
</Box>
)}
</div>
)}
{rows.map((row, index) => {
let rowKey = index.toString();
if (primaryAndUniqueKeys && primaryAndUniqueKeys.length > 0) {
rowKey = primaryAndUniqueKeys
.map((key) => row.values[key])
.filter(Boolean)
.join('-');
} else {
rowKey = `${index}-${Object.keys(row.values)
.map((key) => String(row.values[key]))
.join('-')}`;
}
prepareRow(row);
const rowProps = row.getRowProps({
style: {
width: allowInsertColumn
? totalColumnsWidth + ADD_COLUMN_CELL_WIDTH
: totalColumnsWidth,
},
});
return (
<Fragment key={rowKey.toString()}>
<div
{...rowProps}
id={row.id}
className="flex scroll-mt-10"
role="row"
onKeyDown={(event) => handleKeyDown(event, row)}
tabIndex={-1}
>
{row.cells.map((cell, cellIndex) => {
const column = cell.column as DataBrowserGridColumn<T>;
const isCellDisabled =
cell.value !== 0 &&
!cell.value &&
column.type !== 'boolean' &&
column.id !== 'selection' &&
column.isDisabled;
return (
<DataGridCell
{...cell.getCellProps({
style: {
display: 'inline-flex',
alignItems: 'center',
},
})}
cell={cell}
sx={{
backgroundColor: getBackgroundCellColor(row, column),
color: isCellDisabled ? 'text.secondary' : 'text.primary',
}}
className={twMerge(
'h-12 font-display text-xs motion-safe:transition-colors',
'border-b-1 border-r-1',
'scroll-ml-8 scroll-mt-[57px]',
column.id === 'selection' &&
'sticky left-0 z-20 justify-center px-0',
)}
isEditable={!column.isDisabled && column.isEditable}
id={cellIndex.toString()}
key={column.id}
>
{cell.render('Cell')}
</DataGridCell>
);
})}
{allowInsertColumn && (
<Box className="h-12 w-25 border-b-1 border-r-1" />
)}
</div>
{onInsertRow && index === rows.length - 1 && (
<InsertPlaceholderTableRow
{...rowProps}
key=""
onInsertRow={onInsertRow}
/>
)}
</Fragment>
);
})}
</div>
);
}

View File

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

View File

@@ -1,121 +0,0 @@
import type { CommonDataGridCellProps } from '@/components/dataGrid/DataGridCell';
import { useDataGridCell } from '@/components/dataGrid/DataGridCell';
import { ReadOnlyToggle } from '@/components/presentational/ReadOnlyToggle';
import { Dropdown } from '@/components/ui/v2/Dropdown';
import type { MouseEvent, KeyboardEvent as ReactKeyboardEvent } from 'react';
import { twMerge } from 'tailwind-merge';
export type DataGridBooleanCellProps<TData extends object> =
CommonDataGridCellProps<TData, boolean | null>;
export default function DataGridBooleanCell<TData extends object>({
onSave,
optimisticValue,
temporaryValue,
onTemporaryValueChange,
cell: {
column: { isNullable },
},
}: DataGridBooleanCellProps<TData>) {
const {
inputRef,
isEditing,
focusCell,
editCell,
cancelEditCell,
isSelected,
} = useDataGridCell<HTMLInputElement>();
async function handleMenuClick(
event: MouseEvent<HTMLLIElement> | ReactKeyboardEvent<HTMLLIElement>,
value: boolean | null,
) {
event.stopPropagation();
await onSave(value);
cancelEditCell();
}
async function handleMenuKeyDown(event: ReactKeyboardEvent<HTMLDivElement>) {
if (
event.key === 'ArrowLeft' ||
event.key === 'ArrowRight' ||
event.key === 'ArrowUp' ||
event.key === 'ArrowDown'
) {
event.stopPropagation();
}
// We need to restore the temporary value, because editing was cancelled
if (event.key === 'Escape' && onTemporaryValueChange) {
event.stopPropagation();
onTemporaryValueChange(optimisticValue);
cancelEditCell();
}
if (event.key === 'Tab' && onSave) {
await onSave(temporaryValue);
cancelEditCell();
}
}
function handleTemporaryValueChange(value: boolean | null) {
if (onTemporaryValueChange) {
onTemporaryValueChange(value);
}
}
return isSelected ? (
<Dropdown.Root id="boolean-data-editor" className="h-full w-full">
<Dropdown.Trigger
id="boolean-trigger"
className={twMerge(
'h-full w-full border-none p-0 outline-none',
isEditing && 'p-1.5',
)}
ref={inputRef}
onClick={editCell}
autoFocus={false}
sx={{ '&:hover': { backgroundColor: 'transparent !important' } }}
>
<ReadOnlyToggle checked={optimisticValue} />
</Dropdown.Trigger>
<Dropdown.Content
menu
disablePortal
onKeyDown={handleMenuKeyDown}
PaperProps={{ className: 'w-[200px]' }}
TransitionProps={{ onExited: focusCell }}
>
<Dropdown.Item
selected={optimisticValue === true}
onKeyUp={() => handleTemporaryValueChange(true)}
onClick={(event) => handleMenuClick(event, true)}
>
<ReadOnlyToggle checked />
</Dropdown.Item>
<Dropdown.Item
selected={optimisticValue === false}
onKeyUp={() => handleTemporaryValueChange(false)}
onClick={(event) => handleMenuClick(event, false)}
>
<ReadOnlyToggle checked={false} />
</Dropdown.Item>
{isNullable && (
<Dropdown.Item
selected={optimisticValue === null}
onKeyUp={() => handleTemporaryValueChange(null)}
onClick={(event) => handleMenuClick(event, null)}
>
<ReadOnlyToggle checked={null} />
</Dropdown.Item>
)}
</Dropdown.Content>
</Dropdown.Root>
) : (
<ReadOnlyToggle checked={optimisticValue} />
);
}

View File

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

View File

@@ -1,381 +0,0 @@
import { useDialog } from '@/components/common/DialogProvider';
import type { BoxProps } from '@/components/ui/v2/Box';
import { Box } from '@/components/ui/v2/Box';
import { Tooltip, useTooltip } from '@/components/ui/v2/Tooltip';
import type {
ColumnType,
DataBrowserGridCell,
DataBrowserGridCellProps,
} from '@/features/database/dataGrid/types/dataBrowser';
import { triggerToast } from '@/utils/toast';
import type {
FocusEvent,
JSXElementConstructor,
KeyboardEvent,
MouseEvent,
ReactElement,
ReactNode,
ReactPortal,
} from 'react';
import {
Children,
cloneElement,
isValidElement,
useEffect,
useState,
} from 'react';
import { twMerge } from 'tailwind-merge';
import DataGridCellProvider from './DataGridCellProvider';
import useDataGridCell from './useDataGridCell';
export interface CommonDataGridCellProps<TData extends object, TValue = any>
extends DataBrowserGridCellProps<TData, TValue> {
/**
* Function that is called when the cell is saved.
*/
onSave?: (value: TValue, options?: { reset: boolean }) => Promise<void>;
/**
* Optimistic value for the cell.
*/
optimisticValue?: TValue;
/**
* Function to be called when the optimistic value should be changed.
*/
onOptimisticValueChange?: (value: TValue) => void;
/**
* Temporary value for the cell. This is used for storing the current input
* value, that should be later saved as an optimistic value before saving the
* data.
*/
temporaryValue?: TValue;
/**
* Function to be called when the temporary value should be changed.
*/
onTemporaryValueChange?: (value: TValue) => void;
}
export interface DataGridCellProps<TData extends object, TValue = unknown>
extends BoxProps {
/**
* Current cell's props.
*/
cell: DataBrowserGridCell<TData, TValue>;
/**
* Determines whether the cell is editable.
*/
isEditable?: boolean;
/**
* Determines the column's type.
*/
columnType?: ColumnType;
}
function DataGridCellContent<TData extends object = {}, TValue = unknown>({
isEditable,
children,
className,
cell: {
value: originalValue,
column: { onCellEdit, id, isNullable, isPrimary, type },
row,
},
...props
}: DataGridCellProps<TData, TValue>) {
const { openAlertDialog } = useDialog();
const {
title: tooltipTitle,
open: tooltipOpen,
openTooltip,
closeTooltip,
resetTooltipTitle,
} = useTooltip();
const [optimisticValue, setOptimisticValue] = useState<TValue>(originalValue);
const [temporaryValue, setTemporaryValue] = useState<TValue>(originalValue);
useEffect(() => {
setOptimisticValue(originalValue);
setTemporaryValue(originalValue);
}, [originalValue]);
const {
cellRef,
inputRef,
focusCell,
focusInput,
blurInput,
clickInput,
isEditing,
isSelected,
selectCell,
deselectCell,
cancelEditCell,
editCell,
focusPrevCell,
focusNextCell,
} = useDataGridCell();
function activateInput() {
if (isPrimary) {
openTooltip("Primary keys can't be edited.");
return;
}
editCell();
if (type === 'boolean') {
clickInput();
} else {
focusInput();
}
}
async function handleClick(event: MouseEvent<HTMLDivElement>) {
if (!isEditable || isEditing || isPrimary) {
return;
}
if (event.detail === 2 && type !== 'boolean') {
editCell();
await focusInput();
}
}
function handleFocus() {
if (!isEditable) {
return;
}
selectCell();
}
async function handleSave(
value: TValue,
options: { reset: boolean } = { reset: false },
) {
if (!onCellEdit) {
return;
}
const normalizedValue =
value !== null && typeof value === 'object'
? JSON.stringify(value)
: String(value);
const normalizedOptimisticValue =
optimisticValue !== null && typeof optimisticValue === 'object'
? JSON.stringify(optimisticValue)
: String(optimisticValue);
// We are making sure that optimistic value is not equal to the current
// value. If it is, we are not going to save the value.
if (
normalizedValue.replace(/\n/gi, '\\n') ===
normalizedOptimisticValue.replace(/\n/gi, '\\n') &&
!options.reset
) {
return;
}
// In case of an error, we need to reset optimistic value
const latestOptimisticValue = optimisticValue;
setOptimisticValue(value);
try {
const data = await onCellEdit({
row,
columnsToUpdate: {
[id]: {
value: !options.reset ? value : undefined,
reset: options.reset,
},
},
});
// Syncing optimistic value with server-side value
setTemporaryValue(data.original[id.toString()]);
setOptimisticValue(data.original[id.toString()]);
} catch (error) {
triggerToast(`Error: ${error.message || 'Unknown error occurred.'}`);
// Resetting values
setTemporaryValue(latestOptimisticValue);
setOptimisticValue(latestOptimisticValue);
}
}
async function handleBlur(event: FocusEvent<HTMLDivElement>) {
// We are deselecting cell only if focus target is not a descendant of it.
if (!isEditable || event.currentTarget.contains(event.relatedTarget)) {
return;
}
await handleSave(temporaryValue);
closeTooltip();
deselectCell();
}
function resetCell() {
if (isPrimary) {
openTooltip('Primary keys are non-nullable.');
return;
}
if (!isNullable) {
openTooltip(
<span>
<strong>{id}</strong>
is non-nullable.
</span>,
);
return;
}
openAlertDialog({
title: 'Set value to null',
payload: (
<p>
Are you sure you want to set this cell to <strong>null</strong>?
</p>
),
props: {
primaryButtonText: 'Set to null',
primaryButtonColor: 'error',
onPrimaryAction: async () => {
await handleSave(null, { reset: true });
focusCell();
},
},
});
}
async function handleKeyDown(event: KeyboardEvent<HTMLDivElement>) {
if (!isEditable) {
return;
}
if (event.key === 'Escape') {
closeTooltip();
}
// Resetting temporary value and focusing cell on Escape when input field is
// focused
if (event.key === 'Escape' && event.target === inputRef.current) {
setTemporaryValue(optimisticValue);
await focusCell();
cancelEditCell();
}
// Activating input field on Enter
if (event.key === 'Enter' && event.target === cellRef.current) {
activateInput();
}
// Focusing next cell on Tab
if (event.key === 'Tab' && !event.shiftKey) {
event.stopPropagation();
const nextCellAvailable = focusNextCell();
if (!nextCellAvailable) {
event.preventDefault();
event.stopPropagation();
await blurInput();
await focusCell();
}
}
// Focusing previous cell on Shift-Tab
if (event.key === 'Tab' && event.shiftKey) {
event.stopPropagation();
const prevCellAvailable = focusPrevCell();
if (!prevCellAvailable) {
event.preventDefault();
event.stopPropagation();
await blurInput();
await focusCell();
}
}
// Initiating cell reset when cell is focused
if (event.key === 'Backspace' && event.target === cellRef.current) {
resetCell();
}
}
const content = (
<Box
ref={cellRef}
className={twMerge(
'relative grid h-full w-full cursor-default grid-flow-col items-center gap-1',
isEditable &&
'focus-within:outline-none focus-within:ring-0 focus:ring-0',
isSelected && 'shadow-outline',
isEditing ? 'p-0.5 shadow-outline-dark' : 'px-2 py-1.5',
className,
)}
onFocus={handleFocus}
onBlur={handleBlur}
onKeyDown={handleKeyDown}
tabIndex={isEditable ? 0 : undefined}
onClick={handleClick}
role="textbox"
sx={{ backgroundColor: 'transparent' }}
{...props}
>
{Children.map(
children,
(
child:
| ReactNode
| ReactPortal
| ReactElement<unknown, string | JSXElementConstructor<any>>,
) => {
if (!isValidElement(child)) {
return null;
}
return cloneElement(child, {
...child.props,
onSave: handleSave,
optimisticValue,
onOptimisticValueChange: setOptimisticValue,
temporaryValue,
onTemporaryValueChange: setTemporaryValue,
});
},
)}
</Box>
);
if (isEditable) {
return (
<Tooltip
disableHoverListener
disableFocusListener
open={tooltipOpen}
title={tooltipTitle || ''}
TransitionProps={{ onExited: resetTooltipTitle }}
>
{content}
</Tooltip>
);
}
return content;
}
export default function DataGridCell<TData extends object, TValue = unknown>(
props: DataGridCellProps<TData, TValue>,
) {
return (
<DataGridCellProvider>
<DataGridCellContent {...props} />
</DataGridCellProvider>
);
}

View File

@@ -1,238 +0,0 @@
import type { MutableRefObject, PropsWithChildren } from 'react';
import { createContext, useCallback, useMemo, useReducer, useRef } from 'react';
export interface DataGridCellContextProps<T extends HTMLElement> {
/**
* This `ref` should be attached to the cell element.
*/
cellRef: MutableRefObject<HTMLDivElement>;
/**
* This `ref` should be attached to the input element inside the data grid cell.
*/
inputRef: MutableRefObject<T>;
/**
* Determines whether or not the cell is currently being edited.
*/
isEditing: boolean;
/**
* Determines whether or not the cell is currently selected.
*/
isSelected: boolean;
/**
* Function to be called to start editing.
*/
editCell: VoidFunction;
/**
* Function to be called to cancel editing.
*/
cancelEditCell: VoidFunction;
/**
* Function to be called to select the cell, but not start editing.
*/
selectCell: VoidFunction;
/**
* Function to be called to deselect cell and cancel editing.
*/
deselectCell: VoidFunction;
/**
* Function to be called to focus cell.
*/
focusCell: () => Promise<void>;
/**
* Function to be called to blur cell.
*/
blurCell: () => Promise<void>;
/**
* Function to be called to programatically focus the input in the cell.
*/
focusInput: () => Promise<void>;
/**
* Function to be called to programatically blur the input in the cell.
*/
blurInput: () => Promise<void>;
/**
* Function to be called to programmatically click the input in the cell.
*/
clickInput: () => Promise<void>;
/**
* Function to be called to navigate to next cell if available.
*
* @returns `true` if there is a next cell to focus, `false` otherwise.
*/
focusNextCell: () => boolean;
/**
* Function to be called to navigate to previous cell if available.
*
* @returns `true` if there is a previous cell to focus, `false` otherwise.
*/
focusPrevCell: () => boolean;
}
export const DataGridCellContext =
createContext<DataGridCellContextProps<any>>(null);
interface EditAndSelectState {
isEditing: boolean;
isSelected: boolean;
}
type EditAndSelectAction =
| { type: 'EDIT' }
| { type: 'CANCEL_EDIT' }
| { type: 'SELECT' }
| { type: 'DESELECT' };
function editAndSelectCellReducer(
state: EditAndSelectState,
action: EditAndSelectAction,
): EditAndSelectState {
switch (action.type) {
case 'EDIT':
return { ...state, isEditing: true, isSelected: true };
case 'CANCEL_EDIT':
return { ...state, isEditing: false };
case 'SELECT':
return { ...state, isSelected: true };
case 'DESELECT':
return { ...state, isEditing: false, isSelected: false };
default:
return { ...state };
}
}
export default function DataGridCellProvider<TInput extends HTMLElement>({
children,
}: PropsWithChildren<unknown>) {
const cellRef = useRef<HTMLDivElement>();
const inputRef = useRef<TInput>();
const [{ isEditing, isSelected }, dispatch] = useReducer(
editAndSelectCellReducer,
{
isEditing: false,
isSelected: false,
},
);
function focusCell() {
return new Promise<void>((resolve) => {
requestAnimationFrame(() => {
cellRef.current?.focus();
resolve();
});
});
}
function deselectCell() {
dispatch({ type: 'DESELECT' });
}
const focusPrevCell = useCallback(() => {
const prevCellAvailable =
cellRef.current.previousElementSibling instanceof HTMLElement &&
cellRef.current.previousElementSibling.tabIndex > -1;
requestAnimationFrame(() => {
if (prevCellAvailable) {
(cellRef.current.previousElementSibling as HTMLElement).focus();
deselectCell();
}
});
return prevCellAvailable;
}, []);
const focusNextCell = useCallback(() => {
const nextCellAvailable =
cellRef.current.nextElementSibling instanceof HTMLElement &&
cellRef.current.nextElementSibling.tabIndex > -1;
requestAnimationFrame(() => {
if (nextCellAvailable) {
(cellRef.current.nextElementSibling as HTMLElement).focus();
deselectCell();
}
});
return nextCellAvailable;
}, []);
function blurCell() {
return new Promise<void>((resolve) => {
requestAnimationFrame(() => {
cellRef.current?.blur();
resolve();
});
});
}
function focusInput() {
return new Promise<void>((resolve) => {
requestAnimationFrame(() => {
inputRef.current?.focus();
resolve();
});
});
}
function blurInput() {
return new Promise<void>((resolve) => {
requestAnimationFrame(() => {
inputRef.current?.blur();
resolve();
});
});
}
function clickInput() {
return new Promise<void>((resolve) => {
requestAnimationFrame(() => {
inputRef.current?.click();
resolve();
});
});
}
function editCell() {
dispatch({ type: 'EDIT' });
}
function cancelEditCell() {
dispatch({ type: 'CANCEL_EDIT' });
}
function selectCell() {
dispatch({ type: 'SELECT' });
}
const value = useMemo(
() => ({
focusCell,
blurCell,
focusInput,
blurInput,
clickInput,
isEditing,
isSelected,
editCell,
cancelEditCell,
selectCell,
deselectCell,
cellRef,
inputRef,
focusPrevCell,
focusNextCell,
}),
[focusNextCell, focusPrevCell, isEditing, isSelected],
);
return (
<DataGridCellContext.Provider value={value}>
{children}
</DataGridCellContext.Provider>
);
}

View File

@@ -1,5 +0,0 @@
export * from './DataGridCell';
export { default as DataGridCell } from './DataGridCell';
export * from './DataGridCellProvider';
export { default as DataGridCellProvider } from './DataGridCellProvider';
export { default as useDataGridCell } from './useDataGridCell';

View File

@@ -1,10 +0,0 @@
import { useContext } from 'react';
import type { DataGridCellContextProps } from './DataGridCellProvider';
import { DataGridCellContext } from './DataGridCellProvider';
export default function useDataGridCell<TInput extends HTMLElement>() {
const context =
useContext<DataGridCellContextProps<TInput>>(DataGridCellContext);
return context;
}

View File

@@ -1,6 +0,0 @@
import type { UseDataGridReturn } from '@/components/dataGrid/DataGrid';
import { createContext } from 'react';
const DataGridConfigContext = createContext<Partial<UseDataGridReturn>>(null);
export default DataGridConfigContext;

View File

@@ -1,16 +0,0 @@
import type { UseDataGridReturn } from '@/components/dataGrid/DataGrid';
import type { PropsWithChildren } from 'react';
import DataGridConfigContext from './DataGridConfigContext';
export default function DataGridConfigProvider<T extends object = {}>({
children,
...value
}: PropsWithChildren<UseDataGridReturn<T>>) {
return (
<DataGridConfigContext.Provider
value={value as unknown as UseDataGridReturn<{}>}
>
{children}
</DataGridConfigContext.Provider>
);
}

View File

@@ -1,3 +0,0 @@
export { default as DataGridConfigContext } from './DataGridConfigContext';
export { default as DataGridConfigProvider } from './DataGridConfigProvider';
export { default as useDataGridConfig } from './useDataGridConfig';

View File

@@ -1,15 +0,0 @@
import type { UseDataGridReturn } from '@/components/dataGrid/DataGrid';
import { useContext } from 'react';
import DataGridConfigContext from './DataGridConfigContext';
export default function useDataGridConfig<T extends object = {}>() {
const context = useContext(DataGridConfigContext);
if (!context) {
throw new Error(
`useDataGridConfig must be used within a DataGridConfigContext`,
);
}
return context as unknown as UseDataGridReturn<T>;
}

View File

@@ -1,166 +0,0 @@
import type { CommonDataGridCellProps } from '@/components/dataGrid/DataGridCell';
import { useDataGridCell } from '@/components/dataGrid/DataGridCell';
import { Input, inputClasses } from '@/components/ui/v2/Input';
import type { TextProps } from '@/components/ui/v2/Text';
import { Text } from '@/components/ui/v2/Text';
import { getDateComponents } from '@/utils/getDateComponents';
import type { ChangeEvent, KeyboardEvent } from 'react';
import { twMerge } from 'tailwind-merge';
export interface DataGridDateCellProps<TData extends object>
extends CommonDataGridCellProps<TData, string> {
/**
* Props to be passed to date display.
*/
dateProps?: TextProps;
/**
* Props to be passed to time display.
*/
timeProps?: TextProps;
}
export default function DataGridDateCell<TData extends object>({
onSave,
optimisticValue,
temporaryValue,
onTemporaryValueChange,
cell: {
column: { specificType },
},
dateProps,
timeProps,
className,
}: DataGridDateCellProps<TData>) {
const { className: dateClassName, ...restDateProps } = dateProps || {};
const { className: timeClassName, ...restTimeProps } = timeProps || {};
// Note: No date (year-month-day) is saved for time / timetz columns, so we
// need to add it manually.
const date =
optimisticValue && specificType !== 'interval'
? new Date(
specificType === 'time' || specificType === 'timetz'
? `1970-01-01 ${optimisticValue}`
: optimisticValue,
)
: undefined;
const { year, month, day, hour, minute, second } = getDateComponents(date, {
adjustTimezone: ['date', 'timetz', 'timestamptz'].includes(specificType),
});
const { inputRef, focusCell, isEditing, cancelEditCell } =
useDataGridCell<HTMLInputElement>();
async function handleSave() {
if (onSave) {
await onSave(temporaryValue || '');
}
}
async function handleKeyDown(event: KeyboardEvent<HTMLInputElement>) {
if (
event.key === 'ArrowLeft' ||
event.key === 'ArrowRight' ||
event.key === 'ArrowUp' ||
event.key === 'ArrowDown' ||
event.key === 'Backspace'
) {
event.stopPropagation();
}
if (event.key === 'Tab') {
await handleSave();
}
if (event.key === 'Enter') {
await handleSave();
await focusCell();
cancelEditCell();
}
}
function handleChange(event: ChangeEvent<HTMLInputElement>) {
if (event.target instanceof HTMLInputElement && onTemporaryValueChange) {
onTemporaryValueChange(event.target.value);
}
}
if (isEditing) {
return (
<Input
ref={inputRef}
value={
temporaryValue !== null && typeof temporaryValue !== 'undefined'
? temporaryValue
: ''
}
onKeyDown={handleKeyDown}
onChange={handleChange}
fullWidth
className="absolute top-0 z-10 -mx-0.5 h-full place-content-stretch"
sx={{
[`&.${inputClasses.focused}`]: {
boxShadow: `inset 0 0 0 1.5px rgba(0, 82, 205, 1)`,
borderColor: 'transparent !important',
borderRadius: 0,
backgroundColor: (theme) =>
theme.palette.mode === 'dark'
? `${theme.palette.secondary[100]} !important`
: `${theme.palette.common.white} !important`,
},
[`& .${inputClasses.input}`]: {
backgroundColor: 'transparent',
},
}}
slotProps={{
inputWrapper: { className: 'h-full' },
input: { className: 'h-full' },
inputRoot: {
className:
'resize-none outline-none focus:outline-none !text-xs focus:ring-0',
},
}}
/>
);
}
if (!optimisticValue) {
return (
<Text className="truncate text-xs" color="secondary">
null
</Text>
);
}
if (specificType === 'interval') {
return <Text className="truncate text-xs">{optimisticValue}</Text>;
}
return (
<div className={twMerge('grid grid-flow-row', className)}>
{specificType !== 'time' && specificType !== 'timetz' && (
<Text
className={twMerge('truncate text-xs', dateClassName)}
{...restDateProps}
>
{[year, month, day].filter(Boolean).join('-')}
</Text>
)}
{specificType !== 'date' && (
<Text
className={twMerge('truncate text-xs', timeClassName)}
color={
specificType === 'time' || specificType === 'timetz'
? 'primary'
: 'secondary'
}
{...restTimeProps}
>
{[hour, minute, second].filter(Boolean).join(':')}
</Text>
)}
</div>
);
}

View File

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

View File

@@ -1,29 +0,0 @@
import { useDataGridConfig } from '@/components/dataGrid/DataGridConfigProvider';
import clsx from 'clsx';
import type { DetailedHTMLProps, HTMLProps } from 'react';
export type DataGridFrameProps = DetailedHTMLProps<
HTMLProps<HTMLDivElement>,
HTMLDivElement
>;
export default function DataGridFrame<T extends object>({
style,
children,
className,
...props
}: DataGridFrameProps) {
const { getTableProps } = useDataGridConfig<T>();
const { style: reactTableStyle, ...restTableProps } = getTableProps();
return (
<div
{...restTableProps}
{...props}
className={clsx('min-w-min', className)}
style={{ ...reactTableStyle, minWidth: undefined, ...style }}
>
{children}
</div>
);
}

View File

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

View File

@@ -1,233 +0,0 @@
import type { DataGridProps } from '@/components/dataGrid/DataGrid';
import { useDataGridConfig } from '@/components/dataGrid/DataGridConfigProvider';
import { Box } from '@/components/ui/v2/Box';
import { Button } from '@/components/ui/v2/Button';
import { Divider } from '@/components/ui/v2/Divider';
import { Dropdown } from '@/components/ui/v2/Dropdown';
import { ArrowDownIcon } from '@/components/ui/v2/icons/ArrowDownIcon';
import { ArrowUpIcon } from '@/components/ui/v2/icons/ArrowUpIcon';
import { PencilIcon } from '@/components/ui/v2/icons/PencilIcon';
import { PlusIcon } from '@/components/ui/v2/icons/PlusIcon';
import { TrashIcon } from '@/components/ui/v2/icons/TrashIcon';
import type { DataBrowserGridColumn } from '@/features/database/dataGrid/types/dataBrowser';
import type { DetailedHTMLProps, HTMLProps } from 'react';
import { twMerge } from 'tailwind-merge';
export interface HeaderActionProps
extends DetailedHTMLProps<HTMLProps<HTMLElement>, HTMLElement> {}
export interface DataGridHeaderProps<T extends object>
extends Omit<
DetailedHTMLProps<HTMLProps<HTMLDivElement>, HTMLDivElement>,
'children'
>,
Pick<
DataGridProps<T>,
'onRemoveColumn' | 'onEditColumn' | 'onInsertColumn'
> {
/**
* Props to be passed to component slots.
*/
componentsProps?: {
/**
* Props to be passed to the `Edit Column` header action item.
*/
editActionProps?: HeaderActionProps;
/**
* Props to be passed to the `Delete Column` header action item.
*/
deleteActionProps?: HeaderActionProps;
/**
* Props to be passed to the `Delete Column` header action item.
*/
insertActionProps?: HeaderActionProps;
};
}
// TODO: Get rid of Data Browser related code from here. This component should
// be generic and not depend on Data Browser related data types and logic.
export default function DataGridHeader<T extends object>({
className,
onRemoveColumn,
onEditColumn,
onInsertColumn,
componentsProps,
...props
}: DataGridHeaderProps<T>) {
const { flatHeaders, allowSort, allowResize } = useDataGridConfig<T>();
return (
<div
className={twMerge(
'sticky top-0 z-30 inline-flex w-full items-center pr-5',
className,
)}
{...props}
>
{flatHeaders.map((column: DataBrowserGridColumn<T>) => {
const headerProps = column.getHeaderProps({
style: { display: 'inline-grid' },
});
return (
<Dropdown.Root
sx={{
backgroundColor: (theme) =>
column.isDisabled
? theme.palette.background.default
: theme.palette.background.paper,
color: 'text.primary',
borderColor: 'grey.300',
}}
className={twMerge(
'group relative inline-flex self-stretch overflow-hidden font-display text-xs font-bold focus:outline-none focus-visible:outline-none',
'border-b-1 border-r-1',
column.id === 'selection' && 'sticky left-0 max-w-2',
)}
style={{
...headerProps.style,
maxWidth:
column.id === 'selection' ? 32 : headerProps.style?.maxWidth,
width:
column.id === 'selection' ? '100%' : headerProps.style?.width,
zIndex:
column.id === 'selection' ? 10 : headerProps.style?.zIndex,
position: null,
}}
key={column.id}
>
{column.id === 'selection' ? (
<span
{...headerProps}
className="relative grid w-full grid-flow-col items-center justify-between p-2"
>
{column.render('Header')}
</span>
) : (
<Dropdown.Trigger
className={twMerge(
'focus:outline-none motion-safe:transition-colors',
)}
disabled={
column.isDisabled || (column.disableSortBy && !onRemoveColumn)
}
hideChevron
>
<span
{...headerProps}
className="relative grid w-full grid-flow-col items-center justify-between p-2"
>
{column.render('Header')}
{allowSort && (
<Box component="span" sx={{ color: 'text.primary' }}>
{column.isSorted && !column.isSortedDesc && (
<ArrowUpIcon className="h-3 w-3" />
)}
{column.isSorted && column.isSortedDesc && (
<ArrowDownIcon className="h-3 w-3" />
)}
</Box>
)}
</span>
{allowResize && !column.disableResizing && (
<span
{...column.getResizerProps({
onClick: (event: Event) => event.stopPropagation(),
})}
className="absolute -right-0.5 bottom-0 top-0 z-10 h-full w-1.5 group-hover:bg-slate-900 group-hover:bg-opacity-20 group-active:bg-slate-900 group-active:bg-opacity-20 motion-safe:transition-colors"
/>
)}
</Dropdown.Trigger>
)}
<Dropdown.Content
menu
PaperProps={{ className: 'w-52 mt-1' }}
className="p-0"
>
{onEditColumn && (
<Dropdown.Item
onClick={() => onEditColumn(column)}
className="grid grid-flow-col items-center gap-2 p-2 text-sm+ font-medium"
disabled={componentsProps?.editActionProps?.disabled}
>
<PencilIcon
className="h-4 w-4"
sx={{ color: 'text.secondary' }}
/>
<span>Edit Column</span>
</Dropdown.Item>
)}
{onEditColumn && <Divider component="li" sx={{ margin: 0 }} />}
{!column.disableSortBy && (
<Dropdown.Item
onClick={() => column.toggleSortBy(false)}
className="grid grid-flow-col items-center gap-2 p-2 text-sm+ font-medium"
>
<ArrowUpIcon
className="h-4 w-4"
sx={{ color: 'text.secondary' }}
/>
<span>Sort Ascending</span>
</Dropdown.Item>
)}
{!column.disableSortBy && (
<Dropdown.Item
onClick={() => column.toggleSortBy(true)}
className="grid grid-flow-col items-center gap-2 p-2 text-sm+ font-medium"
>
<ArrowDownIcon
className="h-4 w-4"
sx={{ color: 'text.secondary' }}
/>
<span>Sort Descending</span>
</Dropdown.Item>
)}
{onRemoveColumn && !column.isPrimary && (
<Divider component="li" className="my-1" />
)}
{onRemoveColumn && !column.isPrimary && (
<Dropdown.Item
onClick={() => onRemoveColumn(column)}
className="grid grid-flow-col items-center gap-2 p-2 text-sm+ font-medium"
disabled={componentsProps?.deleteActionProps?.disabled}
sx={{ color: 'error.main' }}
>
<TrashIcon className="h-4 w-4" sx={{ color: 'error.main' }} />
<span>Delete Column</span>
</Dropdown.Item>
)}
</Dropdown.Content>
</Dropdown.Root>
);
})}
{onInsertColumn && (
<Box className="group relative inline-flex w-25 self-stretch overflow-hidden border-b-1 border-r-1 font-display text-xs font-bold focus:outline-none focus-visible:outline-none">
<Button
onClick={onInsertColumn}
variant="borderless"
color="secondary"
className="h-full w-full rounded-none text-xs hover:shadow-none focus:shadow-none focus:outline-none"
aria-label="Insert New Column"
disabled={componentsProps?.insertActionProps?.disabled}
>
<PlusIcon className="h-4 w-4" sx={{ color: 'text.disabled' }} />
</Button>
</Box>
)}
</div>
);
}

View File

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

View File

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

View File

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

View File

@@ -1,91 +0,0 @@
import type { BoxProps } from '@/components/ui/v2/Box';
import { Box } from '@/components/ui/v2/Box';
import type { IconButtonProps } from '@/components/ui/v2/IconButton';
import { IconButton } from '@/components/ui/v2/IconButton';
import { ChevronLeftIcon } from '@/components/ui/v2/icons/ChevronLeftIcon';
import { ChevronRightIcon } from '@/components/ui/v2/icons/ChevronRightIcon';
import { Text } from '@/components/ui/v2/Text';
import clsx from 'clsx';
export interface DataGridPaginationProps extends BoxProps {
/**
* Number of pages.
*/
totalPages: number;
/**
* Current page.
*/
currentPage: number;
/**
* Function to be called when navigating to the previous page.
*/
onOpenPrevPage: VoidFunction;
/**
* Function to be called when navigating to the next page.
*/
onOpenNextPage: VoidFunction;
/**
* Props to be passed to the next button component.
*/
nextButtonProps?: IconButtonProps;
/**
* Props to be passed to the previous button component.
*/
prevButtonProps?: IconButtonProps;
}
export default function DataGridPagination({
className,
totalPages,
currentPage,
onOpenPrevPage,
onOpenNextPage,
nextButtonProps,
prevButtonProps,
...props
}: DataGridPaginationProps) {
return (
<Box
className={clsx(
'grid grid-flow-col items-center justify-around rounded-md border-1',
className,
)}
{...props}
>
<IconButton
variant="borderless"
color="secondary"
disabled={currentPage === 1}
onClick={onOpenPrevPage}
aria-label="Previous page"
{...prevButtonProps}
>
<ChevronLeftIcon className="h-4 w-4" />
</IconButton>
<span
className={clsx(
'mx-1 inline-block font-display font-medium',
currentPage > 99 ? 'text-xs' : 'text-sm+',
)}
>
{currentPage}
<Text component="span" className="mx-1 inline-block" color="disabled">
/
</Text>
{totalPages}
</span>
<IconButton
variant="borderless"
color="secondary"
disabled={currentPage === totalPages}
onClick={onOpenNextPage}
aria-label="Next page"
{...nextButtonProps}
>
<ChevronRightIcon className="h-4 w-4" />
</IconButton>
</Box>
);
}

View File

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

View File

@@ -1,410 +0,0 @@
import { Modal } from '@/components/ui/v1/Modal';
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
import { Box } from '@/components/ui/v2/Box';
import { IconButton } from '@/components/ui/v2/IconButton';
import { AudioPreviewIcon } from '@/components/ui/v2/icons/AudioPreviewIcon';
import { FilePreviewIcon } from '@/components/ui/v2/icons/FilePreviewIcon';
import { PDFPreviewIcon } from '@/components/ui/v2/icons/PDFPreviewIcon';
import { VideoPreviewIcon } from '@/components/ui/v2/icons/VideoPreviewIcon';
import { XIcon } from '@/components/ui/v2/icons/XIcon';
import { useAppClient } from '@/features/projects/common/hooks/useAppClient';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
import clsx from 'clsx';
import type { ReactNode } from 'react';
import { useEffect, useReducer, useState } from 'react';
import type { CellProps } from 'react-table';
export type PreviewProps = {
fetchBlob: (
init?: RequestInit,
size?: { width?: number; height?: number },
) => Promise<Blob | null>;
mimeType?: string;
alt?: string;
blob?: Blob;
id?: string;
};
export type DataGridPreviewCellProps<TData extends object> = CellProps<
TData,
PreviewProps
> & {
/**
* Preview to use when the file is not an image or blob can't be fetched
* properly.
*
* @default null
*/
fallbackPreview?: ReactNode;
};
function useBlob({
fetchBlob,
blob,
mimeType,
}: Pick<PreviewProps, 'fetchBlob' | 'blob' | 'mimeType'>) {
const [objectUrl, setObjectUrl] = useState<string>();
const [error, setError] = useState<Error>();
const [loading, setLoading] = useState<boolean>(false);
// This side-effect fetches the blob of the file from the server and sets the
// relevant `objectUrl` state. Abort controller is reponsible for cancelling
// the fetch if the component is unmounted.
useEffect(() => {
const abortController = new AbortController();
async function generateOptimizedObjectUrl() {
// todo: it could be more declarative if this function was called with the
// actual preview URL here, not pre-generated in useFiles
const fetchedBlob = await fetchBlob(
{ signal: abortController.signal },
mimeType !== 'image/svg+xml' && { width: 80, height: 40 },
);
if (fetchedBlob) {
return URL.createObjectURL(fetchedBlob);
}
return undefined;
}
async function generateObjectUrl() {
setLoading(false);
setError(undefined);
if (objectUrl || (mimeType && !mimeType?.startsWith('image'))) {
return;
}
if (blob) {
setObjectUrl(URL.createObjectURL(blob));
return;
}
try {
setLoading(true);
const generatedObjectUrl = await generateOptimizedObjectUrl();
if (!abortController.signal.aborted) {
setObjectUrl(generatedObjectUrl);
}
} catch (generateError) {
if (!abortController.signal.aborted) {
setError(generateError);
}
}
if (!abortController.signal.aborted) {
setLoading(false);
}
}
generateObjectUrl();
return () => abortController.abort();
}, [blob, fetchBlob, objectUrl, mimeType]);
return { objectUrl, error, loading };
}
const previewableImages = [
'image/jpeg',
'image/png',
'image/svg+xml',
'image/webp',
];
const previewableVideos = [
'video/mp4',
'video/x-m4v',
'video/3gpp',
'video/3gpp2',
];
const previewableFileTypes = [
...previewableImages,
...previewableVideos,
'audio/',
'application/json',
];
function previewReducer(
state: { loading: boolean; error?: Error; data?: string },
action:
| { type: 'PREVIEW_LOADING' }
| { type: 'CLEAR_PREVIEW' }
| { type: 'PREVIEW_FETCHED'; payload: string }
| { type: 'PREVIEW_ERROR'; payload: Error },
): { loading: boolean; error?: Error; data?: string } {
switch (action.type) {
case 'PREVIEW_LOADING':
return { ...state, loading: true, error: undefined, data: undefined };
case 'PREVIEW_FETCHED':
return {
...state,
loading: false,
error: undefined,
data: action.payload,
};
case 'PREVIEW_ERROR':
return {
...state,
loading: false,
error: action.payload,
data: undefined,
};
case 'CLEAR_PREVIEW':
return { ...state, loading: false, error: undefined, data: undefined };
default:
return { ...state };
}
}
export default function DataGridPreviewCell<TData extends object>({
value: { fetchBlob, id, mimeType, alt, blob },
fallbackPreview = null,
}: DataGridPreviewCellProps<TData>) {
const { currentProject } = useCurrentWorkspaceAndProject();
const appClient = useAppClient();
const { objectUrl, loading, error } = useBlob({ fetchBlob, blob, mimeType });
const [showModal, setShowModal] = useState(false);
const [
{ loading: previewLoading, error: previewError, data: previewUrl },
dispatch,
] = useReducer(previewReducer, {
loading: false,
error: undefined,
data: undefined,
});
const isPreviewable = previewableFileTypes.some(
(type) => mimeType?.startsWith(type) || mimeType === type,
);
const isVideo = mimeType?.startsWith('video');
const isAudio = mimeType?.startsWith('audio');
const isImage = mimeType?.startsWith('image');
const isJson = mimeType === 'application/json';
async function handleOpenPreview() {
if (!mimeType) {
dispatch({
type: 'PREVIEW_ERROR',
payload: new Error('mimeType is not defined.'),
});
return;
}
if (isPreviewable) {
setShowModal(true);
dispatch({ type: 'PREVIEW_LOADING' });
}
const { presignedUrl } = await appClient.storage
.setAdminSecret(currentProject?.config?.hasura.adminSecret)
.getPresignedUrl({ fileId: id });
if (!presignedUrl) {
dispatch({
type: 'PREVIEW_ERROR',
payload: new Error('Presigned URL could not be fetched.'),
});
return;
}
if (!isPreviewable) {
window.open(presignedUrl.url, '_blank', 'noopener noreferrer');
return;
}
dispatch({ type: 'PREVIEW_FETCHED', payload: presignedUrl.url });
}
if (loading) {
return <ActivityIndicator delay={500} className="mx-auto" />;
}
if (error) {
return (
<Box
className="grid w-full grid-flow-col items-center justify-center gap-1 text-center"
sx={{ color: 'error.main' }}
>
<FilePreviewIcon error /> Error
</Box>
);
}
return (
<>
<Modal
wrapperClassName="items-center"
showModal={showModal}
close={() => setShowModal(false)}
afterLeave={() => dispatch({ type: 'CLEAR_PREVIEW' })}
className={clsx(
previewableImages.includes(mimeType) || isVideo || isAudio
? 'mx-12 flex h-screen items-center justify-center'
: 'mt-4 inline-block h-near-screen w-full px-12',
)}
>
<Box
className={clsx(
!isJson && 'bg-checker-pattern',
'relative mx-auto flex overflow-hidden rounded-md',
)}
sx={{
backgroundColor: isJson && 'background.default',
color: 'text.primary',
}}
>
{!previewLoading && (
<IconButton
aria-label="Close"
variant="borderless"
color="secondary"
className="absolute right-2 top-2 z-50 p-2"
sx={{
[`&:hover, &:active, &:focus`]: {
backgroundColor: (theme) => {
if (isAudio || isVideo || isJson) {
return 'common.black';
}
return theme.palette.mode === 'dark'
? 'grey.800'
: 'grey.200';
},
},
}}
onClick={() => setShowModal(false)}
>
<XIcon
className="h-5 w-5"
sx={{
color: (theme) => {
if (isAudio || isVideo || isJson) {
return 'common.white';
}
return theme.palette.mode === 'dark'
? 'grey.100'
: 'grey.700';
},
}}
/>
</IconButton>
)}
{previewLoading && !previewUrl && (
<ActivityIndicator
delay={500}
className="mx-auto"
label="Loading preview..."
/>
)}
{previewError && (
<Box
className="px-6 py-3.5 pr-12 text-start font-medium"
sx={{ color: 'error.main' }}
>
<p>Error: Preview can&apos;t be loaded.</p>
<p>{previewError.message}</p>
</Box>
)}
{previewUrl && isImage && (
<picture className="h-auto max-h-near-screen min-h-38 min-w-38">
<source srcSet={previewUrl} type={mimeType} />
<img
src={previewUrl}
alt={alt}
className="h-full w-full object-scale-down"
/>
</picture>
)}
{previewUrl && isVideo && (
<video
autoPlay
controls
className="h-auto max-h-near-screen w-full bg-black"
>
<track kind="captions" />
<source src={previewUrl} type={mimeType} />
Your browser does not support the video tag.
</video>
)}
{previewUrl && isAudio && (
<audio autoPlay controls className="h-28 bg-black">
<track kind="captions" />
<source src={previewUrl} type={mimeType} />
Your browser does not support the audio tag.
</audio>
)}
{!previewLoading &&
previewUrl &&
!previewableImages.includes(mimeType) &&
!isVideo &&
!isAudio && (
<iframe
src={previewUrl}
className="h-near-screen w-full"
title="File preview"
/>
)}
</Box>
</Modal>
<div className="flex h-full w-full justify-center">
{previewableImages.includes(mimeType) && objectUrl && (
<button
type="button"
aria-label={alt}
onClick={handleOpenPreview}
className="mx-auto h-full"
>
<picture className="h-full w-20">
<source srcSet={objectUrl} type={mimeType} />
<img
src={objectUrl}
alt={alt}
className="h-full w-full object-scale-down"
/>
</picture>
</button>
)}
{(!previewableImages.includes(mimeType) || !objectUrl) && (
<button
type="button"
onClick={handleOpenPreview}
aria-label={alt}
className="grid h-full w-full items-center justify-center self-center"
>
{isVideo && <VideoPreviewIcon className="h-5 w-5" />}
{isAudio && <AudioPreviewIcon className="h-5 w-5" />}
{mimeType === 'application/pdf' && (
<PDFPreviewIcon className="h-5 w-5" />
)}
{!isVideo &&
!isAudio &&
mimeType !== 'application/pdf' &&
fallbackPreview}
</button>
)}
</div>
</>
);
}

View File

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

Some files were not shown because too many files have changed in this diff Show More