mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-14 17:02:49 +03:00
console: replace redux fetching logic with react query for insert row tab
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6644 GitOrigin-RevId: ae7809e702edeafa84075bcad1ba37236bdb1d1a
This commit is contained in:
parent
d17b27e91f
commit
a9515cdb68
@ -70,7 +70,7 @@ export interface TableRowProps {
|
|||||||
refName: 'valueNode' | 'nullNode' | 'defaultNode' | 'radioNode',
|
refName: 'valueNode' | 'nullNode' | 'defaultNode' | 'radioNode',
|
||||||
node: HTMLInputElement | null
|
node: HTMLInputElement | null
|
||||||
) => void;
|
) => void;
|
||||||
enumOptions: Record<string, any>;
|
enumOptions: string[];
|
||||||
index: string;
|
index: string;
|
||||||
clone?: Record<string, any>;
|
clone?: Record<string, any>;
|
||||||
onChange?: (e: React.ChangeEvent<HTMLInputElement>, val: unknown) => void;
|
onChange?: (e: React.ChangeEvent<HTMLInputElement>, val: unknown) => void;
|
||||||
|
@ -178,6 +178,7 @@ const loadSchema = (configOptions = {}) => {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const body = {
|
const body = {
|
||||||
type: 'bulk',
|
type: 'bulk',
|
||||||
source,
|
source,
|
||||||
@ -223,7 +224,6 @@ const loadSchema = (configOptions = {}) => {
|
|||||||
return dispatch(requestAction(url, options)).then(
|
return dispatch(requestAction(url, options)).then(
|
||||||
data => {
|
data => {
|
||||||
if (!data || !data[0] || !data[0].result) return;
|
if (!data || !data[0] || !data[0].result) return;
|
||||||
|
|
||||||
let mergedData = [];
|
let mergedData = [];
|
||||||
switch (currentDriver) {
|
switch (currentDriver) {
|
||||||
case 'postgres':
|
case 'postgres':
|
||||||
|
@ -49,7 +49,6 @@ import { ordinalColSort } from '../utils';
|
|||||||
import Spinner from '../../../Common/Spinner/Spinner';
|
import Spinner from '../../../Common/Spinner/Spinner';
|
||||||
|
|
||||||
import { E_SET_EDITITEM } from '../TableEditItem/EditActions';
|
import { E_SET_EDITITEM } from '../TableEditItem/EditActions';
|
||||||
import { I_SET_CLONE } from '../TableInsertItem/InsertActions';
|
|
||||||
import {
|
import {
|
||||||
getTableInsertRowRoute,
|
getTableInsertRowRoute,
|
||||||
getTableEditRowRoute,
|
getTableEditRowRoute,
|
||||||
@ -70,6 +69,8 @@ import {
|
|||||||
getPersistedColumnsOrder,
|
getPersistedColumnsOrder,
|
||||||
} from './tableUtils';
|
} from './tableUtils';
|
||||||
import { compareRows, isTableWithPK } from './utils';
|
import { compareRows, isTableWithPK } from './utils';
|
||||||
|
import { push } from 'react-router-redux';
|
||||||
|
import globals from '@/Globals';
|
||||||
|
|
||||||
const ViewRows = props => {
|
const ViewRows = props => {
|
||||||
const {
|
const {
|
||||||
@ -412,16 +413,19 @@ const ViewRows = props => {
|
|||||||
const cloneIcon = <FaClone />;
|
const cloneIcon = <FaClone />;
|
||||||
|
|
||||||
const handleCloneClick = () => {
|
const handleCloneClick = () => {
|
||||||
dispatch({ type: I_SET_CLONE, clone: row });
|
const urlPrefix = globals.urlPrefix;
|
||||||
dispatch(
|
dispatch(
|
||||||
_push(
|
push({
|
||||||
getTableInsertRowRoute(
|
pathname:
|
||||||
currentSchema,
|
urlPrefix +
|
||||||
currentSource,
|
getTableInsertRowRoute(
|
||||||
curTableName,
|
currentSchema,
|
||||||
true
|
currentSource,
|
||||||
)
|
curTableName,
|
||||||
)
|
true
|
||||||
|
),
|
||||||
|
state: { row },
|
||||||
|
})
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -23,7 +23,6 @@ import { removeAll } from 'react-notification-system-redux';
|
|||||||
import { getNotificationDetails } from '../../Common/Notification';
|
import { getNotificationDetails } from '../../Common/Notification';
|
||||||
import { getTableConfiguration } from '../TableBrowseRows/utils';
|
import { getTableConfiguration } from '../TableBrowseRows/utils';
|
||||||
|
|
||||||
const I_SET_CLONE = 'InsertItem/I_SET_CLONE';
|
|
||||||
const I_RESET = 'InsertItem/I_RESET';
|
const I_RESET = 'InsertItem/I_RESET';
|
||||||
const I_ONGOING_REQ = 'InsertItem/I_ONGOING_REQ';
|
const I_ONGOING_REQ = 'InsertItem/I_ONGOING_REQ';
|
||||||
const I_REQUEST_SUCCESS = 'InsertItem/I_REQUEST_SUCCESS';
|
const I_REQUEST_SUCCESS = 'InsertItem/I_REQUEST_SUCCESS';
|
||||||
@ -302,14 +301,6 @@ const insertReducer = (tableName, state, action) => {
|
|||||||
lastSuccess: null,
|
lastSuccess: null,
|
||||||
enumOptions: null,
|
enumOptions: null,
|
||||||
};
|
};
|
||||||
case I_SET_CLONE:
|
|
||||||
return {
|
|
||||||
clone: action.clone,
|
|
||||||
ongoingRequest: false,
|
|
||||||
lastError: null,
|
|
||||||
lastSuccess: null,
|
|
||||||
enumOptions: null,
|
|
||||||
};
|
|
||||||
case I_ONGOING_REQ:
|
case I_ONGOING_REQ:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
@ -360,4 +351,4 @@ const insertReducer = (tableName, state, action) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default insertReducer;
|
export default insertReducer;
|
||||||
export { fetchEnumOptions, insertItem, I_SET_CLONE, I_RESET, Open, Close };
|
export { fetchEnumOptions, insertItem, I_RESET, Open, Close };
|
||||||
|
@ -1,10 +1,18 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { useAppDispatch, useAppSelector } from '@/store';
|
import { useAppDispatch, useAppSelector } from '@/store';
|
||||||
import { setTable } from '../DataActions';
|
import { useMigrationMode, useReadOnlyMode } from '@/hooks';
|
||||||
import { fetchEnumOptions, I_RESET, insertItem } from './InsertActions';
|
import { useMetadata } from '@/features/MetadataAPI';
|
||||||
|
import { HasuraMetadataV3 } from '@/metadata/types';
|
||||||
|
import { insertItem } from './InsertActions';
|
||||||
import { ColumnName, RowValues } from '../TableCommon/DataTableRowItem.types';
|
import { ColumnName, RowValues } from '../TableCommon/DataTableRowItem.types';
|
||||||
import { DataTableRowItemProps } from '../TableCommon/DataTableRowItem';
|
import { DataTableRowItemProps } from '../TableCommon/DataTableRowItem';
|
||||||
import { TableInsertItems } from './TableInsertItems';
|
import { TableInsertItems } from './TableInsertItems';
|
||||||
|
import {
|
||||||
|
useTableEnums,
|
||||||
|
UseTableEnumsResponseArrayType,
|
||||||
|
} from './hooks/useTableEnums';
|
||||||
|
import { useSchemas } from './hooks/useSchemas';
|
||||||
|
import { TableObject } from './types';
|
||||||
|
|
||||||
type GetButtonTextArgs = {
|
type GetButtonTextArgs = {
|
||||||
insertedRows: number;
|
insertedRows: number;
|
||||||
@ -23,25 +31,93 @@ const getButtonText = ({ insertedRows, ongoingRequest }: GetButtonTextArgs) => {
|
|||||||
return 'Save';
|
return 'Save';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getTableWithEnumRelations = (
|
||||||
|
source: string,
|
||||||
|
schema: string,
|
||||||
|
metadata: HasuraMetadataV3 | undefined
|
||||||
|
) => {
|
||||||
|
return metadata
|
||||||
|
? (metadata?.sources
|
||||||
|
?.find(s => s.name === source)
|
||||||
|
?.tables.filter((t: any) => {
|
||||||
|
return t?.is_enum && t?.table?.schema === schema;
|
||||||
|
})
|
||||||
|
?.map(t => t?.table) as TableObject[])
|
||||||
|
: [];
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatEnumOptions = (
|
||||||
|
tableEnums: UseTableEnumsResponseArrayType | undefined
|
||||||
|
) =>
|
||||||
|
tableEnums
|
||||||
|
? tableEnums?.reduce((tally, curr) => {
|
||||||
|
return {
|
||||||
|
...tally,
|
||||||
|
[curr.from]: curr.values,
|
||||||
|
};
|
||||||
|
}, {})
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const getTableMetadata = (
|
||||||
|
source: string,
|
||||||
|
table: string,
|
||||||
|
metadata: HasuraMetadataV3 | undefined
|
||||||
|
) => {
|
||||||
|
return metadata?.sources
|
||||||
|
?.find((s: { name: string }) => s.name === source)
|
||||||
|
?.tables.filter(
|
||||||
|
(t: { table: { name: string } }) => t?.table?.name === table
|
||||||
|
)?.[0];
|
||||||
|
};
|
||||||
|
|
||||||
type TableInsertItemContainerContainer = {
|
type TableInsertItemContainerContainer = {
|
||||||
params: {
|
params: {
|
||||||
schema: string;
|
schema: string;
|
||||||
source: string;
|
source: string;
|
||||||
table: string;
|
table: string;
|
||||||
};
|
};
|
||||||
|
router: { location: { state: any } };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const TableInsertItemContainer = (
|
export const TableInsertItemContainer = (
|
||||||
props: TableInsertItemContainerContainer
|
props: TableInsertItemContainerContainer
|
||||||
) => {
|
) => {
|
||||||
const { table: tableName } = props.params;
|
const {
|
||||||
|
table: tableName,
|
||||||
|
source: dataSourceName,
|
||||||
|
schema: schemaName,
|
||||||
|
} = props.params;
|
||||||
|
const currentRow = props.router?.location?.state?.row;
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
const [isMigration, setIsMigration] = useState(false);
|
const [isMigration, setIsMigration] = useState(false);
|
||||||
const [insertedRows, setInsertedRows] = useState(0);
|
const [insertedRows, setInsertedRows] = useState(0);
|
||||||
const [values, setValues] = useState<Record<ColumnName, RowValues>>({});
|
const [values, setValues] = useState<Record<ColumnName, RowValues>>({});
|
||||||
|
|
||||||
|
const { data: metadata } = useMetadata();
|
||||||
|
const tableMetadata = getTableMetadata(
|
||||||
|
dataSourceName,
|
||||||
|
tableName,
|
||||||
|
metadata?.metadata
|
||||||
|
);
|
||||||
|
|
||||||
|
const { data: migrationMode } = useMigrationMode();
|
||||||
|
const { data: readOnlyMode } = useReadOnlyMode();
|
||||||
|
const { data: schemas, isLoading: schemasIsLoading } = useSchemas({
|
||||||
|
dataSourceName,
|
||||||
|
schemaName,
|
||||||
|
});
|
||||||
|
|
||||||
|
const tablesWithEnumRelations = getTableWithEnumRelations(
|
||||||
|
dataSourceName,
|
||||||
|
schemaName,
|
||||||
|
metadata?.metadata
|
||||||
|
);
|
||||||
|
|
||||||
|
const { data: tableEnums } = useTableEnums({
|
||||||
|
tables: tablesWithEnumRelations,
|
||||||
|
dataSourceName,
|
||||||
|
});
|
||||||
const onColumnUpdate: DataTableRowItemProps['onColumnUpdate'] = (
|
const onColumnUpdate: DataTableRowItemProps['onColumnUpdate'] = (
|
||||||
columnName,
|
columnName,
|
||||||
rowValues
|
rowValues
|
||||||
@ -59,38 +135,9 @@ export const TableInsertItemContainer = (
|
|||||||
setValues(newValues);
|
setValues(newValues);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
dispatch(setTable(tableName));
|
|
||||||
dispatch(fetchEnumOptions());
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
dispatch({ type: I_RESET });
|
|
||||||
};
|
|
||||||
}, [tableName]);
|
|
||||||
|
|
||||||
const nextInsert = () =>
|
|
||||||
setInsertedRows(prevInsertedRows => prevInsertedRows + 1);
|
|
||||||
|
|
||||||
const toggleMigrationCheckBox = () =>
|
const toggleMigrationCheckBox = () =>
|
||||||
setIsMigration(prevIsMigration => !prevIsMigration);
|
setIsMigration(prevIsMigration => !prevIsMigration);
|
||||||
|
|
||||||
const insert = useAppSelector(store => store.tables.insert);
|
|
||||||
const allSchemas = useAppSelector(store => store.tables.allSchemas);
|
|
||||||
const tablesView = useAppSelector(store => store.tables.view);
|
|
||||||
const currentSchema = useAppSelector(store => store.tables.currentSchema);
|
|
||||||
const currentDataSource = useAppSelector(
|
|
||||||
store => store.tables.currentDataSource
|
|
||||||
);
|
|
||||||
const migrationMode = useAppSelector(store => store.main.migrationMode);
|
|
||||||
const readOnlyMode = useAppSelector(store => store.main.readOnlyMode);
|
|
||||||
|
|
||||||
const { count } = tablesView;
|
|
||||||
const { ongoingRequest, lastError, lastSuccess, clone, enumOptions } = insert;
|
|
||||||
const buttonText = getButtonText({
|
|
||||||
insertedRows,
|
|
||||||
ongoingRequest,
|
|
||||||
});
|
|
||||||
|
|
||||||
const onClickClear = () => {
|
const onClickClear = () => {
|
||||||
const form = document.getElementById('insertForm');
|
const form = document.getElementById('insertForm');
|
||||||
if (!form) {
|
if (!form) {
|
||||||
@ -111,6 +158,22 @@ export const TableInsertItemContainer = (
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const enumOptions = formatEnumOptions(tableEnums);
|
||||||
|
|
||||||
|
// Refactor in next iteration: --- Insert section start ---
|
||||||
|
const insert = useAppSelector(
|
||||||
|
(store: { tables: { insert: any } }) => store.tables.insert
|
||||||
|
);
|
||||||
|
const { ongoingRequest, lastError, lastSuccess } = insert;
|
||||||
|
|
||||||
|
const nextInsert = () =>
|
||||||
|
setInsertedRows(prevInsertedRows => prevInsertedRows + 1);
|
||||||
|
|
||||||
|
const buttonText = getButtonText({
|
||||||
|
insertedRows,
|
||||||
|
ongoingRequest,
|
||||||
|
});
|
||||||
|
|
||||||
const onClickSave: React.MouseEventHandler = e => {
|
const onClickSave: React.MouseEventHandler = e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const inputValues = Object.keys(values).reduce<
|
const inputValues = Object.keys(values).reduce<
|
||||||
@ -133,7 +196,7 @@ export const TableInsertItemContainer = (
|
|||||||
dispatch(
|
dispatch(
|
||||||
insertItem(
|
insertItem(
|
||||||
tableName,
|
tableName,
|
||||||
clone ? { ...clone, ...inputValues } : inputValues,
|
currentRow ? { ...currentRow, ...inputValues } : inputValues,
|
||||||
isMigration
|
isMigration
|
||||||
)
|
)
|
||||||
).then(() => {
|
).then(() => {
|
||||||
@ -141,21 +204,26 @@ export const TableInsertItemContainer = (
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// --- Insert section end ---
|
||||||
|
|
||||||
|
if (schemasIsLoading) return <p>Loading...</p>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TableInsertItems
|
<TableInsertItems
|
||||||
|
isEnum={!!tableMetadata?.is_enum}
|
||||||
toggleMigrationCheckBox={toggleMigrationCheckBox}
|
toggleMigrationCheckBox={toggleMigrationCheckBox}
|
||||||
onColumnUpdate={onColumnUpdate}
|
onColumnUpdate={onColumnUpdate}
|
||||||
isMigration={isMigration}
|
isMigration={isMigration}
|
||||||
dispatch={dispatch}
|
dispatch={dispatch}
|
||||||
tableName={tableName}
|
tableName={tableName}
|
||||||
currentSchema={currentSchema}
|
currentSchema={schemaName}
|
||||||
clone={clone}
|
clone={currentRow}
|
||||||
schemas={allSchemas}
|
schemas={schemas}
|
||||||
migrationMode={migrationMode}
|
migrationMode={!!migrationMode}
|
||||||
readOnlyMode={readOnlyMode}
|
readOnlyMode={!!readOnlyMode}
|
||||||
count={count}
|
count={0}
|
||||||
enumOptions={enumOptions}
|
enumOptions={enumOptions}
|
||||||
currentSource={currentDataSource}
|
currentSource={dataSourceName}
|
||||||
onClickSave={onClickSave}
|
onClickSave={onClickSave}
|
||||||
onClickClear={onClickClear}
|
onClickClear={onClickClear}
|
||||||
lastError={lastError}
|
lastError={lastError}
|
||||||
|
@ -45,6 +45,7 @@ const Alert = ({ lastError, lastSuccess }: AlertProps) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type TableInsertItemsProps = {
|
type TableInsertItemsProps = {
|
||||||
|
isEnum: boolean;
|
||||||
tableName: string;
|
tableName: string;
|
||||||
currentSchema: string;
|
currentSchema: string;
|
||||||
clone: Record<string, unknown>;
|
clone: Record<string, unknown>;
|
||||||
@ -66,6 +67,7 @@ type TableInsertItemsProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const TableInsertItems = ({
|
export const TableInsertItems = ({
|
||||||
|
isEnum,
|
||||||
tableName,
|
tableName,
|
||||||
currentSchema,
|
currentSchema,
|
||||||
clone,
|
clone,
|
||||||
@ -161,7 +163,7 @@ export const TableInsertItems = ({
|
|||||||
Clear
|
Clear
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
{currentTable.is_enum ? (
|
{isEnum ? (
|
||||||
<ReloadEnumValuesButton dispatch={dispatch} />
|
<ReloadEnumValuesButton dispatch={dispatch} />
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
@ -0,0 +1,41 @@
|
|||||||
|
import { getRunSqlQuery } from '@/components/Common/utils/v1QueryUtils';
|
||||||
|
import { dataSource } from '@/dataSources';
|
||||||
|
import Endpoints from '@/Endpoints';
|
||||||
|
import { useHttpClient } from '@/features/Network';
|
||||||
|
import { useQuery } from 'react-query';
|
||||||
|
|
||||||
|
export type UseTableRelationsType = {
|
||||||
|
dataSourceName: string;
|
||||||
|
schemaName: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useSchemas = ({
|
||||||
|
dataSourceName,
|
||||||
|
schemaName,
|
||||||
|
}: UseTableRelationsType) => {
|
||||||
|
const httpClient = useHttpClient();
|
||||||
|
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ['tables-schema', schemaName, dataSourceName],
|
||||||
|
queryFn: async () => {
|
||||||
|
try {
|
||||||
|
// Will always fetch all tables on schema
|
||||||
|
const runSql = dataSource?.getFetchTablesListQuery({
|
||||||
|
schemas: [schemaName],
|
||||||
|
});
|
||||||
|
const url = Endpoints.query;
|
||||||
|
const query = getRunSqlQuery(runSql, dataSourceName, false, true);
|
||||||
|
const response = await httpClient.post(url, {
|
||||||
|
type: 'bulk',
|
||||||
|
source: dataSourceName,
|
||||||
|
args: [query],
|
||||||
|
});
|
||||||
|
|
||||||
|
return JSON.parse(response.data?.[0]?.result?.[1]?.[0]);
|
||||||
|
} catch (err: any) {
|
||||||
|
throw new Error(err);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
refetchOnWindowFocus: false,
|
||||||
|
});
|
||||||
|
};
|
@ -0,0 +1,81 @@
|
|||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
import Endpoints from '@/Endpoints';
|
||||||
|
import { useHttpClient } from '@/features/Network';
|
||||||
|
import { useQuery, UseQueryResult } from 'react-query';
|
||||||
|
import { useTablesForeignKeys } from './useTableForeignKeys';
|
||||||
|
import { TableObject, ForeignKeyMapping } from '../types';
|
||||||
|
|
||||||
|
export type UseTableEnumOptionsProps = {
|
||||||
|
tables: TableObject[];
|
||||||
|
dataSourceName: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type UseTableEnumsResponseType = {
|
||||||
|
from: string;
|
||||||
|
to: string;
|
||||||
|
column: string[];
|
||||||
|
values: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type UseTableEnumsResponseArrayType = UseTableEnumsResponseType[];
|
||||||
|
|
||||||
|
export const useTableEnums = ({
|
||||||
|
tables,
|
||||||
|
dataSourceName,
|
||||||
|
}: UseTableEnumOptionsProps): UseQueryResult<UseTableEnumsResponseArrayType> => {
|
||||||
|
const httpClient = useHttpClient();
|
||||||
|
|
||||||
|
const { data: foreignKeys } = useTablesForeignKeys({
|
||||||
|
tables,
|
||||||
|
dataSourceName,
|
||||||
|
});
|
||||||
|
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ['tables-enum', JSON.stringify(tables), dataSourceName],
|
||||||
|
queryFn: async () => {
|
||||||
|
try {
|
||||||
|
const enums = [];
|
||||||
|
if (!foreignKeys) return [];
|
||||||
|
/* eslint-disable no-await-in-loop */
|
||||||
|
for (const table of tables) {
|
||||||
|
const relation = foreignKeys.reduce(
|
||||||
|
(tally: ForeignKeyMapping | null, fk: ForeignKeyMapping[]) => {
|
||||||
|
const found = fk.find(f => f.to.table === table.name);
|
||||||
|
if (!found) return tally;
|
||||||
|
return found;
|
||||||
|
},
|
||||||
|
null
|
||||||
|
);
|
||||||
|
if (!relation) return [];
|
||||||
|
const body = {
|
||||||
|
type: 'select',
|
||||||
|
args: {
|
||||||
|
source: dataSourceName,
|
||||||
|
columns: relation.to.column,
|
||||||
|
table,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const url = Endpoints.query;
|
||||||
|
const response = await httpClient.post(url, JSON.stringify(body));
|
||||||
|
const column = Object.keys(response?.data?.[0])?.[0];
|
||||||
|
const values = response?.data?.map(
|
||||||
|
(v: Record<string, string>) => v[column]
|
||||||
|
);
|
||||||
|
|
||||||
|
enums.push({
|
||||||
|
from: relation.from.column[0],
|
||||||
|
to: relation.to.table,
|
||||||
|
column,
|
||||||
|
values,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return enums;
|
||||||
|
} catch (err: any) {
|
||||||
|
throw new Error(err);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
enabled: !!foreignKeys,
|
||||||
|
refetchOnWindowFocus: true,
|
||||||
|
});
|
||||||
|
};
|
@ -0,0 +1,41 @@
|
|||||||
|
import { useQuery, UseQueryResult } from 'react-query';
|
||||||
|
import { DataSource } from '@/features/DataSource';
|
||||||
|
import { useHttpClient } from '@/features/Network';
|
||||||
|
|
||||||
|
import { TableObject, ForeignKeyMapping } from '../types';
|
||||||
|
|
||||||
|
export type UseTableForeignKeysProps = {
|
||||||
|
tables: TableObject[];
|
||||||
|
dataSourceName: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useTablesForeignKeys = ({
|
||||||
|
tables,
|
||||||
|
dataSourceName,
|
||||||
|
}: UseTableForeignKeysProps): UseQueryResult<ForeignKeyMapping[][]> => {
|
||||||
|
const httpClient = useHttpClient();
|
||||||
|
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ['tables-fk', JSON.stringify(tables), dataSourceName],
|
||||||
|
queryFn: async () => {
|
||||||
|
try {
|
||||||
|
const foreignKeys = [];
|
||||||
|
/* eslint-disable no-await-in-loop */
|
||||||
|
for (const table of tables) {
|
||||||
|
const response = await DataSource(httpClient).getTableFkRelationships(
|
||||||
|
{
|
||||||
|
dataSourceName,
|
||||||
|
table,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
foreignKeys.push(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
return foreignKeys;
|
||||||
|
} catch (err: any) {
|
||||||
|
throw new Error(err);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
refetchOnWindowFocus: false,
|
||||||
|
});
|
||||||
|
};
|
@ -0,0 +1,14 @@
|
|||||||
|
export type TableObject = {
|
||||||
|
name: string;
|
||||||
|
schema: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ForeignKeyMap = {
|
||||||
|
table: string;
|
||||||
|
column: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ForeignKeyMapping = {
|
||||||
|
to: ForeignKeyMap;
|
||||||
|
from: ForeignKeyMap;
|
||||||
|
};
|
@ -373,6 +373,7 @@ export const mergeLoadSchemaDataPostgres = (
|
|||||||
Table['foreign_key_constraints'][0],
|
Table['foreign_key_constraints'][0],
|
||||||
'is_table_tracked' | 'is_ref_table_tracked'
|
'is_table_tracked' | 'is_ref_table_tracked'
|
||||||
>[];
|
>[];
|
||||||
|
|
||||||
const primaryKeys = JSON.parse(data[2].result[1]) as Table['primary_key'][];
|
const primaryKeys = JSON.parse(data[2].result[1]) as Table['primary_key'][];
|
||||||
const uniqueKeys = JSON.parse(data[3].result[1]) as any;
|
const uniqueKeys = JSON.parse(data[3].result[1]) as any;
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { SERVER_CONSOLE_MODE } from '@/constants';
|
import { SERVER_CONSOLE_MODE } from '@/constants';
|
||||||
import Endpoints from '@/Endpoints';
|
import Endpoints from '@/Endpoints';
|
||||||
import { useQuery, UseQueryOptions } from 'react-query';
|
import { useQuery, UseQueryOptions, UseQueryResult } from 'react-query';
|
||||||
import { useAppSelector } from '../store';
|
import { useAppSelector } from '../store';
|
||||||
import { Api } from './apiUtils';
|
import { Api } from './apiUtils';
|
||||||
import { useConsoleConfig } from './useEnvVars';
|
import { useConsoleConfig } from './useEnvVars';
|
||||||
@ -12,7 +12,7 @@ export interface Config {
|
|||||||
|
|
||||||
export function useMigrationMode(
|
export function useMigrationMode(
|
||||||
queryOptions?: UseQueryOptions<{ migration_mode: boolean }, Error, boolean>
|
queryOptions?: UseQueryOptions<{ migration_mode: boolean }, Error, boolean>
|
||||||
) {
|
): UseQueryResult<boolean> {
|
||||||
const headers = useAppSelector(s => s.tables.dataHeaders);
|
const headers = useAppSelector(s => s.tables.dataHeaders);
|
||||||
const migrationUrl = Endpoints.hasuractlMigrateSettings;
|
const migrationUrl = Endpoints.hasuractlMigrateSettings;
|
||||||
const { mode } = useConsoleConfig();
|
const { mode } = useConsoleConfig();
|
||||||
|
Loading…
Reference in New Issue
Block a user