diff --git a/dashboard/CHANGELOG.md b/dashboard/CHANGELOG.md
index aa2acfe442..cf1f98cf4c 100644
--- a/dashboard/CHANGELOG.md
+++ b/dashboard/CHANGELOG.md
@@ -1,5 +1,11 @@
# @nhost/dashboard
+## 0.20.22
+
+### Patch Changes
+
+- c3efb7ec8: feat(dashboard): query latest announcement from platform
+
## 0.20.21
### Patch Changes
diff --git a/dashboard/package.json b/dashboard/package.json
index aca8c82908..20e471626a 100644
--- a/dashboard/package.json
+++ b/dashboard/package.json
@@ -1,6 +1,6 @@
{
"name": "@nhost/dashboard",
- "version": "0.20.21",
+ "version": "0.20.22",
"private": true,
"scripts": {
"preinstall": "npx only-allow pnpm",
diff --git a/dashboard/src/features/projects/common/components/Announcements/Announcements.tsx b/dashboard/src/features/projects/common/components/Announcements/Announcements.tsx
new file mode 100644
index 0000000000..5ffcd3090a
--- /dev/null
+++ b/dashboard/src/features/projects/common/components/Announcements/Announcements.tsx
@@ -0,0 +1,47 @@
+import { List } from '@/components/ui/v2/List';
+import { ListItem } from '@/components/ui/v2/ListItem';
+import { Text } from '@/components/ui/v2/Text';
+import { useGetAnnouncementsQuery } from '@/utils/__generated__/graphql';
+import formatDistance from 'date-fns/formatDistance';
+
+export default function Announcements() {
+ const { data, loading, error } = useGetAnnouncementsQuery();
+
+ const announcements = data?.announcements || [];
+
+ if (loading || error) {
+ return null;
+ }
+
+ return (
+
+
+ Latest announcements
+
+
+
+ {announcements.map((item) => (
+
+
+
+
+
+ {item.content}
+
+
+
+
+
+ ))}
+
+
+ );
+}
diff --git a/dashboard/src/features/projects/common/components/Announcements/index.ts b/dashboard/src/features/projects/common/components/Announcements/index.ts
new file mode 100644
index 0000000000..fb7f8b90ec
--- /dev/null
+++ b/dashboard/src/features/projects/common/components/Announcements/index.ts
@@ -0,0 +1 @@
+export { default as Announcements } from './Announcements';
diff --git a/dashboard/src/features/projects/common/components/WorkspaceSidebar/WorkspaceSidebar.tsx b/dashboard/src/features/projects/common/components/WorkspaceSidebar/WorkspaceSidebar.tsx
index cde18252e6..f7456ba030 100644
--- a/dashboard/src/features/projects/common/components/WorkspaceSidebar/WorkspaceSidebar.tsx
+++ b/dashboard/src/features/projects/common/components/WorkspaceSidebar/WorkspaceSidebar.tsx
@@ -8,6 +8,7 @@ import { PlusCircleIcon } from '@/components/ui/v2/icons/PlusCircleIcon';
import { List } from '@/components/ui/v2/List';
import { ListItem } from '@/components/ui/v2/ListItem';
import { Text } from '@/components/ui/v2/Text';
+import { Announcements } from '@/features/projects/common/components/Announcements';
import { EditWorkspaceNameForm } from '@/features/projects/workspaces/components/EditWorkspaceNameForm';
import type { Workspace } from '@/types/application';
import Image from 'next/image';
@@ -38,6 +39,8 @@ export default function WorkspaceSidebar({
)}
{...props}
>
+
+
My Workspaces
diff --git a/dashboard/src/gql/platform/getAnnouncements.gql b/dashboard/src/gql/platform/getAnnouncements.gql
new file mode 100644
index 0000000000..e0c9b2dee4
--- /dev/null
+++ b/dashboard/src/gql/platform/getAnnouncements.gql
@@ -0,0 +1,14 @@
+query getAnnouncements($limit: Int) {
+ announcements(
+ order_by: { createdAt: desc }
+ limit: $limit
+ where: {
+ _or: [{ expiresAt: { _is_null: true } }, { expiresAt: { _gt: now } }]
+ }
+ ) {
+ id
+ href
+ content
+ createdAt
+ }
+}
diff --git a/dashboard/src/pages/_app.tsx b/dashboard/src/pages/_app.tsx
index e892eafbac..d5c5330a61 100644
--- a/dashboard/src/pages/_app.tsx
+++ b/dashboard/src/pages/_app.tsx
@@ -1,4 +1,3 @@
-import AnnouncementProvider from '@/components/common/Announcement/AnnouncementProvider';
import { DialogProvider } from '@/components/common/DialogProvider';
import { UIProvider } from '@/components/common/UIProvider';
import { RetryableErrorBoundary } from '@/components/presentational/RetryableErrorBoundary';
@@ -106,9 +105,7 @@ function MyApp({
>
-
- {getLayout()}
-
+ {getLayout()}
diff --git a/dashboard/src/utils/__generated__/graphql.ts b/dashboard/src/utils/__generated__/graphql.ts
index 86aad29fa0..3de901411c 100644
--- a/dashboard/src/utils/__generated__/graphql.ts
+++ b/dashboard/src/utils/__generated__/graphql.ts
@@ -15,6 +15,7 @@ export type Scalars = {
Float: number;
ConfigEmail: any;
ConfigHasuraAPIs: any;
+ ConfigInt32: any;
ConfigLocale: any;
ConfigPort: any;
ConfigRunServiceName: any;
@@ -1030,6 +1031,13 @@ export type ConfigEnvironmentVariableUpdateInput = {
value?: InputMaybe;
};
+export type ConfigFloatComparisonExp = {
+ _eq?: InputMaybe;
+ _in?: InputMaybe>;
+ _neq?: InputMaybe;
+ _nin?: InputMaybe>;
+};
+
/** Configuration for functions service */
export type ConfigFunctions = {
__typename?: 'ConfigFunctions';
@@ -1229,6 +1237,8 @@ export type ConfigHasuraSettings = {
enableRemoteSchemaPermissions?: Maybe;
/** HASURA_GRAPHQL_ENABLED_APIS */
enabledAPIs?: Maybe>;
+ /** HASURA_GRAPHQL_LIVE_QUERIES_MULTIPLEXED_REFETCH_INTERVAL */
+ liveQueriesMultiplexedRefetchInterval?: Maybe;
};
export type ConfigHasuraSettingsComparisonExp = {
@@ -1241,6 +1251,7 @@ export type ConfigHasuraSettingsComparisonExp = {
enableConsole?: InputMaybe;
enableRemoteSchemaPermissions?: InputMaybe;
enabledAPIs?: InputMaybe;
+ liveQueriesMultiplexedRefetchInterval?: InputMaybe;
};
export type ConfigHasuraSettingsInsertInput = {
@@ -1250,6 +1261,7 @@ export type ConfigHasuraSettingsInsertInput = {
enableConsole?: InputMaybe;
enableRemoteSchemaPermissions?: InputMaybe;
enabledAPIs?: InputMaybe>;
+ liveQueriesMultiplexedRefetchInterval?: InputMaybe;
};
export type ConfigHasuraSettingsUpdateInput = {
@@ -1259,6 +1271,7 @@ export type ConfigHasuraSettingsUpdateInput = {
enableConsole?: InputMaybe;
enableRemoteSchemaPermissions?: InputMaybe;
enabledAPIs?: InputMaybe>;
+ liveQueriesMultiplexedRefetchInterval?: InputMaybe;
};
export type ConfigHasuraUpdateInput = {
@@ -1279,6 +1292,13 @@ export type ConfigInsertConfigResponse = {
systemConfig: ConfigSystemConfig;
};
+export type ConfigInt32ComparisonExp = {
+ _eq?: InputMaybe;
+ _in?: InputMaybe>;
+ _neq?: InputMaybe;
+ _nin?: InputMaybe>;
+};
+
export type ConfigIntComparisonExp = {
_eq?: InputMaybe;
_in?: InputMaybe>;
@@ -1386,6 +1406,7 @@ export type ConfigPostgres = {
__typename?: 'ConfigPostgres';
/** Resources for the service */
resources?: Maybe;
+ settings?: Maybe;
/**
* Version of postgres, you can see available versions in the URL below:
* https://hub.docker.com/r/nhost/postgres/tags
@@ -1398,16 +1419,107 @@ export type ConfigPostgresComparisonExp = {
_not?: InputMaybe;
_or?: InputMaybe>;
resources?: InputMaybe;
+ settings?: InputMaybe;
version?: InputMaybe;
};
export type ConfigPostgresInsertInput = {
resources?: InputMaybe;
+ settings?: InputMaybe;
version?: InputMaybe;
};
+export type ConfigPostgresSettings = {
+ __typename?: 'ConfigPostgresSettings';
+ checkpointCompletionTarget?: Maybe;
+ defaultStatisticsTarget?: Maybe;
+ effectiveCacheSize?: Maybe;
+ effectiveIOConcurrency?: Maybe;
+ hugePages?: Maybe;
+ jit?: Maybe;
+ maintenanceWorkMem?: Maybe;
+ maxConnections?: Maybe;
+ maxParallelMaintenanceWorkers?: Maybe;
+ maxParallelWorkers?: Maybe;
+ maxParallelWorkersPerGather?: Maybe;
+ maxWalSize?: Maybe;
+ maxWorkerProcesses?: Maybe;
+ minWalSize?: Maybe;
+ randomPageCost?: Maybe;
+ sharedBuffers?: Maybe;
+ walBuffers?: Maybe;
+ workMem?: Maybe;
+};
+
+export type ConfigPostgresSettingsComparisonExp = {
+ _and?: InputMaybe>;
+ _not?: InputMaybe;
+ _or?: InputMaybe>;
+ checkpointCompletionTarget?: InputMaybe;
+ defaultStatisticsTarget?: InputMaybe;
+ effectiveCacheSize?: InputMaybe;
+ effectiveIOConcurrency?: InputMaybe;
+ hugePages?: InputMaybe;
+ jit?: InputMaybe;
+ maintenanceWorkMem?: InputMaybe;
+ maxConnections?: InputMaybe;
+ maxParallelMaintenanceWorkers?: InputMaybe;
+ maxParallelWorkers?: InputMaybe;
+ maxParallelWorkersPerGather?: InputMaybe;
+ maxWalSize?: InputMaybe;
+ maxWorkerProcesses?: InputMaybe;
+ minWalSize?: InputMaybe;
+ randomPageCost?: InputMaybe;
+ sharedBuffers?: InputMaybe;
+ walBuffers?: InputMaybe;
+ workMem?: InputMaybe;
+};
+
+export type ConfigPostgresSettingsInsertInput = {
+ checkpointCompletionTarget?: InputMaybe;
+ defaultStatisticsTarget?: InputMaybe;
+ effectiveCacheSize?: InputMaybe;
+ effectiveIOConcurrency?: InputMaybe;
+ hugePages?: InputMaybe;
+ jit?: InputMaybe;
+ maintenanceWorkMem?: InputMaybe;
+ maxConnections?: InputMaybe;
+ maxParallelMaintenanceWorkers?: InputMaybe;
+ maxParallelWorkers?: InputMaybe;
+ maxParallelWorkersPerGather?: InputMaybe;
+ maxWalSize?: InputMaybe;
+ maxWorkerProcesses?: InputMaybe;
+ minWalSize?: InputMaybe;
+ randomPageCost?: InputMaybe;
+ sharedBuffers?: InputMaybe;
+ walBuffers?: InputMaybe;
+ workMem?: InputMaybe;
+};
+
+export type ConfigPostgresSettingsUpdateInput = {
+ checkpointCompletionTarget?: InputMaybe;
+ defaultStatisticsTarget?: InputMaybe;
+ effectiveCacheSize?: InputMaybe;
+ effectiveIOConcurrency?: InputMaybe;
+ hugePages?: InputMaybe;
+ jit?: InputMaybe;
+ maintenanceWorkMem?: InputMaybe;
+ maxConnections?: InputMaybe;
+ maxParallelMaintenanceWorkers?: InputMaybe;
+ maxParallelWorkers?: InputMaybe;
+ maxParallelWorkersPerGather?: InputMaybe;
+ maxWalSize?: InputMaybe;
+ maxWorkerProcesses?: InputMaybe;
+ minWalSize?: InputMaybe;
+ randomPageCost?: InputMaybe;
+ sharedBuffers?: InputMaybe;
+ walBuffers?: InputMaybe;
+ workMem?: InputMaybe;
+};
+
export type ConfigPostgresUpdateInput = {
resources?: InputMaybe;
+ settings?: InputMaybe;
version?: InputMaybe;
};
@@ -2133,6 +2245,188 @@ export type UsageSummary = {
appID: Scalars['uuid'];
};
+/** columns and relationships of "announcements" */
+export type Announcements = {
+ __typename?: 'announcements';
+ content: Scalars['String'];
+ createdAt: Scalars['timestamptz'];
+ expiresAt?: Maybe;
+ href: Scalars['String'];
+ id: Scalars['uuid'];
+ updatedAt: Scalars['timestamptz'];
+};
+
+/** aggregated selection of "announcements" */
+export type Announcements_Aggregate = {
+ __typename?: 'announcements_aggregate';
+ aggregate?: Maybe;
+ nodes: Array;
+};
+
+/** aggregate fields of "announcements" */
+export type Announcements_Aggregate_Fields = {
+ __typename?: 'announcements_aggregate_fields';
+ count: Scalars['Int'];
+ max?: Maybe;
+ min?: Maybe;
+};
+
+
+/** aggregate fields of "announcements" */
+export type Announcements_Aggregate_FieldsCountArgs = {
+ columns?: InputMaybe>;
+ distinct?: InputMaybe;
+};
+
+/** Boolean expression to filter rows from the table "announcements". All fields are combined with a logical 'AND'. */
+export type Announcements_Bool_Exp = {
+ _and?: InputMaybe>;
+ _not?: InputMaybe;
+ _or?: InputMaybe>;
+ content?: InputMaybe;
+ createdAt?: InputMaybe;
+ expiresAt?: InputMaybe;
+ href?: InputMaybe;
+ id?: InputMaybe;
+ updatedAt?: InputMaybe;
+};
+
+/** unique or primary key constraints on table "announcements" */
+export enum Announcements_Constraint {
+ /** unique or primary key constraint on columns "id" */
+ AnnouncementsPkey = 'announcements_pkey'
+}
+
+/** input type for inserting data into table "announcements" */
+export type Announcements_Insert_Input = {
+ content?: InputMaybe;
+ createdAt?: InputMaybe;
+ expiresAt?: InputMaybe;
+ href?: InputMaybe;
+ id?: InputMaybe;
+ updatedAt?: InputMaybe;
+};
+
+/** aggregate max on columns */
+export type Announcements_Max_Fields = {
+ __typename?: 'announcements_max_fields';
+ content?: Maybe;
+ createdAt?: Maybe;
+ expiresAt?: Maybe;
+ href?: Maybe;
+ id?: Maybe;
+ updatedAt?: Maybe;
+};
+
+/** aggregate min on columns */
+export type Announcements_Min_Fields = {
+ __typename?: 'announcements_min_fields';
+ content?: Maybe;
+ createdAt?: Maybe;
+ expiresAt?: Maybe;
+ href?: Maybe;
+ id?: Maybe;
+ updatedAt?: Maybe;
+};
+
+/** response of any mutation on the table "announcements" */
+export type Announcements_Mutation_Response = {
+ __typename?: 'announcements_mutation_response';
+ /** number of rows affected by the mutation */
+ affected_rows: Scalars['Int'];
+ /** data from the rows affected by the mutation */
+ returning: Array;
+};
+
+/** on_conflict condition type for table "announcements" */
+export type Announcements_On_Conflict = {
+ constraint: Announcements_Constraint;
+ update_columns?: Array;
+ where?: InputMaybe;
+};
+
+/** Ordering options when selecting data from "announcements". */
+export type Announcements_Order_By = {
+ content?: InputMaybe;
+ createdAt?: InputMaybe;
+ expiresAt?: InputMaybe;
+ href?: InputMaybe;
+ id?: InputMaybe;
+ updatedAt?: InputMaybe;
+};
+
+/** primary key columns input for table: announcements */
+export type Announcements_Pk_Columns_Input = {
+ id: Scalars['uuid'];
+};
+
+/** select columns of table "announcements" */
+export enum Announcements_Select_Column {
+ /** column name */
+ Content = 'content',
+ /** column name */
+ CreatedAt = 'createdAt',
+ /** column name */
+ ExpiresAt = 'expiresAt',
+ /** column name */
+ Href = 'href',
+ /** column name */
+ Id = 'id',
+ /** column name */
+ UpdatedAt = 'updatedAt'
+}
+
+/** input type for updating data in table "announcements" */
+export type Announcements_Set_Input = {
+ content?: InputMaybe;
+ createdAt?: InputMaybe;
+ expiresAt?: InputMaybe;
+ href?: InputMaybe;
+ id?: InputMaybe;
+ updatedAt?: InputMaybe;
+};
+
+/** Streaming cursor of the table "announcements" */
+export type Announcements_Stream_Cursor_Input = {
+ /** Stream column input with initial value */
+ initial_value: Announcements_Stream_Cursor_Value_Input;
+ /** cursor ordering */
+ ordering?: InputMaybe;
+};
+
+/** Initial value of the column from where the streaming should start */
+export type Announcements_Stream_Cursor_Value_Input = {
+ content?: InputMaybe;
+ createdAt?: InputMaybe;
+ expiresAt?: InputMaybe;
+ href?: InputMaybe;
+ id?: InputMaybe;
+ updatedAt?: InputMaybe;
+};
+
+/** update columns of table "announcements" */
+export enum Announcements_Update_Column {
+ /** column name */
+ Content = 'content',
+ /** column name */
+ CreatedAt = 'createdAt',
+ /** column name */
+ ExpiresAt = 'expiresAt',
+ /** column name */
+ Href = 'href',
+ /** column name */
+ Id = 'id',
+ /** column name */
+ UpdatedAt = 'updatedAt'
+}
+
+export type Announcements_Updates = {
+ /** sets the columns of the filtered rows to the given values */
+ _set?: InputMaybe;
+ /** filter the rows which have to be updated */
+ where: Announcements_Bool_Exp;
+};
+
/** columns and relationships of "app_state_history" */
export type AppStateHistory = {
__typename?: 'appStateHistory';
@@ -2737,7 +3031,6 @@ export type Apps = {
appStates: Array;
/** An aggregate relationship */
appStates_aggregate: AppStateHistory_Aggregate;
- autoUpdate: Scalars['Boolean'];
/** An array relationship */
backups: Array;
/** An aggregate relationship */
@@ -2769,15 +3062,14 @@ export type Apps = {
githubRepository?: Maybe;
githubRepositoryId?: Maybe;
id: Scalars['uuid'];
- isProvisioned: Scalars['Boolean'];
+ isLocked?: Maybe;
+ isLockedReason?: Maybe;
metadataFunctions: Scalars['jsonb'];
mimirConfigEnc?: Maybe;
mimirSecretsEnc?: Maybe;
mimirSystemConfigEnc?: Maybe;
name: Scalars['String'];
nhostBaseFolder: Scalars['String'];
- /** whether or not this app is paused */
- paused: Scalars['Boolean'];
/** An object relationship */
plan: Plans;
planId: Scalars['uuid'];
@@ -3017,7 +3309,6 @@ export type Apps_Bool_Exp = {
_or?: InputMaybe>;
appStates?: InputMaybe;
appStates_aggregate?: InputMaybe;
- autoUpdate?: InputMaybe;
backups?: InputMaybe;
backups_aggregate?: InputMaybe;
billingDedicatedCompute?: InputMaybe;
@@ -3036,14 +3327,14 @@ export type Apps_Bool_Exp = {
githubRepository?: InputMaybe;
githubRepositoryId?: InputMaybe;
id?: InputMaybe;
- isProvisioned?: InputMaybe;
+ isLocked?: InputMaybe;
+ isLockedReason?: InputMaybe;
metadataFunctions?: InputMaybe;
mimirConfigEnc?: InputMaybe;
mimirSecretsEnc?: InputMaybe;
mimirSystemConfigEnc?: InputMaybe;
name?: InputMaybe;
nhostBaseFolder?: InputMaybe;
- paused?: InputMaybe;
plan?: InputMaybe;
planId?: InputMaybe;
providersUpdated?: InputMaybe;
@@ -3095,7 +3386,6 @@ export type Apps_Inc_Input = {
/** input type for inserting data into table "apps" */
export type Apps_Insert_Input = {
appStates?: InputMaybe;
- autoUpdate?: InputMaybe;
backups?: InputMaybe;
billingDedicatedCompute?: InputMaybe;
billingDedicatedComputeReports?: InputMaybe;
@@ -3111,15 +3401,14 @@ export type Apps_Insert_Input = {
githubRepository?: InputMaybe;
githubRepositoryId?: InputMaybe;
id?: InputMaybe;
- isProvisioned?: InputMaybe;
+ isLocked?: InputMaybe;
+ isLockedReason?: InputMaybe;
metadataFunctions?: InputMaybe;
mimirConfigEnc?: InputMaybe;
mimirSecretsEnc?: InputMaybe;
mimirSystemConfigEnc?: InputMaybe;
name?: InputMaybe;
nhostBaseFolder?: InputMaybe;
- /** whether or not this app is paused */
- paused?: InputMaybe;
plan?: InputMaybe;
planId?: InputMaybe;
providersUpdated?: InputMaybe;
@@ -3144,6 +3433,7 @@ export type Apps_Max_Fields = {
desiredState?: Maybe;
githubRepositoryId?: Maybe;
id?: Maybe;
+ isLockedReason?: Maybe;
mimirConfigEnc?: Maybe;
mimirSecretsEnc?: Maybe;
mimirSystemConfigEnc?: Maybe;
@@ -3167,6 +3457,7 @@ export type Apps_Max_Order_By = {
desiredState?: InputMaybe;
githubRepositoryId?: InputMaybe;
id?: InputMaybe;
+ isLockedReason?: InputMaybe;
mimirConfigEnc?: InputMaybe;
mimirSecretsEnc?: InputMaybe;
mimirSystemConfigEnc?: InputMaybe;
@@ -3191,6 +3482,7 @@ export type Apps_Min_Fields = {
desiredState?: Maybe;
githubRepositoryId?: Maybe;
id?: Maybe;
+ isLockedReason?: Maybe;
mimirConfigEnc?: Maybe;
mimirSecretsEnc?: Maybe;
mimirSystemConfigEnc?: Maybe;
@@ -3214,6 +3506,7 @@ export type Apps_Min_Order_By = {
desiredState?: InputMaybe;
githubRepositoryId?: InputMaybe;
id?: InputMaybe;
+ isLockedReason?: InputMaybe;
mimirConfigEnc?: InputMaybe;
mimirSecretsEnc?: InputMaybe;
mimirSystemConfigEnc?: InputMaybe;
@@ -3255,7 +3548,6 @@ export type Apps_On_Conflict = {
/** Ordering options when selecting data from "apps". */
export type Apps_Order_By = {
appStates_aggregate?: InputMaybe;
- autoUpdate?: InputMaybe