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:
Vijay Prasanna 2022-04-26 18:00:31 +05:30 committed by hasura-bot
parent 8d8d0cf998
commit c2ab5854f9
16 changed files with 203 additions and 79 deletions

View File

@ -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)

View File

@ -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) {

View File

@ -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 });

View 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;
};

View File

@ -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;

View File

@ -78,7 +78,7 @@ export const RemoteSchemaRelationshipTable = ({
sourceType={sourceType}
/>,
];
if (showActionCell && relType === 'to_source') {
if (showActionCell) {
value.push(
<ModifyActions
onEdit={() =>

View File

@ -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}

View File

@ -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') {

View File

@ -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 = {

View File

@ -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}

View File

@ -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 => (

View File

@ -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>

View File

@ -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}

View File

@ -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>

View File

@ -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}

View File

@ -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"