mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-13 19:33:55 +03:00
console: bug fixes for RS-to-RS relationships
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/4357 Co-authored-by: Abhijeet Khangarot <26903230+abhi40308@users.noreply.github.com> Co-authored-by: Matt Hardman <28978422+mattshardman@users.noreply.github.com> Co-authored-by: Rikin Kachhia <54616969+rikinsk@users.noreply.github.com> GitOrigin-RevId: a695071a42a921e36082d99af110323298cb5569
This commit is contained in:
parent
8d8d0cf998
commit
c2ab5854f9
@ -10,6 +10,7 @@
|
||||
- server: Don't drop nested typed null fields in actions (fix #8237)
|
||||
- server: fixes remote relationships on actions (fix #8399)
|
||||
- console: add remote database relationships for views
|
||||
- console: bug fixes for RS-to-RS relationships
|
||||
- cli: avoid exporting hasura-specific schemas during hasura init (#8352)
|
||||
- cli: fix performance regression in `migrate status` command (fix #8398)
|
||||
|
||||
|
@ -48,22 +48,25 @@ export const RemoteSchemaRelationRenderer = ({
|
||||
});
|
||||
const [formState, setFormState] = useState<RemoteRelOption>('remoteSchema');
|
||||
|
||||
const mutation = useMetadataMigration({
|
||||
onSuccess: () => {
|
||||
fireNotification({
|
||||
title: 'Success!',
|
||||
message: 'Relationship deleted successfully',
|
||||
type: 'success',
|
||||
});
|
||||
const mutation = useMetadataMigration(
|
||||
{
|
||||
onSuccess: () => {
|
||||
fireNotification({
|
||||
title: 'Success!',
|
||||
message: 'Relationship deleted successfully',
|
||||
type: 'success',
|
||||
});
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
fireNotification({
|
||||
title: 'Error',
|
||||
message: error?.message ?? 'Error while deleting the relationship',
|
||||
type: 'error',
|
||||
});
|
||||
},
|
||||
},
|
||||
onError: () => {
|
||||
fireNotification({
|
||||
title: 'Error',
|
||||
message: 'Error while deleting the relationship',
|
||||
type: 'error',
|
||||
});
|
||||
},
|
||||
});
|
||||
true
|
||||
);
|
||||
|
||||
const {
|
||||
enabled: ffEnabled,
|
||||
@ -116,6 +119,7 @@ export const RemoteSchemaRelationRenderer = ({
|
||||
},
|
||||
migrationName: 'deleteRSToDBRelationship',
|
||||
});
|
||||
setIsFormOpen(false);
|
||||
};
|
||||
|
||||
if (isError) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import returnMigrateUrl from '@/components/Services/Data/Common/getMigrateUrl';
|
||||
import { CLI_CONSOLE_MODE, SERVER_CONSOLE_MODE } from '@/constants';
|
||||
import Endpoints from '@/Endpoints';
|
||||
import { useMigrationMode } from '@/hooks';
|
||||
import { Api } from '@/hooks/apiUtils';
|
||||
import { RunSQLResponse } from '@/hooks/types';
|
||||
@ -7,7 +7,8 @@ import { useConsoleConfig } from '@/hooks/useEnvVars';
|
||||
import { useAppSelector } from '@/store';
|
||||
import { useMutation, UseMutationOptions, useQueryClient } from 'react-query';
|
||||
import sanitize from 'sanitize-filename';
|
||||
import { allowedMetadataTypes } from '../types';
|
||||
import { allowedMetadataTypes, MetadataResponse } from '../types';
|
||||
import { returnMigrateUrl } from './utils';
|
||||
|
||||
const maxAllowedLength = 255;
|
||||
const unixEpochLength = 14;
|
||||
@ -23,7 +24,8 @@ export function useMetadataMigration(
|
||||
mutationOptions?: Omit<
|
||||
UseMutationOptions<Record<string, any>, Error, TMigration>,
|
||||
'mutationFn'
|
||||
>
|
||||
>,
|
||||
overrideCliMode?: boolean
|
||||
) {
|
||||
const { mode } = useConsoleConfig();
|
||||
const headers = useAppSelector(state => state.tables.dataHeaders);
|
||||
@ -35,11 +37,15 @@ export function useMetadataMigration(
|
||||
try {
|
||||
const { source, query, migrationName } = props;
|
||||
|
||||
const migrateUrl = returnMigrateUrl(migrationMode ?? false, [query]);
|
||||
const migrateUrl = returnMigrateUrl(
|
||||
migrationMode ?? false,
|
||||
[query],
|
||||
overrideCliMode
|
||||
);
|
||||
|
||||
let body = {};
|
||||
|
||||
if (mode === SERVER_CONSOLE_MODE) {
|
||||
if (mode === SERVER_CONSOLE_MODE || overrideCliMode) {
|
||||
body = query;
|
||||
} else {
|
||||
body = {
|
||||
@ -69,6 +75,16 @@ export function useMetadataMigration(
|
||||
onSuccess: (data, variables, ctx) => {
|
||||
if (mode === CLI_CONSOLE_MODE) {
|
||||
queryClient.refetchQueries('migrationMode', { active: true });
|
||||
queryClient.fetchQuery({
|
||||
queryKey: 'cliExport',
|
||||
queryFn: () => {
|
||||
const cliMetadataExportUrl = `${Endpoints.hasuractlMetadata}?export=true`;
|
||||
return Api.get<MetadataResponse>({
|
||||
headers,
|
||||
url: cliMetadataExportUrl,
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
queryClient.refetchQueries(['metadata'], { active: true });
|
||||
|
49
console/src/features/MetadataAPI/hooks/utils.ts
Normal file
49
console/src/features/MetadataAPI/hooks/utils.ts
Normal file
@ -0,0 +1,49 @@
|
||||
import { CLI_CONSOLE_MODE } from '@/constants';
|
||||
import Endpoints from '@/Endpoints';
|
||||
import globals from '@/Globals';
|
||||
|
||||
const rqlQueryTypes = [
|
||||
'select',
|
||||
'count',
|
||||
'insert',
|
||||
'delete',
|
||||
'update',
|
||||
'run_sql',
|
||||
'mssql_run_sql',
|
||||
'citus_run_sql',
|
||||
];
|
||||
|
||||
type Query = {
|
||||
type: string;
|
||||
args: Record<string, any>;
|
||||
};
|
||||
|
||||
export const returnMigrateUrl = (
|
||||
migrationMode: boolean,
|
||||
upQueries?: Query[],
|
||||
overrideCliMode?: boolean
|
||||
) => {
|
||||
if (globals.consoleMode === CLI_CONSOLE_MODE && !overrideCliMode) {
|
||||
return migrationMode
|
||||
? Endpoints.hasuractlMigrate
|
||||
: Endpoints.hasuractlMetadata;
|
||||
}
|
||||
if (!upQueries) {
|
||||
return Endpoints.query;
|
||||
}
|
||||
|
||||
let endpoint = Endpoints.metadata;
|
||||
upQueries.forEach(query => {
|
||||
let type = '';
|
||||
if (query.type === 'bulk') {
|
||||
type = query?.args?.[0]?.type;
|
||||
} else {
|
||||
type = query.type;
|
||||
}
|
||||
if (rqlQueryTypes.includes(type)) {
|
||||
endpoint = Endpoints.query;
|
||||
}
|
||||
});
|
||||
|
||||
return endpoint;
|
||||
};
|
@ -32,6 +32,7 @@ export const allowedMetadataTypesArr = [
|
||||
'mssql_drop_delete_permission',
|
||||
'mssql_set_permission_comment',
|
||||
'create_remote_schema_remote_relationship',
|
||||
'update_remote_schema_remote_relationship',
|
||||
'delete_remote_schema_remote_relationship',
|
||||
'bulk',
|
||||
] as const;
|
||||
|
@ -78,7 +78,7 @@ export const RemoteSchemaRelationshipTable = ({
|
||||
sourceType={sourceType}
|
||||
/>,
|
||||
];
|
||||
if (showActionCell && relType === 'to_source') {
|
||||
if (showActionCell) {
|
||||
value.push(
|
||||
<ModifyActions
|
||||
onEdit={() =>
|
||||
|
@ -4,7 +4,10 @@ import { FiType } from 'react-icons/fi';
|
||||
|
||||
const RsLeafCell = ({ leafName }: { leafName: ReactText }) => (
|
||||
<>
|
||||
<FaFont className="fill-current text-sm text-muted mr-1 p-0" />
|
||||
<FaFont
|
||||
className="fill-current text-sm text-muted mr-1 p-0"
|
||||
title="Field"
|
||||
/>
|
||||
<span className="mr-2">{leafName}</span>
|
||||
</>
|
||||
);
|
||||
@ -23,6 +26,7 @@ const FromRsCell = ({
|
||||
<div className="flex items-center">
|
||||
<FiType
|
||||
className="fill-current text-sm text-muted mr-1 p-0"
|
||||
title="Type"
|
||||
style={{ strokeWidth: 4.5 }}
|
||||
/>
|
||||
{rsName}
|
||||
|
@ -40,7 +40,10 @@ const RelationshipDestinationCell = ({
|
||||
const columns = Object.values(
|
||||
relationship?.definition?.to_source?.field_mapping ?? {}
|
||||
) as string[];
|
||||
return <TableCell tableName={relationship?.name} cols={columns} />;
|
||||
const tableName =
|
||||
relationship?.definition?.to_source?.table?.name ??
|
||||
relationship?.definition?.to_source?.table;
|
||||
return <TableCell tableName={tableName} cols={columns} />;
|
||||
}
|
||||
|
||||
if (sourceType === 'local_object') {
|
||||
|
@ -4,15 +4,34 @@ import { RelationshipSourceType } from '../types';
|
||||
|
||||
const getRelationIcon = (type: RelationshipSourceType) => {
|
||||
if (type === 'local_object')
|
||||
return <FaTable className="fill-current text-muted text-sm mr-2" />;
|
||||
return (
|
||||
<FaTable className="fill-current text-muted text-sm mr-2" title="Table" />
|
||||
);
|
||||
if (type === 'local_array')
|
||||
return <FaTable className="fill-current text-muted text-sm mr-2" />;
|
||||
return (
|
||||
<FaTable className="fill-current text-muted text-sm mr-2" title="Table" />
|
||||
);
|
||||
if (type === 'to_source')
|
||||
return <FaDatabase className="fill-current text-muted text-sm mr-2" />;
|
||||
return (
|
||||
<FaDatabase
|
||||
className="fill-current text-muted text-sm mr-2"
|
||||
title="Database"
|
||||
/>
|
||||
);
|
||||
if (type === 'to_remote_schema')
|
||||
return <FaPlug className="fill-current text-muted text-sm mr-2" />;
|
||||
return (
|
||||
<FaPlug
|
||||
className="fill-current text-muted text-sm mr-2"
|
||||
title="Remote schema"
|
||||
/>
|
||||
);
|
||||
if (type === 'remote_schema_legacy')
|
||||
return <FaPlug className="fill-current text-muted text-sm mr-2" />;
|
||||
return (
|
||||
<FaPlug
|
||||
className="fill-current text-muted text-sm mr-2"
|
||||
title="Remote schema"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
type SourceColumnCellType = {
|
||||
|
@ -3,8 +3,11 @@ import { FaTable, FaColumns } from 'react-icons/fa';
|
||||
|
||||
const ColumnCell = ({ columnName }: { columnName: ReactText }) => (
|
||||
<>
|
||||
<FaColumns className="fill-current text-sm text-muted mr-1" />
|
||||
{columnName}
|
||||
<FaColumns
|
||||
className="fill-current text-sm text-muted mr-1"
|
||||
title="Column"
|
||||
/>
|
||||
<span className="mr-2">{columnName}</span>
|
||||
</>
|
||||
);
|
||||
|
||||
@ -17,7 +20,7 @@ const TableCell = ({
|
||||
}) => (
|
||||
<>
|
||||
<div className="flex items-center">
|
||||
<FaTable className="fill-current text-sm text-muted mr-1" />
|
||||
<FaTable className="fill-current text-sm text-muted mr-1" title="Table" />
|
||||
{tableName}
|
||||
<span className="px-2">/</span>
|
||||
{cols ? cols.map(i => <ColumnCell columnName={i} />) : null}
|
||||
|
@ -3,7 +3,10 @@ import { FaProjectDiagram, FaFont } from 'react-icons/fa';
|
||||
|
||||
const RsLeafCell = ({ leafName }: { leafName: ReactText }) => (
|
||||
<>
|
||||
<FaFont className="fill-current text-sm text-muted mr-1 p-0" />
|
||||
<FaFont
|
||||
className="fill-current text-sm text-muted mr-1 p-0"
|
||||
title="Field"
|
||||
/>
|
||||
<span className="mr-2">{leafName}</span>
|
||||
</>
|
||||
);
|
||||
@ -20,7 +23,10 @@ const ToRsCell = ({
|
||||
}) => (
|
||||
<>
|
||||
<div className="flex items-center">
|
||||
<FaProjectDiagram className="fill-current text-sm text-muted mr-1 p-0" />
|
||||
<FaProjectDiagram
|
||||
className="fill-current text-sm text-muted mr-1 p-0"
|
||||
title="Remote schema"
|
||||
/>
|
||||
{rsName}
|
||||
<span className="px-2">/</span>
|
||||
{leafs.map(i => (
|
||||
|
@ -68,7 +68,7 @@ export const FormElements = ({
|
||||
);
|
||||
|
||||
const remoteSchemaTypes = getTypesFromIntrospection(data);
|
||||
console.log('form!!');
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="w-full sm:w-6/12 my-md">
|
||||
@ -105,7 +105,7 @@ export const FormElements = ({
|
||||
<div className="grid grid-cols-12">
|
||||
<div className="col-span-5">
|
||||
<RsSourceTypeSelector
|
||||
types={remoteSchemaTypes.map(t => t.typeName)}
|
||||
types={remoteSchemaTypes.map(t => t.typeName).sort()}
|
||||
sourceTypeKey="typeName"
|
||||
/>
|
||||
</div>
|
||||
|
@ -70,23 +70,26 @@ export const RemoteSchemaToDbForm = ({
|
||||
onSuccess,
|
||||
relModeHandler,
|
||||
}: RemoteSchemaToDbFormProps) => {
|
||||
const mutation = useMetadataMigration({
|
||||
onSuccess: () => {
|
||||
fireNotification({
|
||||
title: 'Success!',
|
||||
message: 'Relationship saved successfully',
|
||||
type: 'success',
|
||||
});
|
||||
if (onSuccess) onSuccess();
|
||||
const mutation = useMetadataMigration(
|
||||
{
|
||||
onSuccess: () => {
|
||||
fireNotification({
|
||||
title: 'Success!',
|
||||
message: 'Relationship saved successfully',
|
||||
type: 'success',
|
||||
});
|
||||
if (onSuccess) onSuccess();
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
fireNotification({
|
||||
title: 'Error',
|
||||
message: error?.message ?? 'Error while creating the relationship',
|
||||
type: 'error',
|
||||
});
|
||||
},
|
||||
},
|
||||
onError: () => {
|
||||
fireNotification({
|
||||
title: 'Error',
|
||||
message: 'Error while creating the relationship',
|
||||
type: 'error',
|
||||
});
|
||||
},
|
||||
});
|
||||
true
|
||||
);
|
||||
|
||||
const submit = (values: Schema) => {
|
||||
const field_mapping: Record<string, string> = values.mapping.reduce(
|
||||
@ -142,16 +145,20 @@ export const RemoteSchemaToDbForm = ({
|
||||
Cancel
|
||||
</Button>
|
||||
<span className="font-semibold text-muted ml-sm">
|
||||
Create New Relationship
|
||||
{existingRelationshipName
|
||||
? 'Edit Relationship'
|
||||
: 'Create New Relationship'}
|
||||
</span>
|
||||
</div>
|
||||
<hr className="mb-md border-gray-300" />
|
||||
|
||||
{/* relationship meta */}
|
||||
<RelationshipTypeCardRadioGroup
|
||||
value="remoteDB"
|
||||
onChange={relModeHandler}
|
||||
/>
|
||||
{existingRelationshipName ? null : (
|
||||
<RelationshipTypeCardRadioGroup
|
||||
value="remoteDB"
|
||||
onChange={relModeHandler}
|
||||
/>
|
||||
)}
|
||||
|
||||
<FormElements
|
||||
sourceRemoteSchema={sourceRemoteSchema}
|
||||
|
@ -78,6 +78,7 @@ const useLoadData = (sourceRemoteSchema: string) => {
|
||||
|
||||
export const FormElements = ({
|
||||
sourceRemoteSchema,
|
||||
existingRelationshipName,
|
||||
}: RemoteSchemaToRemoteSchemaFormProps) => {
|
||||
const {
|
||||
data: {
|
||||
@ -110,13 +111,14 @@ export const FormElements = ({
|
||||
label="Name"
|
||||
placeholder="Relationship name"
|
||||
dataTest="rs-to-rs-rel-name"
|
||||
disabled={!!existingRelationshipName}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-12">
|
||||
<div className="col-span-5">
|
||||
<RsSourceTypeSelector
|
||||
types={remoteSchemaTypes.map(t => t.typeName)}
|
||||
types={remoteSchemaTypes.map(t => t.typeName).sort()}
|
||||
sourceTypeKey={rsSourceTypeKey}
|
||||
/>
|
||||
</div>
|
||||
|
@ -74,23 +74,26 @@ export const RemoteSchemaToRemoteSchemaForm = (
|
||||
closeHandler,
|
||||
relModeHandler,
|
||||
} = props;
|
||||
const mutation = useMetadataMigration({
|
||||
onSuccess: () => {
|
||||
fireNotification({
|
||||
title: 'Success!',
|
||||
message: 'Relationship saved successfully',
|
||||
type: 'success',
|
||||
});
|
||||
if (closeHandler) closeHandler();
|
||||
const mutation = useMetadataMigration(
|
||||
{
|
||||
onSuccess: () => {
|
||||
fireNotification({
|
||||
title: 'Success!',
|
||||
message: 'Relationship saved successfully',
|
||||
type: 'success',
|
||||
});
|
||||
if (closeHandler) closeHandler();
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
fireNotification({
|
||||
title: 'Error',
|
||||
message: error?.message ?? 'Error while creating the relationship',
|
||||
type: 'error',
|
||||
});
|
||||
},
|
||||
},
|
||||
onError: () => {
|
||||
fireNotification({
|
||||
title: 'Error',
|
||||
message: 'Error while creating the relationship',
|
||||
type: 'error',
|
||||
});
|
||||
},
|
||||
});
|
||||
true
|
||||
);
|
||||
|
||||
const submit = (values: RsToRsSchema) => {
|
||||
const lhs_fields = generateLhsFields(
|
||||
@ -138,15 +141,21 @@ export const RemoteSchemaToRemoteSchemaForm = (
|
||||
<Button type="button" size="sm" onClick={closeHandler}>
|
||||
Cancel
|
||||
</Button>
|
||||
<p className="font-semibold m-0">Create New Relationship</p>
|
||||
<p className="font-semibold m-0">
|
||||
{existingRelationshipName
|
||||
? 'Edit Relationship'
|
||||
: 'Create New Relationship'}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<hr className="mb-md border-gray-300" />
|
||||
|
||||
<RelationshipTypeCardRadioGroup
|
||||
value="remoteSchema"
|
||||
onChange={relModeHandler}
|
||||
/>
|
||||
{existingRelationshipName ? null : (
|
||||
<RelationshipTypeCardRadioGroup
|
||||
value="remoteSchema"
|
||||
onChange={relModeHandler}
|
||||
/>
|
||||
)}
|
||||
|
||||
<FormElements
|
||||
sourceRemoteSchema={sourceRemoteSchema}
|
||||
|
@ -70,7 +70,7 @@ export const RemoteSchemaWidget = ({
|
||||
<div className="grid gap-4 border border-gray-300 rounded shadow-sm p-4 bg-gray-50">
|
||||
<div className="grid gap-4 w-full">
|
||||
<label className="block ">
|
||||
<span className="text-gray-600 mb-xs font-semibold">Result Set</span>
|
||||
<span className="text-gray-600 mb-xs font-semibold">Mapping</span>
|
||||
<input
|
||||
type="text"
|
||||
className="mt-xs block h-input w-full shadow-sm rounded cursor-not-allowed bg-gray-100 border border-gray-300"
|
||||
|
Loading…
Reference in New Issue
Block a user