Compare commits

..

1 Commits

Author SHA1 Message Date
dbarrosop
4655f8bdfe release(dashboard): 2.42.1 2025-11-19 07:46:18 +00:00
19 changed files with 6 additions and 536 deletions

View File

@@ -1,9 +1,3 @@
## [cli@1.34.8] - 2025-11-19
### 🐛 Bug Fixes
- *(cli)* Update traefik (#3710)
## [cli@1.34.7] - 2025-11-13
### ⚙️ Miscellaneous Tasks

View File

@@ -1,3 +1,9 @@
## [@nhost/dashboard@2.42.1] - 2025-11-19
### 🐛 Bug Fixes
- *(dashboard)* Parse and create one-click installs for run services correctly (#3679)
## [@nhost/dashboard@2.42.0] - 2025-11-12
### 🚀 Features

View File

@@ -1,263 +0,0 @@
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
import { Alert } from '@/components/ui/v2/Alert';
import { Button } from '@/components/ui/v3/button';
import { Form } from '@/components/ui/v3/form';
import type {
BaseTableFormProps,
BaseTableFormValues,
} from '@/features/orgs/projects/database/dataGrid/components/BaseTableForm';
import {
BaseTableForm,
baseTableValidationSchema,
} from '@/features/orgs/projects/database/dataGrid/components/BaseTableForm';
import { useTableQuery } from '@/features/orgs/projects/database/dataGrid/hooks/useTableQuery';
import { useTrackForeignKeyRelationsMutation } from '@/features/orgs/projects/database/dataGrid/hooks/useTrackForeignKeyRelationsMutation';
import { useUpdateTableMutation } from '@/features/orgs/projects/database/dataGrid/hooks/useUpdateTableMutation';
import type {
DatabaseTable,
NormalizedQueryDataRow,
} from '@/features/orgs/projects/database/dataGrid/types/dataBrowser';
import { normalizeDatabaseColumn } from '@/features/orgs/projects/database/dataGrid/utils/normalizeDatabaseColumn';
import { isNotEmptyValue } from '@/lib/utils';
import { triggerToast } from '@/utils/toast';
import { yupResolver } from '@hookform/resolvers/yup';
import { useRouter } from 'next/router';
import { useEffect, useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import type * as Yup from 'yup';
import { defaultFormValues, EditSettingsFormInitialValues, EditSettingsFormValues, validationSchema } from './EditSettingsFormTypes';
import { zodResolver } from '@hookform/resolvers/zod';
export interface EditSettingsFormProps
extends Pick<BaseTableFormProps, 'onCancel' | 'location'> {
/**
* Schema where the table is located.
*/
schema: string;
/**
* Table to be edited.
*/
table: NormalizedQueryDataRow;
/**
* Function to be called when the form is submitted.
*/
onSubmit?: (tableName: string) => Promise<void>;
}
export default function EditSettingsForm({
onSubmit,
schema,
table: originalTable,
...props
}: EditSettingsFormProps) {
const [formInitialized, setFormInitialized] = useState(false);
const router = useRouter();
const {
data,
status: columnsStatus,
error: columnsError,
} = useTableQuery([`default.${schema}.${originalTable.table_name}`], {
schema,
table: originalTable.table_name,
});
const columns = data?.columns;
const foreignKeyRelations = data?.foreignKeyRelations;
const dataGridColumns = (columns || []).map((column) =>
normalizeDatabaseColumn(column),
);
const {
mutateAsync: trackForeignKeyRelations,
error: foreignKeyError,
reset: resetForeignKeyError,
} = useTrackForeignKeyRelationsMutation();
const {
mutateAsync: updateTable,
error: updateError,
reset: resetUpdateError,
} = useUpdateTableMutation({ schema });
const error = columnsError || updateError || foreignKeyError;
function resetError() {
resetForeignKeyError();
resetUpdateError();
}
const form = useForm<
EditSettingsFormValues
>({
defaultValues: defaultFormValues,
reValidateMode: 'onSubmit',
resolver: zodResolver(validationSchema),
});
const handleFormSubmit = form.handleSubmit(async (values) => {
await onSubmit?.(values)
});
// We are initializing the form values lazily, because columns are not
// necessarily available immediately when the form is mounted.
useEffect(() => {
// if (
// columnsStatus === 'success' &&
// dataGridColumns.length > 0 &&
// !formInitialized
// ) {
// const primaryKeyIndices = dataGridColumns.reduce<string[]>(
// (result, col, index) => {
// if (col.isPrimary) {
// return [...result, `${index}`];
// }
// return result;
// },
// [],
// );
// const identityColumnIndex = dataGridColumns.findIndex(
// (column) => column.isIdentity,
// );
// form.reset({
// name: originalTable.table_name,
// columns: dataGridColumns.map((column) => ({
// // ID can't be changed through the form, so we can use it to
// // identify the column in the original array.
// id: column.id,
// name: column.id,
// type: column.type,
// defaultValue: column.defaultValue,
// isNullable: column.isNullable,
// isUnique: column.isUnique,
// comment: column.comment || '',
// })),
// primaryKeyIndices,
// identityColumnIndex:
// identityColumnIndex > -1 ? identityColumnIndex : null,
// foreignKeyRelations,
// });
// setFormInitialized(true);
}
}, [
form,
originalTable,
columnsStatus,
foreignKeyRelations,
dataGridColumns,
formInitialized,
]);
async function handleSubmit(values: BaseTableFormValues) {
const primaryKey = values.primaryKeyIndices.map<string>(
(primaryKeys) => values.columns[primaryKeys].name,
);
try {
const updatedTable: DatabaseTable = {
...values,
primaryKey,
identityColumn:
values.identityColumnIndex !== null &&
typeof values.identityColumnIndex !== 'undefined'
? values.columns[values.identityColumnIndex]?.name
: undefined,
};
await updateTable({
originalTable,
originalColumns: dataGridColumns,
originalForeignKeyRelations: foreignKeyRelations ?? [],
updatedTable,
});
if (isNotEmptyValue(updatedTable.foreignKeyRelations)) {
await trackForeignKeyRelations({
foreignKeyRelations: updatedTable.foreignKeyRelations,
schema,
table: updatedTable.name,
});
}
if (onSubmit) {
await onSubmit(updatedTable.name);
}
if (originalTable.table_name !== updatedTable.name) {
await router.push(
`/orgs/${router.query.orgSlug}/projects/${router.query.appSubdomain}/database/browser/${router.query.dataSourceSlug}/${schema}/${updatedTable.name}`,
);
}
triggerToast('The table has been updated successfully.');
} catch {
// Errors are already handled by hooks.
}
}
if (columnsStatus === 'loading') {
return (
<div className="px-6">
<ActivityIndicator label="Loading columns..." delay={1000} />
</div>
);
}
if (!formInitialized) {
return (
<div className="px-6">
<ActivityIndicator label="Loading..." delay={1000} />
</div>
);
}
if (columnsStatus === 'error') {
return (
<div className="-mt-3 px-6">
<Alert severity="error" className="text-left">
<strong>Error:</strong>{' '}
{columnsError && columnsError instanceof Error
? columnsError?.message
: 'An error occurred while loading the columns. Please try again.'}
</Alert>
</div>
);
}
return (
<Form {...form}>
<form onSubmit={handleFormSubmit}>
{error && error instanceof Error ? (
<div className="-mt-3 mb-4 px-6">
<Alert
severity="error"
className="grid grid-flow-col items-center justify-between px-4 py-3"
>
<span className="text-left">
<strong>Error:</strong> {error.message}
</span>
<Button
variant="ghost"
size="sm"
onClick={resetError}
>
Clear
</Button>
</Alert>
</div>
) : null}
<BaseTableForm
submitButtonText="Save"
onSubmit={handleSubmit}
{...props}
/>
</form>
</Form>
);
}

View File

@@ -1,13 +0,0 @@
import { z } from 'zod';
export const validationSchema = z.object({
name: z.string().min(1, { message: 'Name is required' }),
});
export const defaultFormValues: EditSettingsFormValues = {
name: '',
};
export type EditSettingsFormValues = z.infer<typeof validationSchema>;
export type EditSettingsFormInitialValues = EditSettingsFormValues;

View File

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

View File

@@ -1,44 +0,0 @@
import type { MetadataOperationOptions } from '@/features/orgs/projects/remote-schemas/types';
import { metadataOperation } from '@/utils/hasura-api/generated/default/default';
import type { SetTableIsEnumArgs } from '@/utils/hasura-api/generated/schemas';
export interface SetTableIsEnumVariables {
resourceVersion: number;
args: SetTableIsEnumArgs;
}
export default async function setTableIsEnum({
appUrl,
adminSecret,
resourceVersion,
args,
}: MetadataOperationOptions & SetTableIsEnumVariables) {
try {
const response = await metadataOperation(
{
type: 'bulk',
source: 'default',
resource_version: resourceVersion,
args: [
{
type: 'pg_set_table_is_enum',
args,
},
],
},
{
baseUrl: appUrl,
adminSecret,
},
);
if (response.status === 200) {
return response.data;
}
throw new Error(response.data.error);
} catch (error) {
console.error(error);
throw error;
}
}

View File

@@ -1,16 +0,0 @@
import type { MetadataOperationOptions } from '@/features/orgs/projects/remote-schemas/types';
import type { SetTableIsEnumArgs } from '@/utils/hasura-api/generated/schemas';
export interface SetTableIsEnumMigrationVariables {
resourceVersion: number;
args: SetTableIsEnumArgs;
}
export default async function setTableIsEnumMigration({
appUrl,
adminSecret,
resourceVersion,
args,
}: MetadataOperationOptions & SetTableIsEnumMigrationVariables) {
// TODO: Implement set table is enum migration
}

View File

@@ -1,66 +0,0 @@
import { useIsPlatform } from '@/features/orgs/projects/common/hooks/useIsPlatform';
import { generateAppServiceUrl } from '@/features/orgs/projects/common/utils/generateAppServiceUrl';
import { useProject } from '@/features/orgs/projects/hooks/useProject';
import type { MetadataOperation200 } from '@/utils/hasura-api/generated/schemas/metadataOperation200';
import type { SuccessResponse } from '@/utils/hasura-api/generated/schemas/successResponse';
import type { MutationOptions } from '@tanstack/react-query';
import { useMutation } from '@tanstack/react-query';
import type { SetTableIsEnumVariables } from './setTableIsEnum';
import setTableIsEnum from './setTableIsEnum';
import type { SetTableIsEnumMigrationVariables } from './setTableIsEnumMigration';
import setTableIsEnumMigration from './setTableIsEnumMigration';
export interface UseSetTableIsEnumMutationOptions {
/**
* Props passed to the underlying mutation hook.
*/
mutationOptions?: MutationOptions<
SuccessResponse | MetadataOperation200,
unknown,
SetTableIsEnumVariables | SetTableIsEnumMigrationVariables
>;
}
/**
* This hook is a wrapper around a fetch call that adds a remote schema permission.
*
* @param mutationOptions - Options to use for the mutation.
* @returns The result of the mutation.
*/
export default function useSetTableIsEnumMutation({
mutationOptions,
}: UseSetTableIsEnumMutationOptions = {}) {
const { project } = useProject();
const isPlatform = useIsPlatform();
const mutation = useMutation<
SuccessResponse | MetadataOperation200,
unknown,
SetTableIsEnumVariables | SetTableIsEnumMigrationVariables
>((variables) => {
const appUrl = generateAppServiceUrl(
project!.subdomain,
project!.region,
'hasura',
);
const base = {
appUrl,
adminSecret: project?.config?.hasura.adminSecret!,
} as const;
if (isPlatform) {
return setTableIsEnum({
...(variables as SetTableIsEnumVariables),
...base,
});
}
return setTableIsEnumMigration({
...(variables as SetTableIsEnumMigrationVariables),
...base,
});
}, mutationOptions);
return mutation;
}

View File

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

View File

@@ -1,12 +0,0 @@
/**
* Generated by orval v7.11.2 🍺
* Do not edit manually.
* Hasura Remote Schema API
* API for managing remote schemas in Hasura
* OpenAPI spec version: 1.0.0
*/
import type { ExportMetadataResponseMetadataSourcesItemTablesItemTable } from './exportMetadataResponseMetadataSourcesItemTablesItemTable';
export type ExportMetadataResponseMetadataSourcesItemTablesItem = {
table: ExportMetadataResponseMetadataSourcesItemTablesItemTable;
};

View File

@@ -1,15 +0,0 @@
/**
* Generated by orval v7.11.2 🍺
* Do not edit manually.
* Hasura Remote Schema API
* API for managing remote schemas in Hasura
* OpenAPI spec version: 1.0.0
*/
export type ExportMetadataResponseMetadataSourcesItemTablesItemTable = {
/** Name of the table */
name?: string;
/** Schema of the table */
schema?: string;
[key: string]: unknown;
};

View File

@@ -1,17 +0,0 @@
/**
* Generated by orval v7.11.2 🍺
* Do not edit manually.
* Hasura Remote Schema API
* API for managing remote schemas in Hasura
* OpenAPI spec version: 1.0.0
*/
/**
* Object with table name and schema
*/
export interface QualifiedTable {
/** Name of the table */
name: string;
/** Schema of the table */
schema: string;
}

View File

@@ -1,16 +0,0 @@
/**
* Generated by orval v7.11.2 🍺
* Do not edit manually.
* Hasura Remote Schema API
* API for managing remote schemas in Hasura
* OpenAPI spec version: 1.0.0
*/
import type { QualifiedTable } from './qualifiedTable';
export interface SetTableIsEnumArgs {
table: QualifiedTable;
/** Whether or not the table should be used as an enum table <enum table>. */
is_enum: boolean;
/** Name of the source database of the table */
source?: string;
}

View File

@@ -1,19 +0,0 @@
/**
* Generated by orval v7.11.2 🍺
* Do not edit manually.
* Hasura Remote Schema API
* API for managing remote schemas in Hasura
* OpenAPI spec version: 1.0.0
*/
import type { SetTableIsEnumBulkOperationType } from './setTableIsEnumBulkOperationType';
import type { SetTableIsEnumStep } from './setTableIsEnumStep';
export interface SetTableIsEnumBulkOperation {
/** Type of operation to set table is enum */
type: SetTableIsEnumBulkOperationType;
/** Source of the operation */
source: string;
/** Resource version of the metadata */
resource_version: number;
args: SetTableIsEnumStep[];
}

View File

@@ -1,18 +0,0 @@
/**
* Generated by orval v7.11.2 🍺
* Do not edit manually.
* Hasura Remote Schema API
* API for managing remote schemas in Hasura
* OpenAPI spec version: 1.0.0
*/
/**
* Type of operation to set table is enum
*/
export type SetTableIsEnumBulkOperationType =
(typeof SetTableIsEnumBulkOperationType)[keyof typeof SetTableIsEnumBulkOperationType];
// eslint-disable-next-line @typescript-eslint/no-redeclare
export const SetTableIsEnumBulkOperationType = {
bulk: 'bulk',
} as const;

View File

@@ -1,14 +0,0 @@
/**
* Generated by orval v7.11.2 🍺
* Do not edit manually.
* Hasura Remote Schema API
* API for managing remote schemas in Hasura
* OpenAPI spec version: 1.0.0
*/
import type { SetTableIsEnumArgs } from './setTableIsEnumArgs';
import type { SetTableIsEnumStepType } from './setTableIsEnumStepType';
export interface SetTableIsEnumStep {
type: SetTableIsEnumStepType;
args: SetTableIsEnumArgs;
}

View File

@@ -1,15 +0,0 @@
/**
* Generated by orval v7.11.2 🍺
* Do not edit manually.
* Hasura Remote Schema API
* API for managing remote schemas in Hasura
* OpenAPI spec version: 1.0.0
*/
export type SetTableIsEnumStepType =
(typeof SetTableIsEnumStepType)[keyof typeof SetTableIsEnumStepType];
// eslint-disable-next-line @typescript-eslint/no-redeclare
export const SetTableIsEnumStepType = {
pg_set_table_is_enum: 'pg_set_table_is_enum',
} as const;