diff --git a/CHANGELOG.md b/CHANGELOG.md index 838e6320e59..902e45537a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,7 +25,6 @@ ### Other changes -- console: disable editing action relationships - cli: fix typo in cli example for squash (fix #4047) (#4049) - console: fix run_sql migration modal messaging (close #4020) (#4060) - docs: add note on pg versions for actions (#4034) diff --git a/console/src/components/Services/Actions/Relationships/Components/TypeRelationship.js b/console/src/components/Services/Actions/Relationships/Components/TypeRelationship.js index 70331a77228..562e0e8e32c 100644 --- a/console/src/components/Services/Actions/Relationships/Components/TypeRelationship.js +++ b/console/src/components/Services/Actions/Relationships/Components/TypeRelationship.js @@ -138,7 +138,6 @@ const RelationshipEditor = ({ className={`${styles.select} form-control ${styles.add_pad_left}`} placeholder="Enter relationship name" data-test="rel-name" - disabled={isDisabled} title={relNameInputTitle} value={name} /> @@ -371,7 +370,7 @@ const RelationshipEditor = ({ }; const RelEditor = props => { - const { dispatch, relConfig, objectType } = props; + const { dispatch, relConfig, objectType, isNew } = props; const [relConfigState, setRelConfigState] = React.useState(null); @@ -382,7 +381,7 @@ const RelEditor = props => {
{relConfig.name}
- {getRelDef(relConfig)} + {getRelDef({ ...relConfig, typename: objectType.name })}
); @@ -418,20 +417,24 @@ const RelEditor = props => { ); } dispatch( - addActionRel({ ...relConfigState, typename: objectType.name }, toggle) + addActionRel( + { ...relConfigState, typename: objectType.name }, + toggle, + isNew ? null : relConfig + ) ); }; // function to remove the relationship let removeFunc; - if (relConfig) { + if (!isNew) { removeFunc = toggle => { dispatch(removeActionRel(relConfig.name, objectType.name, toggle)); }; } - const expandButtonText = relConfig ? 'Edit' : 'Add a relationship'; - const collapseButtonText = relConfig ? 'Close' : 'Cancel'; + const expandButtonText = isNew ? 'Add a relationship' : 'Edit'; + const collapseButtonText = isNew ? 'Cancel' : 'Close'; return ( ); diff --git a/console/src/components/Services/Actions/Relationships/utils.js b/console/src/components/Services/Actions/Relationships/utils.js index 98ffc3fd1f6..1533b6669eb 100644 --- a/console/src/components/Services/Actions/Relationships/utils.js +++ b/console/src/components/Services/Actions/Relationships/utils.js @@ -76,7 +76,7 @@ export const getRelDef = relMeta => { ? `${relMeta.remote_table.schema}.${relMeta.remote_table.name}` : relMeta.remote_table; - return `${lcol} → ${tableLabel} . ${rcol}`; + return `${relMeta.typename} . ${lcol} → ${tableLabel} . ${rcol}`; }; export const removeTypeRelationship = (types, typename, relName) => { @@ -90,3 +90,15 @@ export const removeTypeRelationship = (types, typename, relName) => { return t; }); }; + +export const validateRelTypename = (types, typename, relname) => { + for (let i = types.length - 1; i >= 0; i--) { + const type = types[i]; + if (type.kind === 'object' && type.name === typename) { + if ((type.relationships || []).some(r => r.name === relname)) { + return `Relationship with name "${relname}" already exists.`; + } + } + } + return null; +}; diff --git a/console/src/components/Services/Actions/ServerIO.js b/console/src/components/Services/Actions/ServerIO.js index a6f44fdaa88..f50ad0acf74 100644 --- a/console/src/components/Services/Actions/ServerIO.js +++ b/console/src/components/Services/Actions/ServerIO.js @@ -22,6 +22,7 @@ import { import { injectTypeRelationship, removeTypeRelationship, + validateRelTypename, } from './Relationships/utils'; import { getConfirmation } from '../../Common/utils/jsUtils'; import { @@ -406,11 +407,52 @@ export const deleteAction = currentAction => (dispatch, getState) => { ); }; -export const addActionRel = (relConfig, successCb) => (dispatch, getState) => { +export const addActionRel = (relConfig, successCb, existingRelConfig) => ( + dispatch, + getState +) => { const { types: existingTypes } = getState().types; - const typesWithRels = injectTypeRelationship( - existingTypes, + let typesWithRels = [...existingTypes]; + + let validationError; + + if (existingRelConfig) { + // modifying existing relationship + // if the relationship is being renamed + if (existingRelConfig.name !== relConfig.name) { + // validate the new name + validationError = validateRelTypename( + existingTypes, + relConfig.typename, + relConfig.name + ); + // remove old relationship from types + typesWithRels = removeTypeRelationship( + existingTypes, + relConfig.typename, + existingRelConfig.name + ); + } + } else { + // creating a new relationship + + // validate the relationship name + validationError = validateRelTypename( + existingTypes, + relConfig.typename, + relConfig.name + ); + } + + const errorMsg = 'Saving relationship failed'; + if (validationError) { + return dispatch(showErrorNotification(errorMsg, validationError)); + } + + // add modified relationship to types + typesWithRels = injectTypeRelationship( + typesWithRels, relConfig.typename, relConfig ); @@ -426,10 +468,9 @@ export const addActionRel = (relConfig, successCb) => (dispatch, getState) => { const upQueries = [customTypesQueryUp]; const downQueries = [customTypesQueryDown]; - const migrationName = 'add_action_rel'; // TODO: better migration name - const requestMsg = 'Adding relationship...'; - const successMsg = 'Relationship added successfully'; - const errorMsg = 'Adding relationship failed'; + const migrationName = `save_rel_${relConfig.name}_on_${relConfig.typename}`; + const requestMsg = 'Saving relationship...'; + const successMsg = 'Relationship saved successfully'; const customOnSuccess = () => { // dispatch(createActionRequestComplete()); dispatch(fetchCustomTypes());