mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-10-05 14:28:08 +03:00
console: integrate relationships table component to Data tab
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/4353 GitOrigin-RevId: 558b4d02be04e932c02dee885d7c7d4dea983a33
This commit is contained in:
parent
384756f7be
commit
0390bd449b
@ -1,18 +1,30 @@
|
||||
import { NormalizedTable } from '@/dataSources/types';
|
||||
import React from 'react';
|
||||
import { rest } from 'msw';
|
||||
import { ReactQueryDecorator } from '@/storybook/decorators/react-query';
|
||||
import { ComponentMeta } from '@storybook/react';
|
||||
import React from 'react';
|
||||
import { NormalizedTable } from '@/dataSources/types';
|
||||
|
||||
import { DatabaseRelationshipsTab } from './DatabaseRelationshipsTab';
|
||||
import { metadata } from '../RelationshipsTable/DatabaseRelationshipsTable/mocks';
|
||||
|
||||
const url = 'http://localhost:8080';
|
||||
|
||||
export default {
|
||||
title: 'Data Relationships/Database Relationships Tab',
|
||||
component: DatabaseRelationshipsTab,
|
||||
decorators: [ReactQueryDecorator()],
|
||||
parameters: {
|
||||
msw: [
|
||||
rest.post(`${url}/v1/metadata`, (_req, res, ctx) =>
|
||||
res(ctx.json(metadata))
|
||||
),
|
||||
],
|
||||
},
|
||||
} as ComponentMeta<typeof DatabaseRelationshipsTab>;
|
||||
|
||||
const tableSchema: NormalizedTable = {
|
||||
table_schema: 'public',
|
||||
table_name: 'author',
|
||||
table_name: 'user',
|
||||
table_type: 'TABLE',
|
||||
is_table_tracked: true,
|
||||
columns: [],
|
||||
@ -21,6 +33,6 @@ const tableSchema: NormalizedTable = {
|
||||
view_info: null,
|
||||
};
|
||||
|
||||
export const Main = () => (
|
||||
export const Primary = () => (
|
||||
<DatabaseRelationshipsTab tableSchema={tableSchema} currentSource="default" />
|
||||
);
|
||||
|
@ -1,8 +1,117 @@
|
||||
import React from 'react';
|
||||
import { RightContainer } from '@/components/Common/Layout/RightContainer';
|
||||
import { Button } from '@/new-components/Button';
|
||||
import { fireNotification } from '@/new-components/Notifications';
|
||||
import { getConfirmation } from '@/components/Common/utils/jsUtils';
|
||||
|
||||
import { NormalizedTable } from '@/dataSources/types';
|
||||
|
||||
import TableHeader from '../../components/Services/Data/TableCommon/TableHeader';
|
||||
import { FeatureFlagFloatingButton } from '../FeatureFlags/components/FeatureFlagFloatingButton';
|
||||
import {
|
||||
DatabaseRelationshipsTable,
|
||||
OnClickHandlerArgs,
|
||||
RowData,
|
||||
} from '../RelationshipsTable/DatabaseRelationshipsTable';
|
||||
import { allowedMetadataTypes, useMetadataMigration } from '../MetadataAPI';
|
||||
import { DataTarget } from '../Datasources';
|
||||
|
||||
const createTable = (target?: DataTarget) => {
|
||||
if (!target) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if ('schema' in target) {
|
||||
return {
|
||||
name: target.table,
|
||||
schema: target.schema,
|
||||
};
|
||||
}
|
||||
|
||||
if ('dataset' in target) {
|
||||
return {
|
||||
name: target.table,
|
||||
schema: target.dataset,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
name: target.table,
|
||||
};
|
||||
};
|
||||
|
||||
const useFormState = () => {
|
||||
const [isOpen, setIsOpen] = React.useState(false);
|
||||
const [
|
||||
existingRelationship,
|
||||
setExistingRelationship,
|
||||
] = React.useState<RowData>();
|
||||
|
||||
const mutation = useMetadataMigration({
|
||||
onSuccess: () => {
|
||||
fireNotification({
|
||||
title: 'Success!',
|
||||
message: 'Relationship deleted successfully',
|
||||
type: 'success',
|
||||
});
|
||||
},
|
||||
onError: () => {
|
||||
fireNotification({
|
||||
title: 'Error',
|
||||
message: 'Error while deleting the relationship',
|
||||
type: 'error',
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const onOpen = () => {
|
||||
setExistingRelationship(undefined);
|
||||
setIsOpen(true);
|
||||
};
|
||||
|
||||
const onEdit = (row?: RowData) => {
|
||||
console.log(row);
|
||||
setExistingRelationship(row);
|
||||
setIsOpen(true);
|
||||
};
|
||||
|
||||
const onDelete = (row?: RowData) => {
|
||||
setExistingRelationship(undefined);
|
||||
setIsOpen(false);
|
||||
const confirmMessage = `This will permanently delete the ${row?.name} from Hasura`;
|
||||
const isOk = getConfirmation(confirmMessage, true, row?.name);
|
||||
if (!isOk) {
|
||||
return;
|
||||
}
|
||||
|
||||
mutation.mutate({
|
||||
query: {
|
||||
type: 'delete_remote_relationship' as allowedMetadataTypes,
|
||||
args: {
|
||||
table: createTable(row?.relationship?.target),
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const onClick = ({ type, row }: OnClickHandlerArgs) => {
|
||||
switch (type) {
|
||||
case 'add':
|
||||
onOpen();
|
||||
break;
|
||||
case 'edit':
|
||||
onEdit(row);
|
||||
break;
|
||||
case 'delete':
|
||||
onDelete(row);
|
||||
break;
|
||||
default:
|
||||
setIsOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
return { isOpen, onClick, existingRelationship };
|
||||
};
|
||||
|
||||
export const DatabaseRelationshipsTab = ({
|
||||
tableSchema,
|
||||
@ -11,6 +120,8 @@ export const DatabaseRelationshipsTab = ({
|
||||
tableSchema: NormalizedTable;
|
||||
currentSource: string;
|
||||
}) => {
|
||||
const { isOpen, existingRelationship, onClick } = useFormState();
|
||||
|
||||
return (
|
||||
<RightContainer>
|
||||
<TableHeader
|
||||
@ -23,10 +134,29 @@ export const DatabaseRelationshipsTab = ({
|
||||
count={null}
|
||||
isCountEstimated
|
||||
/>
|
||||
<div className="p-4">
|
||||
{/* remove this title when doing the actual implementation */}
|
||||
<h2 className="text-md font-semibold mb-3.5">Table Relationships</h2>
|
||||
<div className="py-4">
|
||||
<h2 className="text-md font-semibold">Data Relationships</h2>
|
||||
</div>
|
||||
<DatabaseRelationshipsTable
|
||||
target={{
|
||||
database: currentSource,
|
||||
table: tableSchema.table_name,
|
||||
schema: tableSchema.table_schema,
|
||||
}}
|
||||
onClick={onClick}
|
||||
/>
|
||||
<Button mode="primary" onClick={() => onClick({ type: 'add' })}>
|
||||
Add Relationship
|
||||
</Button>
|
||||
|
||||
{/* to be replaced with actual form */}
|
||||
{isOpen && (
|
||||
<div className="mt-6">
|
||||
Create relationship form here{' '}
|
||||
{existingRelationship &&
|
||||
`with existing relationship ${existingRelationship.name}`}
|
||||
</div>
|
||||
)}
|
||||
<FeatureFlagFloatingButton />
|
||||
</RightContainer>
|
||||
);
|
||||
|
@ -1,14 +1,18 @@
|
||||
import { RemoteRelationship } from '@/metadata/types';
|
||||
|
||||
export const dbToRemoteSchemaRelationships = {
|
||||
target: {
|
||||
database: 'default',
|
||||
schema: 'public',
|
||||
table: 'user',
|
||||
},
|
||||
remote_relationships: ([
|
||||
remote_relationships: [
|
||||
{
|
||||
definition: {
|
||||
to_source: {
|
||||
relationship_type: '',
|
||||
source: '',
|
||||
table: { name: '', schema: '' },
|
||||
field_mapping: {},
|
||||
},
|
||||
to_remote_schema: {
|
||||
remote_field: {
|
||||
test: {
|
||||
@ -29,6 +33,12 @@ export const dbToRemoteSchemaRelationships = {
|
||||
},
|
||||
{
|
||||
definition: {
|
||||
to_source: {
|
||||
relationship_type: '',
|
||||
source: '',
|
||||
table: { name: '', schema: '' },
|
||||
field_mapping: {},
|
||||
},
|
||||
remote_field: {
|
||||
test: {
|
||||
arguments: {
|
||||
@ -43,7 +53,7 @@ export const dbToRemoteSchemaRelationships = {
|
||||
hasura_fields: ['id'],
|
||||
remote_schema: 'remoteSchema3',
|
||||
},
|
||||
name: 'old_payload',
|
||||
name: 't',
|
||||
},
|
||||
] as unknown) as RemoteRelationship[],
|
||||
],
|
||||
};
|
||||
|
@ -39,7 +39,7 @@ test('transformDbToRemoteSchema returns new and legacy formats consistently', ()
|
||||
"lhs_fields": Array [
|
||||
"id",
|
||||
],
|
||||
"relationshipName": "old_payload",
|
||||
"relationshipName": "t",
|
||||
"remoteSchemaName": "remoteSchema3",
|
||||
"remote_field": Object {
|
||||
"test": Object {
|
||||
|
@ -11,7 +11,7 @@ import {
|
||||
DbToRemoteSchemaRelationship,
|
||||
} from '../types';
|
||||
|
||||
interface TransformDbToRemoteSchemaArgs {
|
||||
export interface TransformDbToRemoteSchemaArgs {
|
||||
target: DataTarget;
|
||||
remote_relationships: RemoteRelationship[];
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import { HasuraMetadataV3 } from '@/metadata/types';
|
||||
import { MetadataQueryType } from '@/metadata/queryUtils';
|
||||
import { IntrospectionQuery } from 'graphql';
|
||||
import { RemoteField } from '../RemoteRelationships/RemoteSchemaRelationships/types';
|
||||
|
||||
import { DataTarget } from '../Datasources';
|
||||
|
||||
export interface MetadataResponse {
|
||||
|
@ -0,0 +1,44 @@
|
||||
import React from 'react';
|
||||
import { FaArrowRight } from 'react-icons/fa';
|
||||
|
||||
import { TableRowIcon } from './TableRowIcon';
|
||||
import { RowData } from '../types';
|
||||
|
||||
interface RelationshipCellProps {
|
||||
row: RowData;
|
||||
}
|
||||
|
||||
export const RelationshipCell = ({ row }: RelationshipCellProps) => {
|
||||
// these will be updated when the table also handles other db to x relationships
|
||||
const secondaryIconFromType = 'table_leaf';
|
||||
const secondaryIconToType =
|
||||
row.type === 'remoteSchema' ? 'remote_schema_leaf' : 'table_leaf';
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex gap-2 items-center">
|
||||
<TableRowIcon type={row.fromType} />
|
||||
{row?.source}
|
||||
{row?.fieldsFrom.map(field => (
|
||||
<React.Fragment key={field}>
|
||||
/
|
||||
<TableRowIcon type={secondaryIconFromType} />
|
||||
{field}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
<FaArrowRight className="fill-current text-sm text-muted col-span-1" />
|
||||
<div className="flex gap-2 items-center">
|
||||
<TableRowIcon type={row.toType} />
|
||||
{row?.destination}
|
||||
{row?.fieldsTo.map(field => (
|
||||
<React.Fragment key={field}>
|
||||
/
|
||||
<TableRowIcon type={secondaryIconToType} />
|
||||
{field}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
@ -7,7 +7,7 @@ import {
|
||||
FaTable,
|
||||
} from 'react-icons/fa';
|
||||
|
||||
const className = 'fill-current text-sm text-muted mr-1';
|
||||
const className = 'fill-current text-sm text-muted p-0';
|
||||
|
||||
interface TableRowIconProps {
|
||||
type:
|
||||
|
@ -1,4 +1,5 @@
|
||||
export * from './ModifyActions';
|
||||
export * from './RelationshipsCell';
|
||||
export * from './SourceRelationshipsCell';
|
||||
export * from './DestinationRelationshipCell';
|
||||
export * from './TableRowIcon';
|
||||
|
@ -692,7 +692,7 @@ export interface RemoteField {
|
||||
* https://hasura.io/docs/latest/graphql/core/api-reference/schema-metadata-api/remote-relationships.html#inputarguments
|
||||
*/
|
||||
export interface InputArguments {
|
||||
[InputField: string]: PGColumn;
|
||||
[InputField: string]: InputArguments | string;
|
||||
}
|
||||
|
||||
// //////////////////////////////
|
||||
|
Loading…
Reference in New Issue
Block a user