Compare commits

..

16 Commits

Author SHA1 Message Date
github-actions[bot]
2e3357b7a3 chore: update versions (#3143)
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.7.0

### Minor Changes

-   5c6ff6e: fix: correct StorageErrorPayload TypeScript typing

## @nhost/apollo@8.0.4

### Patch Changes

-   @nhost/nhost-js@3.2.4

## @nhost/react-apollo@16.0.1

### Patch Changes

-   @nhost/apollo@8.0.4
-   @nhost/react@3.9.1

## @nhost/react-urql@13.0.1

### Patch Changes

-   @nhost/react@3.9.1

## @nhost/nextjs@2.2.2

### Patch Changes

-   @nhost/react@3.9.1

## @nhost/nhost-js@3.2.4

### Patch Changes

-   Updated dependencies [5c6ff6e]
    -   @nhost/hasura-storage-js@2.7.0

## @nhost/react@3.9.1

### Patch Changes

-   @nhost/nhost-js@3.2.4

## @nhost/vue@2.9.1

### Patch Changes

-   @nhost/nhost-js@3.2.4

## @nhost/dashboard@2.16.0

### Minor Changes

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

### Patch Changes

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

## @nhost/docs@2.27.0

### Minor Changes

-   81cc9b3: chore: add missing images to permissions API

### Patch Changes

-   af34015: chore: add note about encryption at rest
-   1956ed2: chore: added pgmq extension to postgres docs
-   88919a3: chore: added support for nodejs22 to functions

## @nhost-examples/cli@0.3.17

### Patch Changes

-   @nhost/nhost-js@3.2.4

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

### Patch Changes

-   @nhost/react@3.9.1
-   @nhost/react-apollo@16.0.1

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

### Patch Changes

-   @nhost/react@3.9.1

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

### Patch Changes

-   @nhost/react@3.9.1
-   @nhost/react-urql@13.0.1

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

### Patch Changes

-   @nhost/nhost-js@3.2.4

## @nhost-examples/nextjs@0.4.2

### Patch Changes

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

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

### Patch Changes

-   @nhost/nhost-js@3.2.4

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

### Patch Changes

-   @nhost/nhost-js@3.2.4

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

### Patch Changes

-   @nhost/react@3.9.1
-   @nhost/react-apollo@16.0.1

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

### Patch Changes

-   @nhost/react@3.9.1

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

### Patch Changes

-   @nhost/react@3.9.1
-   @nhost/react-apollo@16.0.1

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

### Patch Changes

-   @nhost/nhost-js@3.2.4
-   @nhost/apollo@8.0.4
-   @nhost/vue@2.9.1

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

### Patch Changes

-   @nhost/apollo@8.0.4
-   @nhost/vue@2.9.1

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-27 13:08:19 +01:00
David BM
4385524311 fix (dashboard): update url to check service health in local dashboard (#3158)
### **PR Type**
Bug fix, Enhancement


___

### **Description**
- Update health check URL from '/healthz' to '/v1/version'

- Change service from 'auth' to 'hasura' for app URL

- Modify query key to match new endpoint

- Remove duplicate hook file


___



### **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>useIsHealthy.ts</strong><dd><code>Update health check
endpoint and service</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/common/hooks/useIsHealthy/useIsHealthy.ts

<li>Changed app URL service from 'auth' to 'hasura'<br> <li> Updated
health check endpoint from '/healthz' to '/v1/version'<br> <li> Modified
query key to match new endpoint


</details>


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

</tr>
</table></td></tr><tr><td><strong>Miscellaneous</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>index.ts</strong><dd><code>No changes to index
file</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

dashboard/src/features/projects/common/hooks/useIsHealthy/index.ts

- No changes made to file content


</details>


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

</tr>
</table></td></tr><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>useIsHealthy.ts</strong><dd><code>Remove duplicate
useIsHealthy 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; </dd></summary>
<hr>


dashboard/src/features/projects/common/hooks/useIsHealthy/useIsHealthy.ts

- Removed entire file content


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3158/files#diff-4803f83d063ff897b658a3afa833f068ee4d1d1b9457ff89f02b8c8bf11525a0">+0/-31</a>&nbsp;
&nbsp; </td>

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>two-llamas-arrive.md</strong><dd><code>Add changeset
for dashboard package update</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

.changeset/two-llamas-arrive.md

<li>Added changeset file for '@nhost/dashboard' package<br> <li>
Described fix for service health check URL


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3158/files#diff-39aa63faa20d127004027c60151017938e7096a28ac7f747ab78d294436528e9">+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-01-24 13:45:11 -05:00
David BM
9e404c8fc9 fix (dashboard): not redirect to 404 page if using local Nhost backend (#3159)
### **PR Type**
Bug fix, Enhancement


___

### **Description**
- Fix 404 redirect for local Nhost backend

- Improve useNotFoundRedirect hook functionality

- Add isPlatform check for conditional routing

- Update documentation for useNotFoundRedirect hook


___



### **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>useNotFoundRedirect.ts</strong><dd><code>Enhance
useNotFoundRedirect hook for local backend support</code></dd></summary>
<hr>


dashboard/src/features/projects/common/hooks/useNotFoundRedirect/useNotFoundRedirect.ts

<li>Added isPlatform check to prevent 404 redirect for local backend<br>
<li> Updated useNotFoundRedirect hook documentation<br> <li> Imported
useIsPlatform hook and added it to dependencies<br> <li> Modified
conditional logic for pathname validation


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>olive-camels-laugh.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/olive-camels-laugh.md

<li>Added changeset file for version bump<br> <li> Described fix for 404
redirect issue


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3159/files#diff-ad8a4a986988ba4c5a677e9d0b757bd2ef71b86c5dadf83451bb953bc4d35c32">+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-01-24 13:22:49 -05:00
David BM
f8e6b615dd fix (dashboard): postgres add rule group in table permissions (#3157)
### **User description**
Fixes #3156


___

### **PR Type**
Bug fix


___

### **Description**
- Fixed issue with adding rule groups in table permissions

- Updated validation schema for rule group operator

- Replaced useCurrentWorkspaceAndProject with useProject hook

- Added changeset for the bug fix


___



### **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>validationSchemas.ts</strong><dd><code>Simplify rule
group operator validation</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/features/orgs/projects/database/dataGrid/components/EditPermissionsForm/validationSchemas.ts

<li>Simplified operator validation in ruleGroupSchema<br> <li> Removed
complex test function for operator<br> <li> Made operator field required
with error message


</details>


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

</tr>
</table></td></tr><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>RuleGroupEditor.tsx</strong><dd><code>Update hooks and
imports in RuleGroupEditor</code>&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/RuleGroupEditor/RuleGroupEditor.tsx

<li>Replaced useCurrentWorkspaceAndProject with useProject hook<br> <li>
Updated import for generateAppServiceUrl<br> <li> Adjusted references
from currentProject to project


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>lovely-moose-study.md</strong><dd><code>Add changeset
for table permissions fix</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

.changeset/lovely-moose-study.md

<li>Added changeset file for the bug fix<br> <li> Specified minor
version bump for @nhost/dashboard


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3157/files#diff-971dc0fcd0c4c7454432ac76485b57a4c0c22aefde092042b93a12f871004cc7">+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-01-24 08:41:20 -05:00
David BM
ac4aa01ec9 fix (dashboard): can delete column in database page (#3153)
### **User description**
FIxes #3151


___

### **PR Type**
Bug fix


___

### **Description**
- Fixed column deletion in database page

- Updated imports for project and platform hooks

- Replaced currentProject with project in useDeleteColumnMutation

- Added changeset for minor 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>useDeleteColumnMutation.ts</strong><dd><code>Update
project-related imports and references</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>


dashboard/src/features/orgs/projects/database/dataGrid/hooks/useDeleteColumnMutation/useDeleteColumnMutation.ts

<li>Updated imports for useIsPlatform and useProject<br> <li> Replaced
useCurrentWorkspaceAndProject with useProject<br> <li> Changed
currentProject references to project<br> <li> Updated appUrl and
adminSecret generation


</details>


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

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>two-dodos-jam.md</strong><dd><code>Add changeset for
minor 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/two-dodos-jam.md

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


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3153/files#diff-414e28820562fea42077c94888f756df4b476a3427210e15388bf74a3ad60626">+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-01-23 13:23:13 -05:00
robertkasza
e515e71c8b chore: upgrade nodejs and pnpm version in nix config (#3152)
### **PR Type**
Enhancement


___

### **Description**
- Upgrade Node.js from v18 to v20

- Update PNPM from nodePackages.pnpm to pnpm_9

- Modify nix configuration files for dependencies


___



### **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>flake.nix</strong><dd><code>Update PNPM version in
build inputs and dev shells</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></summary>
<hr>

flake.nix

<li>Replace <code>nodePackages.pnpm</code> with <code>pnpm_9</code> in
nativeBuildInputs<br> <li> Update devShells to use <code>pnpm_9</code>
instead of <code>nodePackages.pnpm</code>


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>overlay.nix</strong><dd><code>Upgrade Node.js version
in Nix overlay</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></summary>
<hr>

nix/overlay.nix

- Upgrade Node.js from `nodejs-18_x` to `nodejs_20`


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3152/files#diff-0f31c68216d617b465827b69d5b5cd4c2c0c4489008cd14ee0e88b9887d15295">+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-01-23 15:04:31 +01:00
David BM
1246e0024a chore: update actions/upload-artifact to v4 (#3138)
### **PR Type**
Enhancement


___

### **Description**
- Update actions/upload-artifact from v3 to v4


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Dependencies</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>ci.yaml</strong><dd><code>Upgrade
actions/upload-artifact to latest version</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

.github/workflows/ci.yaml

- Updated actions/upload-artifact from v3 to v4


</details>


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

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

___

> 💡 **PR-Agent usage**: Comment `/help "your question"` on any pull
request to receive relevant information
2025-01-22 12:02:31 -05:00
David BM
81cc9b3810 chore (docs): add missing images in permissions API (#3144)
### **PR Type**
Documentation


___

### **Description**
- Update image paths in permissions API documentation

- Add changeset for minor version bump

- Improve readability of permissions guide


___



### **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>five-panthers-swim.md</strong><dd><code>Add changeset
for minor docs update</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/five-panthers-swim.md

<li>Add new changeset file for minor version bump<br> <li> Specify
changes for '@nhost/docs' package


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>permissions.mdx</strong><dd><code>Update image paths in
permissions guide</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></summary>
<hr>

docs/guides/api/permissions.mdx

<li>Update image paths for insert and select permissions<br> <li>
Replace '/img/graphql/permissions/' with '/images/guides/graphql/'


</details>


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

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

___

> 💡 **PR-Agent usage**: Comment `/help "your question"` on any pull
request to receive relevant information
2025-01-20 06:41:58 -05:00
David BM
5c6ff6efc8 fix (dashboard): correct StorageErrorPayload TypeScript typing (#3137)
### **User description**
Resolves #2440


___

### **PR Type**
Bug fix


___

### **Description**
- Corrected StorageErrorPayload TypeScript typing

- Refactored error handling in file upload

- Improved consistency of error object structure

- Added changeset for 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>upload.ts</strong><dd><code>Refactor error handling in
file upload</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></summary>
<hr>

packages/hasura-storage-js/src/utils/upload.ts

<li>Refactored error handling in <code>fetchUpload</code> function<br>
<li> Created consistent <code>StorageErrorPayload</code> object<br> <li>
Updated error object structure in both success and error callbacks<br>
<li> Improved type safety and error message handling


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3137/files#diff-806cf228c0fefb0c00e2b79108f101e2a26776c19578512ffc3d47ecafe59a5a">+12/-6</a>&nbsp;
&nbsp; </td>

</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>wet-pants-promise.md</strong><dd><code>Add changeset
for StorageErrorPayload fix</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></summary>
<hr>

.changeset/wet-pants-promise.md

<li>Added new changeset file<br> <li> Specified minor version bump for
'@nhost/hasura-storage-js'<br> <li> Described fix for
StorageErrorPayload TypeScript typing


</details>


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

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

___

> 💡 **PR-Agent usage**: Comment `/help "your question"` on any pull
request to receive relevant information
2025-01-20 06:40:50 -05:00
David Barroso
1956ed23f8 chore (docs): added pgmq extension to postgres docs (#3141)
Fixes #3131 

### **PR Type**
Enhancement, Documentation


___

### **Description**
- Added pgmq extension to Postgres docs

- Updated extensions table with pgmq details

- Included pgmq installation and uninstallation instructions

- Added GitHub resource link for pgmq


___



### **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>cyan-suits-provide.md</strong><dd><code>Add changeset
for pgmq documentation update</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

.changeset/cyan-suits-provide.md

<li>Added changeset file for documentation update<br> <li> Specified
patch version bump for @nhost/docs


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>extensions.mdx</strong><dd><code>Add pgmq extension
details and instructions</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

docs/guides/database/extensions.mdx

<li>Added pgmq to the extensions table<br> <li> Included detailed
section on pgmq extension<br> <li> Provided installation and
uninstallation SQL commands<br> <li> Added GitHub resource link for pgmq


</details>


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

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

___

> 💡 **PR-Agent usage**: Comment `/help "your question"` on any pull
request to receive relevant information
2025-01-17 14:48:28 +01:00
David Barroso
af34015dbe chore (docs): add note about encryption at rest (#3142)
### **PR Type**
Enhancement, Documentation


___

### **Description**
- Add note about encryption at rest

- Explain encryption for storage, database, and Run services

- Provide warning about volume encryption status

- Include instructions for enabling encryption on older volumes


___



### **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>brown-suits-drive.md</strong><dd><code>Add changeset
for encryption at rest documentation</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

.changeset/brown-suits-drive.md

<li>Add changeset file for documentation update<br> <li> Specify patch
version bump for '@nhost/docs'


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>compute-resources.mdx</strong><dd><code>Add Encryption
at Rest section to compute resources documentation</code></dd></summary>
<hr>

docs/platform/compute-resources.mdx

<li>Add new section on Encryption at Rest<br> <li> Explain encryption
for storage, database, and Run services<br> <li> Include warning about
volume encryption status<br> <li> Provide instructions for enabling
encryption on older volumes


</details>


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

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

___

> 💡 **PR-Agent usage**: Comment `/help "your question"` on any pull
request to receive relevant information
2025-01-17 14:46:38 +01:00
David Barroso
88919a3d99 chore (docs): added support for nodejs22 to functions (#3140)
### **PR Type**
Enhancement, Documentation


___

### **Description**
- Added support for Node.js 22 runtime in functions

- Updated documentation to include Node.js 22 option

- Added 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>forty-keys-buy.md</strong><dd><code>Add changeset for
Node.js 22 support</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/forty-keys-buy.md

<li>Added new changeset file for patch version bump<br> <li> Specified
'@nhost/docs' package for the change


</details>


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

</tr>

<tr>
  <td>
    <details>
<summary><strong>runtimes.mdx</strong><dd><code>Update documentation
with Node.js 22 runtime support</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

docs/guides/functions/runtimes.mdx

<li>Added Node.js 22 to the list of supported runtimes<br> <li> Included
configuration example for Node.js 22 in <code>nhost.toml</code>


</details>


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

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

___

> 💡 **PR-Agent usage**: Comment `/help "your question"` on any pull
request to receive relevant information
2025-01-17 14:46:26 +01:00
github-actions[bot]
ab26a57d05 chore: update versions (#3134)
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.15.0

### Minor Changes

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

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-16 08:24:00 -05:00
David BM
f1052a8826 fix (dashboard): undefined is not an object issue with paused projects (#3136)
### **User description**
Fixes #3127


___

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


___

### **Description**
- Fix undefined errors in paused projects

- Improve loading states across components

- Handle project and org loading separately

- Update project.id usage for consistency


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Bug
fix</strong></td><td><details><summary>1 files</summary><table>
<tr>
<td><strong>SubscriptionPlan.tsx</strong><dd><code>Fix undefined error
in org plan handling</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/3136/files#diff-2a5f070869055286b669e382b18d656935752803b9a1ef13390ac028c2a48ac4">+3/-3</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>TransferProjectDialog.tsx</strong><dd><code>Add loading
state for project and orgs</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/3136/files#diff-b68d4641a67e07a8bf8c14e1f705059c564e1bca53e591783581af27a488d86e">+7/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>AISettings.tsx</strong><dd><code>Improve loading handling in
AI settings</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/3136/files#diff-6ec092fc4af4c9acd11edb4ae69ff6ad6e8e984c761148836c9fde8daaa6e9a4">+12/-11</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>AppLoader.tsx</strong><dd><code>Add loading screen for
project data</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/3136/files#diff-fdef910b2c808595c77cb3c0ae573db3ff57cdb4a8161db2e36e86ec548b9b6f">+18/-13</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>AuthDomain.tsx</strong><dd><code>Handle project loading in
Auth Domain</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/3136/files#diff-4b8e1e15fc7df8fe284298d5ab47dbc3f554888f98e39f84c4ac995f35c10c86">+8/-4</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>HasuraDomain.tsx</strong><dd><code>Add project loading check
in Hasura Domain</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/3136/files#diff-334177cc61035493cfca775de96635b58d98a28856067048dcfba6cd7f255978">+8/-4</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>ServerlessFunctionsDomain.tsx</strong><dd><code>Include
project loading in Serverless Functions Domain</code>&nbsp; &nbsp;
&nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3136/files#diff-e7cf7b49535f816a9c2c60cf1f8b975036bd6a988e4295529e999075d72044ef">+8/-4</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>MetricsSettings.tsx</strong><dd><code>Improve loading state
in Metrics Settings</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/3136/files#diff-957bb404fee8d18aa45af9e878837d311b69d9805ac16fe8d2c0e9d3b431e906">+15/-6</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>backups.tsx</strong><dd><code>Refactor Backups page for
better loading</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/3136/files#diff-11c24d569a8109344819d2cc9ce6ffbcf3b75abfba604e299c01289690d322f9">+8/-8</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>authentication.tsx</strong><dd><code>Enhance loading logic
in Authentication Settings</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3136/files#diff-d7d59ce72b8bf8a15db18d8dd5132db73cd00c6f99dd1cf58bc2eca676ea1e23">+3/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>custom-domains.tsx</strong><dd><code>Add loading indicator
for Custom Domains</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/3136/files#diff-e35b13396a4aa0b96e35dd7a0b1a27d188c0d45fe20cbda99e2fd59b83da5574">+6/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>database.tsx</strong><dd><code>Improve loading state in
Database Settings</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/3136/files#diff-00045ae38a73178045bcda39c80a03a0cb46413641586896a628c3a2a22c7855">+3/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>index.tsx</strong><dd><code>Enhance loading and form reset
in Settings</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/3136/files#diff-b4185be97a505e25badcdefe31ea86fa9d69f72264c4bb35eae17fba936a3d47">+11/-3</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>metrics.tsx</strong><dd><code>Refactor Metrics Settings page
loading</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/3136/files#diff-f1cb73960dad3c0714aa08f92457282533feaa9b97b1c4f8cac572244a9e070c">+11/-15</a>&nbsp;
</td>

</tr>

</table></details></td></tr><tr><td><strong>Formatting</strong></td><td><details><summary>1
files</summary><table>
<tr>
<td><strong>LogsHeader.tsx</strong><dd><code>Minor formatting changes in
Logs Header</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/3136/files#diff-ebb3285aa776c9c5ea8b72672c4aafd55994c6c694998bbf56ca9c56d1e77664">+10/-10</a>&nbsp;
</td>

</tr>

</table></details></td></tr><tr><td><strong>Documentation</strong></td><td><details><summary>1
files</summary><table>
<tr>
<td><strong>angry-zoos-learn.md</strong><dd><code>Add changeset for
dashboard stability improvements</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3136/files#diff-5ada479d7003769072ae842fdcc5555f7b336466da44dfce5f841b2698382cbc">+5/-0</a>&nbsp;
&nbsp; &nbsp; </td>

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

___

> 💡 **PR-Agent usage**: Comment `/help "your question"` on any pull
request to receive relevant information
2025-01-15 18:02:09 -05:00
David BM
30daa4146e fix (dashboard): update links to docs in overview (#3135)
### **PR Type**
Bug fix, Documentation


___

### **Description**
- Update documentation links in project overview page

- Change 'platform' to 'product' in doc URLs

- Modify links for Database, GraphQL API, Authentication, Storage

- Add changeset for version tracking


___



### **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>features.tsx</strong><dd><code>Update documentation
links in features array</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

dashboard/src/features/orgs/projects/overview/features/features.tsx

<li>Updated documentation links for Database, GraphQL API,
Authentication, <br>and Storage features<br> <li> Changed URL path from
'platform' to 'product' in all links


</details>


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

</tr>
</table></td></tr><tr><td><strong>Configuration
changes</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>early-lobsters-grow.md</strong><dd><code>Add changeset
for documentation link updates</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

.changeset/early-lobsters-grow.md

<li>Added new changeset file for version tracking<br> <li> Specified
minor version bump for '@nhost/dashboard'<br> <li> Included description
of the fix


</details>


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

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

___

> 💡 **PR-Agent usage**: Comment `/help "your question"` on any pull
request to receive relevant information
2025-01-13 11:08:08 -05:00
David BM
7537237465 feat (dashboard): image preview toggle in storage (#3122)
### **User description**
Resolves #2814


___

### **PR Type**
Enhancement


___

### **Description**
- Add image preview toggle in storage

- Implement preview header with switch control

- Refactor data grid components and imports

- Update file preview functionality


___



### **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>21
files</summary><table>
<tr>
<td><strong>DataBrowserGridControls.tsx</strong><dd><code>Update import
paths for data grid components</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/3122/files#diff-640ce3e15c8d5f35d8bbe74792c59493afe5bc69873d2a40f81233da2b02661c">+6/-6</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>DataGrid.tsx</strong><dd><code>Refactor import paths for
data grid components</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3122/files#diff-3bc6476aed14d8e4f26134fa452d22c41b6d3ecb0989871a8a99230a82496474">+8/-8</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>DataGridBody.tsx</strong><dd><code>Update import paths for
data grid components</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/3122/files#diff-e5cdb81b2c99dbd7b9a669a63ed503f6964e9c0bc91ca2c0e61df5334eaa7a1b">+4/-4</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>DataGridBooleanCell.tsx</strong><dd><code>Update import
paths for data grid components</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/3122/files#diff-b700eacab9c73b147e248ce58d47a208c1e499124a20444efd73db7ecb68505f">+3/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>DataGridCell.tsx</strong><dd><code>Update import path for
DataBrowserGridCell type</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3122/files#diff-0049e6acaddf9f9b60fe43a1fbb2657564bd019e690d0361aae39f44a03adaa2">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>DataGridConfigContext.ts</strong><dd><code>Update import
path for UseDataGridReturn type</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3122/files#diff-597368f6e75d76d9a5956f816eaa8c82177b49e1e0d20c027fd85bef81347786">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>DataGridConfigProvider.tsx</strong><dd><code>Update import
path for UseDataGridReturn type</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3122/files#diff-ec52aa04de1bfb16370e811e294efdb3389ee929c2f75f90981933e89ea26a5d">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>useDataGridConfig.ts</strong><dd><code>Update import path
for UseDataGridReturn type</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3122/files#diff-dee956f638a871543fef38fc6b35f2f5e0e7dfcc449b61377d2c5613f24f13d4">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>DataGridDateCell.tsx</strong><dd><code>Update import paths
for data grid components</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/3122/files#diff-95e5b8780946ddb0c020be73a0646e7627c90ea7cc63a408346a434d1f12938e">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>DataGridDecimalCell.tsx</strong><dd><code>Update import
paths for data grid components</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/3122/files#diff-9ad38d4c8a67f8daf6020b9782cb1d7a4933e2901b4937a597a2c19c2367d7d0">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>DataGridFrame.tsx</strong><dd><code>Update import path for
useDataGridConfig hook</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3122/files#diff-d4b27ea795d9008758b8eb7d54d4f4f982cf19818a8bde118afe1c46e12088bc">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>DataGridHeader.tsx</strong><dd><code>Refactor DataGridHeader
component and add DataGridHeaderButton</code></dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3122/files#diff-3f5f16ea95a730255a07806c96b55fd4946c92eebcb869cdf83ad92bfe034b4c">+10/-51</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>DataGridHeaderButton.tsx</strong><dd><code>Add new
DataGridHeaderButton 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/3122/files#diff-4e9624559165361950af94e0775337d6937c300e4184106f08975e9b324c3010">+77/-0</a>&nbsp;
&nbsp; </td>

</tr>

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

</tr>

<tr>
<td><strong>DataGridIntegerCell.tsx</strong><dd><code>Update import
paths for data grid components</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/3122/files#diff-9db68b16a44a34c57b847023c1dd2f74e486b0a028f84fcc0cc1f29e0ff38f0d">+4/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>DataGridPreviewCell.tsx</strong><dd><code>Implement preview
toggle functionality in DataGridPreviewCell</code></dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3122/files#diff-d7bffe5896d2c9bac505fa9675790c59549d4fb35a2ad0cce903cc0aa31a8321">+15/-4</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>DataGridTextCell.tsx</strong><dd><code>Update import paths
for data grid components</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/3122/files#diff-d1ed74fe8eb7a61053dfe908966311e13915ad2127ee107b62f725d6c5282492">+4/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>FilesDataGrid.tsx</strong><dd><code>Add PreviewHeader
component to FilesDataGrid</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/3122/files#diff-18c8df727e1a4fc6a94d03bd4a3a7a8cb3ad44d754803c4c7988c1c00a4b7caf">+5/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>FilesDataGridControls.tsx</strong><dd><code>Update import
paths for data grid components</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/3122/files#diff-b85b40168e9c149331a68cb1a0cbec570c75233fa34385945e094b8f4c032974">+3/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>PreviewHeader.tsx</strong><dd><code>Add new PreviewHeader
component with toggle switch</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3122/files#diff-a435cd33ed8c3cd8cfde506860a5e4d2f84605548292bc0d92b63b55d664ddca">+23/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>index.ts</strong><dd><code>Add index file for PreviewHeader
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/3122/files#diff-18b97d53e328ea33285d6a209f6d535a93d3fde2bcae2c21c59014807f7d0e7a">+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>twelve-llamas-tap.md</strong><dd><code>Add changeset for
image preview toggle feature</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3122/files#diff-275dd9152aa4b1730808a63caaf49742e808c7b53b67b5505b828e6210c83c52">+5/-0</a>&nbsp;
&nbsp; &nbsp; </td>

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

___

> 💡 **PR-Agent usage**: Comment `/help "your question"` on any pull
request to receive relevant information
2025-01-13 07:11:39 -05:00
104 changed files with 656 additions and 330 deletions

View File

@@ -163,7 +163,7 @@ jobs:
# * Run this step only if the previous step failed, and Playwright generated a report # * Run this step only if the previous step failed, and Playwright generated a report
- name: Upload Playwright Report - name: Upload Playwright Report
if: ${{ failure() && hashFiles(format('{0}/playwright-report/**', matrix.package.path)) != ''}} if: ${{ failure() && hashFiles(format('{0}/playwright-report/**', matrix.package.path)) != ''}}
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: playwright-${{ steps.file-name.outputs.fileName }} name: playwright-${{ steps.file-name.outputs.fileName }}
path: ${{format('{0}/playwright-report/**', matrix.package.path)}} path: ${{format('{0}/playwright-report/**', matrix.package.path)}}

View File

@@ -1,5 +1,27 @@
# @nhost/dashboard # @nhost/dashboard
## 2.16.0
### Minor Changes
- f8e6b61: fix: can add rule groups in table permissions
- 9e404c8: fix: not redirect to 404 page if using local Nhost backend
- ac4aa01: fix: can delete column in database page
- 4385524: fix: update url to check service health in local dashboard
### Patch Changes
- @nhost/react-apollo@16.0.1
- @nhost/nextjs@2.2.2
## 2.15.0
### Minor Changes
- f1052a8: fix: improve stability of the dashboard when pausing projects
- 30daa41: fix: update links to docs in overview page
- 7537237: feat: add image preview toggle in storage
## 2.14.0 ## 2.14.0
### Minor Changes ### Minor Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@nhost/dashboard", "name": "@nhost/dashboard",
"version": "2.14.0", "version": "2.16.0",
"private": true, "private": true,
"scripts": { "scripts": {
"preinstall": "npx only-allow pnpm", "preinstall": "npx only-allow pnpm",

View File

@@ -8,6 +8,7 @@ import {
DialogTitle, DialogTitle,
} from '@/components/ui/v3/dialog'; } from '@/components/ui/v3/dialog';
import { LoadingScreen } from '@/components/presentational/LoadingScreen';
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator'; import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
import { import {
Form, Form,
@@ -53,8 +54,8 @@ export default function TransferProjectDialog({
}: TransferProjectDialogProps) { }: TransferProjectDialogProps) {
const { push } = useRouter(); const { push } = useRouter();
const currentUserId = useUserId(); const currentUserId = useUserId();
const { project } = useProject(); const { project, loading: projectLoading } = useProject();
const { orgs, currentOrg } = useOrgs(); const { orgs, currentOrg, loading: orgsLoading } = useOrgs();
const [transferProject] = useBillingTransferAppMutation(); const [transferProject] = useBillingTransferAppMutation();
const form = useForm<z.infer<typeof transferProjectFormSchema>>({ const form = useForm<z.infer<typeof transferProjectFormSchema>>({
@@ -96,6 +97,10 @@ export default function TransferProjectDialog({
member.user.id === userId, member.user.id === userId,
); );
if (projectLoading || orgsLoading) {
return <LoadingScreen />;
}
return ( return (
<Dialog <Dialog
open={open} open={open}

View File

@@ -61,7 +61,7 @@ export default function AISettings() {
const [updateConfig] = useUpdateConfigMutation({ const [updateConfig] = useUpdateConfigMutation({
...(!isPlatform ? { client: localMimirClient } : {}), ...(!isPlatform ? { client: localMimirClient } : {}),
}); });
const { project } = useProject(); const { project, loading: loadingProject } = useProject();
const [aiServiceEnabled, setAIServiceEnabled] = useState(true); const [aiServiceEnabled, setAIServiceEnabled] = useState(true);
@@ -73,9 +73,10 @@ export default function AISettings() {
error: errorGettingAiSettings, error: errorGettingAiSettings,
} = useGetAiSettingsQuery({ } = useGetAiSettingsQuery({
variables: { variables: {
appId: project.id, appId: project?.id,
}, },
...(!isPlatform ? { client: localMimirClient } : {}), ...(!isPlatform ? { client: localMimirClient } : {}),
skip: !project?.id,
}); });
const { data: graphiteVersionsData, loading: loadingGraphiteVersionsData } = const { data: graphiteVersionsData, loading: loadingGraphiteVersionsData } =
@@ -192,11 +193,11 @@ export default function AISettings() {
} }
}; };
if (loadingAiSettings || loadingGraphiteVersionsData) { if (loadingProject || loadingAiSettings || loadingGraphiteVersionsData) {
return ( return (
<ActivityIndicator <ActivityIndicator
delay={1000} delay={1000}
label="Loading Postgres version..." label="Loading AI settings..."
className="justify-center" className="justify-center"
/> />
); );
@@ -269,7 +270,7 @@ export default function AISettings() {
return ( return (
<Box className="space-y-4" sx={{ backgroundColor: 'background.default' }}> <Box className="space-y-4" sx={{ backgroundColor: 'background.default' }}>
<Box className="flex flex-row items-center justify-between p-4 rounded-lg border-1"> <Box className="flex flex-row items-center justify-between rounded-lg border-1 p-4">
<Text className="text-lg font-semibold">Enable AI service</Text> <Text className="text-lg font-semibold">Enable AI service</Text>
<Switch <Switch
checked={aiServiceEnabled} checked={aiServiceEnabled}
@@ -298,7 +299,7 @@ export default function AISettings() {
<Tooltip title="Version of the service to use."> <Tooltip title="Version of the service to use.">
<InfoIcon <InfoIcon
aria-label="Info" aria-label="Info"
className="w-4 h-4" className="h-4 w-4"
color="primary" color="primary"
/> />
</Tooltip> </Tooltip>
@@ -353,7 +354,7 @@ export default function AISettings() {
<Tooltip title="Used to validate requests between postgres and the AI service. The AI service will also include the header X-Graphite-Webhook-Secret with this value set when calling external webhooks so the source of the request can be validated."> <Tooltip title="Used to validate requests between postgres and the AI service. The AI service will also include the header X-Graphite-Webhook-Secret with this value set when calling external webhooks so the source of the request can be validated.">
<InfoIcon <InfoIcon
aria-label="Info" aria-label="Info"
className="w-4 h-4" className="h-4 w-4"
color="primary" color="primary"
/> />
</Tooltip> </Tooltip>
@@ -377,7 +378,7 @@ export default function AISettings() {
<Tooltip title="Dedicated resources allocated for the service."> <Tooltip title="Dedicated resources allocated for the service.">
<InfoIcon <InfoIcon
aria-label="Info" aria-label="Info"
className="w-4 h-4" className="h-4 w-4"
color="primary" color="primary"
/> />
</Tooltip> </Tooltip>
@@ -417,7 +418,7 @@ export default function AISettings() {
<Tooltip title="Key to use for authenticating API requests to OpenAI"> <Tooltip title="Key to use for authenticating API requests to OpenAI">
<InfoIcon <InfoIcon
aria-label="Info" aria-label="Info"
className="w-4 h-4" className="h-4 w-4"
color="primary" color="primary"
/> />
</Tooltip> </Tooltip>
@@ -440,7 +441,7 @@ export default function AISettings() {
<Tooltip title="Optional. OpenAI organization to use."> <Tooltip title="Optional. OpenAI organization to use.">
<InfoIcon <InfoIcon
aria-label="Info" aria-label="Info"
className="w-4 h-4" className="h-4 w-4"
color="primary" color="primary"
/> />
</Tooltip> </Tooltip>
@@ -468,7 +469,7 @@ export default function AISettings() {
<Tooltip title="How often to run the job that keeps embeddings up to date."> <Tooltip title="How often to run the job that keeps embeddings up to date.">
<InfoIcon <InfoIcon
aria-label="Info" aria-label="Info"
className="w-4 h-4" className="h-4 w-4"
color="primary" color="primary"
/> />
</Tooltip> </Tooltip>

View File

@@ -1,4 +1,5 @@
import { ContactUs } from '@/components/common/ContactUs'; import { ContactUs } from '@/components/common/ContactUs';
import { LoadingScreen } from '@/components/presentational/LoadingScreen';
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator'; import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
import { Button } from '@/components/ui/v2/Button'; import { Button } from '@/components/ui/v2/Button';
import { Dropdown } from '@/components/ui/v2/Dropdown'; import { Dropdown } from '@/components/ui/v2/Dropdown';
@@ -6,7 +7,7 @@ import { Text } from '@/components/ui/v2/Text';
import { useProject } from '@/features/orgs/projects/hooks/useProject'; import { useProject } from '@/features/orgs/projects/hooks/useProject';
import { useInterval } from '@/hooks/useInterval'; import { useInterval } from '@/hooks/useInterval';
import { getRelativeDateByApplicationState } from '@/utils/helpers'; import { getRelativeDateByApplicationState } from '@/utils/helpers';
import { useState } from 'react'; import { useEffect, useState } from 'react';
export interface AppLoaderProps { export interface AppLoaderProps {
/** /**
@@ -33,25 +34,31 @@ export default function AppLoader({
date, date,
restoring, restoring,
}: AppLoaderProps) { }: AppLoaderProps) {
const { project } = useProject(); const { project, loading } = useProject();
const [timeElapsed, setTimeElapsed] = useState<number>(0);
let timeElapsedSinceEventCreation: number; useEffect(() => {
if (!project || loading) {
return;
}
if (date) { let timeElapsedSinceEventCreation: number;
timeElapsedSinceEventCreation = getRelativeDateByApplicationState(date);
} else if (unpause) {
timeElapsedSinceEventCreation = getRelativeDateByApplicationState(
project.appStates[0].createdAt,
);
} else {
timeElapsedSinceEventCreation = getRelativeDateByApplicationState(
project.createdAt,
);
}
const [timeElapsed, setTimeElapsed] = useState(timeElapsedSinceEventCreation); if (date) {
timeElapsedSinceEventCreation = getRelativeDateByApplicationState(date);
} else if (unpause) {
timeElapsedSinceEventCreation = getRelativeDateByApplicationState(
project.appStates[0].createdAt,
);
} else {
timeElapsedSinceEventCreation = getRelativeDateByApplicationState(
project.createdAt,
);
}
setTimeElapsed(timeElapsedSinceEventCreation);
}, [project, date, unpause, loading]);
// Would be also valuable to check the appCreatedTime so this doesn't ever appear if not created under a time limit. @GC
useInterval( useInterval(
() => { () => {
setTimeElapsed(timeElapsed + 1); setTimeElapsed(timeElapsed + 1);
@@ -59,6 +66,10 @@ export default function AppLoader({
startLoader ? 1000 : null, startLoader ? 1000 : null,
); );
if (loading) {
return <LoadingScreen />;
}
return ( return (
<div className="grid grid-flow-row gap-2"> <div className="grid grid-flow-row gap-2">
<div className="grid grid-flow-row gap-1"> <div className="grid grid-flow-row gap-1">
@@ -86,9 +97,9 @@ export default function AppLoader({
<ActivityIndicator className="mx-auto" /> <ActivityIndicator className="mx-auto" />
{timeElapsed > 180 && ( {timeElapsed > 180 && (
<Dropdown.Root className="flex flex-col mx-auto"> <Dropdown.Root className="mx-auto flex flex-col">
<Dropdown.Trigger <Dropdown.Trigger
className="flex mx-auto font-medium" className="mx-auto flex font-medium"
hideChevron hideChevron
asChild asChild
> >

View File

@@ -13,12 +13,12 @@ export default function useIsHealthy() {
const appUrl = generateAppServiceUrl( const appUrl = generateAppServiceUrl(
project?.subdomain, project?.subdomain,
project?.region, project?.region,
'auth', 'hasura',
); );
const { failureCount, status } = useQuery( const { failureCount, status } = useQuery(
['/healthz'], ['/v1/version'],
() => fetch(`${appUrl}/healthz`), () => fetch(`${appUrl}/v1/version`),
{ {
enabled: !isPlatform && !!project, enabled: !isPlatform && !!project,
retry: true, retry: true,

View File

@@ -1,3 +1,4 @@
import type { ProjectFragment } from '@/utils/__generated__/graphql';
import { import {
getAuthServiceUrl, getAuthServiceUrl,
getDatabaseServiceUrl, getDatabaseServiceUrl,
@@ -7,7 +8,6 @@ import {
getStorageServiceUrl, getStorageServiceUrl,
isPlatform, isPlatform,
} from '@/utils/env'; } from '@/utils/env';
import type { ProjectFragment } from '@/utils/__generated__/graphql';
export type NhostService = export type NhostService =
| 'auth' | 'auth'
@@ -18,21 +18,6 @@ export type NhostService =
| 'hasura' | 'hasura'
| 'grafana'; | 'grafana';
/**
* The default slugs that are used when running the dashboard locally. These
* values are used both in local mode and when running the dashboard locally
* against the remote (either staging or production) backend.
*/
export const defaultLocalBackendSlugs: Record<NhostService, string> = {
auth: '/v1/auth',
db: '',
graphql: '/v1/graphql',
functions: '/v1/functions',
storage: '/v1/files',
hasura: '',
grafana: '',
};
/** /**
* The default slugs that are used when running the dashboard against the * The default slugs that are used when running the dashboard against the
* remote (either staging or production) backend in a cloud environment. * remote (either staging or production) backend in a cloud environment.

View File

@@ -34,7 +34,11 @@ export default function AuthDomain() {
const localMimirClient = useLocalMimirClient(); const localMimirClient = useLocalMimirClient();
const [isVerified, setIsVerified] = useState(false); const [isVerified, setIsVerified] = useState(false);
const { project, refetch: refetchProject } = useProject(); const {
project,
refetch: refetchProject,
loading: loadingProject,
} = useProject();
const [updateConfig] = useUpdateConfigMutation({ const [updateConfig] = useUpdateConfigMutation({
...(!isPlatform ? { client: localMimirClient } : {}), ...(!isPlatform ? { client: localMimirClient } : {}),
@@ -48,7 +52,7 @@ export default function AuthDomain() {
const { data, loading, error } = useGetAuthenticationSettingsQuery({ const { data, loading, error } = useGetAuthenticationSettingsQuery({
variables: { variables: {
appId: project.id, appId: project?.id,
}, },
...(!isPlatform ? { client: localMimirClient } : {}), ...(!isPlatform ? { client: localMimirClient } : {}),
}); });
@@ -62,7 +66,7 @@ export default function AuthDomain() {
} }
}, [data, loading, form, initialValue]); }, [data, loading, form, initialValue]);
if (loading) { if (loadingProject || loading) {
return ( return (
<ActivityIndicator <ActivityIndicator
delay={1000} delay={1000}
@@ -147,7 +151,7 @@ export default function AuthDomain() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
className="grid grid-flow-row px-4 gap-x-4 gap-y-4 lg:grid-cols-5" className="grid grid-flow-row gap-x-4 gap-y-4 px-4 lg:grid-cols-5"
> >
<Input <Input
{...register('auth_fqdn')} {...register('auth_fqdn')}

View File

@@ -14,10 +14,14 @@ const validationSchema = Yup.object({
export type DatabaseDomainFormValues = Yup.InferType<typeof validationSchema>; export type DatabaseDomainFormValues = Yup.InferType<typeof validationSchema>;
export default function DatabaseDomain() { export default function DatabaseDomain() {
const { project } = useProject(); const { project, loading } = useProject();
const [dbFQDN, setDbFQDN] = useState(''); const [dbFQDN, setDbFQDN] = useState('');
if (loading) {
return null;
}
const postgresHost = generateAppServiceUrl( const postgresHost = generateAppServiceUrl(
project.subdomain, project.subdomain,
project.region, project.region,
@@ -36,7 +40,7 @@ export default function DatabaseDomain() {
className: 'hidden', className: 'hidden',
}, },
}} }}
className="grid grid-flow-row px-4 gap-x-4 gap-y-4 lg:grid-cols-5" className="grid grid-flow-row gap-x-4 gap-y-4 px-4 lg:grid-cols-5"
> >
<Input <Input
id="database_fqdn" id="database_fqdn"

View File

@@ -33,7 +33,11 @@ export default function HasuraDomain() {
const localMimirClient = useLocalMimirClient(); const localMimirClient = useLocalMimirClient();
const [isVerified, setIsVerified] = useState(false); const [isVerified, setIsVerified] = useState(false);
const { project, refetch: refetchProject } = useProject(); const {
project,
refetch: refetchProject,
loading: loadingProject,
} = useProject();
const [updateConfig] = useUpdateConfigMutation({ const [updateConfig] = useUpdateConfigMutation({
...(!isPlatform ? { client: localMimirClient } : {}), ...(!isPlatform ? { client: localMimirClient } : {}),
@@ -47,7 +51,7 @@ export default function HasuraDomain() {
const { data, loading, error } = useGetHasuraSettingsQuery({ const { data, loading, error } = useGetHasuraSettingsQuery({
variables: { variables: {
appId: project.id, appId: project?.id,
}, },
...(!isPlatform ? { client: localMimirClient } : {}), ...(!isPlatform ? { client: localMimirClient } : {}),
}); });
@@ -61,7 +65,7 @@ export default function HasuraDomain() {
} }
}, [data, loading, form, initialValue]); }, [data, loading, form, initialValue]);
if (loading) { if (loadingProject || loading) {
return ( return (
<ActivityIndicator <ActivityIndicator
delay={0} delay={0}
@@ -148,7 +152,7 @@ export default function HasuraDomain() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
className="grid grid-flow-row px-4 gap-x-4 gap-y-4 lg:grid-cols-5" className="grid grid-flow-row gap-x-4 gap-y-4 px-4 lg:grid-cols-5"
> >
<Input <Input
{...register('hasura_fqdn')} {...register('hasura_fqdn')}

View File

@@ -35,7 +35,11 @@ export default function ServerlessFunctionsDomain() {
const { maintenanceActive } = useUI(); const { maintenanceActive } = useUI();
const localMimirClient = useLocalMimirClient(); const localMimirClient = useLocalMimirClient();
const [isVerified, setIsVerified] = useState(false); const [isVerified, setIsVerified] = useState(false);
const { project, refetch: refetchProject } = useProject(); const {
project,
refetch: refetchProject,
loading: loadingProject,
} = useProject();
const [updateConfig] = useUpdateConfigMutation({ const [updateConfig] = useUpdateConfigMutation({
...(!isPlatform ? { client: localMimirClient } : {}), ...(!isPlatform ? { client: localMimirClient } : {}),
@@ -49,7 +53,7 @@ export default function ServerlessFunctionsDomain() {
const { data, loading, error } = useGetServerlessFunctionsSettingsQuery({ const { data, loading, error } = useGetServerlessFunctionsSettingsQuery({
variables: { variables: {
appId: project.id, appId: project?.id,
}, },
...(!isPlatform ? { client: localMimirClient } : {}), ...(!isPlatform ? { client: localMimirClient } : {}),
}); });
@@ -63,7 +67,7 @@ export default function ServerlessFunctionsDomain() {
} }
}, [data, loading, form, initialValue]); }, [data, loading, form, initialValue]);
if (loading) { if (loadingProject || loading) {
return ( return (
<ActivityIndicator <ActivityIndicator
delay={1000} delay={1000}
@@ -151,7 +155,7 @@ export default function ServerlessFunctionsDomain() {
loading: formState.isSubmitting, loading: formState.isSubmitting,
}, },
}} }}
className="grid grid-flow-row px-4 gap-x-4 gap-y-4 lg:grid-cols-5" className="grid grid-flow-row gap-x-4 gap-y-4 px-4 lg:grid-cols-5"
> >
<Input <Input
{...register('functions_fqdn')} {...register('functions_fqdn')}

View File

@@ -1,7 +1,4 @@
import { useDialog } from '@/components/common/DialogProvider'; import { useDialog } from '@/components/common/DialogProvider';
import { useDataGridConfig } from '@/components/dataGrid/DataGridConfigProvider';
import type { DataGridPaginationProps } from '@/components/dataGrid/DataGridPagination';
import { DataGridPagination } from '@/components/dataGrid/DataGridPagination';
import type { BoxProps } from '@/components/ui/v2/Box'; import type { BoxProps } from '@/components/ui/v2/Box';
import { Box } from '@/components/ui/v2/Box'; import { Box } from '@/components/ui/v2/Box';
import { Button } from '@/components/ui/v2/Button'; import { Button } from '@/components/ui/v2/Button';
@@ -13,6 +10,9 @@ import { RowIcon } from '@/components/ui/v2/icons/RowIcon';
import { useDeleteRecordMutation } from '@/features/orgs/projects/database/dataGrid/hooks/useDeleteRecordMutation'; import { useDeleteRecordMutation } from '@/features/orgs/projects/database/dataGrid/hooks/useDeleteRecordMutation';
import type { DataBrowserGridColumn } from '@/features/orgs/projects/database/dataGrid/types/dataBrowser'; import type { DataBrowserGridColumn } from '@/features/orgs/projects/database/dataGrid/types/dataBrowser';
import { useProject } from '@/features/orgs/projects/hooks/useProject'; import { useProject } from '@/features/orgs/projects/hooks/useProject';
import { useDataGridConfig } from '@/features/orgs/projects/storage/dataGrid/components/DataGridConfigProvider';
import type { DataGridPaginationProps } from '@/features/orgs/projects/storage/dataGrid/components/DataGridPagination';
import { DataGridPagination } from '@/features/orgs/projects/storage/dataGrid/components/DataGridPagination';
import { triggerToast } from '@/utils/toast'; import { triggerToast } from '@/utils/toast';
import { useQueryClient } from '@tanstack/react-query'; import { useQueryClient } from '@tanstack/react-query';
import { useState } from 'react'; import { useState } from 'react';
@@ -120,7 +120,7 @@ export default function DataBrowserGridControls({
)} )}
> >
{numberOfSelectedRows > 0 && ( {numberOfSelectedRows > 0 && (
<div className="grid items-center grid-flow-col gap-2 place-content-start"> <div className="grid grid-flow-col place-content-start items-center gap-2">
<Chip <Chip
size="small" size="small"
color="info" color="info"
@@ -161,7 +161,7 @@ export default function DataBrowserGridControls({
)} )}
{numberOfSelectedRows === 0 && ( {numberOfSelectedRows === 0 && (
<div className="grid items-center grid-flow-col col-span-6 gap-2"> <div className="col-span-6 grid grid-flow-col items-center gap-2">
{columns.length > 0 && ( {columns.length > 0 && (
<DataGridPagination <DataGridPagination
className={twMerge( className={twMerge(
@@ -177,7 +177,7 @@ export default function DataBrowserGridControls({
<Dropdown.Root> <Dropdown.Root>
<Dropdown.Trigger asChild hideChevron> <Dropdown.Trigger asChild hideChevron>
<Button <Button
startIcon={<PlusIcon className="w-4 h-4" />} startIcon={<PlusIcon className="h-4 w-4" />}
size="small" size="small"
> >
Insert Insert

View File

@@ -18,21 +18,7 @@ const ruleSchema = Yup.object().shape({
}); });
const ruleGroupSchema = Yup.object().shape({ const ruleGroupSchema = Yup.object().shape({
operator: Yup.string().test( operator: Yup.string().required('Please select an operator.'),
'operator',
'Please select an operator.',
(selectedOperator, ctx) => {
// `from` is part of the Yup API, but it's not typed.
// @ts-ignore
const [, { value }] = ctx.from;
if (Object.keys(value.filter).length > 0 && !selectedOperator) {
return false;
}
return true;
},
),
rules: Yup.array().of(ruleSchema), rules: Yup.array().of(ruleSchema),
groups: Yup.array().of(Yup.lazy(() => ruleGroupSchema) as any), groups: Yup.array().of(Yup.lazy(() => ruleGroupSchema) as any),
}); });

View File

@@ -5,12 +5,12 @@ import { Button } from '@/components/ui/v2/Button';
import { PlusIcon } from '@/components/ui/v2/icons/PlusIcon'; import { PlusIcon } from '@/components/ui/v2/icons/PlusIcon';
import { Link } from '@/components/ui/v2/Link'; import { Link } from '@/components/ui/v2/Link';
import { Text } from '@/components/ui/v2/Text'; import { Text } from '@/components/ui/v2/Text';
import { generateAppServiceUrl } from '@/features/orgs/projects/common/utils/generateAppServiceUrl';
import type { import type {
Rule, Rule,
RuleGroup, RuleGroup,
} from '@/features/orgs/projects/database/dataGrid/types/dataBrowser'; } from '@/features/orgs/projects/database/dataGrid/types/dataBrowser';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject'; import { useProject } from '@/features/orgs/projects/hooks/useProject';
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
import { useMemo } from 'react'; import { useMemo } from 'react';
import { useFieldArray, useFormContext } from 'react-hook-form'; import { useFieldArray, useFormContext } from 'react-hook-form';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
@@ -68,7 +68,7 @@ export default function RuleGroupEditor({
sx, sx,
...props ...props
}: RuleGroupEditorProps) { }: RuleGroupEditorProps) {
const { currentProject } = useCurrentWorkspaceAndProject(); const { project } = useProject();
const form = useFormContext(); const form = useFormContext();
const { control, getValues } = form; const { control, getValues } = form;
@@ -185,13 +185,13 @@ export default function RuleGroupEditor({
<Text> <Text>
This rule group contains one or more objects (e.g: _exists) that This rule group contains one or more objects (e.g: _exists) that
are not supported by our dashboard yet.{' '} are not supported by our dashboard yet.{' '}
{currentProject && ( {project && (
<span> <span>
Please{' '} Please{' '}
<Link <Link
href={`${generateAppServiceUrl( href={`${generateAppServiceUrl(
currentProject.subdomain, project.subdomain,
currentProject.region, project.region,
'hasura', 'hasura',
)}/console/data/default/schema/${schema}/tables/${table}/permissions`} )}/console/data/default/schema/${schema}/tables/${table}/permissions`}
underline="hover" underline="hover"

View File

@@ -1,5 +1,5 @@
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject'; import { useIsPlatform } from '@/features/orgs/projects/common/hooks/useIsPlatform';
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform'; import { useProject } from '@/features/orgs/projects/hooks/useProject';
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl'; import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
import { getHasuraAdminSecret } from '@/utils/env'; import { getHasuraAdminSecret } from '@/utils/env';
import type { MutationOptions } from '@tanstack/react-query'; import type { MutationOptions } from '@tanstack/react-query';
@@ -39,10 +39,10 @@ export default function useDeleteColumnMutation({
const { const {
query: { dataSourceSlug, schemaSlug, tableSlug }, query: { dataSourceSlug, schemaSlug, tableSlug },
} = useRouter(); } = useRouter();
const { currentProject } = useCurrentWorkspaceAndProject(); const { project } = useProject();
const appUrl = generateAppServiceUrl( const appUrl = generateAppServiceUrl(
currentProject?.subdomain, project?.subdomain,
currentProject?.region, project?.region,
'hasura', 'hasura',
); );
const mutationFn = isPlatform ? deleteColumn : deleteColumnMigration; const mutationFn = isPlatform ? deleteColumn : deleteColumnMigration;
@@ -55,7 +55,7 @@ export default function useDeleteColumnMutation({
adminSecret: adminSecret:
process.env.NEXT_PUBLIC_ENV === 'dev' process.env.NEXT_PUBLIC_ENV === 'dev'
? getHasuraAdminSecret() ? getHasuraAdminSecret()
: customAdminSecret || currentProject?.config?.hasura.adminSecret, : customAdminSecret || project?.config?.hasura.adminSecret,
dataSource: customDataSource || (dataSourceSlug as string), dataSource: customDataSource || (dataSourceSlug as string),
schema: customSchema || (schemaSlug as string), schema: customSchema || (schemaSlug as string),
table: customTable || (tableSlug as string), table: customTable || (tableSlug as string),

View File

@@ -13,8 +13,8 @@ import { Tooltip } from '@/components/ui/v2/Tooltip';
import { useProject } from '@/features/orgs/projects/hooks/useProject'; import { useProject } from '@/features/orgs/projects/hooks/useProject';
import { LogsRangeSelector } from '@/features/orgs/projects/logs/components/LogsRangeSelector'; import { LogsRangeSelector } from '@/features/orgs/projects/logs/components/LogsRangeSelector';
import { AvailableLogsService } from '@/features/orgs/projects/logs/utils/constants/services'; import { AvailableLogsService } from '@/features/orgs/projects/logs/utils/constants/services';
import { MINUTES_TO_DECREASE_FROM_CURRENT_DATE } from '@/utils/constants/common';
import { useGetServiceLabelValuesQuery } from '@/utils/__generated__/graphql'; import { useGetServiceLabelValuesQuery } from '@/utils/__generated__/graphql';
import { MINUTES_TO_DECREASE_FROM_CURRENT_DATE } from '@/utils/constants/common';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { subMinutes } from 'date-fns'; import { subMinutes } from 'date-fns';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
@@ -55,7 +55,7 @@ export default function LogsHeader({
const { data, loading: loadingServiceLabelValues } = const { data, loading: loadingServiceLabelValues } =
useGetServiceLabelValuesQuery({ useGetServiceLabelValuesQuery({
variables: { appID: project.id }, variables: { appID: project?.id },
}); });
useEffect(() => { useEffect(() => {
@@ -121,7 +121,7 @@ export default function LogsHeader({
<Box className="flex flex-row space-x-2"> <Box className="flex flex-row space-x-2">
<ControlledSelect <ControlledSelect
{...register('service')} {...register('service')}
className="w-full text-sm font-normal min-w-fit" className="w-full min-w-fit text-sm font-normal"
placeholder="All Services" placeholder="All Services"
aria-label="Select service" aria-label="Select service"
hideEmptyHelperText hideEmptyHelperText
@@ -165,12 +165,12 @@ export default function LogsHeader({
}, },
}} }}
title={ title={
<div className="p-2 space-y-4"> <div className="space-y-4 p-2">
<h2>Here are some useful regular expressions:</h2> <h2>Here are some useful regular expressions:</h2>
<ul className="pl-3 space-y-2 list-disc"> <ul className="list-disc space-y-2 pl-3">
<li> <li>
use use
<code className="px-1 py-px mx-1 rounded-md bg-slate-500 text-slate-100"> <code className="mx-1 rounded-md bg-slate-500 px-1 py-px text-slate-100">
(?i)error (?i)error
</code> </code>
to search for lines with the word <b>error</b> (case to search for lines with the word <b>error</b> (case
@@ -178,7 +178,7 @@ export default function LogsHeader({
</li> </li>
<li> <li>
use use
<code className="px-1 py-px mx-1 rounded-md bg-slate-500 text-slate-100"> <code className="mx-1 rounded-md bg-slate-500 px-1 py-px text-slate-100">
error error
</code> </code>
to search for lines with the word <b>error</b> (case to search for lines with the word <b>error</b> (case
@@ -186,7 +186,7 @@ export default function LogsHeader({
</li> </li>
<li> <li>
use use
<code className="px-1 py-px mx-1 rounded-md bg-slate-500 text-slate-100"> <code className="mx-1 rounded-md bg-slate-500 px-1 py-px text-slate-100">
/metadata.*error /metadata.*error
</code> </code>
to search for errors in hasura&apos;s metadata endpoint to search for errors in hasura&apos;s metadata endpoint
@@ -208,10 +208,10 @@ export default function LogsHeader({
</div> </div>
} }
> >
<Box className="ml-2 rounded-full cursor-pointer"> <Box className="ml-2 cursor-pointer rounded-full">
<InfoIcon <InfoIcon
aria-label="Info" aria-label="Info"
className="w-5 h-5" className="h-5 w-5"
color="info" color="info"
/> />
</Box> </Box>
@@ -224,7 +224,7 @@ export default function LogsHeader({
className="h-10" className="h-10"
startIcon={ startIcon={
loading ? ( loading ? (
<ActivityIndicator className="w-4 h-4" /> <ActivityIndicator className="h-4 w-4" />
) : ( ) : (
<SearchIcon /> <SearchIcon />
) )

View File

@@ -33,15 +33,24 @@ export default function MetricsSettings() {
const isPlatform = useIsPlatform(); const isPlatform = useIsPlatform();
const { maintenanceActive } = useUI(); const { maintenanceActive } = useUI();
const localMimirClient = useLocalMimirClient(); const localMimirClient = useLocalMimirClient();
const { project, refetch: refetchProject } = useProject(); const {
project,
refetch: refetchProject,
loading: loadingProject,
} = useProject();
const [updateConfig] = useUpdateConfigMutation({ const [updateConfig] = useUpdateConfigMutation({
refetchQueries: [GetObservabilitySettingsDocument], refetchQueries: [GetObservabilitySettingsDocument],
...(!isPlatform ? { client: localMimirClient } : {}), ...(!isPlatform ? { client: localMimirClient } : {}),
}); });
const { data, loading, error } = useGetObservabilitySettingsQuery({ const {
data,
loading: loadingObservabilitySettings,
error,
} = useGetObservabilitySettingsQuery({
variables: { appId: project?.id }, variables: { appId: project?.id },
...(!isPlatform ? { client: localMimirClient } : {}), ...(!isPlatform ? { client: localMimirClient } : {}),
skip: !project?.id,
}); });
const { enabled: alertingEnabled } = const { enabled: alertingEnabled } =
@@ -59,14 +68,14 @@ export default function MetricsSettings() {
const alerting = watch('enabled'); const alerting = watch('enabled');
useEffect(() => { useEffect(() => {
if (!loading) { if (!loadingObservabilitySettings) {
alertingForm.reset({ alertingForm.reset({
enabled: alertingEnabled, enabled: alertingEnabled,
}); });
} }
}, [loading, alertingEnabled, alertingForm]); }, [loadingObservabilitySettings, alertingEnabled, alertingForm]);
if (loading) { if (loadingProject || loadingObservabilitySettings) {
return ( return (
<ActivityIndicator <ActivityIndicator
delay={1000} delay={1000}
@@ -124,7 +133,7 @@ export default function MetricsSettings() {
} }
return ( return (
<div className="grid max-w-5xl grid-flow-row bg-transparent gap-y-6"> <div className="grid max-w-5xl grid-flow-row gap-y-6 bg-transparent">
<FormProvider {...alertingForm}> <FormProvider {...alertingForm}>
<Form onSubmit={handleSubmit}> <Form onSubmit={handleSubmit}>
<SettingsContainer <SettingsContainer

View File

@@ -10,28 +10,28 @@ const features: CardProps[] = [
description: 'Learn how to use Postgres with Nhost', description: 'Learn how to use Postgres with Nhost',
icon: <DatabaseIcon className="h-8 w-8" sx={{ color: 'text.secondary' }} />, icon: <DatabaseIcon className="h-8 w-8" sx={{ color: 'text.secondary' }} />,
disableIconBackground: true, disableIconBackground: true,
link: 'https://docs.nhost.io/platform/database', link: 'https://docs.nhost.io/product/database',
}, },
{ {
title: 'GraphQL API', title: 'GraphQL API',
description: 'Learn how to interact with the GraphQL API', description: 'Learn how to interact with the GraphQL API',
icon: <GraphQLIcon className="h-8 w-8" sx={{ color: 'text.secondary' }} />, icon: <GraphQLIcon className="h-8 w-8" sx={{ color: 'text.secondary' }} />,
disableIconBackground: true, disableIconBackground: true,
link: 'https://docs.nhost.io/platform/graphql', link: 'https://docs.nhost.io/product/graphql',
}, },
{ {
title: 'Authentication', title: 'Authentication',
description: 'Learn how to authenticate users with Nhost', description: 'Learn how to authenticate users with Nhost',
icon: <UserIcon className="h-8 w-8" sx={{ color: 'text.secondary' }} />, icon: <UserIcon className="h-8 w-8" sx={{ color: 'text.secondary' }} />,
disableIconBackground: true, disableIconBackground: true,
link: 'https://docs.nhost.io/platform/authentication', link: 'https://docs.nhost.io/product/authentication',
}, },
{ {
title: 'Storage', title: 'Storage',
description: 'Learn how to use Storage with Nhost', description: 'Learn how to use Storage with Nhost',
icon: <StorageIcon className="h-8 w-8" sx={{ color: 'text.secondary' }} />, icon: <StorageIcon className="h-8 w-8" sx={{ color: 'text.secondary' }} />,
disableIconBackground: true, disableIconBackground: true,
link: 'https://docs.nhost.io/platform/storage', link: 'https://docs.nhost.io/product/storage',
}, },
]; ];

View File

@@ -46,7 +46,7 @@ export default function useRunServices() {
refetch: refetchPlatformServices, refetch: refetchPlatformServices,
} = useGetRunServicesQuery({ } = useGetRunServicesQuery({
variables: { variables: {
appID: project.id, appID: project?.id,
resolve: false, resolve: false,
limit: limit.current, limit: limit.current,
offset, offset,
@@ -59,7 +59,7 @@ export default function useRunServices() {
data: localServicesData, data: localServicesData,
refetch: refetchLocalServices, refetch: refetchLocalServices,
} = useGetLocalRunServiceConfigsQuery({ } = useGetLocalRunServiceConfigsQuery({
variables: { appID: project.id as any, resolve: false }, variables: { appID: project?.id as any, resolve: false },
skip: isPlatform, skip: isPlatform,
client: localMimirClient, client: localMimirClient,
}); });

View File

@@ -1,13 +1,13 @@
import type { UseDataGridOptions } from '@/components/dataGrid/DataGrid/useDataGrid';
import { DataGridBody } from '@/components/dataGrid/DataGridBody';
import { DataGridConfigProvider } from '@/components/dataGrid/DataGridConfigProvider';
import { DataGridFrame } from '@/components/dataGrid/DataGridFrame';
import type { DataGridHeaderProps } from '@/components/dataGrid/DataGridHeader';
import { DataGridHeader } from '@/components/dataGrid/DataGridHeader';
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator'; import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
import { Box } from '@/components/ui/v2/Box'; import { Box } from '@/components/ui/v2/Box';
import { DataBrowserEmptyState } from '@/features/database/dataGrid/components/DataBrowserEmptyState'; import { DataBrowserEmptyState } from '@/features/orgs/projects/database/dataGrid/components/DataBrowserEmptyState';
import type { DataBrowserGridColumn } from '@/features/database/dataGrid/types/dataBrowser'; import type { DataBrowserGridColumn } from '@/features/orgs/projects/database/dataGrid/types/dataBrowser';
import type { UseDataGridOptions } from '@/features/orgs/projects/storage/dataGrid/components/DataGrid/useDataGrid';
import { DataGridBody } from '@/features/orgs/projects/storage/dataGrid/components/DataGridBody';
import { DataGridConfigProvider } from '@/features/orgs/projects/storage/dataGrid/components/DataGridConfigProvider';
import { DataGridFrame } from '@/features/orgs/projects/storage/dataGrid/components/DataGridFrame';
import type { DataGridHeaderProps } from '@/features/orgs/projects/storage/dataGrid/components/DataGridHeader';
import { DataGridHeader } from '@/features/orgs/projects/storage/dataGrid/components/DataGridHeader';
import type { ForwardedRef } from 'react'; import type { ForwardedRef } from 'react';
import { forwardRef, useEffect, useRef } from 'react'; import { forwardRef, useEffect, useRef } from 'react';
import mergeRefs from 'react-merge-refs'; import mergeRefs from 'react-merge-refs';

View File

@@ -1,11 +1,11 @@
import type { DataGridProps } from '@/components/dataGrid/DataGrid';
import { DataGridCell } from '@/components/dataGrid/DataGridCell';
import { useDataGridConfig } from '@/components/dataGrid/DataGridConfigProvider';
import type { BoxProps } from '@/components/ui/v2/Box'; import type { BoxProps } from '@/components/ui/v2/Box';
import { Box } from '@/components/ui/v2/Box'; import { Box } from '@/components/ui/v2/Box';
import { Button } from '@/components/ui/v2/Button'; import { Button } from '@/components/ui/v2/Button';
import { PlusIcon } from '@/components/ui/v2/icons/PlusIcon'; import { PlusIcon } from '@/components/ui/v2/icons/PlusIcon';
import type { DataBrowserGridColumn } from '@/features/database/dataGrid/types/dataBrowser'; import type { DataBrowserGridColumn } from '@/features/orgs/projects/database/dataGrid/types/dataBrowser';
import type { DataGridProps } from '@/features/orgs/projects/storage/dataGrid/components/DataGrid/DataGrid';
import { DataGridCell } from '@/features/orgs/projects/storage/dataGrid/components/DataGridCell';
import { useDataGridConfig } from '@/features/orgs/projects/storage/dataGrid/components/DataGridConfigProvider';
import type { DetailedHTMLProps, HTMLProps, KeyboardEvent } from 'react'; import type { DetailedHTMLProps, HTMLProps, KeyboardEvent } from 'react';
import { Fragment, useMemo, useRef } from 'react'; import { Fragment, useMemo, useRef } from 'react';
import type { Row } from 'react-table'; import type { Row } from 'react-table';

View File

@@ -1,8 +1,8 @@
import type { CommonDataGridCellProps } from '@/components/dataGrid/DataGridCell';
import { useDataGridCell } from '@/components/dataGrid/DataGridCell';
import { ReadOnlyToggle } from '@/components/presentational/ReadOnlyToggle'; import { ReadOnlyToggle } from '@/components/presentational/ReadOnlyToggle';
import { Dropdown } from '@/components/ui/v2/Dropdown'; import { Dropdown } from '@/components/ui/v2/Dropdown';
import type { KeyboardEvent as ReactKeyboardEvent, MouseEvent } from 'react'; import type { CommonDataGridCellProps } from '@/features/orgs/projects/storage/dataGrid/components/DataGridCell';
import { useDataGridCell } from '@/features/orgs/projects/storage/dataGrid/components/DataGridCell';
import type { MouseEvent, KeyboardEvent as ReactKeyboardEvent } from 'react';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
export type DataGridBooleanCellProps<TData extends object> = export type DataGridBooleanCellProps<TData extends object> =

View File

@@ -6,7 +6,7 @@ import type {
ColumnType, ColumnType,
DataBrowserGridCell, DataBrowserGridCell,
DataBrowserGridCellProps, DataBrowserGridCellProps,
} from '@/features/database/dataGrid/types/dataBrowser'; } from '@/features/orgs/projects/database/dataGrid/types/dataBrowser';
import { triggerToast } from '@/utils/toast'; import { triggerToast } from '@/utils/toast';
import type { import type {
FocusEvent, FocusEvent,

View File

@@ -1,4 +1,4 @@
import type { UseDataGridReturn } from '@/components/dataGrid/DataGrid'; import type { UseDataGridReturn } from '@/features/orgs/projects/storage/dataGrid/components/DataGrid/useDataGrid';
import { createContext } from 'react'; import { createContext } from 'react';
const DataGridConfigContext = createContext<Partial<UseDataGridReturn>>(null); const DataGridConfigContext = createContext<Partial<UseDataGridReturn>>(null);

View File

@@ -1,4 +1,4 @@
import type { UseDataGridReturn } from '@/components/dataGrid/DataGrid'; import type { UseDataGridReturn } from '@/features/orgs/projects/storage/dataGrid/components/DataGrid/useDataGrid';
import type { PropsWithChildren } from 'react'; import type { PropsWithChildren } from 'react';
import DataGridConfigContext from './DataGridConfigContext'; import DataGridConfigContext from './DataGridConfigContext';

View File

@@ -1,4 +1,4 @@
import type { UseDataGridReturn } from '@/components/dataGrid/DataGrid'; import type { UseDataGridReturn } from '@/features/orgs/projects/storage/dataGrid/components/DataGrid';
import { useContext } from 'react'; import { useContext } from 'react';
import DataGridConfigContext from './DataGridConfigContext'; import DataGridConfigContext from './DataGridConfigContext';

View File

@@ -1,8 +1,8 @@
import type { CommonDataGridCellProps } from '@/components/dataGrid/DataGridCell';
import { useDataGridCell } from '@/components/dataGrid/DataGridCell';
import { Input, inputClasses } from '@/components/ui/v2/Input'; import { Input, inputClasses } from '@/components/ui/v2/Input';
import type { TextProps } from '@/components/ui/v2/Text'; import type { TextProps } from '@/components/ui/v2/Text';
import { Text } from '@/components/ui/v2/Text'; import { Text } from '@/components/ui/v2/Text';
import type { CommonDataGridCellProps } from '@/features/orgs/projects/storage/dataGrid/components/DataGridCell';
import { useDataGridCell } from '@/features/orgs/projects/storage/dataGrid/components/DataGridCell';
import { getDateComponents } from '@/utils/getDateComponents'; import { getDateComponents } from '@/utils/getDateComponents';
import type { ChangeEvent, KeyboardEvent } from 'react'; import type { ChangeEvent, KeyboardEvent } from 'react';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';

View File

@@ -1,7 +1,7 @@
import type { CommonDataGridCellProps } from '@/components/dataGrid/DataGridCell';
import { useDataGridCell } from '@/components/dataGrid/DataGridCell';
import { Input, inputClasses } from '@/components/ui/v2/Input'; import { Input, inputClasses } from '@/components/ui/v2/Input';
import { Text } from '@/components/ui/v2/Text'; import { Text } from '@/components/ui/v2/Text';
import type { CommonDataGridCellProps } from '@/features/orgs/projects/storage/dataGrid/components/DataGridCell';
import { useDataGridCell } from '@/features/orgs/projects/storage/dataGrid/components/DataGridCell';
import type { ChangeEvent, KeyboardEvent } from 'react'; import type { ChangeEvent, KeyboardEvent } from 'react';
export type DataGridDecimalCellProps<TData extends object> = export type DataGridDecimalCellProps<TData extends object> =

View File

@@ -1,4 +1,4 @@
import { useDataGridConfig } from '@/components/dataGrid/DataGridConfigProvider'; import { useDataGridConfig } from '@/features/orgs/projects/storage/dataGrid/components/DataGridConfigProvider';
import clsx from 'clsx'; import clsx from 'clsx';
import type { DetailedHTMLProps, HTMLProps } from 'react'; import type { DetailedHTMLProps, HTMLProps } from 'react';

View File

@@ -1,5 +1,3 @@
import type { DataGridProps } from '@/components/dataGrid/DataGrid';
import { useDataGridConfig } from '@/components/dataGrid/DataGridConfigProvider';
import { Box } from '@/components/ui/v2/Box'; import { Box } from '@/components/ui/v2/Box';
import { Button } from '@/components/ui/v2/Button'; import { Button } from '@/components/ui/v2/Button';
import { Divider } from '@/components/ui/v2/Divider'; import { Divider } from '@/components/ui/v2/Divider';
@@ -9,7 +7,10 @@ import { ArrowUpIcon } from '@/components/ui/v2/icons/ArrowUpIcon';
import { PencilIcon } from '@/components/ui/v2/icons/PencilIcon'; import { PencilIcon } from '@/components/ui/v2/icons/PencilIcon';
import { PlusIcon } from '@/components/ui/v2/icons/PlusIcon'; import { PlusIcon } from '@/components/ui/v2/icons/PlusIcon';
import { TrashIcon } from '@/components/ui/v2/icons/TrashIcon'; import { TrashIcon } from '@/components/ui/v2/icons/TrashIcon';
import type { DataBrowserGridColumn } from '@/features/database/dataGrid/types/dataBrowser'; import type { DataBrowserGridColumn } from '@/features/orgs/projects/database/dataGrid/types/dataBrowser';
import type { DataGridProps } from '@/features/orgs/projects/storage/dataGrid/components/DataGrid';
import { useDataGridConfig } from '@/features/orgs/projects/storage/dataGrid/components/DataGridConfigProvider';
import { DataGridHeaderButton } from '@/features/orgs/projects/storage/dataGrid/components/DataGridHeaderButton';
import type { DetailedHTMLProps, HTMLProps } from 'react'; import type { DetailedHTMLProps, HTMLProps } from 'react';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
@@ -54,7 +55,7 @@ export default function DataGridHeader<T extends object>({
componentsProps, componentsProps,
...props ...props
}: DataGridHeaderProps<T>) { }: DataGridHeaderProps<T>) {
const { flatHeaders, allowSort, allowResize } = useDataGridConfig<T>(); const { flatHeaders } = useDataGridConfig<T>();
return ( return (
<div <div
@@ -96,53 +97,11 @@ export default function DataGridHeader<T extends object>({
}} }}
key={column.id} key={column.id}
> >
{column.id === 'selection' ? ( <DataGridHeaderButton
<span column={column}
{...headerProps} headerProps={headerProps}
className="relative grid w-full grid-flow-col items-center justify-between p-2" onRemoveColumn={onRemoveColumn}
> />
{column.render('Header')}
</span>
) : (
<Dropdown.Trigger
className={twMerge(
'focus:outline-none motion-safe:transition-colors',
)}
disabled={
column.isDisabled || (column.disableSortBy && !onRemoveColumn)
}
hideChevron
>
<span
{...headerProps}
className="relative grid w-full grid-flow-col items-center justify-between p-2"
>
{column.render('Header')}
{allowSort && (
<Box component="span" sx={{ color: 'text.primary' }}>
{column.isSorted && !column.isSortedDesc && (
<ArrowUpIcon className="h-3 w-3" />
)}
{column.isSorted && column.isSortedDesc && (
<ArrowDownIcon className="h-3 w-3" />
)}
</Box>
)}
</span>
{allowResize && !column.disableResizing && (
<span
{...column.getResizerProps({
onClick: (event: Event) => event.stopPropagation(),
})}
className="absolute -right-0.5 bottom-0 top-0 z-10 h-full w-1.5 group-hover:bg-slate-900 group-hover:bg-opacity-20 group-active:bg-slate-900 group-active:bg-opacity-20 motion-safe:transition-colors"
/>
)}
</Dropdown.Trigger>
)}
<Dropdown.Content <Dropdown.Content
menu menu
PaperProps={{ className: 'w-52 mt-1' }} PaperProps={{ className: 'w-52 mt-1' }}

View File

@@ -0,0 +1,77 @@
import { Box } from '@/components/ui/v2/Box';
import { Dropdown } from '@/components/ui/v2/Dropdown';
import { ArrowDownIcon } from '@/components/ui/v2/icons/ArrowDownIcon';
import { ArrowUpIcon } from '@/components/ui/v2/icons/ArrowUpIcon';
import type { DataBrowserGridColumn } from '@/features/orgs/projects/database/dataGrid/types/dataBrowser';
import { useDataGridConfig } from '@/features/orgs/projects/storage/dataGrid/components/DataGridConfigProvider';
import type { TableHeaderProps } from 'react-table';
import { twMerge } from 'tailwind-merge';
interface DataGridHeaderButtonProps<T extends object> {
column: DataBrowserGridColumn<T>;
headerProps: TableHeaderProps;
onRemoveColumn: (column: DataBrowserGridColumn<T>) => void;
}
export default function DataGridHeaderButton<T extends object>({
column,
headerProps,
onRemoveColumn,
}: DataGridHeaderButtonProps<T>) {
const { allowSort, allowResize } = useDataGridConfig();
if (column.id === 'selection') {
return (
<span
{...headerProps}
className="relative grid w-full grid-flow-col items-center justify-between p-2"
>
{column.render('Header')}
</span>
);
}
if (column.id === 'preview') {
return (
<div className="focus:outline-none motion-safe:transition-colors">
{column.render('Header')}
</div>
);
}
return (
<Dropdown.Trigger
className={twMerge('focus:outline-none motion-safe:transition-colors')}
disabled={column.isDisabled || (column.disableSortBy && !onRemoveColumn)}
hideChevron
>
<span
{...headerProps}
className="relative grid w-full grid-flow-col items-center justify-between p-2"
>
{column.render('Header')}
{allowSort && (
<Box component="span" sx={{ color: 'text.primary' }}>
{column.isSorted && !column.isSortedDesc && (
<ArrowUpIcon className="h-3 w-3" />
)}
{column.isSorted && column.isSortedDesc && (
<ArrowDownIcon className="h-3 w-3" />
)}
</Box>
)}
</span>
{allowResize && !column.disableResizing && (
<span
{...column.getResizerProps({
onClick: (event: Event) => event.stopPropagation(),
})}
className="absolute -right-0.5 bottom-0 top-0 z-10 h-full w-1.5 group-hover:bg-slate-900 group-hover:bg-opacity-20 group-active:bg-slate-900 group-active:bg-opacity-20 motion-safe:transition-colors"
/>
)}
</Dropdown.Trigger>
);
}

View File

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

View File

@@ -1,7 +1,9 @@
import type { CommonDataGridCellProps } from '@/components/dataGrid/DataGridCell';
import { useDataGridCell } from '@/components/dataGrid/DataGridCell';
import { Input, inputClasses } from '@/components/ui/v2/Input'; import { Input, inputClasses } from '@/components/ui/v2/Input';
import { Text } from '@/components/ui/v2/Text'; import { Text } from '@/components/ui/v2/Text';
import {
useDataGridCell,
type CommonDataGridCellProps,
} from '@/features/orgs/projects/storage/dataGrid/components/DataGridCell';
import type { ChangeEvent, KeyboardEvent } from 'react'; import type { ChangeEvent, KeyboardEvent } from 'react';
export type DataGridIntegerCellProps<TData extends object> = export type DataGridIntegerCellProps<TData extends object> =

View File

@@ -9,6 +9,8 @@ import { VideoPreviewIcon } from '@/components/ui/v2/icons/VideoPreviewIcon';
import { XIcon } from '@/components/ui/v2/icons/XIcon'; import { XIcon } from '@/components/ui/v2/icons/XIcon';
import { useAppClient } from '@/features/orgs/projects/hooks/useAppClient'; import { useAppClient } from '@/features/orgs/projects/hooks/useAppClient';
import { useProject } from '@/features/orgs/projects/hooks/useProject'; import { useProject } from '@/features/orgs/projects/hooks/useProject';
import { usePreviewToggle } from '@/features/orgs/projects/storage/dataGrid/hooks/usePreviewToggle';
import { useSSRLocalStorage } from '@/hooks/useSSRLocalStorage';
import clsx from 'clsx'; import clsx from 'clsx';
import type { ReactNode } from 'react'; import type { ReactNode } from 'react';
import { useEffect, useReducer, useState } from 'react'; import { useEffect, useReducer, useState } from 'react';
@@ -46,11 +48,16 @@ function useBlob({
const [objectUrl, setObjectUrl] = useState<string>(); const [objectUrl, setObjectUrl] = useState<string>();
const [error, setError] = useState<Error>(); const [error, setError] = useState<Error>();
const [loading, setLoading] = useState<boolean>(false); const [loading, setLoading] = useState<boolean>(false);
const [preview] = useSSRLocalStorage('preview', true);
// This side-effect fetches the blob of the file from the server and sets the // This side-effect fetches the blob of the file from the server and sets the
// relevant `objectUrl` state. Abort controller is reponsible for cancelling // relevant `objectUrl` state. Abort controller is reponsible for cancelling
// the fetch if the component is unmounted. // the fetch if the component is unmounted.
useEffect(() => { useEffect(() => {
if (!preview) {
return undefined;
}
const abortController = new AbortController(); const abortController = new AbortController();
async function generateOptimizedObjectUrl() { async function generateOptimizedObjectUrl() {
@@ -104,7 +111,7 @@ function useBlob({
generateObjectUrl(); generateObjectUrl();
return () => abortController.abort(); return () => abortController.abort();
}, [blob, fetchBlob, objectUrl, mimeType]); }, [blob, fetchBlob, objectUrl, mimeType, preview]);
return { objectUrl, error, loading }; return { objectUrl, error, loading };
} }
@@ -168,8 +175,13 @@ export default function DataGridPreviewCell<TData extends object>({
}: DataGridPreviewCellProps<TData>) { }: DataGridPreviewCellProps<TData>) {
const { project } = useProject(); const { project } = useProject();
const appClient = useAppClient(); const appClient = useAppClient();
const { objectUrl, loading, error } = useBlob({ fetchBlob, blob, mimeType }); const { objectUrl, loading, error } = useBlob({
fetchBlob,
blob,
mimeType,
});
const [showModal, setShowModal] = useState(false); const [showModal, setShowModal] = useState(false);
const { previewEnabled } = usePreviewToggle();
const [ const [
{ loading: previewLoading, error: previewError, data: previewUrl }, { loading: previewLoading, error: previewError, data: previewUrl },
@@ -365,7 +377,7 @@ export default function DataGridPreviewCell<TData extends object>({
</Modal> </Modal>
<div className="flex h-full w-full justify-center"> <div className="flex h-full w-full justify-center">
{previewableImages.includes(mimeType) && objectUrl && ( {previewEnabled && previewableImages.includes(mimeType) && objectUrl ? (
<button <button
type="button" type="button"
aria-label={alt} aria-label={alt}
@@ -381,9 +393,11 @@ export default function DataGridPreviewCell<TData extends object>({
/> />
</picture> </picture>
</button> </button>
)} ) : null}
{(!previewableImages.includes(mimeType) || !objectUrl) && ( {(!previewableImages.includes(mimeType) ||
!objectUrl ||
!previewEnabled) && (
<button <button
type="button" type="button"
onClick={handleOpenPreview} onClick={handleOpenPreview}

View File

@@ -1,9 +1,11 @@
import type { CommonDataGridCellProps } from '@/components/dataGrid/DataGridCell';
import { useDataGridCell } from '@/components/dataGrid/DataGridCell';
import { Button } from '@/components/ui/v2/Button'; import { Button } from '@/components/ui/v2/Button';
import { CopyIcon } from '@/components/ui/v2/icons/CopyIcon'; import { CopyIcon } from '@/components/ui/v2/icons/CopyIcon';
import { Input, inputClasses } from '@/components/ui/v2/Input'; import { Input, inputClasses } from '@/components/ui/v2/Input';
import { Text } from '@/components/ui/v2/Text'; import { Text } from '@/components/ui/v2/Text';
import {
useDataGridCell,
type CommonDataGridCellProps,
} from '@/features/orgs/projects/storage/dataGrid/components/DataGridCell';
import { copy } from '@/utils/copy'; import { copy } from '@/utils/copy';
import type { ChangeEvent, KeyboardEvent, Ref } from 'react'; import type { ChangeEvent, KeyboardEvent, Ref } from 'react';
import { useEffect } from 'react'; import { useEffect } from 'react';

View File

@@ -10,6 +10,7 @@ import { FilePreviewIcon } from '@/components/ui/v2/icons/FilePreviewIcon';
import { useAppClient } from '@/features/orgs/projects/hooks/useAppClient'; import { useAppClient } from '@/features/orgs/projects/hooks/useAppClient';
import { useProject } from '@/features/orgs/projects/hooks/useProject'; import { useProject } from '@/features/orgs/projects/hooks/useProject';
import { FilesDataGridControls } from '@/features/orgs/projects/storage/dataGrid/components/FilesDataGridControls'; import { FilesDataGridControls } from '@/features/orgs/projects/storage/dataGrid/components/FilesDataGridControls';
import { PreviewHeader } from '@/features/orgs/projects/storage/dataGrid/components/PreviewHeader';
import { useBuckets } from '@/features/orgs/projects/storage/dataGrid/hooks/useBuckets'; import { useBuckets } from '@/features/orgs/projects/storage/dataGrid/hooks/useBuckets';
import { useFiles } from '@/features/orgs/projects/storage/dataGrid/hooks/useFiles'; import { useFiles } from '@/features/orgs/projects/storage/dataGrid/hooks/useFiles';
import { useFilesAggregate } from '@/features/orgs/projects/storage/dataGrid/hooks/useFilesAggregate'; import { useFilesAggregate } from '@/features/orgs/projects/storage/dataGrid/hooks/useFilesAggregate';
@@ -112,7 +113,8 @@ export default function FilesDataGrid(props: FilesDataGridProps) {
const memoizedColumns: Column<StoredFile>[] = useMemo( const memoizedColumns: Column<StoredFile>[] = useMemo(
() => [ () => [
{ {
Header: 'Preview', id: 'preview',
Header: PreviewHeader,
accessor: 'preview', accessor: 'preview',
Cell: (cellProps) => Cell: (cellProps) =>
DataGridPreviewCell({ DataGridPreviewCell({
@@ -121,8 +123,8 @@ export default function FilesDataGrid(props: FilesDataGridProps) {
<FilePreviewIcon className="h-5 w-5 fill-current" /> <FilePreviewIcon className="h-5 w-5 fill-current" />
), ),
}), }),
minWidth: 80, minWidth: 120,
width: 80, width: 120,
disableSortBy: true, disableSortBy: true,
disableResizing: true, disableResizing: true,
}, },

View File

@@ -1,7 +1,4 @@
import { useDialog } from '@/components/common/DialogProvider'; import { useDialog } from '@/components/common/DialogProvider';
import { useDataGridConfig } from '@/components/dataGrid/DataGridConfigProvider';
import type { DataGridPaginationProps } from '@/components/dataGrid/DataGridPagination';
import { DataGridPagination } from '@/components/dataGrid/DataGridPagination';
import type { BoxProps } from '@/components/ui/v2/Box'; import type { BoxProps } from '@/components/ui/v2/Box';
import { Box } from '@/components/ui/v2/Box'; import { Box } from '@/components/ui/v2/Box';
import { Button } from '@/components/ui/v2/Button'; import { Button } from '@/components/ui/v2/Button';
@@ -10,6 +7,9 @@ import type { InputProps } from '@/components/ui/v2/Input';
import { Input } from '@/components/ui/v2/Input'; import { Input } from '@/components/ui/v2/Input';
import { useAppClient } from '@/features/orgs/projects/hooks/useAppClient'; import { useAppClient } from '@/features/orgs/projects/hooks/useAppClient';
import { useProject } from '@/features/orgs/projects/hooks/useProject'; import { useProject } from '@/features/orgs/projects/hooks/useProject';
import { useDataGridConfig } from '@/features/orgs/projects/storage/dataGrid/components/DataGridConfigProvider';
import type { DataGridPaginationProps } from '@/features/orgs/projects/storage/dataGrid/components/DataGridPagination';
import { DataGridPagination } from '@/features/orgs/projects/storage/dataGrid/components/DataGridPagination';
import type { FileUploadButtonProps } from '@/features/orgs/projects/storage/dataGrid/components/FileUploadButton'; import type { FileUploadButtonProps } from '@/features/orgs/projects/storage/dataGrid/components/FileUploadButton';
import { FileUploadButton } from '@/features/orgs/projects/storage/dataGrid/components/FileUploadButton'; import { FileUploadButton } from '@/features/orgs/projects/storage/dataGrid/components/FileUploadButton';
import type { Files } from '@/utils/__generated__/graphql'; import type { Files } from '@/utils/__generated__/graphql';

View File

@@ -0,0 +1,22 @@
import { Switch } from '@/components/ui/v2/Switch';
import { usePreviewToggle } from '@/features/orgs/projects/storage/dataGrid/hooks/usePreviewToggle';
import { type ChangeEvent } from 'react';
export default function PreviewHeader() {
const { previewEnabled, setPreviewEnabled } = usePreviewToggle();
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
setPreviewEnabled(e.target.checked);
};
return (
<div className="flex flex-row items-center gap-2 p-2">
Preview
<Switch
className="self-center"
checked={previewEnabled}
onChange={handleChange}
/>
</div>
);
}

View File

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

View File

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

View File

@@ -0,0 +1,29 @@
import { useProject } from '@/features/orgs/projects/hooks/useProject';
import { useSSRLocalStorage } from '@/hooks/useSSRLocalStorage';
// Store {projectId: previewEnabled, projectId2: previewEnabled, ...}
type PreviewLocalStorage = {
[key: string]: boolean | undefined;
};
export default function usePreviewToggle() {
const [preview, setPreview] = useSSRLocalStorage<PreviewLocalStorage>(
'preview',
{},
);
const { project } = useProject();
// Default to previewEnabled true if not set
const previewEnabled = preview[project?.id] ?? true;
const setPreviewEnabled = (value: boolean) => {
const newPreview = { ...preview };
newPreview[project?.id] = value;
setPreview(newPreview);
};
return {
previewEnabled,
setPreviewEnabled,
};
}

View File

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

View File

@@ -1,31 +0,0 @@
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
import { useIsPlatform } from '@/features/projects/common/hooks/useIsPlatform';
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
import { useQuery } from '@tanstack/react-query';
/**
* Returns whether or not the app is healthy.
*/
export default function useIsHealthy() {
const isPlatform = useIsPlatform();
const { currentProject } = useCurrentWorkspaceAndProject();
const appUrl = generateAppServiceUrl(
currentProject?.subdomain,
currentProject?.region,
'auth',
);
const { failureCount, status } = useQuery(
['/healthz'],
() => fetch(`${appUrl}/healthz`),
{
enabled: !isPlatform && !!currentProject,
retry: true,
retryDelay: 5000,
cacheTime: 0,
},
);
return isPlatform || (status === 'success' && failureCount === 0);
}

View File

@@ -1,3 +1,4 @@
import { useIsPlatform } from '@/features/orgs/projects/common/hooks/useIsPlatform';
import { useCurrentOrg } from '@/features/orgs/projects/hooks/useCurrentOrg'; import { useCurrentOrg } from '@/features/orgs/projects/hooks/useCurrentOrg';
import { useProject } from '@/features/orgs/projects/hooks/useProject'; import { useProject } from '@/features/orgs/projects/hooks/useProject';
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject'; import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
@@ -5,7 +6,9 @@ import { useRouter } from 'next/router';
import { useEffect } from 'react'; import { useEffect } from 'react';
/** /**
* Redirects to 404 page if either currentWorkspace/currentProject resolves to undefined. * Redirects to 404 page if either currentWorkspace/currentProject resolves to undefined
* or if the current pathname is not a valid organization/project.
* Not applicable if running dashboard with local Nhost backend.
*/ */
export default function useNotFoundRedirect() { export default function useNotFoundRedirect() {
const router = useRouter(); const router = useRouter();
@@ -21,6 +24,7 @@ export default function useNotFoundRedirect() {
} = router; } = router;
const { project, loading: projectLoading } = useProject(); const { project, loading: projectLoading } = useProject();
const isPlatform = useIsPlatform();
const { org, loading: orgLoading } = useCurrentOrg(); const { org, loading: orgLoading } = useCurrentOrg();
const { subdomain: projectSubdomain } = project || {}; const { subdomain: projectSubdomain } = project || {};
@@ -49,6 +53,8 @@ export default function useNotFoundRedirect() {
router.pathname === '/run-one-click-install' || router.pathname === '/run-one-click-install' ||
router.pathname.includes('/orgs/_') || router.pathname.includes('/orgs/_') ||
router.pathname.includes('/orgs/_/projects/_') || router.pathname.includes('/orgs/_/projects/_') ||
(!isPlatform &&
router.pathname.includes('/orgs/[orgSlug]/projects/[appSubdomain]')) ||
(urlOrgSlug === currentOrgSlug && !urlAppSubdomain) || (urlOrgSlug === currentOrgSlug && !urlAppSubdomain) ||
(urlOrgSlug === currentOrgSlug && urlAppSubdomain === projectSubdomain) || (urlOrgSlug === currentOrgSlug && urlAppSubdomain === projectSubdomain) ||
// If we are on a valid workspace and project, we don't want to redirect to 404 // If we are on a valid workspace and project, we don't want to redirect to 404
@@ -75,5 +81,6 @@ export default function useNotFoundRedirect() {
projectSubdomain, projectSubdomain,
urlWorkspaceSlug, urlWorkspaceSlug,
urlOrgSlug, urlOrgSlug,
isPlatform,
]); ]);
} }

View File

@@ -11,7 +11,7 @@ import type { ReactElement } from 'react';
function BackupsContent() { function BackupsContent() {
return ( return (
<div className="grid w-full grid-flow-row gap-6 mt-6"> <div className="mt-6 grid w-full grid-flow-row gap-6">
<div> <div>
<Text className="font-medium">Database</Text> <Text className="font-medium">Database</Text>
<Text color="secondary"> <Text color="secondary">
@@ -27,12 +27,13 @@ function BackupsContent() {
export default function BackupsPage() { export default function BackupsPage() {
const { currentOrg: org, loading } = useOrgs(); const { currentOrg: org, loading } = useOrgs();
const isPlanFree = org.plan.isFree;
if (loading) { if (loading) {
return <ActivityIndicator label="Loading project..." delay={1000} />; return <ActivityIndicator label="Loading project..." delay={1000} />;
} }
const isPlanFree = org.plan.isFree;
if (isPlanFree) { if (isPlanFree) {
return ( return (
<Container <Container
@@ -44,20 +45,19 @@ export default function BackupsPage() {
description="" description=""
/> />
</Container> </Container>
) );
} }
return ( return (
<Container className="grid max-w-5xl grid-flow-row bg-transparent gap-y-6"> <Container className="grid max-w-5xl grid-flow-row gap-y-6 bg-transparent">
<div className="grid justify-between grid-flow-col gap-2"> <div className="grid grid-flow-col justify-between gap-2">
<Text className="text-2xl font-medium" variant="h1"> <Text className="text-2xl font-medium" variant="h1">
Backups Backups
</Text> </Text>
<Chip <Chip
color={org?.plan.isFree ? 'default' : 'success'} color={isPlanFree ? 'default' : 'success'}
label={org?.plan.isFree ? 'Off' : 'Live'} label={isPlanFree ? 'Off' : 'Live'}
size="small" size="small"
/> />
</div> </div>

View File

@@ -8,11 +8,11 @@ import {
} from '@/features/orgs/projects/logs/components/LogsHeader'; } from '@/features/orgs/projects/logs/components/LogsHeader';
import { AvailableLogsService } from '@/features/orgs/projects/logs/utils/constants/services'; import { AvailableLogsService } from '@/features/orgs/projects/logs/utils/constants/services';
import { useRemoteApplicationGQLClientWithSubscriptions } from '@/hooks/useRemoteApplicationGQLClientWithSubscriptions'; import { useRemoteApplicationGQLClientWithSubscriptions } from '@/hooks/useRemoteApplicationGQLClientWithSubscriptions';
import { MINUTES_TO_DECREASE_FROM_CURRENT_DATE } from '@/utils/constants/common';
import { import {
GetLogsSubscriptionDocument, GetLogsSubscriptionDocument,
useGetProjectLogsQuery, useGetProjectLogsQuery,
} from '@/utils/__generated__/graphql'; } from '@/utils/__generated__/graphql';
import { MINUTES_TO_DECREASE_FROM_CURRENT_DATE } from '@/utils/constants/common';
import { subMinutes } from 'date-fns'; import { subMinutes } from 'date-fns';
import { import {
useCallback, useCallback,
@@ -45,7 +45,7 @@ export default function LogsPage() {
const { data, error, subscribeToMore, client, loading, refetch } = const { data, error, subscribeToMore, client, loading, refetch } =
useGetProjectLogsQuery({ useGetProjectLogsQuery({
variables: { appID: project.id, ...filters }, variables: { appID: project?.id, ...filters },
client: clientWithSplit, client: clientWithSplit,
fetchPolicy: 'cache-and-network', fetchPolicy: 'cache-and-network',
notifyOnNetworkStatusChange: true, notifyOnNetworkStatusChange: true,
@@ -56,7 +56,7 @@ export default function LogsPage() {
subscribeToMore({ subscribeToMore({
document: GetLogsSubscriptionDocument, document: GetLogsSubscriptionDocument,
variables: { variables: {
appID: project.id, appID: project?.id,
service: filters.service, service: filters.service,
from: filters.from, from: filters.from,
regexFilter: filters.regexFilter, regexFilter: filters.regexFilter,
@@ -98,7 +98,7 @@ export default function LogsPage() {
}; };
}, },
}), }),
[subscribeToMore, project.id, filters], [subscribeToMore, project?.id, filters],
); );
useEffect(() => { useEffect(() => {
@@ -133,7 +133,7 @@ export default function LogsPage() {
); );
return ( return (
<div className="flex flex-col w-full h-full"> <div className="flex h-full w-full flex-col">
<RetryableErrorBoundary> <RetryableErrorBoundary>
<LogsHeader <LogsHeader
loading={loading} loading={loading}

View File

@@ -22,18 +22,18 @@ import { useLocalMimirClient } from '@/features/orgs/projects/hooks/useLocalMimi
import { useProject } from '@/features/orgs/projects/hooks/useProject'; import { useProject } from '@/features/orgs/projects/hooks/useProject';
export default function SettingsAuthenticationPage() { export default function SettingsAuthenticationPage() {
const { project } = useProject(); const { project, loading: loadingProject } = useProject();
const isPlatform = useIsPlatform(); const isPlatform = useIsPlatform();
const localMimirClient = useLocalMimirClient(); const localMimirClient = useLocalMimirClient();
const { data, loading, error } = useGetAuthenticationSettingsQuery({ const { data, loading, error } = useGetAuthenticationSettingsQuery({
variables: { appId: project?.id }, variables: { appId: project?.id },
fetchPolicy: 'cache-and-network', fetchPolicy: 'cache-and-network',
skip: !project, skip: !project?.id,
...(!isPlatform ? { client: localMimirClient } : {}), ...(!isPlatform ? { client: localMimirClient } : {}),
}); });
if (!data && loading) { if (!data || loadingProject || loading) {
return ( return (
<ActivityIndicator <ActivityIndicator
delay={1000} delay={1000}

View File

@@ -1,5 +1,6 @@
import { UpgradeToProBanner } from '@/components/common/UpgradeToProBanner'; import { UpgradeToProBanner } from '@/components/common/UpgradeToProBanner';
import { Container } from '@/components/layout/Container'; import { Container } from '@/components/layout/Container';
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
import { Box } from '@/components/ui/v2/Box'; import { Box } from '@/components/ui/v2/Box';
import { ArrowSquareOutIcon } from '@/components/ui/v2/icons/ArrowSquareOutIcon'; import { ArrowSquareOutIcon } from '@/components/ui/v2/icons/ArrowSquareOutIcon';
import { Link } from '@/components/ui/v2/Link'; import { Link } from '@/components/ui/v2/Link';
@@ -15,7 +16,11 @@ import { useCurrentOrg } from '@/features/orgs/projects/hooks/useCurrentOrg';
import { type ReactElement } from 'react'; import { type ReactElement } from 'react';
export default function CustomDomains() { export default function CustomDomains() {
const { org } = useCurrentOrg(); const { org, loading: loadingOrg } = useCurrentOrg();
if (loadingOrg) {
return <ActivityIndicator delay={1000} label="Loading project..." />;
}
if (org?.plan?.isFree) { if (org?.plan?.isFree) {
return ( return (

View File

@@ -15,15 +15,15 @@ import type { ReactElement } from 'react';
export default function DatabaseSettingsPage() { export default function DatabaseSettingsPage() {
const isPlatform = useIsPlatform(); const isPlatform = useIsPlatform();
const localMimirClient = useLocalMimirClient(); const localMimirClient = useLocalMimirClient();
const { project } = useProject(); const { project, loading: loadingProject } = useProject();
const { loading, error } = useGetPostgresSettingsQuery({ const { loading, error } = useGetPostgresSettingsQuery({
variables: { appId: project?.id }, variables: { appId: project?.id },
skip: !project, skip: !project?.id,
...(!isPlatform ? { client: localMimirClient } : {}), ...(!isPlatform ? { client: localMimirClient } : {}),
}); });
if (loading) { if (loadingProject || loading) {
return ( return (
<ActivityIndicator <ActivityIndicator
delay={1000} delay={1000}

View File

@@ -3,7 +3,7 @@ import { useUI } from '@/components/common/UIProvider';
import { Form } from '@/components/form/Form'; import { Form } from '@/components/form/Form';
import { Container } from '@/components/layout/Container'; import { Container } from '@/components/layout/Container';
import { SettingsContainer } from '@/components/layout/SettingsContainer'; import { SettingsContainer } from '@/components/layout/SettingsContainer';
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator'; import { LoadingScreen } from '@/components/presentational/LoadingScreen';
import { Alert } from '@/components/ui/v2/Alert'; import { Alert } from '@/components/ui/v2/Alert';
import { Input } from '@/components/ui/v2/Input'; import { Input } from '@/components/ui/v2/Input';
import { Link } from '@/components/ui/v2/Link'; import { Link } from '@/components/ui/v2/Link';
@@ -29,7 +29,7 @@ import { ApplicationStatus } from '@/types/application';
import { slugifyString } from '@/utils/helpers'; import { slugifyString } from '@/utils/helpers';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { useMemo, type ReactElement } from 'react'; import { useEffect, useMemo, type ReactElement } from 'react';
import { FormProvider, useForm } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import * as Yup from 'yup'; import * as Yup from 'yup';
@@ -96,6 +96,14 @@ export default function SettingsGeneralPage() {
const { register, formState } = form; const { register, formState } = form;
useEffect(() => {
if (!loading) {
form.reset({
name: project?.name,
});
}
}, [loading, project?.name, form]);
async function handleProjectNameChange(data: ProjectNameValidationSchema) { async function handleProjectNameChange(data: ProjectNameValidationSchema) {
const newProjectSlug = slugifyString(data.name); const newProjectSlug = slugifyString(data.name);
@@ -186,7 +194,7 @@ export default function SettingsGeneralPage() {
} }
if (loading) { if (loading) {
return <ActivityIndicator label="Loading project..." />; return <LoadingScreen />;
} }
return ( return (

View File

@@ -1,5 +1,5 @@
import { Container } from '@/components/layout/Container'; import { Container } from '@/components/layout/Container';
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator'; import { LoadingScreen } from '@/components/presentational/LoadingScreen';
import { ProjectLayout } from '@/features/orgs/layout/ProjectLayout'; import { ProjectLayout } from '@/features/orgs/layout/ProjectLayout';
import { SettingsLayout } from '@/features/orgs/layout/SettingsLayout'; import { SettingsLayout } from '@/features/orgs/layout/SettingsLayout';
import { useIsPlatform } from '@/features/orgs/projects/common/hooks/useIsPlatform'; import { useIsPlatform } from '@/features/orgs/projects/common/hooks/useIsPlatform';
@@ -12,21 +12,17 @@ import type { ReactElement } from 'react';
export default function MetricsSettingsPage() { export default function MetricsSettingsPage() {
const isPlatform = useIsPlatform(); const isPlatform = useIsPlatform();
const localMimirClient = useLocalMimirClient(); const localMimirClient = useLocalMimirClient();
const { project } = useProject(); const { project, loading: loadingProject } = useProject();
const { loading, error } = useGetObservabilitySettingsQuery({ const { loading: loadingObservabilitySettings, error } =
variables: { appId: project?.id }, useGetObservabilitySettingsQuery({
...(!isPlatform ? { client: localMimirClient } : {}), variables: { appId: project?.id },
}); ...(!isPlatform ? { client: localMimirClient } : {}),
skip: !project?.id,
});
if (loading) { if (loadingProject || loadingObservabilitySettings) {
return ( return <LoadingScreen />;
<ActivityIndicator
delay={1000}
label="Loading Observability settings..."
className="justify-center"
/>
);
} }
if (error) { if (error) {
@@ -35,7 +31,7 @@ export default function MetricsSettingsPage() {
return ( return (
<Container <Container
className="grid max-w-5xl grid-flow-row bg-transparent gap-y-6" className="grid max-w-5xl grid-flow-row gap-y-6 bg-transparent"
rootClassName="bg-transparent" rootClassName="bg-transparent"
> >
<MetricsSettings /> <MetricsSettings />

View File

@@ -1,5 +1,17 @@
# @nhost/docs # @nhost/docs
## 2.27.0
### Minor Changes
- 81cc9b3: chore: add missing images to permissions API
### Patch Changes
- af34015: chore: add note about encryption at rest
- 1956ed2: chore: added pgmq extension to postgres docs
- 88919a3: chore: added support for nodejs22 to functions
## 2.26.0 ## 2.26.0
### Minor Changes ### Minor Changes

View File

@@ -113,22 +113,22 @@ GraphQL requests from unauthenticated users resolve permissions using the `publi
## Insert Permissions ## Insert Permissions
![Insert permissions](/img/graphql/permissions/insert-permissions.png) ![Insert permissions](/images/guides/todos-react-permissions-insert.png)
Here is a popular approach for insert permission for authenticated users. Here is a popular approach for insert permission for authenticated users.
1. At the top of the page, click **"insert"** on the **"user"** role. 1. At the top of the page, click **"insert"** on the **"user"** role.
1. Select **"Without any checks"**. 1. Select **"Without any checks"**.
1. Select the columns you want to allow users to insert. In our example, we only mark `title`, because that's the only column that should be inserted by the user. The `id` is automatically generated by the database and `user_id` is set using a column preset. 1. Select the columns you want to allow users to insert. In our example, we do not mark `id` nor `user_id`, because they should not be inserted by the user. The `id` is automatically generated by the database and `user_id` is set using a column preset.
1. Under **Column presets**, set `user_id` to `x-hasura-user-id`. This way, every new record's `user_id` value is set to the ID of the user making the request. 1. Under **Column presets**, set `user_id` to `x-hasura-user-id`. This way, every new record's `user_id` value is set to the ID of the user making the request.
Now, authenticated users are allowed to insert posts. Users are allowed to add a title when inserting a post. The post's `id` is automatically generated by the database and the `user_id` is automatically set to the user's id using the `user_id = x-hasura-user-id` column preset. Now, authenticated users are allowed to insert todos. Users are allowed to add a title when inserting a todo. The todo's `id` is automatically generated by the database and the `user_id` is automatically set to the user's id using the `user_id = x-hasura-user-id` column preset.
## Select, Update and Delete Permissions ## Select, Update and Delete Permissions
Select, update, and delete permissions usually follow the same pattern. Here's an example of how to add select permissions: Select, update, and delete permissions usually follow the same pattern. Here's an example of how to add select permissions:
![Select permissions](/img/graphql/permissions/select-permissions.png) ![Select permissions](/images/guides/todos-react-permissions-select.png)
One of the most common permission requirements is that authenticated users should only be able to read their own data. This is how to do that: One of the most common permission requirements is that authenticated users should only be able to read their own data. This is how to do that:

View File

@@ -53,6 +53,7 @@ In the table below you can find a list of available extensions with Nhost Postgr
| pg_trgm | 1.6 | text similarity measurement and index searching based on trigrams | | pg_trgm | 1.6 | text similarity measurement and index searching based on trigrams |
| pg_visibility | 1.2 | examine the visibility map (VM) and page-level visibility info | | pg_visibility | 1.2 | examine the visibility map (VM) and page-level visibility info |
| pgcrypto | 1.3 | cryptographic functions | | pgcrypto | 1.3 | cryptographic functions |
| pgmq | 1.4.5 | A lightweight message queue. Like AWS SQS and RSMQ but on Postgres. |
| pgrowlocks | 1.2 | show row-level locking information | | pgrowlocks | 1.2 | show row-level locking information |
| pgstattuple | 1.5 | show tuple-level statistics | | pgstattuple | 1.5 | show tuple-level statistics |
| plpgsql | 1.0 | PL/pgSQL procedural language | | plpgsql | 1.0 | PL/pgSQL procedural language |
@@ -147,6 +148,30 @@ DROP EXTENSION ip4r;
- [GitHub](https://github.com/RhodiumToad/ip4r) - [GitHub](https://github.com/RhodiumToad/ip4r)
## pgmq
A lightweight message queue. Like AWS SQS and RSMQ but on Postgres.
### Managing
To install the extension you can create a migration with the following contents:
```sql SQL
SET ROLE postgres;
CREATE EXTENSION pgmq;
```
To uninstall it, you can use the following migration:
```sql SQL
SET ROLE postgres;
DROP EXTENSION pgmq;
```
### Resources
- [GitHub](https://github.com/tembo-io/pgmq)
## postgis ## postgis
PostGIS extends the capabilities of the PostgreSQL relational database by adding support storing, indexing and querying geographic data. PostGIS extends the capabilities of the PostgreSQL relational database by adding support storing, indexing and querying geographic data.

View File

@@ -10,6 +10,7 @@ The following runtimes are supported:
- [Node.js 18](https://nodejs.org) - [Node.js 18](https://nodejs.org)
- [Node.js 20](https://nodejs.org) - [Node.js 20](https://nodejs.org)
- [Node.js 22](https://nodejs.org)
To select your preferred runtime ensure the following configuration is present in your `nhost.toml` file: To select your preferred runtime ensure the following configuration is present in your `nhost.toml` file:
@@ -27,6 +28,14 @@ version = 18
```toml ```toml
[functions.node] [functions.node]
version = 20 version = 20
```
</Tab>
<Tab title="Node.js 22">
```toml
[functions.node]
version = 22
``` ```
</Tab> </Tab>

View File

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

View File

@@ -97,3 +97,11 @@ This borrowing of resources is convenient in case of short and unexpected bursts
## Disk Performance ## Disk Performance
By default disks are provisioned with a capacity for 3000 IOPS and 125 Mbps of throughput. If you need higher performance don't hesitate to contact us. By default disks are provisioned with a capacity for 3000 IOPS and 125 Mbps of throughput. If you need higher performance don't hesitate to contact us.
## Encryption at Rest
All files uploaded to the [storage](/product/storage) service are encrypted at rest using AES-256 encryption. Similarly, any volumes provisioned for your [database](/product/database) and [Run services](/product/run) are also encrypted using AES-256.
<Warning>
Only volumes provisioned after December 2024 are encrypted with AES-256. You can verify your volume's encryption status by navigating to your project's settings -> Database -> Storage capacity. If your volume is not encrypted, you'll see a warning message indicating this. To enable encryption on your volume, you can pause and then unpause your project. This action will provision new volumes with encryption enabled.
</Warning>

View File

@@ -1,5 +1,11 @@
# @nhost-examples/cli # @nhost-examples/cli
## 0.3.17
### Patch Changes
- @nhost/nhost-js@3.2.4
## 0.3.16 ## 0.3.16
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,12 @@
# @nhost-examples/codegen-react-apollo # @nhost-examples/codegen-react-apollo
## 0.4.18
### Patch Changes
- @nhost/react@3.9.1
- @nhost/react-apollo@16.0.1
## 0.4.17 ## 0.4.17
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,11 @@
# @nhost-examples/codegen-react-query # @nhost-examples/codegen-react-query
## 0.4.18
### Patch Changes
- @nhost/react@3.9.1
## 0.4.17 ## 0.4.17
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,12 @@
# @nhost-examples/react-urql # @nhost-examples/react-urql
## 0.3.18
### Patch Changes
- @nhost/react@3.9.1
- @nhost/react-urql@13.0.1
## 0.3.17 ## 0.3.17
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,11 @@
# @nhost-examples/multi-tenant-one-to-many # @nhost-examples/multi-tenant-one-to-many
## 2.2.18
### Patch Changes
- @nhost/nhost-js@3.2.4
## 2.2.17 ## 2.2.17
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,13 @@
# @nhost-examples/nextjs # @nhost-examples/nextjs
## 0.4.2
### Patch Changes
- @nhost/react@3.9.1
- @nhost/react-apollo@16.0.1
- @nhost/nextjs@2.2.2
## 0.4.1 ## 0.4.1
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@nhost-examples/nextjs", "name": "@nhost-examples/nextjs",
"version": "0.4.1", "version": "0.4.2",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "next dev", "dev": "next dev",

View File

@@ -1,5 +1,11 @@
# @nhost-examples/node-storage # @nhost-examples/node-storage
## 0.2.17
### Patch Changes
- @nhost/nhost-js@3.2.4
## 0.2.16 ## 0.2.16
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,11 @@
# @nhost-examples/nextjs-server-components # @nhost-examples/nextjs-server-components
## 0.5.2
### Patch Changes
- @nhost/nhost-js@3.2.4
## 0.5.1 ## 0.5.1
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@nhost-examples/nextjs-server-components", "name": "@nhost-examples/nextjs-server-components",
"version": "0.5.1", "version": "0.5.2",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "next dev", "dev": "next dev",

View File

@@ -1,5 +1,12 @@
# @nhost-examples/react-apollo # @nhost-examples/react-apollo
## 1.2.1
### Patch Changes
- @nhost/react@3.9.1
- @nhost/react-apollo@16.0.1
## 1.2.0 ## 1.2.0
### Minor Changes ### Minor Changes

View File

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

View File

@@ -1,5 +1,11 @@
# @nhost-examples/react-gqty # @nhost-examples/react-gqty
## 1.2.18
### Patch Changes
- @nhost/react@3.9.1
## 1.2.17 ## 1.2.17
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,12 @@
# @nhost-examples/react-native # @nhost-examples/react-native
## 0.1.3
### Patch Changes
- @nhost/react@3.9.1
- @nhost/react-apollo@16.0.1
## 0.1.2 ## 0.1.2
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,13 @@
# @nhost-examples/vue-apollo # @nhost-examples/vue-apollo
## 0.8.1
### Patch Changes
- @nhost/nhost-js@3.2.4
- @nhost/apollo@8.0.4
- @nhost/vue@2.9.1
## 0.8.0 ## 0.8.0
### Minor Changes ### Minor Changes

View File

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

View File

@@ -1,5 +1,12 @@
# @nhost-examples/vue-quickstart # @nhost-examples/vue-quickstart
## 0.2.18
### Patch Changes
- @nhost/apollo@8.0.4
- @nhost/vue@2.9.1
## 0.2.17 ## 0.2.17
### Patch Changes ### Patch Changes

View File

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

24
flake.lock generated
View File

@@ -5,11 +5,11 @@
"systems": "systems" "systems": "systems"
}, },
"locked": { "locked": {
"lastModified": 1710146030, "lastModified": 1731533236,
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide", "owner": "numtide",
"repo": "flake-utils", "repo": "flake-utils",
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -20,11 +20,11 @@
}, },
"nix-filter": { "nix-filter": {
"locked": { "locked": {
"lastModified": 1710156097, "lastModified": 1731533336,
"narHash": "sha256-1Wvk8UP7PXdf8bCCaEoMnOT1qe5/Duqgj+rL8sRQsSM=", "narHash": "sha256-oRam5PS1vcrr5UPgALW0eo1m/5/pls27Z/pabHNy2Ms=",
"owner": "numtide", "owner": "numtide",
"repo": "nix-filter", "repo": "nix-filter",
"rev": "3342559a24e85fc164b295c3444e8a139924675b", "rev": "f7653272fd234696ae94229839a99b73c9ab7de0",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -40,11 +40,11 @@
"nixpkgs": "nixpkgs" "nixpkgs": "nixpkgs"
}, },
"locked": { "locked": {
"lastModified": 1718635840, "lastModified": 1736258395,
"narHash": "sha256-yAc2I1Y05hzAMI8atcxg3g7eXehsJIifTl/BOWIvD3o=", "narHash": "sha256-G55pFLtWxy8pzR5k/UOXBSgHoU8oO263YyYkxbaWzXM=",
"owner": "nhost", "owner": "nhost",
"repo": "nixops", "repo": "nixops",
"rev": "9ea5d933111bcfb1e2ff881e98dd2c48d1b80965", "rev": "52d9d8ff772a58b2cedac9f2f8a89517a86b35a4",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -55,11 +55,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1716715802, "lastModified": 1732238832,
"narHash": "sha256-usk0vE7VlxPX8jOavrtpOqphdfqEQpf9lgedlY/r66c=", "narHash": "sha256-sQxuJm8rHY20xq6Ah+GwIUkF95tWjGRd1X8xF+Pkk38=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "e2dd4e18cc1c7314e24154331bae07df76eb582f", "rev": "8edf06bea5bcbee082df1b7369ff973b91618b8d",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@@ -36,7 +36,7 @@
pname = "node_modules"; pname = "node_modules";
nativeBuildInputs = with pkgs; [ nativeBuildInputs = with pkgs; [
nodePackages.pnpm pnpm_9
cacert cacert
nodejs nodejs
]; ];
@@ -131,7 +131,7 @@
buildInputs = with pkgs; [ buildInputs = with pkgs; [
nhost-cli nhost-cli
nodejs nodejs
nodePackages.pnpm pnpm_9
go go
golangci-lint golangci-lint
] ++ buildInputs ++ nativeBuildInputs; ] ++ buildInputs ++ nativeBuildInputs;

View File

@@ -1,5 +1,11 @@
# @nhost/apollo # @nhost/apollo
## 8.0.4
### Patch Changes
- @nhost/nhost-js@3.2.4
## 8.0.3 ## 8.0.3
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,12 @@
# @nhost/react-apollo # @nhost/react-apollo
## 16.0.1
### Patch Changes
- @nhost/apollo@8.0.4
- @nhost/react@3.9.1
## 16.0.0 ## 16.0.0
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,11 @@
# @nhost/react-urql # @nhost/react-urql
## 13.0.1
### Patch Changes
- @nhost/react@3.9.1
## 13.0.0 ## 13.0.0
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,5 @@
(final: prev: rec { (final: prev: rec {
nodejs = final.nodejs-18_x; nodejs = final.nodejs_20;
nodePackages = nodejs.pkgs; nodePackages = nodejs.pkgs;
nhost-cli = final.callPackage ./nhost-cli.nix { inherit final; }; nhost-cli = final.callPackage ./nhost-cli.nix { inherit final; };
}) })

View File

@@ -1,5 +1,11 @@
# @nhost/hasura-storage-js # @nhost/hasura-storage-js
## 2.7.0
### Minor Changes
- 5c6ff6e: fix: correct StorageErrorPayload TypeScript typing
## 2.6.0 ## 2.6.0
### Minor Changes ### Minor Changes

View File

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

View File

@@ -92,13 +92,14 @@ export const fetchUpload = async (
xhr.onload = () => { xhr.onload = () => {
if (xhr.status < 200 || xhr.status >= 300) { if (xhr.status < 200 || xhr.status >= 300) {
const error: StorageErrorPayload = {
error: xhr.response?.error?.message ?? xhr.response?.error ?? xhr.response,
message: xhr.response?.error?.message ?? xhr.response,
status: xhr.status
}
return resolve({ return resolve({
fileMetadata: null, fileMetadata: null,
error: { error
error: xhr.response?.error ?? xhr.response,
message: xhr.response?.error?.message ?? xhr.response,
status: xhr.status
}
}) })
} }
return resolve({ fileMetadata: xhr.response, error: null }) return resolve({ fileMetadata: xhr.response, error: null })
@@ -106,9 +107,14 @@ export const fetchUpload = async (
xhr.onerror = () => { xhr.onerror = () => {
// only triggers if the request couldn't be made at all e.g. network error // only triggers if the request couldn't be made at all e.g. network error
const error: StorageErrorPayload = {
error: xhr.statusText,
message: xhr.statusText,
status: xhr.status
}
return resolve({ return resolve({
fileMetadata: null, fileMetadata: null,
error: { error: xhr.statusText, message: xhr.statusText, status: xhr.status } error
}) })
} }

View File

@@ -1,5 +1,11 @@
# @nhost/nextjs # @nhost/nextjs
## 2.2.2
### Patch Changes
- @nhost/react@3.9.1
## 2.2.1 ## 2.2.1
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@nhost/nextjs", "name": "@nhost/nextjs",
"version": "2.2.1", "version": "2.2.2",
"description": "Nhost NextJS library", "description": "Nhost NextJS library",
"license": "MIT", "license": "MIT",
"keywords": [ "keywords": [

View File

@@ -1,5 +1,12 @@
# @nhost/nhost-js # @nhost/nhost-js
## 3.2.4
### Patch Changes
- Updated dependencies [5c6ff6e]
- @nhost/hasura-storage-js@2.7.0
## 3.2.3 ## 3.2.3
### Patch Changes ### Patch Changes

View File

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

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