mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-16 01:44:03 +03:00
parent
2d5d3210b5
commit
5dfe3b86f2
@ -1356,6 +1356,10 @@ code {
|
|||||||
width: 325px;
|
width: 325px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cursorNotAllowed {
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
/* container height subtracting top header and bottom scroll bar */
|
/* container height subtracting top header and bottom scroll bar */
|
||||||
$mainContainerHeight: calc(100vh - 50px - 25px);
|
$mainContainerHeight: calc(100vh - 50px - 25px);
|
||||||
|
|
||||||
|
@ -14,15 +14,21 @@ const WarningSymbol = ({
|
|||||||
return (
|
return (
|
||||||
<div className={styles.display_inline}>
|
<div className={styles.display_inline}>
|
||||||
<OverlayTrigger placement={tooltipPlacement} overlay={tooltip}>
|
<OverlayTrigger placement={tooltipPlacement} overlay={tooltip}>
|
||||||
<i
|
<WarningIcon customStyle={customStyle} />
|
||||||
className={`fa fa-exclamation-triangle ${styles.warningSymbol} ${
|
|
||||||
customStyle ? customStyle : ''
|
|
||||||
}`}
|
|
||||||
aria-hidden="true"
|
|
||||||
/>
|
|
||||||
</OverlayTrigger>
|
</OverlayTrigger>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const WarningIcon = ({ customStyle }) => {
|
||||||
|
return (
|
||||||
|
<i
|
||||||
|
className={`fa fa-exclamation-triangle ${styles.warningSymbol} ${
|
||||||
|
customStyle ? customStyle : ''
|
||||||
|
}`}
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default WarningSymbol;
|
export default WarningSymbol;
|
||||||
|
@ -82,10 +82,6 @@
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.cursorNotAllowed {
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.apiExplorerWrapper {
|
.apiExplorerWrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
height: $mainContainerHeight;
|
height: $mainContainerHeight;
|
||||||
|
@ -0,0 +1,72 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import Toggle from 'react-toggle';
|
||||||
|
import styles from '../../../../Common/Common.scss';
|
||||||
|
|
||||||
|
const enumCompatibilityDocsUrl =
|
||||||
|
'https://docs.hasura.io/1.0/graphql/manual/schema/enums.html#create-an-enum-table';
|
||||||
|
|
||||||
|
export const EnumTableModifyWarning = ({ isEnum }) => {
|
||||||
|
if (!isEnum) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.add_mar_bottom}>
|
||||||
|
<i>
|
||||||
|
* This table is set as an enum. Modifying it may cause your Hasura
|
||||||
|
metadata to become inconsistent.
|
||||||
|
<br />
|
||||||
|
<a
|
||||||
|
href={enumCompatibilityDocsUrl}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
See enum table requirements.
|
||||||
|
</a>
|
||||||
|
</i>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const EnumsSection = ({ isEnum, toggleEnum, loading }) => {
|
||||||
|
let title;
|
||||||
|
if (loading) {
|
||||||
|
title = 'Please wait...';
|
||||||
|
}
|
||||||
|
|
||||||
|
const getCompatibilityNote = () => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<i>
|
||||||
|
* The table must meet some requirements for you to set it as an enum.{' '}
|
||||||
|
<a
|
||||||
|
href={enumCompatibilityDocsUrl}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
See requirements.
|
||||||
|
</a>
|
||||||
|
</i>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h4 className={`${styles.subheading_text}`}>Set table as enum</h4>
|
||||||
|
<div
|
||||||
|
className={`${styles.display_flex} ${styles.add_mar_bottom}`}
|
||||||
|
title={title}
|
||||||
|
data-toggle="tooltip"
|
||||||
|
>
|
||||||
|
<span className={styles.add_mar_right_mid}>
|
||||||
|
Expose the table values as GraphQL enums
|
||||||
|
</span>
|
||||||
|
<Toggle checked={isEnum} icons={false} onChange={toggleEnum} />
|
||||||
|
</div>
|
||||||
|
{getCompatibilityNote()}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EnumsSection;
|
@ -0,0 +1,32 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import ReloadEnumMetadata from '../../../Metadata/MetadataOptions/ReloadMetadata';
|
||||||
|
import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger';
|
||||||
|
import Tooltip from 'react-bootstrap/lib/Tooltip';
|
||||||
|
import styles from '../../../../Common/Common.scss';
|
||||||
|
|
||||||
|
const ReloadEnumValuesButton = ({ isEnum, dispatch, tooltipStyle }) => {
|
||||||
|
if (!isEnum) return null;
|
||||||
|
|
||||||
|
const tooltip = (
|
||||||
|
<Tooltip id="tooltip-reload-enum-metadata">
|
||||||
|
Reload enum values in your GraphQL schema after inserting, updating or
|
||||||
|
deleting enum values
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<ReloadEnumMetadata buttonText="Reload enum values" dispatch={dispatch} />
|
||||||
|
<OverlayTrigger overlay={tooltip} placement="right">
|
||||||
|
<i
|
||||||
|
className={`fa fa-info-circle ${
|
||||||
|
styles.cursorPointer
|
||||||
|
} ${tooltipStyle || ''}`}
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
|
</OverlayTrigger>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ReloadEnumValuesButton;
|
@ -90,6 +90,9 @@ const defaultModifyState = {
|
|||||||
rel: null,
|
rel: null,
|
||||||
perm: '',
|
perm: '',
|
||||||
},
|
},
|
||||||
|
tableEnum: {
|
||||||
|
loading: false
|
||||||
|
},
|
||||||
columnEdit: {},
|
columnEdit: {},
|
||||||
pkEdit: [''],
|
pkEdit: [''],
|
||||||
pkModify: [''],
|
pkModify: [''],
|
||||||
|
@ -8,6 +8,8 @@ import JsonInput from '../../../Common/CustomInputTypes/JsonInput';
|
|||||||
import TextInput from '../../../Common/CustomInputTypes/TextInput';
|
import TextInput from '../../../Common/CustomInputTypes/TextInput';
|
||||||
import Button from '../../../Common/Button/Button';
|
import Button from '../../../Common/Button/Button';
|
||||||
|
|
||||||
|
import ReloadEnumValuesButton from '../Common/ReusableComponents/ReloadEnumValuesButton';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getPlaceholder,
|
getPlaceholder,
|
||||||
INTEGER,
|
INTEGER,
|
||||||
@ -69,9 +71,12 @@ class EditItem extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const styles = require('../../../Common/TableCommon/Table.scss');
|
const styles = require('../../../Common/TableCommon/Table.scss');
|
||||||
const columns = schemas.find(
|
|
||||||
|
const currentTable = schemas.find(
|
||||||
x => x.table_name === tableName && x.table_schema === currentSchema
|
x => x.table_name === tableName && x.table_schema === currentSchema
|
||||||
).columns;
|
);
|
||||||
|
|
||||||
|
const columns = currentTable.columns;
|
||||||
|
|
||||||
const refs = {};
|
const refs = {};
|
||||||
const elements = columns.map((col, i) => {
|
const elements = columns.map((col, i) => {
|
||||||
@ -246,6 +251,10 @@ class EditItem extends Component {
|
|||||||
>
|
>
|
||||||
{buttonText}
|
{buttonText}
|
||||||
</Button>
|
</Button>
|
||||||
|
<ReloadEnumValuesButton
|
||||||
|
dispatch={dispatch}
|
||||||
|
isEnum={currentTable.is_enum}
|
||||||
|
/>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-xs-3">{alert}</div>
|
<div className="col-xs-3">{alert}</div>
|
||||||
|
@ -23,6 +23,7 @@ import {
|
|||||||
} from './FilterActions.js';
|
} from './FilterActions.js';
|
||||||
import { setDefaultQuery, runQuery, setOffset } from './FilterActions';
|
import { setDefaultQuery, runQuery, setOffset } from './FilterActions';
|
||||||
import Button from '../../../Common/Button/Button';
|
import Button from '../../../Common/Button/Button';
|
||||||
|
import ReloadEnumValuesButton from '../Common/ReusableComponents/ReloadEnumValuesButton';
|
||||||
|
|
||||||
const renderCols = (colName, tableSchema, onChange, usage, key) => {
|
const renderCols = (colName, tableSchema, onChange, usage, key) => {
|
||||||
const columns = tableSchema.columns.map(c => c.column_name);
|
const columns = tableSchema.columns.map(c => c.column_name);
|
||||||
@ -176,6 +177,7 @@ class FilterQuery extends Component {
|
|||||||
render() {
|
render() {
|
||||||
const { dispatch, whereAnd, tableSchema, orderBy } = this.props; // eslint-disable-line no-unused-vars
|
const { dispatch, whereAnd, tableSchema, orderBy } = this.props; // eslint-disable-line no-unused-vars
|
||||||
const styles = require('../../../Common/FilterQuery/FilterQuery.scss');
|
const styles = require('../../../Common/FilterQuery/FilterQuery.scss');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.add_mar_top}>
|
<div className={styles.add_mar_top}>
|
||||||
<form
|
<form
|
||||||
@ -209,9 +211,15 @@ class FilterQuery extends Component {
|
|||||||
color="yellow"
|
color="yellow"
|
||||||
size="sm"
|
size="sm"
|
||||||
data-test="run-query"
|
data-test="run-query"
|
||||||
|
className={styles.add_mar_right}
|
||||||
>
|
>
|
||||||
Run query
|
Run query
|
||||||
</Button>
|
</Button>
|
||||||
|
<ReloadEnumValuesButton
|
||||||
|
dispatch={dispatch}
|
||||||
|
isEnum={tableSchema.is_enum}
|
||||||
|
tooltipStyle={styles.add_mar_left_mid}
|
||||||
|
/>
|
||||||
{/* <div className={styles.count + ' alert alert-info'}><i>Total <b>{tableName}</b> rows in the database for current query: {count} </i></div> */}
|
{/* <div className={styles.count + ' alert alert-info'}><i>Total <b>{tableName}</b> rows in the database for current query: {count} </i></div> */}
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
@ -22,6 +22,9 @@ import {
|
|||||||
FETCH_COLUMN_TYPE_CASTS_FAIL,
|
FETCH_COLUMN_TYPE_CASTS_FAIL,
|
||||||
RESET,
|
RESET,
|
||||||
SET_UNIQUE_KEYS,
|
SET_UNIQUE_KEYS,
|
||||||
|
TOGGLE_ENUM,
|
||||||
|
TOGGLE_ENUM_SUCCESS,
|
||||||
|
TOGGLE_ENUM_FAILURE,
|
||||||
} from '../TableModify/ModifyActions';
|
} from '../TableModify/ModifyActions';
|
||||||
|
|
||||||
// TABLE RELATIONSHIPS
|
// TABLE RELATIONSHIPS
|
||||||
@ -586,6 +589,28 @@ const modifyReducer = (tableName, schemas, modifyStateOrig, action) => {
|
|||||||
...modifyState,
|
...modifyState,
|
||||||
uniqueKeyModify: action.keys,
|
uniqueKeyModify: action.keys,
|
||||||
};
|
};
|
||||||
|
case TOGGLE_ENUM:
|
||||||
|
return {
|
||||||
|
...modifyState,
|
||||||
|
tableEnum: {
|
||||||
|
loading: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
case TOGGLE_ENUM_FAILURE:
|
||||||
|
return {
|
||||||
|
...modifyState,
|
||||||
|
tableEnum: {
|
||||||
|
loading: false,
|
||||||
|
error: action.error,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
case TOGGLE_ENUM_SUCCESS:
|
||||||
|
return {
|
||||||
|
...modifyState,
|
||||||
|
tableEnum: {
|
||||||
|
loading: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
default:
|
default:
|
||||||
return modifyState;
|
return modifyState;
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import { setTable } from '../DataActions';
|
|||||||
import JsonInput from '../../../Common/CustomInputTypes/JsonInput';
|
import JsonInput from '../../../Common/CustomInputTypes/JsonInput';
|
||||||
import TextInput from '../../../Common/CustomInputTypes/TextInput';
|
import TextInput from '../../../Common/CustomInputTypes/TextInput';
|
||||||
import Button from '../../../Common/Button/Button';
|
import Button from '../../../Common/Button/Button';
|
||||||
|
import ReloadEnumValuesButton from '../Common/ReusableComponents/ReloadEnumValuesButton';
|
||||||
import { getPlaceholder, BOOLEAN, JSONB, JSONDTYPE, TEXT } from '../utils';
|
import { getPlaceholder, BOOLEAN, JSONB, JSONDTYPE, TEXT } from '../utils';
|
||||||
|
|
||||||
import { NotFoundError } from '../../../Error/PageNotFound';
|
import { NotFoundError } from '../../../Error/PageNotFound';
|
||||||
@ -325,6 +326,10 @@ class InsertItem extends Component {
|
|||||||
>
|
>
|
||||||
Clear
|
Clear
|
||||||
</Button>
|
</Button>
|
||||||
|
<ReloadEnumValuesButton
|
||||||
|
dispatch={dispatch}
|
||||||
|
isEnum={currentTable.is_enum}
|
||||||
|
/>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-xs-3">{alert}</div>
|
<div className="col-xs-3">{alert}</div>
|
||||||
|
@ -65,9 +65,20 @@ const FETCH_COLUMN_TYPE_CASTS_FAIL = 'ModifyTable/FETCH_COLUMN_TYPE_CASTS_FAIL';
|
|||||||
const SET_UNIQUE_KEYS = 'ModifyTable/SET_UNIQUE_KEYS';
|
const SET_UNIQUE_KEYS = 'ModifyTable/SET_UNIQUE_KEYS';
|
||||||
const SAVE_UNIQUE_KEY = 'ModifyTable/SAVE_UNIQUE_KEY';
|
const SAVE_UNIQUE_KEY = 'ModifyTable/SAVE_UNIQUE_KEY';
|
||||||
const REMOVE_UNIQUE_KEY = 'ModifyTable/REMOVE_UNIQUE_KEY';
|
const REMOVE_UNIQUE_KEY = 'ModifyTable/REMOVE_UNIQUE_KEY';
|
||||||
|
const TOGGLE_ENUM = 'ModifyTable/TOGGLE_ENUM';
|
||||||
|
const TOGGLE_ENUM_SUCCESS = 'ModifyTable/TOGGLE_ENUM_SUCCESS';
|
||||||
|
const TOGGLE_ENUM_FAILURE = 'ModifyTable/TOGGLE_ENUM_FAILURE';
|
||||||
|
|
||||||
const RESET = 'ModifyTable/RESET';
|
const RESET = 'ModifyTable/RESET';
|
||||||
|
|
||||||
|
const toggleEnumSuccess = () => ({
|
||||||
|
type: TOGGLE_ENUM_SUCCESS,
|
||||||
|
});
|
||||||
|
|
||||||
|
const toggleEnumFailure = () => ({
|
||||||
|
type: TOGGLE_ENUM_FAILURE,
|
||||||
|
});
|
||||||
|
|
||||||
const setForeignKeys = fks => ({
|
const setForeignKeys = fks => ({
|
||||||
type: SET_FOREIGN_KEYS,
|
type: SET_FOREIGN_KEYS,
|
||||||
fks,
|
fks,
|
||||||
@ -319,14 +330,14 @@ const saveForeignKeys = (index, tableSchema, columns) => {
|
|||||||
alter table "${schemaName}"."${tableName}" drop constraint "${generatedConstraintName}",
|
alter table "${schemaName}"."${tableName}" drop constraint "${generatedConstraintName}",
|
||||||
add constraint "${constraintName}"
|
add constraint "${constraintName}"
|
||||||
foreign key (${Object.keys(oldConstraint.column_mapping)
|
foreign key (${Object.keys(oldConstraint.column_mapping)
|
||||||
.map(lc => `"${lc}"`)
|
.map(lc => `"${lc}"`)
|
||||||
.join(', ')})
|
.join(', ')})
|
||||||
references "${oldConstraint.ref_table_table_schema}"."${
|
references "${oldConstraint.ref_table_table_schema}"."${
|
||||||
oldConstraint.ref_table
|
oldConstraint.ref_table
|
||||||
}"
|
}"
|
||||||
(${Object.values(oldConstraint.column_mapping)
|
(${Object.values(oldConstraint.column_mapping)
|
||||||
.map(rc => `"${rc}"`)
|
.map(rc => `"${rc}"`)
|
||||||
.join(', ')})
|
.join(', ')})
|
||||||
on update ${pgConfTypes[oldConstraint.on_update]}
|
on update ${pgConfTypes[oldConstraint.on_update]}
|
||||||
on delete ${pgConfTypes[oldConstraint.on_delete]};
|
on delete ${pgConfTypes[oldConstraint.on_delete]};
|
||||||
`;
|
`;
|
||||||
@ -584,8 +595,8 @@ const deleteTrigger = (trigger, table) => {
|
|||||||
|
|
||||||
downMigrationSql += `CREATE TRIGGER "${triggerName}"
|
downMigrationSql += `CREATE TRIGGER "${triggerName}"
|
||||||
${trigger.action_timing} ${
|
${trigger.action_timing} ${
|
||||||
trigger.event_manipulation
|
trigger.event_manipulation
|
||||||
} ON "${tableSchema}"."${tableName}"
|
} ON "${tableSchema}"."${tableName}"
|
||||||
FOR EACH ${trigger.action_orientation} ${trigger.action_statement};`;
|
FOR EACH ${trigger.action_orientation} ${trigger.action_statement};`;
|
||||||
|
|
||||||
if (trigger.comment) {
|
if (trigger.comment) {
|
||||||
@ -1446,24 +1457,24 @@ const saveColumnChangesSql = (colName, column, onSuccess) => {
|
|||||||
const schemaChangesUp =
|
const schemaChangesUp =
|
||||||
originalColType !== colType
|
originalColType !== colType
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
type: 'run_sql',
|
type: 'run_sql',
|
||||||
args: {
|
args: {
|
||||||
sql: columnChangesUpQuery,
|
sql: columnChangesUpQuery,
|
||||||
},
|
|
||||||
},
|
},
|
||||||
]
|
},
|
||||||
|
]
|
||||||
: [];
|
: [];
|
||||||
const schemaChangesDown =
|
const schemaChangesDown =
|
||||||
originalColType !== colType
|
originalColType !== colType
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
type: 'run_sql',
|
type: 'run_sql',
|
||||||
args: {
|
args: {
|
||||||
sql: columnChangesDownQuery,
|
sql: columnChangesDownQuery,
|
||||||
},
|
|
||||||
},
|
},
|
||||||
]
|
},
|
||||||
|
]
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
/* column default up/down migration */
|
/* column default up/down migration */
|
||||||
@ -2055,6 +2066,96 @@ const removeUniqueKey = (index, tableName, existingConstraints, callback) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const toggleTableAsEnum = (isEnum, successCallback, failureCallback) => (
|
||||||
|
dispatch,
|
||||||
|
getState
|
||||||
|
) => {
|
||||||
|
const isOk = window.confirm(
|
||||||
|
`Are you sure you want to ${isEnum ? 'un' : ''}set this table as an enum?`
|
||||||
|
);
|
||||||
|
if (!isOk) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch({ type: TOGGLE_ENUM });
|
||||||
|
|
||||||
|
const { currentTable, currentSchema } = getState().tables;
|
||||||
|
const { allSchemas } = getState().tables;
|
||||||
|
|
||||||
|
const getEnumQuery = is_enum => ({
|
||||||
|
type: 'set_table_is_enum',
|
||||||
|
args: {
|
||||||
|
table: {
|
||||||
|
schema: currentSchema,
|
||||||
|
name: currentTable,
|
||||||
|
},
|
||||||
|
is_enum,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const upQuery = [getEnumQuery(!isEnum)];
|
||||||
|
const downQuery = [getEnumQuery(isEnum)];
|
||||||
|
|
||||||
|
const migrationName =
|
||||||
|
'alter_table_' +
|
||||||
|
currentSchema +
|
||||||
|
'_' +
|
||||||
|
currentTable +
|
||||||
|
'_set_enum_' +
|
||||||
|
!isEnum;
|
||||||
|
|
||||||
|
const action = !isEnum ? 'Setting' : 'Unsetting';
|
||||||
|
|
||||||
|
const requestMsg = `${action} table as enum...`;
|
||||||
|
const successMsg = `${action} table as enum successful`;
|
||||||
|
const errorMsg = `${action} table as enum failed`;
|
||||||
|
|
||||||
|
const customOnSuccess = () => {
|
||||||
|
// success callback
|
||||||
|
if (successCallback) {
|
||||||
|
successCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(toggleEnumSuccess());
|
||||||
|
|
||||||
|
const newAllSchemas = allSchemas.map(schema => {
|
||||||
|
if (
|
||||||
|
schema.table_name === currentTable &&
|
||||||
|
schema.table_schema === currentSchema
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
...schema,
|
||||||
|
is_enum: !isEnum,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return schema;
|
||||||
|
});
|
||||||
|
|
||||||
|
dispatch({ type: LOAD_SCHEMA, allSchemas: newAllSchemas });
|
||||||
|
};
|
||||||
|
|
||||||
|
const customOnError = () => {
|
||||||
|
dispatch(toggleEnumFailure());
|
||||||
|
|
||||||
|
if (failureCallback) {
|
||||||
|
failureCallback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
makeMigrationCall(
|
||||||
|
dispatch,
|
||||||
|
getState,
|
||||||
|
upQuery,
|
||||||
|
downQuery,
|
||||||
|
migrationName,
|
||||||
|
customOnSuccess,
|
||||||
|
customOnError,
|
||||||
|
requestMsg,
|
||||||
|
successMsg,
|
||||||
|
errorMsg
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const saveUniqueKey = (
|
const saveUniqueKey = (
|
||||||
index,
|
index,
|
||||||
tableName,
|
tableName,
|
||||||
@ -2181,6 +2282,9 @@ export {
|
|||||||
SET_FOREIGN_KEYS,
|
SET_FOREIGN_KEYS,
|
||||||
RESET,
|
RESET,
|
||||||
SET_UNIQUE_KEYS,
|
SET_UNIQUE_KEYS,
|
||||||
|
TOGGLE_ENUM,
|
||||||
|
TOGGLE_ENUM_SUCCESS,
|
||||||
|
TOGGLE_ENUM_FAILURE,
|
||||||
changeTableOrViewName,
|
changeTableOrViewName,
|
||||||
fetchViewDefinition,
|
fetchViewDefinition,
|
||||||
handleMigrationErrors,
|
handleMigrationErrors,
|
||||||
@ -2211,4 +2315,6 @@ export {
|
|||||||
removeUniqueKey,
|
removeUniqueKey,
|
||||||
saveUniqueKey,
|
saveUniqueKey,
|
||||||
deleteTrigger,
|
deleteTrigger,
|
||||||
|
toggleEnumSuccess,
|
||||||
|
toggleEnumFailure,
|
||||||
};
|
};
|
||||||
|
@ -4,11 +4,15 @@ import TableHeader from '../TableCommon/TableHeader';
|
|||||||
|
|
||||||
import { getAllDataTypeMap } from '../Common/utils';
|
import { getAllDataTypeMap } from '../Common/utils';
|
||||||
|
|
||||||
|
import { TABLE_ENUMS_SUPPORT } from '../../../../helpers/versionUtils';
|
||||||
|
import globals from '../../../../Globals';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
deleteTableSql,
|
deleteTableSql,
|
||||||
untrackTableSql,
|
untrackTableSql,
|
||||||
RESET,
|
RESET,
|
||||||
setUniqueKeys,
|
setUniqueKeys,
|
||||||
|
toggleTableAsEnum,
|
||||||
} from '../TableModify/ModifyActions';
|
} from '../TableModify/ModifyActions';
|
||||||
import {
|
import {
|
||||||
setTable,
|
setTable,
|
||||||
@ -20,6 +24,9 @@ import ColumnEditorList from './ColumnEditorList';
|
|||||||
import ColumnCreator from './ColumnCreator';
|
import ColumnCreator from './ColumnCreator';
|
||||||
import PrimaryKeyEditor from './PrimaryKeyEditor';
|
import PrimaryKeyEditor from './PrimaryKeyEditor';
|
||||||
import TableCommentEditor from './TableCommentEditor';
|
import TableCommentEditor from './TableCommentEditor';
|
||||||
|
import EnumsSection, {
|
||||||
|
EnumTableModifyWarning,
|
||||||
|
} from '../Common/ReusableComponents/EnumsSection';
|
||||||
import ForeignKeyEditor from './ForeignKeyEditor';
|
import ForeignKeyEditor from './ForeignKeyEditor';
|
||||||
import UniqueKeyEditor from './UniqueKeyEditor';
|
import UniqueKeyEditor from './UniqueKeyEditor';
|
||||||
import TriggerEditorList from './TriggerEditorList';
|
import TriggerEditorList from './TriggerEditorList';
|
||||||
@ -54,6 +61,7 @@ class ModifyTable extends React.Component {
|
|||||||
uniqueKeyModify,
|
uniqueKeyModify,
|
||||||
columnDefaultFunctions,
|
columnDefaultFunctions,
|
||||||
schemaList,
|
schemaList,
|
||||||
|
tableEnum,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const dataTypeIndexMap = getAllDataTypeMap(dataTypes);
|
const dataTypeIndexMap = getAllDataTypeMap(dataTypes);
|
||||||
@ -74,7 +82,7 @@ class ModifyTable extends React.Component {
|
|||||||
color="white"
|
color="white"
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const isOk = confirm('Are you sure to untrack?');
|
const isOk = confirm('Are you sure?');
|
||||||
if (isOk) {
|
if (isOk) {
|
||||||
dispatch(untrackTableSql(tableName));
|
dispatch(untrackTableSql(tableName));
|
||||||
}
|
}
|
||||||
@ -102,6 +110,26 @@ class ModifyTable extends React.Component {
|
|||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const getEnumsSection = () => {
|
||||||
|
const supportEnums =
|
||||||
|
globals.featuresCompatibility &&
|
||||||
|
globals.featuresCompatibility[TABLE_ENUMS_SUPPORT];
|
||||||
|
if (!supportEnums) return null;
|
||||||
|
|
||||||
|
const toggleEnum = () => dispatch(toggleTableAsEnum(tableSchema.is_enum));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<EnumsSection
|
||||||
|
isEnum={tableSchema.is_enum}
|
||||||
|
toggleEnum={toggleEnum}
|
||||||
|
loading={tableEnum.loading}
|
||||||
|
/>
|
||||||
|
<hr />
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
// if (tableSchema.primary_key.columns > 0) {}
|
// if (tableSchema.primary_key.columns > 0) {}
|
||||||
return (
|
return (
|
||||||
<div className={`${styles.container} container-fluid`}>
|
<div className={`${styles.container} container-fluid`}>
|
||||||
@ -127,6 +155,7 @@ class ModifyTable extends React.Component {
|
|||||||
isTable
|
isTable
|
||||||
dispatch={dispatch}
|
dispatch={dispatch}
|
||||||
/>
|
/>
|
||||||
|
<EnumTableModifyWarning isEnum={tableSchema.is_enum} />
|
||||||
<h4 className={styles.subheading_text}>Columns</h4>
|
<h4 className={styles.subheading_text}>Columns</h4>
|
||||||
<ColumnEditorList
|
<ColumnEditorList
|
||||||
validTypeCasts={validTypeCasts}
|
validTypeCasts={validTypeCasts}
|
||||||
@ -178,6 +207,7 @@ class ModifyTable extends React.Component {
|
|||||||
<h4 className={styles.subheading_text}>Triggers</h4>
|
<h4 className={styles.subheading_text}>Triggers</h4>
|
||||||
<TriggerEditorList tableSchema={tableSchema} dispatch={dispatch} />
|
<TriggerEditorList tableSchema={tableSchema} dispatch={dispatch} />
|
||||||
<hr />
|
<hr />
|
||||||
|
{getEnumsSection()}
|
||||||
{untrackBtn}
|
{untrackBtn}
|
||||||
{deleteBtn}
|
{deleteBtn}
|
||||||
<br />
|
<br />
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
import globals from '../../../Globals';
|
||||||
|
import { TABLE_ENUMS_SUPPORT } from '../../../helpers/versionUtils';
|
||||||
|
|
||||||
export const INTEGER = 'integer';
|
export const INTEGER = 'integer';
|
||||||
export const SERIAL = 'serial';
|
export const SERIAL = 'serial';
|
||||||
export const BIGINT = 'bigint';
|
export const BIGINT = 'bigint';
|
||||||
@ -228,6 +231,14 @@ export const fetchTrackedTableListQuery = options => {
|
|||||||
order_by: [{ column: 'table_name', type: 'asc' }],
|
order_by: [{ column: 'table_name', type: 'asc' }],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const supportEnums =
|
||||||
|
globals.featuresCompatibility &&
|
||||||
|
globals.featuresCompatibility[TABLE_ENUMS_SUPPORT];
|
||||||
|
if (supportEnums) {
|
||||||
|
query.args.columns.push('is_enum');
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(options.schemas && options.schemas.length !== 0) ||
|
(options.schemas && options.schemas.length !== 0) ||
|
||||||
(options.tables && options.tables.length !== 0)
|
(options.tables && options.tables.length !== 0)
|
||||||
@ -468,12 +479,14 @@ export const mergeLoadSchemaData = (
|
|||||||
let _uniqueConstraints = [];
|
let _uniqueConstraints = [];
|
||||||
let _fkConstraints = [];
|
let _fkConstraints = [];
|
||||||
let _refFkConstraints = [];
|
let _refFkConstraints = [];
|
||||||
|
let _isEnum = false;
|
||||||
|
|
||||||
if (_isTableTracked) {
|
if (_isTableTracked) {
|
||||||
_primaryKey = trackedTableInfo.primary_key;
|
_primaryKey = trackedTableInfo.primary_key;
|
||||||
_relationships = trackedTableInfo.relationships;
|
_relationships = trackedTableInfo.relationships;
|
||||||
_permissions = trackedTableInfo.permissions;
|
_permissions = trackedTableInfo.permissions;
|
||||||
_uniqueConstraints = trackedTableInfo.unique_constraints;
|
_uniqueConstraints = trackedTableInfo.unique_constraints;
|
||||||
|
_isEnum = trackedTableInfo.is_enum;
|
||||||
|
|
||||||
_fkConstraints = fkData.filter(
|
_fkConstraints = fkData.filter(
|
||||||
fk => fk.table_schema === _tableSchema && fk.table_name === _tableName
|
fk => fk.table_schema === _tableSchema && fk.table_name === _tableName
|
||||||
@ -501,6 +514,7 @@ export const mergeLoadSchemaData = (
|
|||||||
foreign_key_constraints: _fkConstraints,
|
foreign_key_constraints: _fkConstraints,
|
||||||
opp_foreign_key_constraints: _refFkConstraints,
|
opp_foreign_key_constraints: _refFkConstraints,
|
||||||
view_info: _viewInfo,
|
view_info: _viewInfo,
|
||||||
|
is_enum: _isEnum,
|
||||||
};
|
};
|
||||||
|
|
||||||
_mergedTableData.push(_mergedInfo);
|
_mergedTableData.push(_mergedInfo);
|
||||||
|
@ -11,15 +11,23 @@ import {
|
|||||||
class ReloadMetadata extends Component {
|
class ReloadMetadata extends Component {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.state = {};
|
|
||||||
this.state.isReloading = false;
|
this.state = {
|
||||||
|
isReloading: false,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { dispatch } = this.props;
|
const { dispatch } = this.props;
|
||||||
const { isReloading } = this.state;
|
const { isReloading } = this.state;
|
||||||
|
|
||||||
const metaDataStyles = require('../Metadata.scss');
|
const metaDataStyles = require('../Metadata.scss');
|
||||||
const reloadMetadataAndLoadInconsistentMetadata = () => {
|
|
||||||
|
const reloadMetadataAndLoadInconsistentMetadata = e => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
this.setState({ isReloading: true });
|
this.setState({ isReloading: true });
|
||||||
|
|
||||||
dispatch(
|
dispatch(
|
||||||
reloadMetadata(
|
reloadMetadata(
|
||||||
() => {
|
() => {
|
||||||
@ -42,9 +50,10 @@ class ReloadMetadata extends Component {
|
|||||||
data-test="data-reload-metadata"
|
data-test="data-reload-metadata"
|
||||||
color="white"
|
color="white"
|
||||||
size="sm"
|
size="sm"
|
||||||
|
disabled={this.state.isReloading}
|
||||||
onClick={reloadMetadataAndLoadInconsistentMetadata}
|
onClick={reloadMetadataAndLoadInconsistentMetadata}
|
||||||
>
|
>
|
||||||
{buttonText}
|
{this.props.buttonText || buttonText}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -53,7 +62,7 @@ class ReloadMetadata extends Component {
|
|||||||
|
|
||||||
ReloadMetadata.propTypes = {
|
ReloadMetadata.propTypes = {
|
||||||
dispatch: PropTypes.func.isRequired,
|
dispatch: PropTypes.func.isRequired,
|
||||||
dataHeaders: PropTypes.object.isRequired,
|
buttonText: PropTypes.string,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ReloadMetadata;
|
export default ReloadMetadata;
|
||||||
|
@ -4,6 +4,7 @@ export const FT_JWT_ANALYZER = 'JWTAnalyzer';
|
|||||||
export const RELOAD_METADATA_API_CHANGE = 'reloadMetaDataApiChange';
|
export const RELOAD_METADATA_API_CHANGE = 'reloadMetaDataApiChange';
|
||||||
export const REMOTE_SCHEMA_TIMEOUT_CONF_SUPPORT =
|
export const REMOTE_SCHEMA_TIMEOUT_CONF_SUPPORT =
|
||||||
'remoteSchemaTimeoutConfSupport';
|
'remoteSchemaTimeoutConfSupport';
|
||||||
|
export const TABLE_ENUMS_SUPPORT = 'tableEnumsSupport';
|
||||||
|
|
||||||
// list of feature launch versions
|
// list of feature launch versions
|
||||||
const featureLaunchVersions = {
|
const featureLaunchVersions = {
|
||||||
@ -11,6 +12,7 @@ const featureLaunchVersions = {
|
|||||||
[RELOAD_METADATA_API_CHANGE]: 'v1.0.0-beta.3',
|
[RELOAD_METADATA_API_CHANGE]: 'v1.0.0-beta.3',
|
||||||
[FT_JWT_ANALYZER]: 'v1.0.0-beta.3',
|
[FT_JWT_ANALYZER]: 'v1.0.0-beta.3',
|
||||||
[REMOTE_SCHEMA_TIMEOUT_CONF_SUPPORT]: 'v1.0.0-beta.5',
|
[REMOTE_SCHEMA_TIMEOUT_CONF_SUPPORT]: 'v1.0.0-beta.5',
|
||||||
|
[TABLE_ENUMS_SUPPORT]: 'v1.0.0-beta.6'
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getFeaturesCompatibility = serverVersion => {
|
export const getFeaturesCompatibility = serverVersion => {
|
||||||
|
Loading…
Reference in New Issue
Block a user