Compare commits

...

113 Commits

Author SHA1 Message Date
github-actions[bot]
6ad1cfcb13 chore: update versions (#3476)
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.37.0

### Minor Changes

-   cc98f33: fix: rename filename typo

### Patch Changes

-   25c0ffa: fix (dashboard): Parse tablename correctly into SQL query
- 8812d9d: feat (dsashboard): Simplyfy column and row controls in
database view

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-09-23 15:14:19 +02:00
robertkasza
25c0ffa83b fix (dashboard): Parse tablename correctly into SQL query (#3483)
### **PR Type**
Bug fix, Tests


___

### **Description**
- Fix SQL identifier placeholder to parse table names correctly

- Add `toPascalCase` utility and use in E2E tests

- Update create-table test to assert `id` column header


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["toPascalCase utility"] --> B["create-table.test uses PascalCase"]
  B --> C["prepareTable creates table"]
  C --> D["fetchTable uses %I placeholders"]
```



<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>create-table.test.ts</strong><dd><code>Update E2E test
to use PascalCase table names</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

dashboard/e2e/database/create-table.test.ts

<ul><li>Imported <code>toPascalCase</code> from utils<br> <li> Switched
tableName generation from snakeCase to PascalCase<br> <li> Added
assertion for <code>id</code> column presence</ul>


</details>


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

</tr>
</table></td></tr><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>utils.ts</strong><dd><code>Add toPascalCase utility
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; &nbsp; </dd></summary>
<hr>

dashboard/e2e/utils.ts

<ul><li>Introduced <code>toPascalCase</code> function for string
conversion<br> <li> Default divider set to space for word splitting</ul>


</details>


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

</tr>
</table></td></tr><tr><td><strong>Bug fix</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>fetchTable.ts</strong><dd><code>Use identifier
placeholders in SQL query generation</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/features/orgs/projects/database/dataGrid/hooks/useTableQuery/fetchTable.ts

<ul><li>Replaced <code>%1$s</code> with <code>%1$I</code> identifier
placeholders<br> <li> Ensures proper REGCLASS SQL parsing for table
names</ul>


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3483/files#diff-a58cb7660972ff84991cdd9777de5cf0834485072cbd421f8809638227c36820">+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>mean-cheetahs-greet.md</strong><dd><code>Add changeset
for SQL table parsing fix</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

.changeset/mean-cheetahs-greet.md

<ul><li>Added changeset entry for dashboard patch version<br> <li>
Documented SQL table name parsing fix</ul>


</details>


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

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

</details>

___
2025-09-23 10:30:55 +02:00
David BM
cc98f33440 fix (dashboard): typo in test filename (#3482)
### **PR Type**
Tests


___

### **Description**
- Add comprehensive tests for `DeploymentServiceLogsHeader`

- Mock project hook and GraphQL service label query

- Simulate user selecting service and submitting regex

- Validate `onSubmit` callback invocation


___



<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>DeploymentServiceLogsHeader.test.tsx</strong><dd><code>Add
DeploymentServiceLogsHeader tests</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/deployments/components/DeploymentServiceLogs/DeploymentServiceLogsHeader.test.tsx

<ul><li>New test file for <code>DeploymentServiceLogsHeader</code>
component<br> <li> Mocks <code>useProject</code> hook and GraphQL
<code>useGetServiceLabelValuesQuery</code><br> <li> Sets up MSW server
and environment variables<br> <li> Simulates UI interactions and asserts
<code>onSubmit</code> call</ul>


</details>


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

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

</details>

___
2025-09-19 18:12:02 +02:00
robertkasza
8812d9dcaf feat (dsashboard): Simplyfy column and row controls in database view (#3474)
### **PR Type**
Enhancement


___

### **Description**
- Remove insert column functionality from DataBrowser grid

- Simplify controls: only "Insert row" button remains

- Clean DataGridBody: remove row placeholders and column insertion

- Remove unused props and imports across components


___



<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>DataBrowserGrid.tsx</strong><dd><code>Remove insert
column control from DataBrowserGrid</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>


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

<ul><li>Removed <code>onInsertColumnClick</code> prop in
<code>controls</code><br> <li> Kept only <code>onInsertRowClick</code>
handler</ul>


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>DataBrowserGridControls.tsx</strong><dd><code>Simplify
insert controls to only row</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/DataBrowserGridControls/DataBrowserGridControls.tsx

<ul><li>Removed dropdown menu and <code>onInsertColumnClick</code>
logic<br> <li> Simplified UI to single "Insert row" button<br> <li>
Cleared unused imports (<code>Dropdown</code>, <code>RowIcon</code>,
<code>ColumnIcon</code>)</ul>


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>DataGrid.tsx</strong><dd><code>Remove onInsertRow prop
forwarding</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/features/orgs/projects/storage/dataGrid/components/DataGrid/DataGrid.tsx

- Deleted forwarding of `onInsertRow` prop to `DataGridBody`


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>DataGridBody.tsx</strong><dd><code>Remove row insertion
placeholders</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/features/orgs/projects/storage/dataGrid/components/DataGridBody/DataGridBody.tsx

<ul><li>Deleted <code>InsertPlaceholderTableRow</code> component and
row-insert code<br> <li> Simplified empty state rendering without insert
slots<br> <li> Removed unused imports and key-generation logic</ul>


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3474/files#diff-e5cdb81b2c99dbd7b9a669a63ed503f6964e9c0bc91ca2c0e61df5334eaa7a1b">+61/-143</a></td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>DataGridHeader.tsx</strong><dd><code>Drop column
insertion button</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/storage/dataGrid/components/DataGridHeader/DataGridHeader.tsx

<ul><li>Removed insert column button and <code>PlusIcon</code>
import<br> <li> Cleaned up unused <code>Box</code> and
<code>Button</code> imports</ul>


</details>


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

</tr>
</table></td></tr><tr><td><strong>Configuration
changes</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>nine-mayflies-explain.md</strong><dd><code>Add 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;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

.changeset/nine-mayflies-explain.md

- Added patch changeset metadata for `@nhost/dashboard`


</details>


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

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

</details>

___
2025-09-17 14:42:05 +02:00
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
800 changed files with 20194 additions and 9204 deletions

19
.github/labeler.yml vendored
View File

@@ -1,24 +1,25 @@
dashboard:
- dashboard/**/*
- any:
- changed-files:
- any-glob-to-any-file: ['dashboard/**/*']
documentation:
- any:
- docs/**/*
- any: ['docs/**/*']
examples:
- examples/**/*
- any: ['examples/**/*']
sdk:
- packages/**/*
- any: ['packages/**/*']
integrations:
- integrations/**/*
- any: ['integrations/**/*']
react:
- '{packages,examples,integrations}/*react*/**/*'
- any: ['{packages,examples,integrations}/*react*/**/*']
nextjs:
- '{packages,examples}/*next*/**/*'
- any: ['{packages,examples}/*next*/**/*']
vue:
- '{packages,examples,integrations}/*vue*/**/*'
- any: ['{packages,examples,integrations}/*vue*/**/*']

View File

@@ -7,12 +7,14 @@ on:
- 'assets/**'
- '**.md'
- 'LICENSE'
- 'docs/**'
pull_request:
types: [opened, synchronize]
paths-ignore:
- 'assets/**'
- '**.md'
- 'LICENSE'
- 'docs/**'
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: nhost
@@ -27,12 +29,13 @@ env:
NHOST_PRO_TEST_PROJECT_NAME: ${{ vars.NHOST_PRO_TEST_PROJECT_NAME }}
NHOST_TEST_USER_EMAIL: ${{ secrets.NHOST_TEST_USER_EMAIL }}
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:
build:
name: Build @nhost packages
runs-on: ubuntu-latest
runs-on: blacksmith-2vcpu-ubuntu-2404
steps:
- uses: actions/checkout@v3
with:
@@ -72,7 +75,7 @@ jobs:
unit:
name: Unit tests
needs: build
runs-on: ubuntu-latest
runs-on: blacksmith-2vcpu-ubuntu-2404
steps:
- uses: actions/checkout@v3
# * Install Node and dependencies. Package dependencies won't be downloaded again as they have been cached by the `build` job.
@@ -97,7 +100,7 @@ jobs:
lint:
name: Lint
needs: build
runs-on: ubuntu-latest
runs-on: blacksmith-2vcpu-ubuntu-2404
steps:
- uses: actions/checkout@v3
# * Install Node and dependencies. Package dependencies won't be downloaded again as they have been cached by the `build` job.
@@ -124,7 +127,7 @@ jobs:
fail-fast: false
matrix:
package: ${{ fromJson(needs.build.outputs.matrix) }}
runs-on: ubuntu-latest
runs-on: blacksmith-2vcpu-ubuntu-2404
steps:
- uses: actions/checkout@v3
# * Install Node and dependencies. Package dependencies won't be downloaded again as they have been cached by the `build` job.
@@ -169,6 +172,10 @@ jobs:
- name: Set Dashboard 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
- 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
- name: Run e2e tests
timeout-minutes: 20
@@ -177,23 +184,31 @@ jobs:
- name: Run Local Dashboard e2e tests
if: matrix.package.path == 'dashboard'
timeout-minutes: 5
run: |
pnpm --filter="${{ matrix.package.name }}" run e2e-local
run: pnpm --filter="${{ matrix.package.name }}" run e2e:local
- name: Stop Nhost CLI
if: matrix.package.path == 'dashboard'
working-directory: ./nhost-test-project
run: nhost down
- id: file-name
if: ${{ failure() }}
name: Transform package name into a valid file name
- name: Stop Nhost CLI for packages
if: always() && (matrix.package.path == 'packages/hasura-auth-js' || matrix.package.path == 'packages/hasura-storage-js')
working-directory: ./${{ matrix.package.path }}
run: nhost down
- name: Encrypt Playwright report
if: ${{ failure() && hashFiles('dashboard/playwright-report/**') != ''}}
run: |
PACKAGE_FILE_NAME=$(echo "${{ matrix.package.name }}" | sed 's/@//g; s/\//-/g')
echo "fileName=$PACKAGE_FILE_NAME" >> $GITHUB_OUTPUT
# * Run this step only if the previous step failed, and Playwright generated a report
- name: Upload Playwright Report
if: ${{ failure() && hashFiles(format('{0}/playwright-report/**', matrix.package.path)) != ''}}
tar -czf dashboard/playwright-report.tar.gz dashboard/playwright-report/
openssl enc -aes-256-cbc -salt -pbkdf2 -iter 100000 \
-in dashboard/playwright-report.tar.gz \
-out playwright-report.tar.gz.enc \
-k "${{ secrets.PLAYWRIGHT_REPORT_ENCRYPTION_KEY }}"
rm dashboard/playwright-report.tar.gz
- name: Upload encrypted Playwright report
uses: actions/upload-artifact@v4
if: ${{ failure() && hashFiles('dashboard/playwright-report/**') != ''}}
with:
name: playwright-${{ steps.file-name.outputs.fileName }}
path: ${{format('{0}/playwright-report/**', matrix.package.path)}}
name: encrypted-playwright-report-${{ github.run_id }}
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 build --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
jobs:
triage:
labeler:
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v4
- uses: actions/labeler@v5
with:
repo-token: '${{ secrets.GH_PAT }}'
sync-labels: ''
repo-token: ${{ secrets.GH_PAT }}

View File

@@ -2,9 +2,7 @@
## Requirements
### Node.js v18
_⚠️ Node.js v16 is also supported for the time being but support will be dropped in the near future_.
### Node.js v20 or later
### [pnpm](https://pnpm.io/) package manager

View File

@@ -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.
## 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
import { NhostClient } from '@nhost/nhost-js'

View File

@@ -2,5 +2,5 @@
// $schema provides code completion hints to IDEs.
"$schema": "https://github.com/IBM/audit-ci/raw/main/docs/schema.json",
"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,
"skipLibCheck": true,
"moduleResolution": "node",
"target": "ES6",
"target": "ESNext",
"module": "CommonJS",
"lib": [
"es5",
"dom",
"es2015.promise",
"es2015.symbol",
"es2015.iterable",
"es2015.collection",
"es2015.symbol.wellknown",
"es2015.core",
"es2017.object",
"es2017.string"
],
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"resolveJsonModule": true,
"esModuleInterop": true,
"sourceMap": true,
@@ -79,4 +68,4 @@
"**/*/__tests__",
"**/*/__mocks__"
]
}
}

View File

@@ -25,4 +25,6 @@ NEXT_PUBLIC_ZENDESK_USER_EMAIL=
CODEGEN_GRAPHQL_URL=https://local.graphql.local.nhost.run/v1
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: [
{

View File

@@ -1,8 +1,9 @@
import { NhostProvider } from '@/providers/nhost';
import '@fontsource/inter';
import '@fontsource/inter/500.css';
import '@fontsource/inter/700.css';
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 { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { Buffer } from 'buffer';
@@ -58,7 +59,9 @@ export const decorators = [
</NhostApolloProvider>
),
(Story) => (
<NhostProvider nhost={new NhostClient({ subdomain: 'local' })}>
<NhostProvider
nhost={createClient({ subdomain: 'local', region: 'local' })}
>
<Story />
</NhostProvider>
),

View File

@@ -1,5 +1,153 @@
# @nhost/dashboard
## 2.37.0
### Minor Changes
- cc98f33: fix: rename filename typo
### Patch Changes
- 25c0ffa: fix (dashboard): Parse tablename correctly into SQL query
- 8812d9d: feat (dsashboard): Simplyfy column and row controls in database view
## 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

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_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_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 "$@"

View File

@@ -13,6 +13,9 @@ test('should be able to ban and unban a user', async ({
const password = faker.internet.password();
await createUser({ page, email, password });
await page.waitForSelector(
'div:has-text("User has been created successfully.")',
);
await page
.getByRole('button', { name: `View ${email}`, exact: true })

View File

@@ -11,6 +11,9 @@ test('should create a user', async ({ authenticatedNhostPage: page }) => {
const password = faker.internet.password();
await createUser({ page, email, password });
await page.waitForSelector(
'div:has-text("User has been created successfully.")',
);
await expect(
page.getByRole('button', { name: `View ${email}`, exact: true }),

View File

@@ -14,6 +14,9 @@ test('should be able to delete a user', async ({
const password = faker.internet.password();
await createUser({ page, email, password });
await page.waitForSelector(
'div:has-text("User has been created successfully.")',
);
await expect(
page.getByRole('button', { name: `View ${email}`, exact: true }),
@@ -39,6 +42,7 @@ test('should be able to delete a user', async ({
await expect(
page.getByRole('button', { name: `View ${email}`, exact: true }),
).not.toBeVisible();
await expect(page.getByText('User deleted successfully.')).toBeVisible();
});
test('should be able to delete a user from the details page', async ({
@@ -49,6 +53,10 @@ test('should be able to delete a user from the details page', async ({
await createUser({ page, email, password });
await page.waitForSelector(
'div:has-text("User has been created successfully.")',
);
await page
.getByRole('button', { name: `View ${email}`, exact: true })
.click();
@@ -68,4 +76,5 @@ test('should be able to delete a user from the details page', async ({
await expect(
page.getByRole('button', { name: `View ${email}`, exact: true }),
).not.toBeVisible();
await expect(page.getByText('User deleted successfully.')).toBeVisible();
});

View File

@@ -13,6 +13,9 @@ test('should be able to edit user roles from the details page', async ({
const password = faker.internet.password();
await createUser({ page, email, password });
await page.waitForSelector(
'div:has-text("User has been created successfully.")',
);
await page
.getByRole('button', { name: `View ${email}`, exact: true })

View File

@@ -14,6 +14,10 @@ test('should be able to verify the email of a user', async ({
await createUser({ page, email, password });
await page.waitForSelector(
'div:has-text("User has been created successfully.")',
);
await page
.getByRole('button', { name: `View ${email}`, exact: true })
.click();

View File

@@ -1,6 +1,6 @@
import { TEST_ORGANIZATION_SLUG, TEST_PROJECT_SUBDOMAIN } from '@/e2e/env';
import { expect, test } from '@/e2e/fixtures/auth-hook';
import { prepareTable } from '@/e2e/utils';
import { prepareTable, toPascalCase } from '@/e2e/utils';
import { faker } from '@faker-js/faker';
import { snakeCase } from 'snake-case';
@@ -16,12 +16,12 @@ test('should create a simple table', async ({
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));
const tableName = toPascalCase(faker.lorem.words(3));
await prepareTable({
page,
name: tableName,
primaryKey: 'id',
primaryKeys: ['id'],
columns: [
{ name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'title', type: 'text' },
@@ -38,6 +38,7 @@ test('should create a simple table', async ({
await expect(
page.getByRole('link', { name: tableName, exact: true }),
).toBeVisible();
await expect(page.getByRole('columnheader', { name: 'id' })).toBeVisible();
});
test('should create a table with unique constraints', async ({
@@ -51,7 +52,7 @@ test('should create a table with unique constraints', async ({
await prepareTable({
page,
name: tableName,
primaryKey: 'id',
primaryKeys: ['id'],
columns: [
{ name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'title', type: 'text', unique: true },
@@ -82,7 +83,7 @@ test('should create a table with nullable columns', async ({
await prepareTable({
page,
name: tableName,
primaryKey: 'id',
primaryKeys: ['id'],
columns: [
{ name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'title', type: 'text', nullable: true },
@@ -113,7 +114,7 @@ test('should create a table with an identity column', async ({
await prepareTable({
page,
name: tableName,
primaryKey: 'id',
primaryKeys: ['id'],
columns: [
{ name: 'id', type: 'int4' },
{ name: 'title', type: 'text', nullable: true },
@@ -148,7 +149,7 @@ test('should create table with foreign key constraint', async ({
await prepareTable({
page,
name: firstTableName,
primaryKey: 'id',
primaryKeys: ['id'],
columns: [
{ name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'name', type: 'text' },
@@ -170,7 +171,7 @@ test('should create table with foreign key constraint', async ({
await prepareTable({
page,
name: secondTableName,
primaryKey: 'id',
primaryKeys: ['id'],
columns: [
{ name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'title', type: 'text' },
@@ -196,6 +197,10 @@ test('should create table with foreign key constraint', async ({
await page.getByRole('button', { name: /add/i }).click();
await expect(
page.getByTestId('foreignKeyFormSubmitButton'),
).not.toBeVisible();
await expect(
page.getByText(`public.${firstTableName}.id`, { exact: true }),
).toBeVisible();
@@ -223,7 +228,7 @@ test('should not be able to create a table with a name that already exists', asy
await prepareTable({
page,
name: tableName,
primaryKey: 'id',
primaryKeys: ['id'],
columns: [
{ name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'name', type: 'text' },
@@ -243,7 +248,7 @@ test('should not be able to create a table with a name that already exists', asy
await prepareTable({
page,
name: tableName,
primaryKey: 'id',
primaryKeys: ['id'],
columns: [
{ name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'title', type: 'text' },
@@ -258,3 +263,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),
).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

@@ -19,7 +19,7 @@ test('should delete a table', async ({ authenticatedNhostPage: page }) => {
await prepareTable({
page,
name: tableName,
primaryKey: 'id',
primaryKeys: ['id'],
columns: [
{ name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'title', type: 'text' },
@@ -59,7 +59,7 @@ test('should not be able to delete a table if other tables have foreign keys ref
await prepareTable({
page,
name: firstTableName,
primaryKey: 'id',
primaryKeys: ['id'],
columns: [
{ name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'name', type: 'text' },
@@ -81,7 +81,7 @@ test('should not be able to delete a table if other tables have foreign keys ref
await prepareTable({
page,
name: secondTableName,
primaryKey: 'id',
primaryKeys: ['id'],
columns: [
{ name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'title', type: 'text' },

View File

@@ -21,7 +21,7 @@ test('should create a table with role permissions to select row', async ({
await prepareTable({
page,
name: tableName,
primaryKey: 'id',
primaryKeys: ['id'],
columns: [
{ name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'title', type: 'text' },
@@ -69,7 +69,7 @@ test('should create a table with role permissions and a custom check to select r
await prepareTable({
page,
name: tableName,
primaryKey: 'id',
primaryKeys: ['id'],
columns: [
{ name: 'id', type: 'uuid', defaultValue: 'gen_random_uuid()' },
{ name: 'title', type: 'text' },

View File

@@ -1,42 +1,46 @@
/**
* 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 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.
*/
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.
*/
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.
*/
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.
*/
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.
*/
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.
*/
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

@@ -10,10 +10,11 @@ export const test = base.extend<{ authenticatedNhostPage: Page }>({
await page.goto('/');
await page.waitForURL(
`${TEST_DASHBOARD_URL}/orgs/${TEST_PERSONAL_ORG_SLUG}/projects`,
{ waitUntil: 'networkidle' },
{ 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();
},

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

@@ -18,7 +18,7 @@ setup('authenticate user', async ({ page }) => {
await page.waitForURL(
`${TEST_DASHBOARD_URL}/orgs/${TEST_PERSONAL_ORG_SLUG}/projects`,
{ waitUntil: 'networkidle' },
{ waitUntil: 'load' },
);
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,6 +1,12 @@
import { TEST_ORGANIZATION_SLUG, TEST_PROJECT_SUBDOMAIN } from '@/e2e/env';
import {
TEST_FREE_USER_EMAILS,
TEST_ORGANIZATION_SLUG,
TEST_PROJECT_SUBDOMAIN,
TEST_USER_PASSWORD,
} from '@/e2e/env';
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.
@@ -22,7 +28,7 @@ export async function navigateToProject({
const projectUrl = `/orgs/${orgSlug}/projects/${projectSubdomain}`;
try {
await page.goto(projectUrl, { waitUntil: 'networkidle' });
await page.goto(projectUrl, { waitUntil: 'load' });
await page.waitForURL(projectUrl, { timeout: 10000 });
} catch (error) {
console.error(`Failed to navigate to project URL: ${projectUrl}`, error);
@@ -40,12 +46,12 @@ export async function navigateToProject({
export async function prepareTable({
page,
name: tableName,
primaryKey,
primaryKeys,
columns,
}: {
page: Page;
name: string;
primaryKey: string;
primaryKeys: string[];
columns: Array<{
name: string;
type: string;
@@ -54,7 +60,7 @@ export async function prepareTable({
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.');
}
@@ -118,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.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();
}
/**
@@ -213,8 +221,101 @@ export async function clickPermissionButton({
.click();
}
export async function gotoAuthURL(page) {
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: 'networkidle' });
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,
});
}
export function toPascalCase(str: string, divider = ' ') {
return str
.split(divider)
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
.join('');
}

View File

@@ -5,21 +5,24 @@ const withBundleAnalyzer = require('@next/bundle-analyzer')({
const { version } = require('./package.json');
const cspHeader = `
default-src 'self' *.nhost.run ws://*.nhost.run nhost.run ws://nhost.run;
script-src 'self' 'unsafe-eval' 'unsafe-inline' cdn.segment.com js.stripe.com;
connect-src 'self' *.nhost.run ws://*.nhost.run nhost.run ws://nhost.run discord.com api.segment.io api.segment.com cdn.segment.com nhost.zendesk.com;
default-src 'self' *.nhost.run wss://*.nhost.run nhost.run wss://nhost.run;
script-src 'self' 'unsafe-eval' cdn.segment.com js.stripe.com challenges.cloudflare.com googletagmanager.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';
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:;
object-src 'none';
base-uri 'self';
form-action 'self';
frame-ancestors 'none';
frame-src 'self' js.stripe.com;
frame-src 'self' js.stripe.com challenges.cloudflare.com;
block-all-mixed-content;
upgrade-insecure-requests;
`;
if (process.env.NEXT_PUBLIC_ENV !== 'development') {
cspHeader.concat(` upgrade-insecure-requests;`);
}
module.exports = withBundleAnalyzer({
reactStrictMode: false,
swcMinify: false,
@@ -38,10 +41,10 @@ module.exports = withBundleAnalyzer({
{
source: '/(.*)',
headers: [
// {
// key: 'Content-Security-Policy',
// hgvalue: cspHeader.replace(/\s+/g, ' ').trim(),
// },
{
key: 'Content-Security-Policy',
value: cspHeader.replace(/\s+/g, ' ').trim(),
},
{
key: 'X-Frame-Options',
value: 'DENY',

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/dashboard",
"version": "2.27.0",
"version": "2.37.0",
"private": true,
"scripts": {
"preinstall": "npx only-allow pnpm",
@@ -16,8 +16,10 @@
"storybook": "start-storybook -p 6006 -s public",
"build-storybook": "build-storybook",
"install-browsers": "pnpm playwright install && pnpm playwright install-deps",
"e2e": "pnpm install-browsers && pnpm playwright test --config=playwright.config.ts",
"e2e-local": "pnpm install-browsers && pnpm playwright test --config=playwright.local.config.ts"
"e2e:tests": "pnpm install-browsers && pnpm playwright test --config=playwright.config.ts -x",
"e2e": "pnpm e2e:tests --project=main",
"e2e:local": "pnpm e2e:tests --project=local",
"e2e:onboarding": "pnpm e2e:tests --project=onboarding"
},
"dependencies": {
"@apollo/client": "^3.9.9",
@@ -37,29 +39,30 @@
"@heroicons/react": "^1.0.6",
"@hookform/resolvers": "^3.9.0",
"@iarna/toml": "^2.2.5",
"@icons-pack/react-simple-icons": "^9.6.0",
"@marsidev/react-turnstile": "^1.0.2",
"@mui/base": "5.0.0-beta.31",
"@mui/material": "^5.15.14",
"@mui/system": "^5.15.14",
"@mui/x-date-pickers": "^5.0.20",
"@nhost/nextjs": "workspace:*",
"@nhost/react-apollo": "workspace:*",
"@nhost/nhost-js-beta": "npm:@nhost/nhost-js@5.0.0-beta.9",
"@radix-ui/react-accordion": "^1.2.1",
"@radix-ui/react-alert-dialog": "^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-hover-card": "^1.1.2",
"@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-radio-group": "^1.2.0",
"@radix-ui/react-select": "^2.1.2",
"@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-tooltip": "^1.1.2",
"@segment/analytics-next": "^1.77.0",
"@simplewebauthn/browser": "^9.0.1",
"@stripe/react-stripe-js": "^2.6.2",
"@stripe/stripe-js": "^1.54.2",
"@tailwindcss/forms": "^0.5.7",
@@ -85,9 +88,10 @@
"graphql-tag": "^2.12.6",
"graphql-ws": "^5.16.0",
"just-kebab-case": "^4.2.0",
"jwt-decode": "^4.0.0",
"lodash.debounce": "^4.0.8",
"lucide-react": "^0.416.0",
"next": "^14.2.25",
"next": "^14.2.31",
"next-nprogress-bar": "^2.3.13",
"next-seo": "^6.5.0",
"next-themes": "^0.3.0",
@@ -95,7 +99,7 @@
"pluralize": "^8.0.0",
"react": "18.2.0",
"react-children-utilities": "^2.10.0",
"react-complex-tree": "^2.4.5",
"react-complex-tree": "^2.6.0",
"react-day-picker": "9.6.3",
"react-dom": "18.2.0",
"react-error-boundary": "^4.0.13",
@@ -105,7 +109,7 @@
"react-is": "18.2.0",
"react-loading-skeleton": "^2.2.0",
"react-markdown": "^9.0.1",
"react-merge-refs": "^1.1.0",
"react-merge-refs": "^3.0.2",
"react-resizable-layout": "^0.7.2",
"react-table": "^7.8.0",
"recoil": "^0.7.7",
@@ -116,6 +120,7 @@
"stripe": "^10.17.0",
"tailwind-merge": "^1.14.0",
"tailwindcss-animate": "^1.0.7",
"test@latest": "link:playwright/test@latest",
"timezones-list": "^3.1.0",
"utility-types": "^3.11.0",
"uuid": "^9.0.1",
@@ -194,7 +199,7 @@
"tailwindcss": "^3.4.12",
"ts-node": "^10.9.2",
"tsconfig-paths-webpack-plugin": "^4.1.0",
"vite": "^5.4.17",
"vite": "^5.4.20",
"vite-tsconfig-paths": "^4.3.2",
"vitest": "^0.32.4"
},

View File

@@ -6,7 +6,7 @@ dotenv.config({ path: path.resolve(__dirname, '.env.test') });
export default defineConfig({
testDir: './e2e',
timeout: 60 * 1000,
timeout: 120 * 1000,
expect: {
timeout: 10000,
},
@@ -17,7 +17,7 @@ export default defineConfig({
reporter: 'html',
use: {
actionTimeout: 0,
trace: 'on-first-retry',
trace: 'retain-on-failure',
baseURL: process.env.NHOST_TEST_DASHBOARD_URL,
launchOptions: {
slowMo: 500,
@@ -34,13 +34,28 @@ export default defineConfig({
testMatch: ['**/teardown/*.teardown.ts'],
},
{
name: 'chromium',
name: 'main',
use: {
...devices['Desktop Chrome'],
storageState: 'e2e/.auth/user.json',
},
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

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

@@ -64,29 +64,29 @@ describe('DateTimePicker', () => {
await screen.findByRole('button', { name: 'Select' }),
).toBeInTheDocument();
expect(await screen.getByText('March 2025')).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(await screen.getByText('13'));
await user.click(screen.getByText('13'));
const hoursInput = await screen.getByLabelText('Hours');
const hoursInput = screen.getByLabelText('Hours');
await user.type(hoursInput, '11');
const minutesInput = await screen.getByLabelText('Minutes');
const minutesInput = screen.getByLabelText('Minutes');
await user.type(minutesInput, '12');
const secondsInput = await screen.getByLabelText('Seconds');
const secondsInput = screen.getByLabelText('Seconds');
await user.type(secondsInput, '13');
user.click(await screen.getByRole('button', { name: 'Select' }));
await user.click(screen.getByRole('button', { name: 'Select' }));
await waitFor(async () =>
expect(
await screen.queryByRole('button', { name: 'Select' }),
screen.queryByRole('button', { name: 'Select' }),
).not.toBeInTheDocument(),
);
@@ -119,7 +119,7 @@ describe('DateTimePicker', () => {
await user.type(tzInput, 'America/Chicago{ArrowDown}{Enter}');
expect(
await screen.queryByPlaceholderText('Search timezones...'),
screen.queryByPlaceholderText('Search timezones...'),
).not.toBeInTheDocument();
expect(await screen.findByText(/Timezone: /i)).toHaveTextContent(
@@ -148,7 +148,7 @@ describe('DateTimePicker', () => {
'Timezone: UTC+02:00',
);
expect(await screen.getByText('March 2025')).toBeInTheDocument();
expect(screen.getByText('March 2025')).toBeInTheDocument();
await user.click(
screen.getByRole('button', { name: 'Go to the Next Month' }),
@@ -156,7 +156,7 @@ describe('DateTimePicker', () => {
expect(screen.getByText('April 2025')).toBeInTheDocument();
await user.click(await screen.getByText('18'));
await user.click(screen.getByText('18'));
expect(await screen.findByText(/Timezone: /i)).toHaveTextContent(
'Timezone: UTC+03:00',
@@ -166,9 +166,9 @@ describe('DateTimePicker', () => {
screen.getByRole('button', { name: 'Go to the Previous Month' }),
);
expect(await screen.getByText('March 2025')).toBeInTheDocument();
expect(screen.getByText('March 2025')).toBeInTheDocument();
await user.click(await screen.getByText('21'));
await user.click(screen.getByText('21'));
expect(await screen.findByText(/Timezone: /i)).toHaveTextContent(
'Timezone: UTC+02:00',

View File

@@ -51,7 +51,7 @@ export interface DialogContextProps {
/**
* 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.
*/

View File

@@ -23,6 +23,10 @@ import {
drawerReducer,
} from './dialogReducers';
function isBaseSyntheticEvent(event: any): event is BaseSyntheticEvent {
return event?.type !== undefined;
}
function DialogProvider({ children }: PropsWithChildren<unknown>) {
const router = useRouter();
@@ -87,7 +91,7 @@ function DialogProvider({ children }: PropsWithChildren<unknown>) {
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 });
}
@@ -122,8 +126,12 @@ function DialogProvider({ children }: PropsWithChildren<unknown>) {
);
const closeDrawerWithDirtyGuard = useCallback(
(event?: BaseSyntheticEvent) => {
if (isDrawerDirty.current && event?.type !== 'submit') {
(event?: any) => {
if (
isDrawerDirty.current &&
isBaseSyntheticEvent(event) &&
event.type !== 'submit'
) {
setShowDirtyConfirmation(true);
openDirtyConfirmation({ props: { onPrimaryAction: closeDrawer } });
return;
@@ -135,8 +143,12 @@ function DialogProvider({ children }: PropsWithChildren<unknown>) {
);
const closeDialogWithDirtyGuard = useCallback(
(event?: BaseSyntheticEvent) => {
if (isDialogDirty.current && event?.type !== 'submit') {
(event?: any) => {
if (
isDialogDirty.current &&
isBaseSyntheticEvent(event) &&
event.type !== 'submit'
) {
setShowDirtyConfirmation(true);
openDirtyConfirmation({ props: { onPrimaryAction: closeDialog } });
return;
@@ -250,7 +262,7 @@ function DialogProvider({ children }: PropsWithChildren<unknown>) {
<BaseDialog
{...dialogProps}
title={dialogTitle}
open={dialogOpen}
open={!!dialogOpen}
onClose={closeDialogWithDirtyGuard}
TransitionProps={{ onExited: clearDialogContent, unmountOnExit: false }}
PaperProps={{

View File

@@ -115,7 +115,7 @@ export function drawerReducer(
}
export type AlertDialogAction =
| { type: 'OPEN_ALERT'; payload?: DialogConfig }
| { type: 'OPEN_ALERT'; payload: DialogConfig }
| { type: 'HIDE_ALERT' }
| { type: 'CLEAR_ALERT_CONTENT' };

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 { Link } from '@/components/ui/v2/Link';
import type { MakeRequired } from '@/types/common';
import NextLink from 'next/link';
import type { ForwardedRef, PropsWithoutRef } from 'react';
import { forwardRef } from 'react';
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.
*/

View File

@@ -5,7 +5,7 @@ import { useIsCurrentUserOwner } from '@/features/orgs/projects/common/hooks/use
interface Props {
buttonText?: string;
onClick?: () => void;
onClick: () => void;
}
function OpenTransferDialogButton({ buttonText, onClick }: Props) {

View File

@@ -19,7 +19,7 @@ export type PaginationProps = DetailedHTMLProps<
/**
* Number of total elements per page.
*/
elementsPerPage?: number;
elementsPerPage: number;
/**
* 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 { Text } from '@/components/ui/v2/Text';
import { useOrgs } from '@/features/orgs/projects/hooks/useOrgs';
import {} from '@/utils/__generated__/graphql';
import { Divider } from '@mui/material';
import debounce from 'lodash.debounce';
import Image from 'next/image';

View File

@@ -7,7 +7,7 @@ import { TimePickerInput } from './TimePickerInput';
interface TimePickerProps {
date: Date | undefined;
setDate: (date: Date | undefined) => void;
setDate: (date: Date) => void;
}
function TimePicker({ date, setDate }: TimePickerProps) {

View File

@@ -15,7 +15,7 @@ export interface TimePickerInputProps
extends React.InputHTMLAttributes<HTMLInputElement> {
picker: TimePickerType;
date: Date | undefined;
setDate: (date: Date | undefined) => void;
setDate: (date: Date) => void;
period?: Period;
onRightFocus?: () => void;
onLeftFocus?: () => void;

View File

@@ -19,7 +19,7 @@ function getOrderedTimezones(dateTime: string, selectedTimezone: string) {
) {
const selectedTimezoneOption = timezones.find(
(tz) => tz.value === selectedTimezone,
);
)!;
orderedTimezones = [
selectedTimezoneOption,
...timezones.filter((tz) => tz.value !== selectedTimezone),

View File

@@ -8,7 +8,7 @@ export interface UIContextProps {
/**
* The date and time when maintenance mode will end.
*/
maintenanceEndDate: Date;
maintenanceEndDate: Date | null;
}
const UIContext = createContext<UIContextProps>({

View File

@@ -24,7 +24,7 @@ type Option = {
};
interface VirtualizedCommandProps<O extends Option> {
height: string;
height?: string;
options: O[];
placeholder: string;
selectedOption: string;
@@ -181,7 +181,7 @@ interface VirtualizedComboboxProps<O extends Option> {
width?: string;
height?: string;
button?: React.JSX.Element;
onSelectOption?: (option: O) => void;
onSelectOption: (option: O) => void;
selectedOption: string;
align?: 'start' | 'center' | 'end';
side?: 'right' | 'top' | 'bottom' | 'left';
@@ -210,7 +210,7 @@ function VirtualizedCombobox<O extends Option>({
}}
>
{selectedOption
? options.find((option) => option.value === selectedOption).value
? options.find((option) => option.value === selectedOption)!.value
: searchPlaceholder}
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>

View File

@@ -3,12 +3,15 @@ import type {
AutocompleteProps,
} from '@/components/ui/v2/Autocomplete';
import { Autocomplete } from '@/components/ui/v2/Autocomplete';
import { isNotEmptyValue } from '@/lib/utils';
import type { MakeRequired } from '@/types/common';
import { callAll } from '@/utils/callAll';
import type { FilterOptionsState } from '@mui/material';
import type { ForwardedRef } from 'react';
import { forwardRef } from 'react';
import type { FieldValues, UseControllerProps } from 'react-hook-form';
import { useController, useFormContext } from 'react-hook-form';
import mergeRefs from 'react-merge-refs';
import { mergeRefs } from 'react-merge-refs';
export interface ControlledAutocompleteProps<
TOption extends AutocompleteOption = AutocompleteOption,
@@ -28,6 +31,63 @@ export interface ControlledAutocompleteProps<
control?: UseControllerProps<TFieldValues>['control'];
}
export function defaultFilterOptions(
options: AutocompleteOption<string>[],
{ inputValue }: FilterOptionsState<AutocompleteOption<string>>,
) {
const inputValueLower = inputValue.toLowerCase();
const matched: AutocompleteOption<string>[] = [];
const otherOptions: AutocompleteOption<string>[] = [];
options.forEach((option) => {
const optionLabelLower = option.label.toLowerCase();
if (optionLabelLower.startsWith(inputValueLower)) {
matched.push(option);
} else {
otherOptions.push(option);
}
});
const result = [...matched, ...otherOptions];
return result;
}
export function defaultFilterGroupedOptions(
options: AutocompleteOption<string>[],
{ inputValue }: FilterOptionsState<AutocompleteOption<string>>,
) {
const optionsWithGroup = options as MakeRequired<
AutocompleteOption<string>,
'group'
>[];
const inputValueLower = inputValue.toLowerCase();
const matchedSet = new Set<string>();
const otherOptionsSet = new Set<string>();
optionsWithGroup.forEach((option) => {
const optionLabelLower = option.label.toLowerCase();
if (optionLabelLower.includes(inputValueLower)) {
matchedSet.add(option.group);
otherOptionsSet.delete(option.group);
} else if (!matchedSet.has(option.group)) {
otherOptionsSet.add(option.group);
}
});
const matchedOptions = optionsWithGroup.filter((option) =>
matchedSet.has(option.group),
);
const otherOptions = optionsWithGroup.filter((option) =>
otherOptionsSet.has(option.group),
);
const result = [...matchedOptions, ...otherOptions];
return result;
}
function ControlledAutocomplete(
{
controllerProps,
@@ -38,9 +98,10 @@ function ControlledAutocomplete(
ref: ForwardedRef<HTMLInputElement>,
) {
const form = useFormContext();
const nameAttr = controllerProps?.name || name || '';
const { field } = useController({
...(controllerProps || {}),
name: controllerProps?.name || name || '',
name: nameAttr,
control: controllerProps?.control || control,
});
@@ -53,13 +114,15 @@ function ControlledAutocomplete(
return (
<Autocomplete
inputValue={
typeof field.value !== 'object' ? field.value.toString() : undefined
typeof field.value !== 'object' && isNotEmptyValue(field.value)
? field.value.toString()
: undefined
}
{...props}
{...field}
ref={mergeRefs([field.ref, ref])}
onChange={(event, options, reason, details) => {
setValue?.(controllerProps?.name || name, options, {
setValue?.(nameAttr, options, {
shouldDirty: true,
});
@@ -67,7 +130,10 @@ function ControlledAutocomplete(
props.onChange(event, options, reason, details);
}
}}
onBlur={callAll(field.onBlur, props.onBlur)}
onBlur={callAll<[React.FocusEvent<HTMLDivElement>]>(
field.onBlur,
props.onBlur,
)}
/>
);
}

View File

@@ -5,7 +5,7 @@ import type { ForwardedRef } from 'react';
import { forwardRef } from 'react';
import type { FieldValues, UseControllerProps } from 'react-hook-form';
import { useController, useFormContext } from 'react-hook-form';
import mergeRefs from 'react-merge-refs';
import { mergeRefs } from 'react-merge-refs';
export interface ControlledCheckboxProps<TFieldValues extends FieldValues = any>
extends CheckboxProps {
@@ -38,12 +38,13 @@ function ControlledCheckbox(
uncheckWhenDisabled,
...props
}: ControlledCheckboxProps,
ref: ForwardedRef<HTMLInputElement>,
ref: ForwardedRef<HTMLButtonElement>,
) {
const { setValue } = useFormContext();
const nameAttr = controllerProps?.name || name || '';
const { field } = useController({
...controllerProps,
name: controllerProps?.name || name || '',
name: nameAttr,
control: controllerProps?.control || control,
});
@@ -53,13 +54,16 @@ function ControlledCheckbox(
name={field.name}
ref={mergeRefs([field.ref, ref])}
onChange={(event, checked) => {
setValue(controllerProps?.name || name, checked, { shouldDirty: true });
setValue(nameAttr, checked, { shouldDirty: true });
if (props.onChange) {
props.onChange(event, checked);
}
}}
onBlur={callAll(field.onBlur, props.onBlur)}
onBlur={callAll<[React.FocusEvent<HTMLButtonElement>]>(
field.onBlur,
props.onBlur,
)}
checked={uncheckWhenDisabled && props.disabled ? false : field.value}
/>
);

View File

@@ -4,7 +4,7 @@ import type { ForwardedRef } from 'react';
import { forwardRef } from 'react';
import type { FieldValues, UseControllerProps } from 'react-hook-form';
import { useController, useFormContext } from 'react-hook-form';
import mergeRefs from 'react-merge-refs';
import { mergeRefs } from 'react-merge-refs';
export interface ControlledSelectProps<TFieldValues extends FieldValues = any>
extends SelectProps<TFieldValues> {
@@ -24,12 +24,13 @@ export interface ControlledSelectProps<TFieldValues extends FieldValues = any>
function ControlledSelect(
{ controllerProps, name, control, ...props }: ControlledSelectProps,
ref: ForwardedRef<HTMLInputElement>,
ref: ForwardedRef<HTMLButtonElement>,
) {
const { setValue } = useFormContext();
const nameAttr = controllerProps?.name || name || '';
const { field } = useController({
...controllerProps,
name: controllerProps?.name || name || '',
name: nameAttr,
control: controllerProps?.control || control,
});
@@ -39,7 +40,7 @@ function ControlledSelect(
{...field}
ref={mergeRefs([field.ref, ref])}
onChange={(event, value) => {
setValue(controllerProps?.name || name, value, { shouldDirty: true });
setValue(nameAttr, value, { shouldDirty: true });
if (props.onChange) {
props.onChange(event, value);

View File

@@ -2,13 +2,13 @@ import type { SwitchProps } from '@/components/ui/v2/Switch';
import { Switch } from '@/components/ui/v2/Switch';
import type { ForwardedRef } from 'react';
import { forwardRef } from 'react';
import { useController, useFormContext } from 'react-hook-form';
import type {
ControllerProps,
FieldValues,
UseControllerProps,
} from 'react-hook-form/dist/types';
import mergeRefs from 'react-merge-refs';
} from 'react-hook-form';
import { useController, useFormContext } from 'react-hook-form';
import { mergeRefs } from 'react-merge-refs';
export interface ControlledSwitchProps<TFieldValues extends FieldValues = any>
extends SwitchProps {
@@ -31,9 +31,10 @@ function ControlledSwitch(
ref: ForwardedRef<HTMLSpanElement>,
) {
const { setValue } = useFormContext();
const nameAttr = controllerProps?.name || name || '';
const { field } = useController({
...controllerProps,
name: controllerProps?.name || name || '',
name: nameAttr,
control: controllerProps?.control || control,
});
@@ -43,7 +44,7 @@ function ControlledSwitch(
{...field}
ref={mergeRefs([field.ref, ref])}
onChange={(event) => {
setValue(controllerProps?.name || name, event.target.checked, {
setValue(nameAttr, event.target.checked, {
shouldDirty: true,
});

View File

@@ -8,11 +8,11 @@ export interface FormProps extends BoxProps {
/**
* Function to be called when the form is submitted.
*/
onSubmit?: (...args: any[]) => any;
onSubmit: (...args: any[]) => any;
}
export default function Form({ onSubmit, onKeyDown, ...props }: FormProps) {
const formRef = useRef<HTMLDivElement>();
const formRef = useRef<HTMLDivElement | null>(null);
const {
handleSubmit,
formState: { isSubmitting },
@@ -28,7 +28,7 @@ export default function Form({ onSubmit, onKeyDown, ...props }: FormProps) {
}
const submitButton = Array.from(
formRef.current.getElementsByTagName('button'),
formRef.current!.getElementsByTagName('button'),
).find((item) => item.type === 'submit');
// Disabling submit if the submit button is disabled

View File

@@ -0,0 +1,59 @@
import {
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/components/ui/v3/form';
import { Input } from '@/components/ui/v3/input';
import type { Control, FieldPath, FieldValues } from 'react-hook-form';
const inputClasses =
'!bg-transparent aria-[invalid=true]:border-red-500 aria-[invalid=true]:focus:border-red-500 aria-[invalid=true]:focus:ring-red-500';
interface FormInputProps<
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
> {
control: Control<TFieldValues>;
name: TName;
label: string;
placeholder?: string;
className?: string;
type?: string;
}
function FormInput<
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
>({
control,
name,
label,
placeholder,
className = '',
type = 'text',
}: FormInputProps<TFieldValues, TName>) {
return (
<FormField
control={control}
name={name}
render={({ field }) => (
<FormItem>
<FormLabel>{label}</FormLabel>
<FormControl>
<Input
type={type}
placeholder={placeholder || label}
{...field}
className={`${inputClasses} ${className}`}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
);
}
export default FormInput;

View File

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

View File

@@ -6,19 +6,24 @@ import { Button } from '@/components/ui/v2/Button';
import { Divider } from '@/components/ui/v2/Divider';
import { Dropdown, useDropdown } from '@/components/ui/v2/Dropdown';
import { Text } from '@/components/ui/v2/Text';
import { useUserData } from '@/hooks/useUserData';
import { useAuth } from '@/providers/Auth';
import { useApolloClient } from '@apollo/client';
import { useSignOut, useUserData } from '@nhost/nextjs';
import getConfig from 'next/config';
import { useRouter } from 'next/router';
function AccountMenuContent() {
const user = useUserData();
const { signOut } = useSignOut();
const router = useRouter();
const { signout } = useAuth();
const apolloClient = useApolloClient();
const { handleClose } = useDropdown();
const { publicRuntimeConfig } = getConfig();
async function handleSignOut() {
handleClose();
await apolloClient.clearStore();
await signout();
}
return (
<Box className="grid grid-flow-row">
<Box className="grid grid-flow-col items-center justify-start gap-3 p-4">
@@ -70,12 +75,7 @@ function AccountMenuContent() {
color="error"
variant="borderless"
className="w-full justify-start"
onClick={async () => {
handleClose();
await apolloClient.clearStore();
await signOut();
await router.push('/signin');
}}
onClick={handleSignOut}
>
Sign out
</Button>

View File

@@ -2,48 +2,50 @@ import type { BaseLayoutProps } from '@/components/layout/BaseLayout';
import { BaseLayout } from '@/components/layout/BaseLayout';
import { Container } from '@/components/layout/Container';
import { Header } from '@/components/layout/Header';
import { MainNav } from '@/components/layout/MainNav';
import { useTreeNavState } from '@/components/layout/MainNav/TreeNavStateContext';
import { HighlightedText } from '@/components/presentational/HighlightedText';
import { RetryableErrorBoundary } from '@/components/presentational/RetryableErrorBoundary';
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
import { Link } from '@/components/ui/v2/Link';
import { Text } from '@/components/ui/v2/Text';
import { useIsPlatform } from '@/features/orgs/projects/common/hooks/useIsPlatform';
import { useAuthenticationStatus } from '@nhost/nextjs';
import Analytics from '@/components/analytics/analytics';
import { useMediaQuery } from '@/components/common/useMediaQuery';
import { MainNav } from '@/components/layout/MainNav';
import PinnedMainNav from '@/components/layout/MainNav/PinnedMainNav';
import { useTreeNavState } from '@/components/layout/MainNav/TreeNavStateContext';
import { RetryableErrorBoundary } from '@/components/presentational/RetryableErrorBoundary';
import { OrgStatus } from '@/features/orgs/components/OrgStatus';
import { useIsHealthy } from '@/features/orgs/projects/common/hooks/useIsHealthy';
import { useNotFoundRedirect } from '@/features/orgs/projects/common/hooks/useNotFoundRedirect';
import { cn } from '@/lib/utils';
import { useAuth } from '@/providers/Auth';
import Image from 'next/image';
import { useRouter } from 'next/router';
import { useEffect, useState } from 'react';
export interface AuthenticatedLayoutProps extends BaseLayoutProps {}
export interface AuthenticatedLayoutProps extends BaseLayoutProps {
withMainNav?: boolean;
}
export default function AuthenticatedLayout({
children,
withMainNav = true,
...props
}: AuthenticatedLayoutProps) {
const router = useRouter();
const isPlatform = useIsPlatform();
const isMdOrLarger = useMediaQuery('md');
const { isAuthenticated, isLoading } = useAuthenticationStatus();
const isHealthy = useIsHealthy();
const [mainNavContainer, setMainNavContainer] = useState(null);
const { isAuthenticated, isLoading, isSigningOut } = useAuth();
const { isHealthy, isLoading: isHealthyLoading } = useIsHealthy();
const [mainNavContainer, setMainNavContainer] = useState<HTMLElement | null>(
null,
);
const { mainNavPinned } = useTreeNavState();
useNotFoundRedirect();
useEffect(() => {
if (!isPlatform || isLoading || isAuthenticated) {
return;
}
router.push('/signin');
}, [isLoading, isAuthenticated, router, isPlatform]);
@@ -62,15 +64,15 @@ export default function AuthenticatedLayout({
router.push('/orgs/local/projects/local');
}, [isPlatform, router]);
if (isPlatform && isLoading) {
if ((isPlatform && isLoading) || isSigningOut) {
return (
<BaseLayout className="h-full" {...props}>
<Header className="flex max-h-[59px] flex-auto" />
<Header className="flex max-h-[59px] flex-auto py-1" />
</BaseLayout>
);
}
if (!isPlatform && !isHealthy) {
if (!isPlatform && !isHealthy && !isHealthyLoading) {
return (
<BaseLayout className="h-full" {...props}>
<Header className="flex max-h-[59px] flex-auto" />
@@ -124,10 +126,9 @@ export default function AuthenticatedLayout({
{mainNavPinned && isMdOrLarger && <PinnedMainNav />}
<div
className={cn(
'relative flex h-full w-full flex-row bg-accent',
mainNavPinned && isMdOrLarger ? 'overflow-x-auto' : '',
)}
className={cn('relative flex h-full w-full flex-row bg-accent', {
'overflow-x-auto': mainNavPinned && isMdOrLarger && withMainNav,
})}
>
{(!mainNavPinned || !isMdOrLarger) && (
<div className="flex h-full w-6 justify-center">
@@ -142,6 +143,7 @@ export default function AuthenticatedLayout({
>
<div className="flex h-full w-full flex-col overflow-auto">
<OrgStatus />
<Analytics />
{children}
</div>
</RetryableErrorBoundary>

View File

@@ -30,7 +30,7 @@ type Option = {
export default function OrgsComboBox() {
const { orgs } = useOrgs();
const isPlatform = useIsPlatform();
const [, setLastSlug] = useSSRLocalStorage('slug', null);
const [, setLastSlug] = useSSRLocalStorage<string | null>('slug', null);
const {
query: { orgSlug },

View File

@@ -33,6 +33,7 @@ import {
PopoverTrigger,
} from '@/components/ui/v3/popover';
import { useIsPlatform } from '@/features/orgs/projects/common/hooks/useIsPlatform';
import { useSettingsDisabled } from '@/hooks/useSettingsDisabled';
import { cn } from '@/lib/utils';
import { useRouter } from 'next/router';
import { useEffect, useMemo, useState, type ReactElement } from 'react';
@@ -55,6 +56,8 @@ export default function ProjectPagesComboBox() {
const isPlatform = useIsPlatform();
const isSettingsDisabled = useSettingsDisabled();
const projectPages = useMemo(
() => [
{
@@ -68,7 +71,7 @@ export default function ProjectPagesComboBox() {
label: 'Database',
value: 'database',
icon: <DatabaseIcon className="h-4 w-4" />,
slug: '/database/browser/default',
slug: 'database/browser/default',
disabled: false,
},
{
@@ -146,10 +149,10 @@ export default function ProjectPagesComboBox() {
value: 'settings',
icon: <CogIcon className="h-4 w-4" />,
slug: 'settings',
disabled: false,
disabled: isSettingsDisabled,
},
],
[isPlatform],
[isPlatform, isSettingsDisabled],
);
const pathSegments = useMemo(() => asPath.split('/'), [asPath]);

View File

@@ -14,7 +14,7 @@ import NavTree from './NavTree';
import { useTreeNavState } from './TreeNavStateContext';
interface MainNavProps {
container: HTMLElement;
container: HTMLElement | null;
}
export default function MainNav({ container }: MainNavProps) {
@@ -41,7 +41,7 @@ export default function MainNav({ container }: MainNavProps) {
return (
<Sheet open={open} onOpenChange={setOpen}>
<div
className="min- absolute left-0 z-50 flex h-full w-6 justify-center border-r-[1px] bg-background pt-1 hover:bg-accent"
className="min- absolute left-0 z-[39] flex h-full w-6 justify-center border-r-[1px] bg-background pt-1 hover:bg-accent"
onMouseEnter={() => setOpen(true)}
>
<Menu className="h-4 w-4" />

View File

@@ -12,12 +12,12 @@ import { StorageIcon } from '@/components/ui/v2/icons/StorageIcon';
import { UserIcon } from '@/components/ui/v2/icons/UserIcon';
import { Badge } from '@/components/ui/v3/badge';
import { Button } from '@/components/ui/v3/button';
import { useIsPlatform } from '@/features/orgs/projects/common/hooks/useIsPlatform';
import { useOrgs, type Org } from '@/features/orgs/projects/hooks/useOrgs';
import { cn } from '@/lib/utils';
import { cn, isNotEmptyValue } from '@/lib/utils';
import { getConfigServerUrl, isPlatform as getIsPlatform } from '@/utils/env';
import { Box, ChevronDown, ChevronRight, Plus } from 'lucide-react';
import Link from 'next/link';
import { useMemo, type ReactElement } from 'react';
import { type ReactElement } from 'react';
import {
ControlledTreeEnvironment,
@@ -160,7 +160,12 @@ const projectSettingsPages = [
{ name: 'Configuration Editor', slug: 'editor', route: 'editor' },
];
const createOrganization = (org: Org, isPlatform: boolean) => {
const createOrganization = (org: Org) => {
const isNotPlatform = !getIsPlatform();
const configServerVariableNotSet = getConfigServerUrl() === '';
const shouldDisableSettings = isNotPlatform && configServerVariableNotSet;
const shouldDisableGraphite = shouldDisableSettings;
const result = {};
result[org.slug] = {
@@ -211,7 +216,7 @@ const createOrganization = (org: Org, isPlatform: boolean) => {
slug: 'new',
icon: <Plus className="mr-1 h-4 w-4 font-bold" strokeWidth={3} />,
targetUrl: `/orgs/${org.slug}/projects/new`,
disabled: !isPlatform,
disabled: isNotPlatform,
},
};
@@ -238,9 +243,9 @@ const createOrganization = (org: Org, isPlatform: boolean) => {
result[`${org.slug}-${_app.subdomain}-${_page.slug}`] = {
index: `${org.slug}-${_app.subdomain}-${_page.slug}`,
canMove: false,
isFolder: _page.name === 'Settings',
isFolder: _page.name === 'Settings' && !shouldDisableSettings,
children:
_page.name === 'Settings'
_page.name === 'Settings' && !shouldDisableSettings
? projectSettingsPages.map(
(p) => `${org.slug}-${_app.subdomain}-settings-${p.slug}`,
)
@@ -251,9 +256,12 @@ const createOrganization = (org: Org, isPlatform: boolean) => {
isProjectPage: true,
targetUrl: `/orgs/${org.slug}/projects/${_app.subdomain}/${_page.route}`,
disabled:
['deployments', 'backups', 'logs', 'metrics'].includes(
(['deployments', 'backups', 'logs', 'metrics'].includes(
_page.slug,
) && !isPlatform,
) &&
isNotPlatform) ||
(_page.name === 'Settings' && shouldDisableSettings) ||
(_page.name === 'AI' && shouldDisableGraphite),
},
canRename: false,
};
@@ -272,6 +280,7 @@ const createOrganization = (org: Org, isPlatform: boolean) => {
p.slug === 'general'
? `/orgs/${org.slug}/projects/${_app.subdomain}/settings`
: `/orgs/${org.slug}/projects/${_app.subdomain}/settings/${p.route}`,
disabled: shouldDisableSettings,
},
canRename: false,
};
@@ -286,7 +295,7 @@ const createOrganization = (org: Org, isPlatform: boolean) => {
data: {
name: 'Settings',
targetUrl: `/orgs/${org.slug}/settings`,
disabled: !isPlatform,
disabled: isNotPlatform,
},
canRename: false,
};
@@ -299,7 +308,7 @@ const createOrganization = (org: Org, isPlatform: boolean) => {
data: {
name: 'Members',
targetUrl: `/orgs/${org.slug}/members`,
disabled: !isPlatform,
disabled: isNotPlatform,
},
canRename: false,
};
@@ -312,7 +321,7 @@ const createOrganization = (org: Org, isPlatform: boolean) => {
data: {
name: 'Billing',
targetUrl: `/orgs/${org.slug}/billing`,
disabled: !isPlatform,
disabled: isNotPlatform,
},
canRename: false,
};
@@ -332,8 +341,7 @@ type NavItem = {
};
const buildNavTreeData = (
org: Org,
isPlatform: boolean,
org?: Org,
): { items: Record<TreeItemIndex, TreeItem<NavItem>> } => {
if (!org) {
return {
@@ -365,7 +373,7 @@ const buildNavTreeData = (
data: { name: 'root' },
canRename: false,
},
...createOrganization(org, isPlatform),
...createOrganization(org),
},
};
@@ -374,11 +382,9 @@ const buildNavTreeData = (
export default function NavTree() {
const { currentOrg: org } = useOrgs();
const isPlatform = useIsPlatform();
const navTree = useMemo(
() => buildNavTreeData(org, isPlatform),
[org, isPlatform],
);
const navTree = buildNavTreeData(org);
const { orgsTreeViewState, setOrgsTreeViewState, setOpen } =
useTreeNavState();
@@ -421,7 +427,7 @@ export default function NavTree() {
asChild
onClick={() => {
// do not focus an item if we already there
// this will prevent the case where clikcing on the project name
// this will prevent the case where clicking on the project name
// would focus on the project name instead of the overview page
if (
navTree.items[item.index].data.targetUrl ===
@@ -436,8 +442,10 @@ export default function NavTree() {
}}
className={cn(
'flex h-8 w-full flex-row justify-start gap-1 bg-background px-1 text-foreground hover:bg-accent dark:hover:bg-muted',
context.isFocused &&
'bg-[#ebf3ff] hover:bg-[#ebf3ff] dark:bg-muted',
{
'bg-[#ebf3ff] hover:bg-[#ebf3ff] dark:bg-muted':
context.isFocused,
},
item.data.disabled && 'pointer-events-none opacity-50',
)}
>
@@ -510,13 +518,19 @@ export default function NavTree() {
canSearch={false}
onExpandItem={(item) => {
setOrgsTreeViewState(
({ expandedItems: prevExpandedItems, ...rest }) => ({
...rest,
// Add item index to expandedItems only if it's not already present
expandedItems: prevExpandedItems.includes(item.index)
? prevExpandedItems
: [...prevExpandedItems, item.index],
}),
({ expandedItems: prevExpandedItems, ...rest }) => {
const newExpandedItems = isNotEmptyValue(prevExpandedItems)
? [...prevExpandedItems]
: [];
return {
...rest,
// Add item index to expandedItems only if it's not already present
expandedItems: newExpandedItems?.includes(item.index)
? prevExpandedItems
: [...newExpandedItems, item.index],
};
},
);
}}
onCollapseItem={(item) => {
@@ -524,7 +538,7 @@ export default function NavTree() {
({ expandedItems: prevExpandedItems, ...rest }) => ({
...rest,
// Remove the item index from expandedItems
expandedItems: prevExpandedItems.filter(
expandedItems: (prevExpandedItems ?? []).filter(
(index) => index !== item.index,
),
}),

View File

@@ -12,7 +12,7 @@ export default function PinnedMainNav() {
query: { orgSlug },
} = useRouter();
const scrollContainerRef = useRef();
const scrollContainerRef = useRef<HTMLDivElement | null>(null);
const { mainNavPinned, setMainNavPinned } = useTreeNavState();
useEffect(() => {
@@ -33,6 +33,8 @@ export default function PinnedMainNav() {
observer.observe(scrollContainerRef.current, {
childList: true,
subtree: true,
// run scrollToElement when the class changes because of focus
attributeFilter: ['class'],
});
}

View File

@@ -31,25 +31,19 @@ interface TreeNavProviderProps {
children: ReactNode;
}
function useSyncedTreeViewState(
useTreeStateFromURL: () => {
expandedItems: string[];
focusedItem: string | null;
},
) {
const { expandedItems, focusedItem } = useTreeStateFromURL();
function useSyncedTreeViewState() {
const { expandedItems, focusedItem } = useNavTreeStateFromURL();
const [state, setState] = useState<IndividualTreeViewState<never>>({
const [state, setState] = useState<IndividualTreeViewState>({
expandedItems,
focusedItem,
selectedItems: null,
});
useEffect(() => {
setState((prevState) => ({
...prevState,
expandedItems: [
...new Set([...prevState.expandedItems, ...expandedItems]),
...new Set([...(prevState.expandedItems ?? []), ...expandedItems]),
],
focusedItem,
}));
@@ -64,7 +58,7 @@ function TreeNavStateProvider({ children }: TreeNavProviderProps) {
'pin-nav-tree',
true,
);
const orgsTreeViewState = useSyncedTreeViewState(useNavTreeStateFromURL);
const orgsTreeViewState = useSyncedTreeViewState();
const value = useMemo(
() => ({

View File

@@ -10,8 +10,8 @@ import { List } from '@/components/ui/v2/List';
import { ListItem } from '@/components/ui/v2/ListItem';
import { Text } from '@/components/ui/v2/Text';
import { useIsPlatform } from '@/features/orgs/projects/common/hooks/useIsPlatform';
import { useAuth } from '@/providers/Auth';
import { useApolloClient } from '@apollo/client';
import { useSignOut } from '@nhost/nextjs';
import getConfig from 'next/config';
import { useRouter } from 'next/router';
import { useState } from 'react';
@@ -22,11 +22,18 @@ export interface MobileNavProps extends ButtonProps {}
export default function MobileNav({ className, ...props }: MobileNavProps) {
const isPlatform = useIsPlatform();
const [menuOpen, setMenuOpen] = useState(false);
const { signOut } = useSignOut();
const { signout } = useAuth();
const apolloClient = useApolloClient();
const router = useRouter();
const { publicRuntimeConfig } = getConfig();
async function handleSignOut() {
setMenuOpen(false);
await apolloClient.clearStore();
await signout();
await router.push('/signin');
}
return (
<>
<Button
@@ -120,12 +127,7 @@ export default function MobileNav({ className, ...props }: MobileNavProps) {
variant="borderless"
sx={{ color: 'error.main' }}
className="justify-start border-none px-2 py-2.5 text-[16px]"
onClick={async () => {
setMenuOpen(false);
await apolloClient.clearStore();
await signOut();
await router.push('/signin');
}}
onClick={handleSignOut}
>
Sign Out
</ListItem.Button>

View File

@@ -146,7 +146,7 @@ export default function SettingsContainer({
{!switchId && showSwitch && (
<Switch
checked={enabled}
onChange={(e) => onEnabledChange(e.target.checked)}
onChange={(e) => onEnabledChange?.(e.target.checked)}
className="self-center"
{...switchSlot}
/>

View File

@@ -6,21 +6,24 @@ import { RetryableErrorBoundary } from '@/components/presentational/RetryableErr
import { Box } from '@/components/ui/v2/Box';
import { ThemeProvider } from '@/components/ui/v2/ThemeProvider';
import { useIsPlatform } from '@/features/orgs/projects/common/hooks/useIsPlatform';
import { useAuth } from '@/providers/Auth';
import GlobalStyles from '@mui/material/GlobalStyles';
import { useAuthenticationStatus } from '@nhost/nextjs';
import Image from 'next/image';
import { useRouter } from 'next/router';
import { useEffect } from 'react';
export interface UnauthenticatedLayoutProps extends BaseLayoutProps {}
export interface UnauthenticatedLayoutProps extends BaseLayoutProps {
rightColumnContent?: React.ReactNode;
}
export default function UnauthenticatedLayout({
children,
rightColumnContent,
...props
}: UnauthenticatedLayoutProps) {
const router = useRouter();
const isPlatform = useIsPlatform();
const { isAuthenticated, isLoading } = useAuthenticationStatus();
const { isAuthenticated, isLoading } = useAuth();
const isOnResetPassword = router.route === '/password/reset';
useEffect(() => {
@@ -63,38 +66,46 @@ export default function UnauthenticatedLayout({
>
<Container
rootClassName="bg-transparent h-full"
className="grid h-full w-full items-center justify-items-center gap-12 bg-transparent pb-12 pt-8 lg:grid-cols-2 lg:gap-4 lg:pb-0 lg:pt-0"
className="grid h-full w-full items-center justify-items-center gap-12 bg-transparent pb-12 pt-8 lg:grid-cols-2 lg:gap-4 lg:pb-0 lg:pt-8"
>
<div className="relative z-10 order-2 grid w-full max-w-[544px] grid-flow-row gap-12 lg:order-1">
{children}
</div>
<div className="relative z-0 order-1 flex h-full w-full items-center justify-center md:min-h-[150px] lg:order-2 lg:min-h-[none]">
<div className="absolute bottom-0 left-0 right-0 top-0 mx-auto flex h-full w-full max-w-xl items-center justify-center overflow-hidden opacity-70">
<div className="relative z-0 order-1 flex h-full w-full flex-col items-center justify-center md:min-h-[150px] lg:order-2 lg:min-h-[none] lg:gap-8">
<div className="relative flex items-center justify-center">
<div className="absolute bottom-0 left-0 right-0 top-0 mx-auto flex h-full w-full max-w-xl items-center justify-center overflow-hidden opacity-70">
<Image
priority
src="/assets/line-grid.svg"
width={1003}
height={644}
alt="Transparent lines"
objectFit="fill"
className="h-full w-full scale-[200%]"
/>
</div>
<Box
className="backface-hidden absolute left-0 right-0 z-0 mx-auto h-20 w-20 transform-gpu rounded-full opacity-80 blur-[56px]"
sx={{
backgroundColor: (theme) => theme.palette.primary.main,
}}
/>
<Image
priority
src="/assets/line-grid.svg"
width={1003}
height={644}
alt="Transparent lines"
objectFit="fill"
className="h-full w-full scale-[200%]"
src="/assets/logo.svg"
width={119}
height={40}
alt="Nhost Logo"
/>
</div>
<Box
className="backface-hidden absolute left-0 right-0 z-0 mx-auto h-20 w-20 transform-gpu rounded-full opacity-80 blur-[56px]"
sx={{
backgroundColor: (theme) => theme.palette.primary.main,
}}
/>
<Image
src="/assets/logo.svg"
width={119}
height={40}
alt="Nhost Logo"
/>
{rightColumnContent && (
<div className="relative z-10 w-full max-w-md px-4 lg:px-0">
{rightColumnContent}
</div>
)}
</div>
</Container>
</Box>

View File

@@ -6,8 +6,8 @@ import {
type ReactElement,
} from 'react';
import { CopyToClipboardButton as CopyToClipboardButtonOriginal } from '@/components/presentational/CopyToClipboardButton';
import { Box } from '@/components/ui/v2/Box';
import { CopyToClipboardButton as CopyToClipboardButtonOriginal } from './CopyToClipboardButton';
import { getNodeText } from './getNodeText';
export interface CodeBlockPropsBase {
@@ -19,7 +19,7 @@ export interface CodeBlockPropsBase {
/**
* Text of the toast that appears when the code is copied to the clipboard.
*/
copyToClipboardToastTitle?: string;
copyToClipboardToastTitle: string;
}
export type CodeBlockProps = CodeBlockPropsBase &
@@ -63,7 +63,7 @@ interface CopyToClipboardButtonProps
> {
filenameColor?: string;
tooltipColor?: string;
toastTitle?: string;
toastTitle: string;
}
function CopyToClipboardButton({

View File

@@ -1,22 +1,19 @@
import { Button, type ButtonProps } from '@/components/ui/v3/button';
import { isNotEmptyValue } from '@/lib/utils';
import { copy } from '@/utils/copy';
import { clsx } from 'clsx';
import { Copy } from 'lucide-react';
import { useEffect, useState } from 'react';
import {
IconButton,
type IconButtonProps,
} from '@/components/ui/v2/IconButton';
import { CopyIcon } from '@/components/ui/v2/icons/CopyIcon';
import { copy } from '@/utils/copy';
export function CopyToClipboardButton({
function CopyToClipboardButton({
textToCopy,
className,
title,
...props
}: {
textToCopy: string;
textToCopy?: string | null;
title: string;
} & IconButtonProps) {
} & ButtonProps) {
const [disabled, setDisabled] = useState(true);
useEffect(() => {
@@ -35,12 +32,18 @@ export function CopyToClipboardButton({
if (!textToCopy || disabled) {
return null;
}
const hasChildren = isNotEmptyValue(props.children);
return (
<IconButton
variant="borderless"
color="secondary"
className={clsx('group', className)}
<Button
type="button"
size="icon"
variant="outline"
className={clsx(
'group h-fit w-fit border-0 bg-transparent p-[2px] hover:bg-[#d6eefb] dark:hover:bg-[#1e2942]',
className,
{ 'gap-3': hasChildren },
)}
onClick={(event) => {
event.stopPropagation();
@@ -49,7 +52,9 @@ export function CopyToClipboardButton({
aria-label={textToCopy}
{...props}
>
<CopyIcon className="top-5 h-4 w-4" />
</IconButton>
{props.children}
<Copy className="top-5 h-4 w-4" />
</Button>
);
}
export default CopyToClipboardButton;

View File

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

View File

@@ -1,13 +1,11 @@
import { useUI } from '@/components/common/UIProvider';
import { Alert } from '@/components/ui/v2/Alert';
export default function MaintenanceAlert() {
const { maintenanceActive, maintenanceEndDate } = useUI();
if (!maintenanceActive) {
return null;
}
function MaintenceEndDate({
maintenanceEndDate,
}: {
maintenanceEndDate: Date;
}) {
const dateTimeFormat = Intl.DateTimeFormat(undefined, {
hour: '2-digit',
minute: '2-digit',
@@ -27,6 +25,21 @@ export default function MaintenanceAlert() {
const minute = parts.find((part) => part.type === 'minute')?.value;
const timeZone = parts.find((part) => part.type === 'timeZoneName')?.value;
return (
<p>
Maintenance is expected to be completed at {year}-{month}-{day} {hour}:
{minute} {timeZone}.
</p>
);
}
export default function MaintenanceAlert() {
const { maintenanceActive, maintenanceEndDate } = useUI();
if (!maintenanceActive) {
return null;
}
return (
<Alert severity="warning" className="mt-4">
<p>
@@ -36,10 +49,7 @@ export default function MaintenanceAlert() {
</p>
{maintenanceEndDate && (
<p>
Maintenance is expected to be completed at {year}-{month}-{day} {hour}
:{minute} {timeZone}.
</p>
<MaintenceEndDate maintenanceEndDate={maintenanceEndDate} />
)}
</Alert>
);

View File

@@ -5,8 +5,10 @@ import type { DetailedHTMLProps, ForwardedRef, HTMLProps } from 'react';
import { forwardRef } from 'react';
import { twMerge } from 'tailwind-merge';
export interface ReadOnlyToggleProps
extends DetailedHTMLProps<HTMLProps<HTMLSpanElement>, HTMLSpanElement> {
export type ReadOnlyToggleProps = Omit<
DetailedHTMLProps<HTMLProps<HTMLSpanElement>, HTMLSpanElement>,
'checked'
> & {
/**
* Determines whether the toggle is checked or not.
*/
@@ -24,7 +26,7 @@ export interface ReadOnlyToggleProps
*/
label?: TextProps;
};
}
};
function ReadOnlyToggle(
{ checked, className, slotProps = {}, ...props }: ReadOnlyToggleProps,

View File

@@ -1,64 +0,0 @@
import type { BoxProps } from '@/components/ui/v2/Box';
import { Box } from '@/components/ui/v2/Box';
import { twMerge } from 'tailwind-merge';
export type AvatarProps = Pick<BoxProps, 'component'> & {
style?: {
[key: string]: string;
};
className?: string;
avatarUrl?: string | null;
name?: string | null;
};
/**
* @deprecated Use `v2/Avatar` instead.
*/
export default function Avatar({
style = {},
className = '',
avatarUrl,
name = '',
...rest
}: AvatarProps) {
const noAvatar = !avatarUrl || avatarUrl.includes('blank');
const classes = twMerge(
'border rounded-full bg-cover bg-center',
className,
noAvatar && 'border-0 text-white flex items-center justify-center',
);
if (noAvatar) {
const initials = name
.split(' ')
.slice(0, 2)
.map((currentNamePart) => `${currentNamePart.charAt(0).toUpperCase()}`)
.join('');
return (
<Box
className={classes}
style={style}
sx={{
backgroundColor: (theme) =>
theme.palette.mode === 'dark' ? `grey.400` : `grey.500`,
color: (theme) => `${theme.palette.common.white} !important`,
}}
{...rest}
>
{initials}
</Box>
);
}
return (
<Box
style={Object.assign(style, { backgroundImage: `url(${avatarUrl})` })}
className={classes}
aria-label={name ? `Avatar of ${name}` : 'Avatar'}
role="img"
{...rest}
/>
);
}

View File

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

View File

@@ -11,7 +11,7 @@ export default function ClientOnlyPortal({
children,
selector,
}: ClientOnlyPortalProps) {
const ref = useRef();
const ref = useRef<Element | DocumentFragment>();
const [mounted, setMounted] = useState(false);
useEffect(() => {
@@ -19,5 +19,5 @@ export default function ClientOnlyPortal({
setMounted(true);
}, [selector]);
return mounted ? createPortal(children, ref.current) : null;
return mounted ? createPortal(children, ref.current!) : null;
}

View File

@@ -18,7 +18,7 @@ import MaterialAutocomplete, {
} from '@mui/material/Autocomplete';
import clsx from 'clsx';
import type { ForwardedRef } from 'react';
import { forwardRef, useEffect, useRef, useState } from 'react';
import { forwardRef, useEffect, useState } from 'react';
export interface AutocompleteOption<TValue = string> {
/**
@@ -51,7 +51,7 @@ export interface AutocompleteProps<
TOption extends AutocompleteOption = AutocompleteOption,
> extends Omit<
MaterialAutocompleteProps<TOption, boolean, boolean, boolean>,
'renderInput' | 'autoSelect' | 'componentsProps'
'renderInput' | 'autoSelect' | 'componentsProps' | 'isOptionEqualToValue'
>,
Pick<
InputProps,
@@ -100,11 +100,20 @@ export interface AutocompleteProps<
*
* @default 'never'
*/
showCustomOption?: 'always' | 'never' | 'auto';
showCustomOption?: 'always' | 'never' | 'auto' | 'first';
/**
* Custom option label.
*/
customOptionLabel?: string | ((customOptionLabel: string) => string);
isOptionEqualToValue?: (
option: AutocompleteOption<string>,
value: string | AutocompleteOption<string>,
) => boolean;
sortByOptions?: (
option1: AutocompleteOption<string>,
option2: AutocompleteOption<string>,
) => number;
}
const StyledTag = styled(Chip)(({ theme }) => ({
@@ -213,11 +222,11 @@ function Autocomplete(
customOptionLabel: externalCustomOptionLabel,
showCustomOption = 'never',
'aria-label': ariaLabel,
sortByOptions,
...props
}: AutocompleteProps<AutocompleteOption>,
ref: ForwardedRef<HTMLInputElement>,
) {
const inputRef = useRef<HTMLInputElement>();
const { formControl: formControlSlotProps, ...defaultComponentsProps } =
slotProps || {};
@@ -228,7 +237,7 @@ function Autocomplete(
// TODO: Revisit this implementation. We should probably have a better way to
// make this component controlled.
useEffect(() => {
setInputValue(externalInputValue);
setInputValue(externalInputValue ?? '');
}, [externalInputValue]);
const filterOptionsFn = externalFilterOptions || filterOptions;
@@ -264,6 +273,7 @@ function Autocomplete(
openOnFocus
disablePortal
disableClearable
autoFocus={false}
componentsProps={{
...defaultComponentsProps,
popper: {
@@ -316,7 +326,7 @@ function Autocomplete(
}}
isOptionEqualToValue={(
option,
value: string | number | AutocompleteOption<string>,
value: string | AutocompleteOption<string>,
) => {
if (!value) {
return false;
@@ -392,7 +402,24 @@ function Autocomplete(
if (!inputValue) {
return filteredOptions;
}
if (showCustomOption === 'first') {
const isInputValueInOptions = filteredOptions.some(
(filteredOption) => filteredOption.label === inputValue,
);
return isInputValueInOptions
? filteredOptions
: [
{
value: inputValue,
label: inputValue,
dropdownLabel:
customOptionLabel || `Select "${inputValue}"`,
custom: Boolean(inputValue),
},
...filteredOptions,
];
}
if (showCustomOption === 'auto') {
const isInputValueInOptions = filteredOptions.some(
(filteredOption) => filteredOption.label === inputValue,
@@ -431,7 +458,6 @@ function Autocomplete(
...params
}) => (
<Input
ref={inputRef}
slotProps={{
input: {
className: slotProps?.input?.className,

View File

@@ -92,7 +92,7 @@ function Checkbox(
'aria-label': ariaLabel,
...props
}: CheckboxProps,
ref: ForwardedRef<HTMLInputElement>,
ref: ForwardedRef<HTMLButtonElement>,
) {
if (!label) {
return (

View File

@@ -31,7 +31,9 @@ function ColorPreferenceProvider({
colorPreferenceStorageKey,
);
if (!['light', 'dark', 'system'].includes(storedColorPreference)) {
if (
!['light', 'dark', 'system'].includes(storedColorPreference as string)
) {
setColorPreference('system');
return;

View File

@@ -9,16 +9,15 @@ import { pickersDayClasses } from '@mui/x-date-pickers/PickersDay';
import type { StaticDatePickerProps } from '@mui/x-date-pickers/StaticDatePicker';
import { StaticDatePicker } from '@mui/x-date-pickers/StaticDatePicker';
export interface DatePickerProps
extends Omit<
StaticDatePickerProps<any, Date>,
'renderInput' | 'componentsProps' | 'renderDay'
> {
export type DatePickerProps = Omit<
StaticDatePickerProps<any, Date>,
'renderInput' | 'componentsProps' | 'renderDay' | 'onChange' | 'value'
> & {
/**
* Date value to be displayed in the datepicker.
* It should be of "yyyy-MM-dd'T'HH:mm" format.
*/
value: Date;
value: Date | null;
/**
* If true, it will not allow the user to select any date.
*/
@@ -35,7 +34,7 @@ export interface DatePickerProps
* Function to be called when the user selects a date.
*/
onChange: (value: Date, keyboardInputValue?: string) => void;
}
};
const CustomStaticDatePicker = styled(StaticDatePicker)(({ theme }) => ({
borderRadius: '10px',
@@ -177,7 +176,12 @@ function DatePicker({
minDate={minDate}
maxDate={maxDate}
onChange={(newValue) => onChange(newValue as Date)}
renderInput={() => null}
renderInput={
(() => null) as unknown as StaticDatePickerProps<
any,
Date
>['renderInput']
}
/>
</LocalizationProvider>
);

View File

@@ -3,10 +3,10 @@ import { ChevronUpIcon } from '@/components/ui/v2/icons/ChevronUpIcon';
import { CopyIcon } from '@/components/ui/v2/icons/CopyIcon';
import { XIcon } from '@/components/ui/v2/icons/XIcon';
import { useProject } from '@/features/orgs/projects/hooks/useProject';
import { useUserData } from '@/hooks/useUserData';
import { getToastBackgroundColor } from '@/utils/constants/settings';
import { copy } from '@/utils/copy';
import type { ApolloError } from '@apollo/client';
import { useUserData } from '@nhost/nextjs';
import { AnimatePresence, motion } from 'framer-motion';
import { useRouter } from 'next/router';
import { useState } from 'react';

View File

@@ -5,7 +5,7 @@ import type { InputBaseProps as MaterialInputBaseProps } from '@mui/material/Inp
import MaterialInputBase, { inputBaseClasses } from '@mui/material/InputBase';
import type { DetailedHTMLProps, ForwardedRef, HTMLProps } from 'react';
import { forwardRef } from 'react';
import mergeRefs from 'react-merge-refs';
import { mergeRefs } from 'react-merge-refs';
export interface InputProps
extends Omit<MaterialInputBaseProps, 'componentsProps' | 'slotProps'>,

View File

@@ -15,7 +15,9 @@ const LinearProgress = styled(MaterialLinearProgress)(({ theme, value }) => ({
},
[`& .${linearProgressClasses.bar}`]: {
backgroundColor:
value >= 100 ? theme.palette.error.dark : theme.palette.primary.main,
value && value >= 100
? theme.palette.error.dark
: theme.palette.primary.main,
},
}));

View File

@@ -41,7 +41,7 @@ const StyledOption = styled(BaseOption)(({ theme }) => ({
},
}));
function Option<TValue>(
function Option<TValue extends {}>(
{ children, ...props }: OptionProps<TValue>,
ref: ForwardedRef<HTMLLIElement>,
) {

View File

@@ -57,7 +57,7 @@ const StyledRadio = styled(MaterialRadio)(({ theme }) => ({
function Radio(
{ label, value, slotProps, ...props }: RadioProps,
ref: ForwardedRef<HTMLInputElement>,
ref: ForwardedRef<HTMLButtonElement>,
) {
return (
<StyledFormControlLabel

View File

@@ -63,7 +63,7 @@ const StyledPopper = styled(BasePopper)`
z-index: 9999;
`;
function Select<TValue>(
function Select<TValue extends {}>(
{
className,
slotProps,

View File

@@ -60,7 +60,7 @@ function Slider(
ref={ref}
components={{
Rail: SliderRail({
value: allowed,
value: allowed ?? 0,
max: props.max,
marks: props.marks,
step: props.step,
@@ -69,7 +69,7 @@ function Slider(
}}
color="primary"
{...props}
marks={allowed > 0 ? false : props.marks}
marks={allowed && allowed > 0 ? false : props.marks}
/>
);
}

View File

@@ -29,9 +29,6 @@ function ThemeProviderContent({
'html, body': {
backgroundColor: `${theme.palette.background.default} !important`,
},
html: {
class: `${preferredColor}`,
},
}}
/>
<Head>

View File

@@ -1,5 +1,5 @@
import { cva, type VariantProps } from 'class-variance-authority';
import * as React from 'react';
import { forwardRef, type ForwardedRef } from 'react';
import { cn } from '@/lib/utils';
@@ -27,10 +27,19 @@ export interface BadgeProps
extends React.HTMLAttributes<HTMLDivElement>,
VariantProps<typeof badgeVariants> {}
function Badge({ className, variant, ...props }: BadgeProps) {
return (
<div className={cn(badgeVariants({ variant }), className)} {...props} />
);
}
const Badge = forwardRef(
(
{ className, variant, ...props }: BadgeProps,
ref: ForwardedRef<HTMLDivElement>,
) => {
return (
<div
ref={ref}
className={cn(badgeVariants({ variant }), className)}
{...props}
/>
);
},
);
export { Badge, badgeVariants };

View File

@@ -30,36 +30,44 @@ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
interface DialogContentProps
extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> {
disableOutsideClick?: boolean;
hideCloseButton?: boolean;
}
const DialogContent = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Content>,
DialogContentProps
>(({ className, children, disableOutsideClick, ...props }, ref) => (
<DialogPortal>
<DialogOverlay>
<DialogPrimitive.Content
ref={ref}
className={cn(
'relative z-50 grid w-full max-w-lg gap-4 bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 sm:rounded-lg md:w-full',
className,
)}
onInteractOutside={
disableOutsideClick
? (e) => e.preventDefault()
: props.onInteractOutside
}
{...props}
>
{children}
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
<X className="h-4 w-4" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
</DialogPrimitive.Content>
</DialogOverlay>
</DialogPortal>
));
>(
(
{ className, children, disableOutsideClick, hideCloseButton, ...props },
ref,
) => (
<DialogPortal>
<DialogOverlay>
<DialogPrimitive.Content
ref={ref}
className={cn(
'relative z-50 grid w-full max-w-lg gap-4 bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 sm:rounded-lg md:w-full',
className,
)}
onInteractOutside={
disableOutsideClick
? (e) => e.preventDefault()
: props.onInteractOutside
}
{...props}
>
{children}
{!hideCloseButton && (
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
<X className="h-4 w-4" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
)}
</DialogPrimitive.Content>
</DialogOverlay>
</DialogPortal>
),
);
DialogContent.displayName = DialogPrimitive.Content.displayName;
const DialogHeader = ({

View File

@@ -13,16 +13,17 @@ import { cn } from '@/lib/utils';
import { Command as CommandPrimitive } from 'cmdk';
import {
useCallback,
useEffect,
useMemo,
useRef,
useState,
type KeyboardEvent,
} from 'react';
type Option = Record<'value' | 'label', string>;
export type Option = Record<'value' | 'label', string>;
interface FancyMultiSelectProps {
defaultValue?: Option[];
value?: Option[];
options?: Option[];
creatable?: boolean;
className?: string;
@@ -30,7 +31,7 @@ interface FancyMultiSelectProps {
}
export function FancyMultiSelect({
defaultValue = [],
value = [],
options = [],
creatable = false,
className,
@@ -38,9 +39,13 @@ export function FancyMultiSelect({
}: FancyMultiSelectProps) {
const inputRef = useRef<HTMLInputElement>(null);
const [open, setOpen] = useState(false);
const [selected, setSelected] = useState<Option[]>(defaultValue);
const [selected, setSelected] = useState<Option[]>(value);
const [inputValue, setInputValue] = useState('');
useEffect(() => {
setSelected(value);
}, [value]);
const handleUnselect = useCallback((option: Option) => {
setSelected((prev) => prev.filter((s) => s.value !== option.value));
}, []);
@@ -64,17 +69,12 @@ export function FancyMultiSelect({
}
}, []);
const handleSelect = useCallback(
(option: Option) => {
setInputValue('');
setSelected((prev) => {
const newSelected = [...prev, option];
onChange?.(newSelected);
return newSelected;
});
},
[onChange],
);
function handleSelect(option: Option) {
setInputValue('');
const newSelected = [...selected, option];
setSelected(newSelected);
onChange?.(newSelected);
}
const selectables = useMemo(() => {
const filtered = options.filter(
@@ -87,7 +87,7 @@ export function FancyMultiSelect({
return [
...filtered,
{
value: inputValue.toLowerCase(),
value: inputValue,
label: inputValue,
},
];
@@ -115,7 +115,10 @@ export function FancyMultiSelect({
key={option.value}
variant="outline"
>
<span className="overflow-x-hidden text-ellipsis whitespace-nowrap break-words font-medium">
<span
className="overflow-x-hidden text-ellipsis whitespace-nowrap break-words font-medium"
data-testid={`badge-${option.label}`}
>
{option.label}
</span>
<button

View File

@@ -20,7 +20,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
type={type}
className={cn(
'flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-0 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-accent',
prefix && 'pl-6',
{ 'pl-6': prefix },
className,
)}
ref={ref}

View File

@@ -0,0 +1,363 @@
import { Badge } from '@/components/ui/v3/badge';
import { Button } from '@/components/ui/v3/button';
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
CommandSeparator,
} from '@/components/ui/v3/command';
import {
Popover,
PopoverContent,
PopoverTrigger,
} from '@/components/ui/v3/popover';
import { cn, isNotEmptyValue } from '@/lib/utils';
import { CheckIcon, ChevronsUpDownIcon, XIcon } from 'lucide-react';
import {
createContext,
useCallback,
useContext,
useEffect,
useLayoutEffect,
useMemo,
useRef,
useState,
type ComponentPropsWithoutRef,
type ReactNode,
} from 'react';
type MultiSelectContextType = {
open: boolean;
setOpen: (open: boolean) => void;
selectedValues: Set<string>;
toggleValue: (value: string) => void;
items: Map<string, ReactNode>;
onItemAdded: (value: string, label: ReactNode) => void;
};
const MultiSelectContext = createContext<MultiSelectContextType | null>(null);
function useMultiSelectContext() {
const context = useContext(MultiSelectContext);
if (context == null) {
throw new Error(
'useMultiSelectContext must be used within a MultiSelectContext',
);
}
return context;
}
export function MultiSelect({
children,
values,
defaultValues,
onValuesChange,
}: {
children: ReactNode;
values?: string[];
defaultValues?: string[];
onValuesChange?: (values: string[]) => void;
}) {
const [open, setOpen] = useState(false);
const [selectedValues, setSelectedValues] = useState(
new Set<string>(values ?? defaultValues),
);
const [items, setItems] = useState<Map<string, ReactNode>>(new Map());
const toggleValue = useCallback(
(value: string) => {
const getNewSet = (prev: Set<string>) => {
const newSet = new Set(prev);
if (newSet.has(value)) {
newSet.delete(value);
} else {
newSet.add(value);
}
return newSet;
};
setSelectedValues(getNewSet);
onValuesChange?.([...getNewSet(selectedValues)]);
},
[onValuesChange, selectedValues],
);
const onItemAdded = useCallback((value: string, label: ReactNode) => {
setItems((prev) => {
if (prev.get(value) === label) {
return prev;
}
return new Map(prev).set(value, label);
});
}, []);
const value = useMemo(
() => ({
open,
setOpen,
selectedValues: values ? new Set(values) : selectedValues,
toggleValue,
items,
onItemAdded,
}),
[open, values, items, toggleValue, onItemAdded, selectedValues],
);
return (
<MultiSelectContext.Provider value={value}>
<Popover open={open} onOpenChange={setOpen}>
{children}
</Popover>
</MultiSelectContext.Provider>
);
}
export function MultiSelectTrigger({
className,
children,
...props
}: {
className?: string;
children?: ReactNode;
} & ComponentPropsWithoutRef<typeof Button>) {
const { open } = useMultiSelectContext();
return (
<PopoverTrigger asChild>
<Button
{...props}
variant={props.variant ?? 'outline'}
role={props.role ?? 'combobox'}
aria-expanded={props['aria-expanded'] ?? open}
className={cn(
"shadow-xs aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 flex h-auto min-h-9 w-fit items-center justify-between gap-2 overflow-hidden whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-1.5 text-sm outline-none transition-[color,box-shadow] focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 data-[placeholder]:text-muted-foreground dark:bg-input/30 dark:hover:bg-input/50 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0",
className,
)}
>
{children}
<ChevronsUpDownIcon className="size-4 shrink-0 opacity-50" />
</Button>
</PopoverTrigger>
);
}
export function MultiSelectValue({
placeholder,
clickToRemove = true,
className,
placeHolderClassName,
overflowBehavior = 'wrap-when-open',
...props
}: {
placeholder?: string;
clickToRemove?: boolean;
overflowBehavior?: 'wrap' | 'wrap-when-open' | 'cutoff';
placeHolderClassName?: string;
} & Omit<ComponentPropsWithoutRef<'div'>, 'children'>) {
const { selectedValues, toggleValue, items, open } = useMultiSelectContext();
const [overflowAmount, setOverflowAmount] = useState(0);
const valueRef = useRef<HTMLDivElement | null>(null);
const overflowRef = useRef<HTMLDivElement | null>(null);
const resizeObserverRef = useRef<ResizeObserver | null>(null);
const shouldWrap =
overflowBehavior === 'wrap' ||
(overflowBehavior === 'wrap-when-open' && open);
const checkOverflow = useCallback(() => {
if (valueRef.current == null) {
return;
}
const containerElement = valueRef.current;
const overflowElement = overflowRef.current;
const selectedItems = containerElement.querySelectorAll<HTMLElement>(
'[data-selected-item]',
);
if (overflowElement != null) {
overflowElement.style.display = 'none';
}
selectedItems.forEach((child) => child.style.removeProperty('display'));
let amount = 0;
// eslint-disable-next-line no-plusplus
for (let i = selectedItems.length - 1; i >= 0; i--) {
const child = selectedItems[i];
if (containerElement.scrollWidth <= containerElement.clientWidth) {
break;
}
amount = selectedItems.length - i;
child.style.display = 'none';
overflowElement?.style.removeProperty('display');
}
setOverflowAmount(amount);
}, []);
useLayoutEffect(() => {
checkOverflow();
}, [selectedValues, checkOverflow, shouldWrap]);
const handleResize = useCallback(
(node: HTMLDivElement) => {
if (isNotEmptyValue(node)) {
valueRef.current = node;
resizeObserverRef.current = new ResizeObserver(checkOverflow);
resizeObserverRef.current.observe(node);
} else {
resizeObserverRef.current?.disconnect();
resizeObserverRef.current = null;
valueRef.current = null;
}
},
[checkOverflow],
);
if (selectedValues.size === 0 && placeholder) {
return (
<span
className={cn(
'min-w-0 overflow-hidden font-normal text-muted-foreground',
placeHolderClassName,
)}
>
{placeholder}
</span>
);
}
return (
<div
{...props}
ref={handleResize}
className={cn(
'flex w-full gap-1.5 overflow-hidden',
shouldWrap && 'h-full flex-wrap',
className,
)}
>
{[...selectedValues]
.filter((value) => items.has(value))
.map((value) => (
<Badge
variant="outline"
data-selected-item
className="group flex items-center gap-1"
key={value}
onClick={
clickToRemove
? (e) => {
e.stopPropagation();
toggleValue(value);
}
: undefined
}
>
{items.get(value)}
{clickToRemove && (
<XIcon className="size-2 text-muted-foreground group-hover:text-destructive" />
)}
</Badge>
))}
<Badge
style={{
display: overflowAmount > 0 && !shouldWrap ? 'block' : 'none',
}}
variant="outline"
ref={overflowRef}
>
+{overflowAmount}
</Badge>
</div>
);
}
export function MultiSelectContent({
search = true,
children,
...props
}: {
search?: boolean | { placeholder?: string; emptyMessage?: string };
children: ReactNode;
} & Omit<ComponentPropsWithoutRef<typeof Command>, 'children'>) {
const canSearch = typeof search === 'object' ? true : search;
return (
<>
<div style={{ display: 'none' }}>
<Command>
<CommandList>{children}</CommandList>
</Command>
</div>
<PopoverContent className="min-w-[var(--radix-popover-trigger-width)] p-0">
<Command {...props}>
{canSearch ? (
<CommandInput
placeholder={
typeof search === 'object' ? search.placeholder : undefined
}
/>
) : (
// eslint-disable-next-line jsx-a11y/control-has-associated-label, jsx-a11y/no-autofocus
<button type="button" autoFocus className="sr-only" />
)}
<CommandList>
{canSearch && (
<CommandEmpty>
{typeof search === 'object' ? search.emptyMessage : undefined}
</CommandEmpty>
)}
{children}
</CommandList>
</Command>
</PopoverContent>
</>
);
}
export function MultiSelectItem({
value,
children,
badgeLabel,
onSelect,
...props
}: {
badgeLabel?: ReactNode;
value: string;
} & Omit<ComponentPropsWithoutRef<typeof CommandItem>, 'value'>) {
const { toggleValue, selectedValues, onItemAdded } = useMultiSelectContext();
const isSelected = selectedValues.has(value);
useEffect(() => {
onItemAdded(value, badgeLabel ?? children);
}, [value, children, onItemAdded, badgeLabel]);
return (
<CommandItem
{...props}
value={value}
onSelect={(v) => {
toggleValue(v);
onSelect?.(v);
}}
>
<CheckIcon
className={cn('mr-2 size-4', isSelected ? 'opacity-100' : 'opacity-0')}
/>
{children}
</CommandItem>
);
}
export function MultiSelectGroup(
props: ComponentPropsWithoutRef<typeof CommandGroup>,
) {
return <CommandGroup {...props} />;
}
export function MultiSelectSeparator(
props: ComponentPropsWithoutRef<typeof CommandSeparator>,
) {
return <CommandSeparator {...props} />;
}

View File

@@ -17,7 +17,7 @@ const PopoverContent = React.forwardRef<
align={align}
sideOffset={sideOffset}
className={cn(
'z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
'z-50 w-72 origin-[--radix-popover-content-transform-origin] rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
className,
)}
{...props}

View File

@@ -52,7 +52,7 @@ const sheetVariants = cva(
interface SheetContentProps
extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,
VariantProps<typeof sheetVariants> {
container?: HTMLElement;
container?: HTMLElement | null;
hideCloseButton?: boolean;
}
@@ -64,7 +64,7 @@ const SheetContent = React.forwardRef<
{
side = 'right',
className,
container,
container = null,
hideCloseButton,
children,
...props

View File

@@ -0,0 +1,44 @@
import { Badge } from '@/components/ui/v3/badge';
import useMfaEnabled from '@/features/account/settings/components/AccountMfaSettings/hooks/useMfaEnabled';
import DisableMfaButton from './DisableMfaButton/DisableMfaButton';
import EnableMfaButton from './EnableMfaButton/EnableMfaButton';
function MFaEnabledBadge() {
return (
<Badge variant="outline" className="border-green-400 text-green-400">
Enabled
</Badge>
);
}
function MFaDisabledBadge() {
return (
<Badge
variant="outline"
className="text- border-destructive text-destructive"
>
Disabled
</Badge>
);
}
function AccountMfaSettings() {
const { isMfaEnabled } = useMfaEnabled();
return (
<div className="rounded-lg border border-[#EAEDF0] bg-white font-['Inter_var'] dark:border-[#2F363D] dark:bg-paper">
<div className="flex w-full flex-col items-start gap-6 p-4">
<div className="flex w-full items-center justify-between">
<h3 className="flex items-center text-[1.125rem] font-semibold leading-[1.75]">
<span className="mr-4">Multi-Factor Authentication </span>
{isMfaEnabled ? <MFaEnabledBadge /> : <MFaDisabledBadge />}
</h3>
</div>
</div>
<div className="flex w-full items-center border-t border-[#EAEDF0] px-4 py-2 dark:border-[#2F363D]">
{isMfaEnabled ? <DisableMfaButton /> : <EnableMfaButton />}
</div>
</div>
);
}
export default AccountMfaSettings;

Some files were not shown because too many files have changed in this diff Show More