mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-14 17:02:49 +03:00
Console: refactor the table Modify tab
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6419 GitOrigin-RevId: 620e37be5275e339bff2d3da6758d894f035987f
This commit is contained in:
parent
e692c3b20d
commit
b591d68d81
@ -4,13 +4,13 @@ import { useServerConfig } from '@/hooks';
|
||||
import KnowMoreLink from '@/components/Common/KnowMoreLink/KnowMoreLink';
|
||||
import ToolTip from '../../../../Common/Tooltip/Tooltip';
|
||||
|
||||
type ApolloFederationSupportProps = {
|
||||
toggleApollofederation: () => void;
|
||||
export type ApolloFederationSupportProps = {
|
||||
toggleApolloFederation: () => void;
|
||||
isApolloFederationSupported: boolean;
|
||||
};
|
||||
|
||||
export const ApolloFederationSupport = ({
|
||||
toggleApollofederation,
|
||||
toggleApolloFederation,
|
||||
isApolloFederationSupported,
|
||||
}: ApolloFederationSupportProps) => {
|
||||
const { data: configData, isLoading, isError } = useServerConfig();
|
||||
@ -49,7 +49,7 @@ export const ApolloFederationSupport = ({
|
||||
<div data-toggle="tooltip">
|
||||
<Toggle
|
||||
icons={false}
|
||||
onChange={() => toggleApollofederation()}
|
||||
onChange={() => toggleApolloFederation()}
|
||||
checked={isApolloFederationSupported}
|
||||
/>
|
||||
</div>
|
||||
|
@ -33,8 +33,8 @@ export const getForeignKeyConfig = (foreignKey, orderedColumns) => {
|
||||
return `${lCol} → ${refTableName} . ${rCol}`;
|
||||
};
|
||||
|
||||
export const getExistingFKConstraints = (tableSchema, orderedColumns) => {
|
||||
return tableSchema.foreign_key_constraints.map(fkc => {
|
||||
export const getExistingFKConstraints = (tableSchema, orderedColumns) =>
|
||||
(tableSchema?.foreign_key_constraints || []).map(fkc => {
|
||||
const fk = {};
|
||||
fk.refTableName = fkc.ref_table;
|
||||
fk.refSchemaName = fkc.ref_table_table_schema;
|
||||
@ -48,7 +48,6 @@ export const getExistingFKConstraints = (tableSchema, orderedColumns) => {
|
||||
fk.colMappings.push({ column: '', refColumn: '' });
|
||||
return fk;
|
||||
});
|
||||
};
|
||||
|
||||
export const generateFKConstraintName = (
|
||||
tableName,
|
||||
|
@ -10,7 +10,6 @@ import {
|
||||
rawSQLConnector,
|
||||
addExistingTableViewConnector,
|
||||
addTableConnector,
|
||||
modifyTableConnector,
|
||||
modifyViewConnector,
|
||||
relationshipsConnector,
|
||||
relationshipsViewConnector,
|
||||
@ -34,6 +33,7 @@ import { getSourcesFromMetadata } from '../../../metadata/selector';
|
||||
import { ManageContainer } from '@/features/Data';
|
||||
import { Connect } from '@/features/ConnectDB';
|
||||
import { TableInsertItemContainer } from './TableInsertItem/TableInsertItemContainer';
|
||||
import { ModifyTableContainer } from './TableModify/ModifyTableContainer';
|
||||
import { TableEditItemContainer } from './TableEditItem/TableEditItemContainer';
|
||||
|
||||
const makeDataRouter = (
|
||||
@ -96,7 +96,7 @@ const makeDataRouter = (
|
||||
<Route
|
||||
path=":schema/tables/:table/modify"
|
||||
onEnter={migrationRedirects}
|
||||
component={modifyTableConnector(connect)}
|
||||
component={ModifyTableContainer}
|
||||
/>
|
||||
<Route
|
||||
path=":schema/tables/:table/relationships"
|
||||
|
@ -22,14 +22,14 @@ import { FaDatabase, FaFolder, FaTable } from 'react-icons/fa';
|
||||
import styles from '../../../Common/TableCommon/Table.module.scss';
|
||||
|
||||
const TableHeader = ({
|
||||
tabName,
|
||||
count,
|
||||
dispatch,
|
||||
isCountEstimated,
|
||||
table,
|
||||
migrationMode,
|
||||
readOnlyMode,
|
||||
source,
|
||||
dispatch,
|
||||
table,
|
||||
tabName,
|
||||
}) => {
|
||||
const tableName = table.table_name;
|
||||
const tableSchema = table.table_schema;
|
||||
|
@ -132,7 +132,7 @@ const useColumnEditor = (dispatch: Dispatch, tableName: string) => {
|
||||
interface ColumnCreatorProps {
|
||||
dispatch: Dispatch;
|
||||
tableName: string;
|
||||
dataTypes: string[];
|
||||
dataTypes: string[][];
|
||||
validTypeCasts: Record<string, string[]>;
|
||||
columnDefaultFunctions: Record<string, string[]>;
|
||||
postgresVersion: string;
|
||||
|
@ -1,4 +1,3 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { connect, ConnectedProps } from 'react-redux';
|
||||
|
||||
@ -42,11 +41,6 @@ const ComputedFields = (props: ComputedFieldsProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
ComputedFields.propTypes = {
|
||||
currentSchema: PropTypes.string.isRequired,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
type OwnProps = {
|
||||
tableSchema: Table;
|
||||
};
|
||||
|
@ -1,20 +1,14 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { ordinalColSort } from '../utils';
|
||||
import React from 'react';
|
||||
import {
|
||||
setForeignKeys,
|
||||
saveForeignKeys,
|
||||
removeForeignKey,
|
||||
} from './ModifyActions';
|
||||
import {
|
||||
getForeignKeyConfig,
|
||||
getExistingFKConstraints,
|
||||
} from '../Common/Components/utils';
|
||||
import { getForeignKeyConfig } from '../Common/Components/utils';
|
||||
import ExpandableEditor from '../../../Common/Layout/ExpandableEditor/Editor';
|
||||
import ForeignKeySelector from '../Common/Components/ForeignKeySelector';
|
||||
import { updateSchemaInfo } from '../DataActions';
|
||||
|
||||
import { getConfirmation } from '../../../Common/utils/jsUtils';
|
||||
import { dataSource } from '../../../../dataSources';
|
||||
|
||||
const ForeignKeyEditor = ({
|
||||
tableSchema,
|
||||
@ -23,36 +17,9 @@ const ForeignKeyEditor = ({
|
||||
fkModify,
|
||||
schemaList,
|
||||
readOnlyMode,
|
||||
orderedColumns,
|
||||
existingForeignKeys,
|
||||
}) => {
|
||||
const columns = tableSchema.columns.sort(ordinalColSort);
|
||||
|
||||
// columns in the right order with their indices
|
||||
const orderedColumns = columns.map((c, i) => ({
|
||||
name: c.column_name,
|
||||
index: i,
|
||||
}));
|
||||
|
||||
// restructure the existing foreign keys and add it to fkModify (for easy processing)
|
||||
const existingForeignKeys = getExistingFKConstraints(
|
||||
tableSchema,
|
||||
orderedColumns
|
||||
);
|
||||
const schemasToBeFetched = {};
|
||||
existingForeignKeys.forEach(efk => {
|
||||
schemasToBeFetched[efk.refSchemaName] = true;
|
||||
});
|
||||
existingForeignKeys.push({
|
||||
refSchemaName: '',
|
||||
refTableName: '',
|
||||
onUpdate: dataSource?.violationActions?.[0],
|
||||
onDelete: dataSource?.violationActions?.[0],
|
||||
colMappings: [{ column: '', refColumn: '' }],
|
||||
});
|
||||
useEffect(() => {
|
||||
dispatch(setForeignKeys(existingForeignKeys));
|
||||
dispatch(updateSchemaInfo({ schemas: Object.keys(schemasToBeFetched) }));
|
||||
}, []);
|
||||
|
||||
const numFks = fkModify.length;
|
||||
|
||||
// Map the foreign keys in the fkModify state and render
|
||||
|
@ -1810,7 +1810,7 @@ export const toggleTableAsEnum =
|
||||
);
|
||||
};
|
||||
|
||||
export const toggleAsApollofederation =
|
||||
export const toggleAsApolloFederation =
|
||||
(isApolloFederationSupported, successCallback, failureCallback) =>
|
||||
(dispatch, getState) => {
|
||||
const confirmMessage = `This will ${
|
||||
|
@ -1,466 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
|
||||
import { Button } from '@/new-components/Button';
|
||||
import TableHeader from '../TableCommon/TableHeader';
|
||||
import { getAllDataTypeMap } from '../Common/utils';
|
||||
import {
|
||||
deleteTableSql,
|
||||
untrackTableSql,
|
||||
RESET,
|
||||
setUniqueKeys,
|
||||
toggleTableAsEnum,
|
||||
toggleAsApollofederation,
|
||||
} from '../TableModify/ModifyActions';
|
||||
import {
|
||||
setTable,
|
||||
fetchColumnTypeInfo,
|
||||
RESET_COLUMN_TYPE_INFO,
|
||||
fetchFunctionInit,
|
||||
} from '../DataActions';
|
||||
import ColumnEditorList from './ColumnEditorList';
|
||||
import ColumnCreator from './ColumnCreator';
|
||||
import PrimaryKeyEditor from './PrimaryKeyEditor';
|
||||
import TableCommentEditor from './TableCommentEditor';
|
||||
import EnumsSection, {
|
||||
EnumTableModifyWarning,
|
||||
} from '../Common/Components/EnumsSection';
|
||||
import ForeignKeyEditor from './ForeignKeyEditor';
|
||||
import UniqueKeyEditor from './UniqueKeyEditor';
|
||||
import TriggerEditorList from './TriggerEditorList';
|
||||
import CheckConstraints from './CheckConstraints';
|
||||
import RootFields from './RootFields';
|
||||
import { NotFoundError } from '../../../Error/PageNotFound';
|
||||
import { getConfirmation } from '../../../Common/utils/jsUtils';
|
||||
import {
|
||||
currentDriver,
|
||||
driverToLabel,
|
||||
findTable,
|
||||
generateTableDef,
|
||||
getTableCustomColumnNames,
|
||||
isFeatureSupported,
|
||||
} from '../../../../dataSources';
|
||||
import Tooltip from '../../../Common/Tooltip/Tooltip';
|
||||
import {
|
||||
foreignKeyDescription,
|
||||
primaryKeyDescription,
|
||||
uniqueKeyDescription,
|
||||
checkConstraintsDescription,
|
||||
indexFieldsDescription,
|
||||
} from '../Common/TooltipMessages';
|
||||
import { RightContainer } from '../../../Common/Layout/RightContainer';
|
||||
import { NotSupportedNote } from '../../../Common/NotSupportedNote';
|
||||
import ConnectedComputedFields from './ComputedFields';
|
||||
import FeatureDisabled from '../FeatureDisabled';
|
||||
import IndexFields from './IndexFields';
|
||||
import PartitionInfo from './PartitionInfo';
|
||||
import { FaFlask } from 'react-icons/fa';
|
||||
import { ApolloFederationSupport } from '../Common/Components/ApolloFederationSupport';
|
||||
|
||||
class ModifyTable extends React.Component {
|
||||
componentDidMount() {
|
||||
if (!isFeatureSupported('tables.modify.enabled')) return;
|
||||
const { dispatch } = this.props;
|
||||
dispatch({ type: RESET });
|
||||
dispatch(setTable(this.props.tableName));
|
||||
if (!isFeatureSupported('tables.modify.readOnly'))
|
||||
dispatch(fetchColumnTypeInfo());
|
||||
dispatch(fetchFunctionInit());
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.dispatch({
|
||||
type: RESET_COLUMN_TYPE_INFO,
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
tableName,
|
||||
allTables,
|
||||
dispatch,
|
||||
migrationMode,
|
||||
readOnlyMode,
|
||||
currentSchema,
|
||||
tableCommentEdit,
|
||||
columnEdit,
|
||||
pkModify,
|
||||
fkModify,
|
||||
checkConstraintsModify,
|
||||
dataTypes,
|
||||
validTypeCasts,
|
||||
uniqueKeyModify,
|
||||
columnDefaultFunctions,
|
||||
schemaList,
|
||||
tableEnum,
|
||||
postgresVersion,
|
||||
currentSource,
|
||||
} = this.props;
|
||||
|
||||
if (!isFeatureSupported('tables.modify.enabled')) {
|
||||
return (
|
||||
<FeatureDisabled
|
||||
tab="modify"
|
||||
tableName={tableName}
|
||||
schemaName={currentSchema}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const dataTypeIndexMap = getAllDataTypeMap(dataTypes);
|
||||
|
||||
const table = findTable(
|
||||
allTables,
|
||||
generateTableDef(tableName, currentSchema)
|
||||
);
|
||||
|
||||
if (!table && isFeatureSupported('tables.modify.enabled')) {
|
||||
throw new NotFoundError();
|
||||
}
|
||||
|
||||
const tableComment = table.comment;
|
||||
|
||||
const untrackBtn = (
|
||||
<Button
|
||||
type="submit"
|
||||
className="mr-sm"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
const confirmMessage = `This will remove the table "${tableName}" from the GraphQL schema`;
|
||||
const isOk = getConfirmation(confirmMessage);
|
||||
if (isOk) {
|
||||
dispatch(untrackTableSql(tableName));
|
||||
}
|
||||
}}
|
||||
data-test="untrack-table"
|
||||
>
|
||||
Untrack Table
|
||||
</Button>
|
||||
);
|
||||
|
||||
const deleteBtn = (
|
||||
<Button
|
||||
type="submit"
|
||||
mode="destructive"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
const confirmMessage = `This will permanently delete the table "${tableName}" from the database`;
|
||||
const isOk = getConfirmation(confirmMessage, true, tableName);
|
||||
if (isOk) {
|
||||
dispatch(deleteTableSql(tableName, table));
|
||||
}
|
||||
}}
|
||||
data-test="delete-table"
|
||||
>
|
||||
Delete table
|
||||
</Button>
|
||||
);
|
||||
|
||||
const getEnumsSection = () => {
|
||||
const toggleEnum = () => dispatch(toggleTableAsEnum(table.is_enum));
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<EnumsSection
|
||||
isEnum={table.is_enum}
|
||||
toggleEnum={toggleEnum}
|
||||
loading={tableEnum.loading}
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const toggleApollofederation = () =>
|
||||
dispatch(toggleAsApollofederation(table.is_apollo_federation_supported));
|
||||
|
||||
return (
|
||||
<RightContainer>
|
||||
<div>
|
||||
<TableHeader
|
||||
dispatch={dispatch}
|
||||
table={table}
|
||||
source={currentSource}
|
||||
tabName="modify"
|
||||
migrationMode={migrationMode}
|
||||
readOnlyMode={readOnlyMode}
|
||||
/>
|
||||
<br />
|
||||
<div>
|
||||
<div>
|
||||
{isFeatureSupported('tables.modify.readOnly') && (
|
||||
<div className={'py-sm px-sm bg-gray-200 rounded-md mb-md'}>
|
||||
<p className="mb-xs font-bold">
|
||||
<FaFlask aria-hidden="true" /> Coming soon for{' '}
|
||||
{driverToLabel[currentDriver]}
|
||||
</p>
|
||||
<p className="m-0">
|
||||
This page is currently read-only, but we're actively working
|
||||
on making it available for the Console.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
{isFeatureSupported('tables.modify.comments.view') && (
|
||||
<>
|
||||
<div className="w-full sm:w-6/12 mb-lg">
|
||||
<EnumTableModifyWarning isEnum={table.is_enum} />
|
||||
|
||||
<h4 className="flex items-center text-gray-600 font-semibold mb-formlabel">
|
||||
Table Comments
|
||||
</h4>
|
||||
<TableCommentEditor
|
||||
tableComment={tableComment}
|
||||
tableCommentEdit={tableCommentEdit}
|
||||
tableType="TABLE"
|
||||
dispatch={dispatch}
|
||||
readOnly={
|
||||
!isFeatureSupported('tables.modify.comments.edit')
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className="w-full sm:w-full">
|
||||
<h3 className="text-sm tracking-widest text-gray-400 uppercase font-semibold mb-sm">
|
||||
Configure Fields
|
||||
</h3>
|
||||
|
||||
{isFeatureSupported('tables.modify.columns.view') && (
|
||||
<>
|
||||
<h4 className="flex items-center text-gray-600 font-semibold mb-formlabel">
|
||||
Columns
|
||||
</h4>
|
||||
<ColumnEditorList
|
||||
validTypeCasts={validTypeCasts}
|
||||
dataTypeIndexMap={dataTypeIndexMap}
|
||||
tableSchema={table}
|
||||
columnEdit={columnEdit}
|
||||
dispatch={dispatch}
|
||||
readOnlyMode={
|
||||
!isFeatureSupported('tables.modify.columns.edit')
|
||||
}
|
||||
currentSchema={currentSchema}
|
||||
columnDefaultFunctions={columnDefaultFunctions}
|
||||
customColumnNames={getTableCustomColumnNames(table)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="w-full mb-lg">
|
||||
{isFeatureSupported('tables.modify.columns.edit') && (
|
||||
<>
|
||||
<ColumnCreator
|
||||
dispatch={dispatch}
|
||||
tableName={tableName}
|
||||
dataTypes={dataTypes}
|
||||
validTypeCasts={validTypeCasts}
|
||||
columnDefaultFunctions={columnDefaultFunctions}
|
||||
postgresVersion={postgresVersion}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<h3 className="text-sm tracking-widest text-gray-400 uppercase font-semibold mb-sm">
|
||||
Table Properties
|
||||
</h3>
|
||||
|
||||
{isFeatureSupported('tables.modify.primaryKeys.view') && (
|
||||
<>
|
||||
<div className="w-full sm:w-6/12 mb-md">
|
||||
<h4 className="flex items-center text-gray-600 font-semibold mb-formlabel">
|
||||
Primary Key
|
||||
<Tooltip message={primaryKeyDescription} />
|
||||
</h4>
|
||||
<PrimaryKeyEditor
|
||||
tableSchema={table}
|
||||
readOnlyMode={
|
||||
!isFeatureSupported('tables.modify.primaryKeys.edit')
|
||||
}
|
||||
pkModify={pkModify}
|
||||
dispatch={dispatch}
|
||||
currentSchema={currentSchema}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{isFeatureSupported('tables.modify.foreignKeys.view') && (
|
||||
<>
|
||||
<div className="w-full sm:w-8/12 mb-md">
|
||||
<h4 className="flex items-center text-gray-600 font-semibold mb-formlabel">
|
||||
Foreign Keys
|
||||
<Tooltip message={foreignKeyDescription} />
|
||||
</h4>
|
||||
<ForeignKeyEditor
|
||||
tableSchema={table}
|
||||
currentSchema={currentSchema}
|
||||
allSchemas={allTables}
|
||||
schemaList={schemaList}
|
||||
dispatch={dispatch}
|
||||
fkModify={fkModify}
|
||||
readOnlyMode={
|
||||
!isFeatureSupported('tables.modify.foreignKeys.edit')
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{isFeatureSupported('tables.modify.uniqueKeys.view') && (
|
||||
<>
|
||||
<div className="w-full sm:w-6/12 mb-md">
|
||||
<h4 className="flex items-center text-gray-600 font-semibold mb-formlabel">
|
||||
Unique Keys
|
||||
<Tooltip message={uniqueKeyDescription} />
|
||||
</h4>
|
||||
<UniqueKeyEditor
|
||||
tableSchema={table}
|
||||
currentSchema={currentSchema}
|
||||
allSchemas={allTables}
|
||||
dispatch={dispatch}
|
||||
uniqueKeys={uniqueKeyModify}
|
||||
setUniqueKeys={setUniqueKeys}
|
||||
readOnlyMode={
|
||||
!isFeatureSupported('tables.modify.uniqueKeys.edit')
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{isFeatureSupported('tables.modify.checkConstraints.view') && (
|
||||
<>
|
||||
<div className="w-full sm:w-6/12 mb-md">
|
||||
<h4 className="flex items-center text-gray-600 font-semibold mb-formlabel">
|
||||
Check Constraints
|
||||
<Tooltip message={checkConstraintsDescription} />
|
||||
</h4>
|
||||
<NotSupportedNote unsupported={['mysql']} />
|
||||
<CheckConstraints
|
||||
constraints={table.check_constraints}
|
||||
checkConstraintsModify={checkConstraintsModify}
|
||||
dispatch={dispatch}
|
||||
readOnlyMode={
|
||||
!isFeatureSupported(
|
||||
'tables.modify.checkConstraints.edit'
|
||||
)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{isFeatureSupported('tables.modify.indexes.view') ? (
|
||||
<>
|
||||
<div className="w-full sm:w-6/12 mb-md">
|
||||
<h4 className="flex items-center text-gray-600 font-semibold mb-formlabel">
|
||||
Indexes
|
||||
<Tooltip message={indexFieldsDescription} />
|
||||
</h4>
|
||||
<IndexFields tableSchema={table} />
|
||||
</div>
|
||||
</>
|
||||
) : null}
|
||||
|
||||
{table.table_type === 'PARTITIONED TABLE' && (
|
||||
<PartitionInfo table={table} dispatch={dispatch} />
|
||||
)}
|
||||
|
||||
{isFeatureSupported('tables.modify.triggers') && (
|
||||
<>
|
||||
<div className="w-full sm:w-6/12 mb-lg">
|
||||
<h4 className="flex items-center text-gray-600 font-semibold mb-formlabel">
|
||||
Triggers
|
||||
</h4>
|
||||
<NotSupportedNote unsupported={['mysql']} />
|
||||
<TriggerEditorList
|
||||
tableSchema={table}
|
||||
dispatch={dispatch}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<h3 className="text-sm tracking-widest text-gray-400 uppercase font-semibold mb-sm">
|
||||
GraphQL Features
|
||||
</h3>
|
||||
|
||||
{isFeatureSupported('tables.modify.computedFields') && (
|
||||
<>
|
||||
<div className="w-full sm:w-6/12 mb-md">
|
||||
<ConnectedComputedFields tableSchema={table} />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{isFeatureSupported('tables.modify.customGqlRoot') && (
|
||||
<>
|
||||
<div className="w-full sm:w-6/12 mb-md">
|
||||
<RootFields tableSchema={table} />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{isFeatureSupported('tables.modify.setAsEnum') &&
|
||||
getEnumsSection()}
|
||||
|
||||
<ApolloFederationSupport
|
||||
toggleApollofederation={toggleApollofederation}
|
||||
isApolloFederationSupported={
|
||||
table.is_apollo_federation_supported
|
||||
}
|
||||
/>
|
||||
|
||||
<div className="mb-lg">
|
||||
{isFeatureSupported('tables.modify.untrack') && untrackBtn}
|
||||
{isFeatureSupported('tables.modify.delete') && deleteBtn}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</RightContainer>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ModifyTable.propTypes = {
|
||||
tableName: PropTypes.string.isRequired,
|
||||
currentSchema: PropTypes.string.isRequired,
|
||||
allTables: PropTypes.array.isRequired,
|
||||
migrationMode: PropTypes.bool.isRequired,
|
||||
readOnlyMode: PropTypes.bool.isRequired,
|
||||
activeEdit: PropTypes.object.isRequired,
|
||||
fkAdd: PropTypes.object.isRequired,
|
||||
relAdd: PropTypes.object.isRequired,
|
||||
ongoingRequest: PropTypes.bool.isRequired,
|
||||
lastError: PropTypes.object,
|
||||
lastFormError: PropTypes.object,
|
||||
columnEdit: PropTypes.object.isRequired,
|
||||
lastSuccess: PropTypes.bool,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
pkModify: PropTypes.array.isRequired,
|
||||
fkModify: PropTypes.array.isRequired,
|
||||
serverVersion: PropTypes.string,
|
||||
};
|
||||
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
tableName: ownProps.params.table,
|
||||
allTables: state.tables.allSchemas,
|
||||
migrationMode: state.main.migrationMode,
|
||||
readOnlyMode: state.main.readOnlyMode,
|
||||
serverVersion: state.main.serverVersion,
|
||||
currentSchema: state.tables.currentSchema,
|
||||
columnEdit: state.tables.modify.columnEdit,
|
||||
pkModify: state.tables.modify.pkModify,
|
||||
fkModify: state.tables.modify.fkModify,
|
||||
dataTypes: state.tables.columnDataTypes,
|
||||
columnDefaultFunctions: state.tables.columnDefaultFunctions,
|
||||
validTypeCasts: state.tables.columnTypeCasts,
|
||||
columnDataTypeFetchErr: state.tables.columnDataTypeFetchErr,
|
||||
schemaList: state.tables.schemaList,
|
||||
postgresVersion: state.main.postgresVersion,
|
||||
currentSource: state.tables.currentDataSource,
|
||||
...state.tables.modify,
|
||||
});
|
||||
|
||||
const modifyTableConnector = connect => connect(mapStateToProps)(ModifyTable);
|
||||
|
||||
export default modifyTableConnector;
|
391
console/src/components/Services/Data/TableModify/ModifyTable.tsx
Normal file
391
console/src/components/Services/Data/TableModify/ModifyTable.tsx
Normal file
@ -0,0 +1,391 @@
|
||||
import React from 'react';
|
||||
import { FaFlask } from 'react-icons/fa';
|
||||
import {
|
||||
isFeatureSupported,
|
||||
driverToLabel,
|
||||
currentDriver,
|
||||
getTableCustomColumnNames,
|
||||
Table,
|
||||
} from '@/dataSources';
|
||||
import { AppDispatch } from '@/store';
|
||||
import { IconTooltip } from '@/new-components/Tooltip';
|
||||
import { NotSupportedNote } from '@/components/Common/NotSupportedNote';
|
||||
import { Button } from '@/new-components/Button';
|
||||
import {
|
||||
primaryKeyDescription,
|
||||
foreignKeyDescription,
|
||||
uniqueKeyDescription,
|
||||
checkConstraintsDescription,
|
||||
indexFieldsDescription,
|
||||
} from '../Common/TooltipMessages';
|
||||
import { RightContainer } from '../../../Common/Layout/RightContainer';
|
||||
import TableHeader from '../TableCommon/TableHeader';
|
||||
import EnumsSection, {
|
||||
EnumTableModifyWarning,
|
||||
} from '../Common/Components/EnumsSection';
|
||||
import { setUniqueKeys } from './ModifyActions';
|
||||
import TableCommentEditor from './TableCommentEditor';
|
||||
import ColumnEditorList from './ColumnEditorList';
|
||||
import ColumnCreator from './ColumnCreator';
|
||||
import PrimaryKeyEditor from './PrimaryKeyEditor';
|
||||
import ForeignKeyEditor from './ForeignKeyEditor';
|
||||
import UniqueKeyEditor from './UniqueKeyEditor';
|
||||
import CheckConstraints from './CheckConstraints';
|
||||
import IndexFields from './IndexFields';
|
||||
import PartitionInfo from './PartitionInfo';
|
||||
import TriggerEditorList from './TriggerEditorList';
|
||||
import ConnectedComputedFields from './ComputedFields';
|
||||
import RootFields from './RootFields';
|
||||
import {
|
||||
ApolloFederationSupport,
|
||||
ApolloFederationSupportProps,
|
||||
} from '../Common/Components/ApolloFederationSupport';
|
||||
import { useModifyTableSupportedFeatures } from './hooks/useModifyTableSupportedFeatures';
|
||||
import { ColumnName } from '../TableCommon/DataTableRowItem.types';
|
||||
import {
|
||||
CheckConstraintsType,
|
||||
ColumnEdit,
|
||||
DbDataType,
|
||||
DbFunctionName,
|
||||
ForeignKey,
|
||||
TypeAvailable,
|
||||
TypeCategory,
|
||||
TypeDescription,
|
||||
TypeDisplayName,
|
||||
} from './ModifyTable.types';
|
||||
|
||||
export type ModifyTableProps = {
|
||||
allTables: Table[];
|
||||
checkConstraintsModify: CheckConstraintsType[];
|
||||
columnDefaultFunctions: Record<DbDataType, DbFunctionName[]>;
|
||||
columnEdit: ColumnEdit;
|
||||
currentSchema: string;
|
||||
currentSource: string;
|
||||
dataTypeIndexMap: Record<DbDataType, string[]>;
|
||||
dataTypes: [TypeAvailable, TypeDisplayName, TypeDescription, TypeCategory][];
|
||||
dispatch: AppDispatch;
|
||||
existingForeignKeys: ForeignKey[];
|
||||
fkModify: ForeignKey[];
|
||||
migrationMode: boolean;
|
||||
onDeleteTable: () => void;
|
||||
onToggleApolloFederation: ApolloFederationSupportProps['toggleApolloFederation'];
|
||||
onToggleEnum: () => void;
|
||||
onUntrackTable: () => void;
|
||||
orderedColumns: { name: ColumnName; index: number }[];
|
||||
pkModify: string[];
|
||||
postgresVersion: string;
|
||||
readOnlyMode: boolean;
|
||||
schemaList: string[];
|
||||
table: Table;
|
||||
tableCommentEdit: { enabled: boolean; editedValue: string | null };
|
||||
tableEnum: { loading: boolean };
|
||||
tableName: string;
|
||||
uniqueKeyModify: number[][];
|
||||
validTypeCasts: Record<DbDataType, string[]>;
|
||||
};
|
||||
|
||||
export const ModifyTable: React.VFC<ModifyTableProps> = ({
|
||||
allTables,
|
||||
checkConstraintsModify,
|
||||
columnDefaultFunctions,
|
||||
columnEdit,
|
||||
currentSchema,
|
||||
currentSource,
|
||||
dataTypeIndexMap,
|
||||
dataTypes,
|
||||
dispatch,
|
||||
existingForeignKeys,
|
||||
fkModify,
|
||||
migrationMode,
|
||||
onDeleteTable,
|
||||
onToggleApolloFederation,
|
||||
onToggleEnum,
|
||||
onUntrackTable,
|
||||
orderedColumns,
|
||||
pkModify,
|
||||
postgresVersion,
|
||||
readOnlyMode,
|
||||
schemaList,
|
||||
table,
|
||||
tableCommentEdit,
|
||||
tableEnum,
|
||||
tableName,
|
||||
uniqueKeyModify,
|
||||
validTypeCasts,
|
||||
}) => {
|
||||
const {
|
||||
areComputedFieldSupported,
|
||||
areTriggersSupported,
|
||||
isCheckConstraintsEditSupported,
|
||||
isCheckConstraintsViewSupported,
|
||||
isColumnsEditSupported,
|
||||
isColumnsViewSupported,
|
||||
isCommentsEditSupported,
|
||||
isCommentsViewSupported,
|
||||
isCustomGqlRootSupported,
|
||||
isForeignKeysEditSupported,
|
||||
isIndexViewSupported,
|
||||
isModifySupported,
|
||||
isPrimaryKeysEditSupported,
|
||||
isPrimaryKeysViewSupported,
|
||||
isReadOnlySupported,
|
||||
isSetAsEnumSupported,
|
||||
isUniqueKeysEditSupported,
|
||||
isUntrackSupported,
|
||||
} = useModifyTableSupportedFeatures();
|
||||
|
||||
return (
|
||||
<RightContainer>
|
||||
<div>
|
||||
<TableHeader
|
||||
dispatch={dispatch}
|
||||
table={table}
|
||||
source={currentSource}
|
||||
tabName="modify"
|
||||
migrationMode={migrationMode}
|
||||
readOnlyMode={readOnlyMode}
|
||||
count={undefined}
|
||||
isCountEstimated={undefined}
|
||||
/>
|
||||
<br />
|
||||
<div>
|
||||
<div>
|
||||
{isReadOnlySupported && (
|
||||
<div className="py-sm px-sm bg-gray-200 rounded-md mb-md">
|
||||
<p className="mb-xs font-bold">
|
||||
<FaFlask aria-hidden="true" /> Coming soon for{' '}
|
||||
{driverToLabel[currentDriver]}
|
||||
</p>
|
||||
<p className="m-0">
|
||||
This page is currently read-only, but we're actively
|
||||
working on making it available for the Console.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
{isCommentsViewSupported && (
|
||||
<>
|
||||
<div className="w-full sm:w-6/12 mb-lg">
|
||||
<EnumTableModifyWarning isEnum={table.is_enum} />
|
||||
|
||||
<h4 className="flex items-center text-gray-600 font-semibold mb-formlabel">
|
||||
Table Comments
|
||||
</h4>
|
||||
<TableCommentEditor
|
||||
tableComment={table.comment}
|
||||
tableCommentEdit={tableCommentEdit}
|
||||
tableType="TABLE"
|
||||
dispatch={dispatch}
|
||||
readOnly={!isCommentsEditSupported}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className="w-full sm:w-full">
|
||||
<h3 className="text-sm tracking-widest text-gray-400 uppercase font-semibold mb-sm">
|
||||
Configure Fields
|
||||
</h3>
|
||||
|
||||
{isColumnsViewSupported && (
|
||||
<>
|
||||
<h4 className="flex items-center text-gray-600 font-semibold mb-formlabel">
|
||||
Columns
|
||||
</h4>
|
||||
<ColumnEditorList
|
||||
validTypeCasts={validTypeCasts}
|
||||
dataTypeIndexMap={dataTypeIndexMap}
|
||||
tableSchema={table}
|
||||
columnEdit={columnEdit}
|
||||
dispatch={dispatch}
|
||||
readOnlyMode={!isColumnsEditSupported}
|
||||
currentSchema={currentSchema}
|
||||
columnDefaultFunctions={columnDefaultFunctions}
|
||||
customColumnNames={getTableCustomColumnNames(table)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="w-full mb-lg">
|
||||
{isColumnsEditSupported && (
|
||||
<>
|
||||
<ColumnCreator
|
||||
dispatch={dispatch}
|
||||
tableName={tableName || ''}
|
||||
dataTypes={dataTypes}
|
||||
validTypeCasts={validTypeCasts}
|
||||
columnDefaultFunctions={columnDefaultFunctions}
|
||||
postgresVersion={postgresVersion}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<h3 className="text-sm tracking-widest text-gray-400 uppercase font-semibold mb-sm">
|
||||
Table Properties
|
||||
</h3>
|
||||
|
||||
{isPrimaryKeysViewSupported && (
|
||||
<>
|
||||
<div className="w-full sm:w-6/12 mb-md">
|
||||
<h4 className="flex items-center text-gray-600 font-semibold mb-formlabel">
|
||||
Primary Key
|
||||
<IconTooltip message={primaryKeyDescription} />
|
||||
</h4>
|
||||
<PrimaryKeyEditor
|
||||
tableSchema={table}
|
||||
readOnlyMode={!isPrimaryKeysEditSupported}
|
||||
pkModify={pkModify}
|
||||
dispatch={dispatch}
|
||||
currentSchema={currentSchema}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{isFeatureSupported('tables.modify.foreignKeys.view') && (
|
||||
<>
|
||||
<div className="w-full sm:w-8/12 mb-md">
|
||||
<h4 className="flex items-center text-gray-600 font-semibold mb-formlabel">
|
||||
Foreign Keys
|
||||
<IconTooltip message={foreignKeyDescription} />
|
||||
</h4>
|
||||
<ForeignKeyEditor
|
||||
tableSchema={table}
|
||||
allSchemas={allTables}
|
||||
dispatch={dispatch}
|
||||
schemaList={schemaList}
|
||||
fkModify={fkModify}
|
||||
orderedColumns={orderedColumns}
|
||||
existingForeignKeys={existingForeignKeys}
|
||||
readOnlyMode={!isForeignKeysEditSupported}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{isFeatureSupported('tables.modify.uniqueKeys.view') && (
|
||||
<>
|
||||
<div className="w-full sm:w-6/12 mb-md">
|
||||
<h4 className="flex items-center text-gray-600 font-semibold mb-formlabel">
|
||||
Unique Keys
|
||||
<IconTooltip message={uniqueKeyDescription} />
|
||||
</h4>
|
||||
<UniqueKeyEditor
|
||||
tableSchema={table}
|
||||
dispatch={dispatch}
|
||||
uniqueKeys={uniqueKeyModify}
|
||||
setUniqueKeys={setUniqueKeys}
|
||||
readOnlyMode={!isUniqueKeysEditSupported}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{isCheckConstraintsViewSupported && (
|
||||
<>
|
||||
<div className="w-full sm:w-6/12 mb-md">
|
||||
<h4 className="flex items-center text-gray-600 font-semibold mb-formlabel">
|
||||
Check Constraints
|
||||
<IconTooltip message={checkConstraintsDescription} />
|
||||
</h4>
|
||||
<NotSupportedNote unsupported={['mysql']} />
|
||||
<CheckConstraints
|
||||
constraints={table.check_constraints}
|
||||
checkConstraintsModify={checkConstraintsModify}
|
||||
dispatch={dispatch}
|
||||
readOnlyMode={!isCheckConstraintsEditSupported}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{isIndexViewSupported ? (
|
||||
<>
|
||||
<div className="w-full sm:w-6/12 mb-md">
|
||||
<h4 className="flex items-center text-gray-600 font-semibold mb-formlabel">
|
||||
Indexes
|
||||
<IconTooltip message={indexFieldsDescription} />
|
||||
</h4>
|
||||
<IndexFields tableSchema={table} />
|
||||
</div>
|
||||
</>
|
||||
) : null}
|
||||
|
||||
{table.table_type === 'PARTITIONED TABLE' && (
|
||||
<PartitionInfo table={table} dispatch={dispatch} />
|
||||
)}
|
||||
|
||||
{areTriggersSupported && (
|
||||
<>
|
||||
<div className="w-full sm:w-6/12 mb-lg">
|
||||
<h4 className="flex items-center text-gray-600 font-semibold mb-formlabel">
|
||||
Triggers
|
||||
</h4>
|
||||
<NotSupportedNote unsupported={['mysql']} />
|
||||
<TriggerEditorList tableSchema={table} dispatch={dispatch} />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<h3 className="text-sm tracking-widest text-gray-400 uppercase font-semibold mb-sm">
|
||||
GraphQL Features
|
||||
</h3>
|
||||
|
||||
{areComputedFieldSupported && (
|
||||
<>
|
||||
<div className="w-full sm:w-6/12 mb-md">
|
||||
<ConnectedComputedFields tableSchema={table} />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{isCustomGqlRootSupported && (
|
||||
<>
|
||||
<div className="w-full sm:w-6/12 mb-md">
|
||||
<RootFields tableSchema={table} />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{isSetAsEnumSupported && (
|
||||
<EnumsSection
|
||||
isEnum={table.is_enum}
|
||||
toggleEnum={() => onToggleEnum()}
|
||||
loading={tableEnum.loading}
|
||||
/>
|
||||
)}
|
||||
|
||||
<ApolloFederationSupport
|
||||
toggleApolloFederation={onToggleApolloFederation}
|
||||
isApolloFederationSupported={
|
||||
table?.is_apollo_federation_supported || false
|
||||
}
|
||||
/>
|
||||
|
||||
<div className="mb-lg">
|
||||
{isUntrackSupported && (
|
||||
<Button
|
||||
type="submit"
|
||||
className="mr-sm"
|
||||
size="sm"
|
||||
onClick={() => onUntrackTable()}
|
||||
data-test="untrack-table"
|
||||
>
|
||||
Untrack Table
|
||||
</Button>
|
||||
)}
|
||||
{isModifySupported && (
|
||||
<Button
|
||||
type="submit"
|
||||
mode="destructive"
|
||||
size="sm"
|
||||
onClick={() => onDeleteTable()}
|
||||
data-test="delete-table"
|
||||
>
|
||||
Delete table
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</RightContainer>
|
||||
);
|
||||
};
|
@ -0,0 +1,47 @@
|
||||
import { ColumnName } from '../TableCommon/DataTableRowItem.types';
|
||||
|
||||
export type CheckConstraintsType = {
|
||||
check: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
export type DbFunctionName = string;
|
||||
export type DbDataType = string;
|
||||
|
||||
export type ColumnEdit = Record<
|
||||
ColumnName,
|
||||
{
|
||||
comment: string;
|
||||
customFieldName: string;
|
||||
default: string;
|
||||
display_type_name: string;
|
||||
isArrayDataType: boolean;
|
||||
isIdentity: boolean;
|
||||
isNullable: boolean;
|
||||
isOnlyPrimaryKey: boolean | undefined;
|
||||
isUnique: boolean;
|
||||
name: string;
|
||||
pkConstraint: string | undefined;
|
||||
schemaName: string;
|
||||
tableName: string;
|
||||
type: string;
|
||||
}
|
||||
>;
|
||||
|
||||
export type ForeignKey = {
|
||||
colMappings: { column: string; refColumn: string }[];
|
||||
constraintName: string;
|
||||
onDelete: string;
|
||||
onUpdate: string;
|
||||
refSchemaName?: string;
|
||||
refTableName?: string;
|
||||
};
|
||||
|
||||
// Types available in a particular group
|
||||
export type TypeAvailable = string;
|
||||
// Display Name of a type
|
||||
export type TypeDisplayName = string;
|
||||
// Description of a type
|
||||
export type TypeDescription = string;
|
||||
// Category the particular type belongs to
|
||||
export type TypeCategory = string;
|
@ -0,0 +1,199 @@
|
||||
import { getConfirmation } from '@/components/Common/utils/jsUtils';
|
||||
import {
|
||||
findTable,
|
||||
generateTableDef,
|
||||
isFeatureSupported,
|
||||
Table,
|
||||
} from '@/dataSources';
|
||||
import { useAppDispatch, useAppSelector } from '@/store';
|
||||
import React, { useEffect } from 'react';
|
||||
import { getAllDataTypeMap } from '../Common/utils';
|
||||
import {
|
||||
fetchColumnTypeInfo,
|
||||
fetchFunctionInit,
|
||||
RESET_COLUMN_TYPE_INFO,
|
||||
setTable,
|
||||
} from '../DataActions';
|
||||
import FeatureDisabled from '../FeatureDisabled';
|
||||
import { useForeignKeys } from './hooks/useForeignKeys';
|
||||
import {
|
||||
deleteTableSql,
|
||||
RESET,
|
||||
toggleAsApolloFederation,
|
||||
toggleTableAsEnum,
|
||||
untrackTableSql,
|
||||
} from './ModifyActions';
|
||||
import { ModifyTable, ModifyTableProps } from './ModifyTable';
|
||||
|
||||
type ColumnEdit = {
|
||||
comment: string;
|
||||
customFieldName: string;
|
||||
default: string;
|
||||
display_type_name: string;
|
||||
isArrayDataType: boolean;
|
||||
isIdentity: boolean;
|
||||
isNullable: boolean;
|
||||
isOnlyPrimaryKey: boolean;
|
||||
isUnique: boolean;
|
||||
name: string;
|
||||
pkConstraint: string;
|
||||
schemaName: string;
|
||||
tableName: string;
|
||||
type: string;
|
||||
};
|
||||
|
||||
type FkModify = {
|
||||
colMappings: any[];
|
||||
constraintName: string;
|
||||
onDelete: string;
|
||||
onUpdate: string;
|
||||
refSchemaName: string;
|
||||
refTableName: string;
|
||||
};
|
||||
|
||||
type TableModify = {
|
||||
columnEdit: Record<string, ColumnEdit>;
|
||||
pkModify: string[];
|
||||
fkModify: FkModify[];
|
||||
tableEnum: any;
|
||||
tableCommentEdit: any;
|
||||
checkConstraintsModify: any;
|
||||
uniqueKeyModify: any;
|
||||
};
|
||||
|
||||
type Props = {
|
||||
params: {
|
||||
table: string;
|
||||
};
|
||||
};
|
||||
|
||||
export const ModifyTableContainer: React.VFC<Props> = ({ params }) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const tableName = params.table;
|
||||
|
||||
useEffect(() => {
|
||||
dispatch({ type: RESET });
|
||||
dispatch(setTable(tableName));
|
||||
|
||||
if (!isFeatureSupported('tables.modify.readOnly')) {
|
||||
dispatch(fetchColumnTypeInfo());
|
||||
}
|
||||
dispatch(fetchFunctionInit());
|
||||
|
||||
return () => {
|
||||
dispatch({
|
||||
type: RESET_COLUMN_TYPE_INFO,
|
||||
});
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [tableName]);
|
||||
|
||||
const allTables: Table[] = useAppSelector(store => store.tables.allSchemas);
|
||||
const migrationMode: boolean = useAppSelector(
|
||||
store => store.main.migrationMode
|
||||
);
|
||||
const readOnlyMode = useAppSelector(store => store.main.readOnlyMode);
|
||||
const currentSchema = useAppSelector(store => store.tables.currentSchema);
|
||||
|
||||
const tableModify: TableModify = useAppSelector(store => store.tables.modify);
|
||||
|
||||
const {
|
||||
columnEdit,
|
||||
pkModify,
|
||||
fkModify,
|
||||
tableEnum,
|
||||
tableCommentEdit,
|
||||
checkConstraintsModify,
|
||||
uniqueKeyModify,
|
||||
} = tableModify;
|
||||
|
||||
const dataTypes = useAppSelector(store => store.tables.columnDataTypes);
|
||||
const columnDefaultFunctions = useAppSelector(
|
||||
store => store.tables.columnDefaultFunctions
|
||||
);
|
||||
const validTypeCasts = useAppSelector(store => store.tables.columnTypeCasts);
|
||||
const schemaList = useAppSelector(store => store.tables.schemaList);
|
||||
const postgresVersion = useAppSelector(store => store.main.postgresVersion);
|
||||
const currentSource = useAppSelector(store => store.tables.currentDataSource);
|
||||
|
||||
const table = findTable(
|
||||
allTables,
|
||||
generateTableDef(tableName, currentSchema)
|
||||
);
|
||||
|
||||
const { orderedColumns, existingForeignKeys } = useForeignKeys({ table });
|
||||
|
||||
if (!table) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const isModifyEnabled = isFeatureSupported('tables.modify.enabled');
|
||||
if (!isModifyEnabled) {
|
||||
return (
|
||||
<FeatureDisabled
|
||||
tab="modify"
|
||||
tableName={tableName}
|
||||
schemaName={currentSchema}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const dataTypeIndexMap = getAllDataTypeMap(
|
||||
dataTypes
|
||||
) as ModifyTableProps['dataTypeIndexMap'];
|
||||
|
||||
const onUntrackTable = () => {
|
||||
const confirmMessage = `This will remove the table "${tableName}" from the GraphQL schema`;
|
||||
const isOk = getConfirmation(confirmMessage);
|
||||
if (isOk) {
|
||||
dispatch(untrackTableSql(tableName));
|
||||
}
|
||||
};
|
||||
|
||||
const onDeleteTable = () => {
|
||||
const confirmMessage = `This will permanently delete the table "${tableName}" from the database`;
|
||||
const isOk = getConfirmation(confirmMessage, true, tableName);
|
||||
if (isOk) {
|
||||
dispatch(deleteTableSql(tableName));
|
||||
}
|
||||
};
|
||||
|
||||
const onToggleEnum = () => dispatch(toggleTableAsEnum(table?.is_enum));
|
||||
|
||||
const onToggleApolloFederation = () =>
|
||||
dispatch(
|
||||
toggleAsApolloFederation(table?.is_apollo_federation_supported || false)
|
||||
);
|
||||
|
||||
return (
|
||||
<ModifyTable
|
||||
allTables={allTables}
|
||||
checkConstraintsModify={checkConstraintsModify}
|
||||
columnDefaultFunctions={columnDefaultFunctions}
|
||||
columnEdit={columnEdit}
|
||||
currentSchema={currentSchema}
|
||||
currentSource={currentSource}
|
||||
dataTypeIndexMap={dataTypeIndexMap}
|
||||
dataTypes={dataTypes}
|
||||
dispatch={dispatch}
|
||||
existingForeignKeys={existingForeignKeys}
|
||||
fkModify={fkModify}
|
||||
migrationMode={migrationMode}
|
||||
onDeleteTable={onDeleteTable}
|
||||
onToggleApolloFederation={onToggleApolloFederation}
|
||||
onToggleEnum={onToggleEnum}
|
||||
onUntrackTable={onUntrackTable}
|
||||
orderedColumns={orderedColumns}
|
||||
pkModify={pkModify}
|
||||
postgresVersion={postgresVersion}
|
||||
readOnlyMode={readOnlyMode}
|
||||
schemaList={schemaList}
|
||||
table={table}
|
||||
tableCommentEdit={tableCommentEdit}
|
||||
tableEnum={tableEnum}
|
||||
tableName={tableName}
|
||||
uniqueKeyModify={uniqueKeyModify}
|
||||
validTypeCasts={validTypeCasts}
|
||||
/>
|
||||
);
|
||||
};
|
@ -0,0 +1,43 @@
|
||||
import { dataSource, Table } from '@/dataSources';
|
||||
import { useAppDispatch } from '@/store';
|
||||
import { useEffect } from 'react';
|
||||
import { getExistingFKConstraints } from '../../Common/Components/utils';
|
||||
import { updateSchemaInfo } from '../../DataActions';
|
||||
import { ordinalColSort } from '../../utils';
|
||||
import { setForeignKeys } from '../ModifyActions';
|
||||
|
||||
type UseForeignKeysProps = {
|
||||
table: Table | undefined;
|
||||
};
|
||||
|
||||
export const useForeignKeys = ({ table }: UseForeignKeysProps) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const columns = table?.columns?.sort(ordinalColSort) || [];
|
||||
|
||||
const orderedColumns = columns.map((c, i) => ({
|
||||
name: c.column_name,
|
||||
index: i,
|
||||
}));
|
||||
|
||||
const existingForeignKeys = getExistingFKConstraints(table, orderedColumns);
|
||||
const schemasToBeFetched: Record<string, boolean> = {};
|
||||
existingForeignKeys.forEach((efk: { refSchemaName: string }) => {
|
||||
schemasToBeFetched[efk.refSchemaName] = true;
|
||||
});
|
||||
|
||||
existingForeignKeys.push({
|
||||
onUpdate: dataSource?.violationActions?.[0],
|
||||
onDelete: dataSource?.violationActions?.[0],
|
||||
colMappings: [{ column: '', refColumn: '' }],
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(setForeignKeys(existingForeignKeys));
|
||||
dispatch(updateSchemaInfo({ schemas: Object.keys(schemasToBeFetched) }));
|
||||
}, []);
|
||||
|
||||
return {
|
||||
orderedColumns,
|
||||
existingForeignKeys,
|
||||
};
|
||||
};
|
@ -0,0 +1,67 @@
|
||||
import { isFeatureSupported } from '@/dataSources';
|
||||
|
||||
export const useModifyTableSupportedFeatures = () => {
|
||||
const isUntrackSupported = isFeatureSupported('tables.modify.untrack');
|
||||
const isModifySupported = isFeatureSupported('tables.modify.delete');
|
||||
const isSetAsEnumSupported = isFeatureSupported('tables.modify.setAsEnum');
|
||||
const isReadOnlySupported = isFeatureSupported('tables.modify.readOnly');
|
||||
const isCommentsViewSupported = isFeatureSupported(
|
||||
'tables.modify.comments.view'
|
||||
);
|
||||
const isCommentsEditSupported = isFeatureSupported(
|
||||
'tables.modify.comments.edit'
|
||||
);
|
||||
const isColumnsViewSupported = isFeatureSupported(
|
||||
'tables.modify.columns.view'
|
||||
);
|
||||
const isColumnsEditSupported = isFeatureSupported(
|
||||
'tables.modify.columns.edit'
|
||||
);
|
||||
const isPrimaryKeysViewSupported = isFeatureSupported(
|
||||
'tables.modify.primaryKeys.view'
|
||||
);
|
||||
const isPrimaryKeysEditSupported = isFeatureSupported(
|
||||
'tables.modify.primaryKeys.edit'
|
||||
);
|
||||
const isForeignKeysEditSupported = isFeatureSupported(
|
||||
'tables.modify.foreignKeys.edit'
|
||||
);
|
||||
const isUniqueKeysEditSupported = isFeatureSupported(
|
||||
'tables.modify.uniqueKeys.edit'
|
||||
);
|
||||
const isCheckConstraintsViewSupported = isFeatureSupported(
|
||||
'tables.modify.checkConstraints.view'
|
||||
);
|
||||
const isCheckConstraintsEditSupported = isFeatureSupported(
|
||||
'tables.modify.checkConstraints.edit'
|
||||
);
|
||||
const isIndexViewSupported = isFeatureSupported('tables.modify.indexes.view');
|
||||
const areTriggersSupported = isFeatureSupported('tables.modify.triggers');
|
||||
const areComputedFieldSupported = isFeatureSupported(
|
||||
'tables.modify.computedFields'
|
||||
);
|
||||
const isCustomGqlRootSupported = isFeatureSupported(
|
||||
'tables.modify.customGqlRoot'
|
||||
);
|
||||
|
||||
return {
|
||||
areComputedFieldSupported,
|
||||
areTriggersSupported,
|
||||
isCheckConstraintsEditSupported,
|
||||
isCheckConstraintsViewSupported,
|
||||
isColumnsEditSupported,
|
||||
isColumnsViewSupported,
|
||||
isCommentsEditSupported,
|
||||
isCommentsViewSupported,
|
||||
isCustomGqlRootSupported,
|
||||
isForeignKeysEditSupported,
|
||||
isIndexViewSupported,
|
||||
isModifySupported,
|
||||
isPrimaryKeysEditSupported,
|
||||
isPrimaryKeysViewSupported,
|
||||
isReadOnlySupported,
|
||||
isSetAsEnumSupported,
|
||||
isUniqueKeysEditSupported,
|
||||
isUntrackSupported,
|
||||
};
|
||||
};
|
@ -12,7 +12,6 @@ import addExistingTableViewConnector from './Add/AddExistingTableView';
|
||||
import addTableConnector from './Add/AddTable';
|
||||
import rawSQLConnector from './RawSQL/RawSQL';
|
||||
import permissionsSummaryConnector from './PermissionsSummary/PermissionsSummary';
|
||||
import modifyTableConnector from './TableModify/ModifyTable';
|
||||
import modifyViewConnector from './TableModify/ModifyView';
|
||||
import relationshipsConnector from './TableRelationships/Relationships';
|
||||
import relationshipsViewConnector from './TableRelationships/RelationshipsView';
|
||||
@ -36,7 +35,6 @@ export {
|
||||
addTableConnector,
|
||||
rawSQLConnector,
|
||||
permissionsSummaryConnector,
|
||||
modifyTableConnector,
|
||||
modifyViewConnector,
|
||||
relationshipsConnector,
|
||||
relationshipsViewConnector,
|
||||
|
@ -73,9 +73,8 @@ export const getTableNameWithSchema = (
|
||||
return fullTableName;
|
||||
};
|
||||
|
||||
export const findTable = (allTables: Table[], tableDef: QualifiedTable) => {
|
||||
return allTables.find(t => isEqual(getTableDef(t), tableDef));
|
||||
};
|
||||
export const findTable = (allTables: Table[], tableDef: QualifiedTable) =>
|
||||
allTables.find(t => isEqual(getTableDef(t), tableDef));
|
||||
|
||||
export const getTrackedTables = (tables: Table[]) => {
|
||||
return tables.filter(t => t.is_table_tracked);
|
||||
|
@ -240,6 +240,7 @@ export interface Table extends BaseTable {
|
||||
}[];
|
||||
citusTableType?: string;
|
||||
unique_constraints: UniqueKey[] | null;
|
||||
is_apollo_federation_supported?: boolean;
|
||||
}
|
||||
|
||||
export type Partition = {
|
||||
|
Loading…
Reference in New Issue
Block a user