Compare commits
1 Commits
feat/modif
...
release/da
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4655f8bdfe |
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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;
|
||||
@@ -1 +0,0 @@
|
||||
export { default as EditSettingsForm } from './EditSettingsForm';
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export { default as useTableIsEnumQuery } from './useTableIsEnumQuery';
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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[];
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
Reference in New Issue
Block a user