Skip to content

Commit 9d0a4ff

Browse files
Merge pull request #25 from DhiWise/feature/model-save-warning
fix(model data save warning): when model data change and change the m…
2 parents 6949d44 + 98a7e54 commit 9d0a4ff

9 files changed

Lines changed: 116 additions & 29 deletions

File tree

packages/client/src/container/CRUD/Modal/DeleteModel.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const DeleteModel = React.memo(({ currentId, className, isDeleteWhiteIcon }) =>
1414
const [visibleDelete, setVisibleDelete, hideVisibleDelete] = useBoolean(false);
1515
const [deleteLoader, setDeleteLoader, hideDeleteLoader] = useBoolean(false);
1616
const { addErrorToast, addSuccessToast } = useToastNotifications();
17-
const { setModelErrors } = useModel();
17+
const { setModelErrors, setNoChangeInTable } = useModel();
1818
const modelList = useSelector((state) => state.models.modelList);
1919
const currentApplicationCode = useSelector(({ projects }) => (projects.currentApplicationCode));
2020
const [delData, setDelData] = useState();
@@ -49,6 +49,7 @@ const DeleteModel = React.memo(({ currentId, className, isDeleteWhiteIcon }) =>
4949
addErrorToast(data.message);
5050
hideVisibleDelete();
5151
}
52+
setNoChangeInTable();
5253
// dispatch(deleteCurrentModel());
5354
}).catch((err) => {
5455
hideVisibleDelete();

packages/client/src/container/CRUD/Modal/Editor/ModelProvider.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
import React, { useState } from 'react';
22
import { flatten } from 'lodash';
3+
import { useBoolean } from '../../../../components/hooks';
34

45
export const ModelContext = React.createContext();
56

67
const ModelProvider = React.memo(({ children }) => {
78
const [modelErrors, setModelErrors] = useState();
89
const [modelErrCount, setModelErrCount] = useState(0);
910
const [isJsonError, setIsJsonError] = useState(false);
11+
const [isChangeInTable, setChangeInTable, setNoChangeInTable] = useBoolean(false);
12+
const changeNextEvent = React.useRef();
13+
const [isSaveWarning, setSaveWarning, hideSaveWarning] = useBoolean(false);
1014

1115
React.useEffect(() => {
1216
if (!modelErrors) return;
@@ -24,6 +28,16 @@ const ModelProvider = React.memo(({ children }) => {
2428
isError,
2529
isJsonError,
2630
setIsJsonError,
31+
setChangeInTable,
32+
setNoChangeInTable,
33+
isChangeInTable,
34+
setChangeNextEvent: (event) => {
35+
changeNextEvent.current = event;
36+
},
37+
changeNextEvent, // when model some changes and do next event for store that
38+
hideSaveWarning,
39+
setSaveWarning,
40+
isSaveWarning,
2741
};
2842
return <ModelContext.Provider value={value}>{children}</ModelContext.Provider>;
2943
});

packages/client/src/container/CRUD/Modal/Editor/TableView/AddRelation/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { Select } from '../../../../../../components';
66
import { RELATION_TYPE, SEQUELIZE_RELATION_TYPE } from '../../../../../../constant/model';
77
import { onSingleKeyDown } from '../../../../../../utils/domMethods';
88
import { useEditor } from '../../EditorProvider';
9+
import { useModel } from '../../ModelProvider';
910

1011
const FiledPosition = {
1112
model: 1,
@@ -28,6 +29,7 @@ export const AddRelation = React.memo(({
2829
const [foreignField, setForeignField] = React.useState(foreignKey);
2930
const [refAttribute, setRefAttribute] = React.useState();
3031
const [relType, setRelType] = React.useState(); // default "hasMany"
32+
const { setChangeInTable } = useModel();
3133

3234
React.useEffect(() => setRefAttribute(otherProps?.refAttribute), [otherProps?.refAttribute]);
3335
React.useEffect(() => setRelType(otherProps?.relType || RELATION_TYPE.HAS_MANY), [otherProps?.relType]);
@@ -113,6 +115,7 @@ export const AddRelation = React.memo(({
113115
if (fields?.length > 0) setForeignKeys(fields.map((x) => ({ id: x, name: x }))); // ff
114116
else setForeignKeys([]);
115117
}
118+
setChangeInTable();
116119
};
117120

118121
return (

packages/client/src/container/CRUD/Modal/Editor/TableView/TableData/TableRow.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import RowSuspense from './RowSuspense';
3232
import { modelAttrRegex } from '../../../../../../utils/regex';
3333
import { MAX_INPUT_FIELD_LIMIT } from '../../../../../../constant/common';
3434
import { ORM_TYPE } from '../../../../../../constant/Project/applicationStep';
35+
import { useModel } from '../../ModelProvider';
3536

3637
const TableSubRow = React.lazy(() => new Promise((resolve) => resolve(import('./TableSubRow'))));
3738

@@ -115,7 +116,7 @@ const TableRow = React.memo((props) => {
115116
} = useForm({
116117
shouldUnregister: false,
117118
});
118-
119+
const { setChangeInTable } = useModel();
119120
const disable = React.useMemo(() => getDisableField(watch('type'),
120121
{
121122
isAutoIncrement: watch('isAutoIncrement'), match: watch('match'), unique: watch('unique'), default: watch('default'), filter: watch('filter'),
@@ -192,6 +193,7 @@ const TableRow = React.memo((props) => {
192193
}
193194

194195
if (fieldValue !== row[fieldName]) {
196+
setChangeInTable();
195197
// on change only when value is updated
196198
setDependency(dependency.map((x) => {
197199
if (row[fieldName] === x.oldKey) {

packages/client/src/container/CRUD/Modal/Editor/TableView/TableData/TableSubRow.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { MAX_INPUT_FIELD_LIMIT } from '../../../../../../constant/common';
2323
import { modelAttrRegex } from '../../../../../../utils/regex';
2424
import { useEditor } from '../../EditorProvider';
2525
import { ORM_TYPE } from '../../../../../../constant/Project/applicationStep';
26+
import { useModel } from '../../ModelProvider';
2627

2728
const AllCheckBox = ({
2829
cname, onInputChange, watch, control, disable, onKeyDownHandle, id,
@@ -67,7 +68,7 @@ const TableSubRow = React.memo((props) => {
6768
const {
6869
dependency, setDependency, ormType,
6970
} = useEditor();
70-
71+
const { setChangeInTable } = useModel();
7172
const { TABLE_TYPES, TYPE_OPTIONS } = CONST_VARIABLE;
7273
const {
7374
getValues, control, errors, setValue, watch,
@@ -208,6 +209,10 @@ const TableSubRow = React.memo((props) => {
208209

209210
const onInputChange = React.useCallback((fieldName, value, focusId) => {
210211
if (['enum', 'isEnum'].includes(fieldName)) { setValue(fieldName, value); }
212+
if (value && value !== subRow[fieldName]) {
213+
setChangeInTable();
214+
}
215+
211216
if (fieldName === 'type' || fieldName === 'isEnum') {
212217
setValue('isAutoIncrement', undefined);
213218
setValue('default', undefined);

packages/client/src/container/CRUD/Modal/Editor/index.js

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import omitDeep from 'omit-deep-lodash';
1010
import { useHistory } from 'react-router';
1111
import { Icons } from '@dhiwise/icons';
1212
import {
13-
Button, MessageNotify, Error, Loader,
13+
Button, MessageNotify, Error, Loader, ConfirmationAlert,
1414
} from '../../../../components';
1515
import ModelHeader from './ModelHeader';
1616
import { updateModel } from '../../../../redux/reducers/models';
@@ -46,7 +46,7 @@ const ErrorNotify = () => (
4646

4747
const Editor = React.memo(({ currentId, saveRef, loaderRef }) => {
4848
const {
49-
modelErrors, modelErrCount, isError, setModelErrors, setIsJsonError,
49+
modelErrors, modelErrCount, isError, setModelErrors, setIsJsonError, setNoChangeInTable, isSaveWarning, hideSaveWarning, changeNextEvent,
5050
} = useModel();
5151
const history = useHistory();
5252
const { addErrorToast, addSuccessToast } = useToastNotifications();
@@ -67,6 +67,7 @@ const Editor = React.memo(({ currentId, saveRef, loaderRef }) => {
6767
const [jsonError, setJsonError] = useState(false);
6868
// const [showError, setShowError] = useBoolean(false);
6969
const [showError, setShowError, setHideError] = useBoolean(false);
70+
const [isSaveLoading, setSaveLoading, hideSaveLoading] = useBoolean(false); // for save warning popup loading
7071
// Remove
7172
// const [, setSaveLoader, hideSaveLoader] = useBoolean(false);
7273
// saveLoader,
@@ -264,13 +265,14 @@ const Editor = React.memo(({ currentId, saveRef, loaderRef }) => {
264265
}, []);
265266

266267
const saveJSON = React.useCallback(({
267-
showMsg, tCode, tcustomSetting, indexes, tHooks, msg, isRedirect = false, tDependency,
268+
isInSaveWarning = false, showMsg, tCode, tcustomSetting, indexes, tHooks, msg, isRedirect = false, tDependency,
268269
}) => {
269270
// Remove
270271
// isRedirect= if step remove ,remove await and async
271272
try {
272273
if (jsonError && !jsonError?.isCustom && !modelErrCount) {
273274
// if error then open error popup
275+
if (isInSaveWarning) hideSaveWarning();
274276
handleShowError();
275277
return;
276278
}
@@ -396,6 +398,7 @@ const Editor = React.memo(({ currentId, saveRef, loaderRef }) => {
396398
errorFlag = { name: 'Error', message: `${isDuplicateAttr}: ${ERROR_MSG.duplicateAttr}`, isCustom: true };
397399
}
398400
if (errorFlag) {
401+
if (isInSaveWarning) hideSaveWarning();
399402
setJsonError(errorFlag);
400403
return;
401404
}
@@ -510,12 +513,15 @@ const Editor = React.memo(({ currentId, saveRef, loaderRef }) => {
510513
});
511514
}
512515
if (errorFlag) {
516+
if (isInSaveWarning) hideSaveWarning();
513517
setJsonError(errorFlag);
514518
return;
515519
}
516520
// error handler, to read data we'll have to parse twice due to backslash escaping
517521
errorFlag = isCustomErr(schema, null, null, { customSetting });
518522
if (errorFlag) {
523+
if (isInSaveWarning) hideSaveWarning();
524+
519525
setJsonError(errorFlag);
520526
// setShowError();
521527
// hideSaveLoader();
@@ -616,7 +622,10 @@ const Editor = React.memo(({ currentId, saveRef, loaderRef }) => {
616622
if (showError) setHideError();
617623

618624
// loaderCallBack({ isHidePopup: false });
619-
loaderRef.current.setLoader();
625+
if (isInSaveWarning) { setSaveLoading(); } else {
626+
loaderRef.current?.setLoader();
627+
}
628+
620629
apiClient(`${API_URLS.schema.update}/${currentId}`, {
621630
customJson,
622631
schemaJson: schema,
@@ -631,7 +640,8 @@ const Editor = React.memo(({ currentId, saveRef, loaderRef }) => {
631640
}).then((res) => {
632641
if (res?.code === 'E_BAD_REQUEST') {
633642
// manage multiple errors
634-
loaderRef.current.setLoader();
643+
if (isInSaveWarning) hideSaveLoading();
644+
else loaderRef.current?.setLoader();
635645

636646
if (res.data?.length > 0) { setModelErrors(res.data); }
637647
// hideSaveLoader();
@@ -643,7 +653,15 @@ const Editor = React.memo(({ currentId, saveRef, loaderRef }) => {
643653
// hideSaveLoader();
644654
// if (tableRef?.current && res?.message) addSuccessToast(res.message);
645655
// setCode(JSON.stringify(res?.data?.schemaJson || {}));
646-
loaderRef.current.setLoader();
656+
setNoChangeInTable(); // when direct save that
657+
if (isInSaveWarning) {
658+
changeNextEvent.current();
659+
hideSaveLoading();
660+
661+
hideSaveWarning();
662+
} else {
663+
loaderRef.current?.setLoader();
664+
}
647665

648666
// loaderCallBack({ isHidePopup: true });
649667
if (isRedirect) {
@@ -653,7 +671,12 @@ const Editor = React.memo(({ currentId, saveRef, loaderRef }) => {
653671
}).catch((err) => {
654672
// hideSaveLoader();
655673
addErrorToast(err);
656-
loaderRef.current.setLoader();
674+
if (isInSaveWarning) {
675+
hideSaveLoading();
676+
hideSaveWarning();
677+
} else {
678+
loaderRef.current?.setLoader();
679+
}
657680
});
658681
updateRef.current?.setHideEdit();
659682
} catch (err) {
@@ -731,6 +754,23 @@ const Editor = React.memo(({ currentId, saveRef, loaderRef }) => {
731754
/>
732755
) : null
733756
}
757+
<ConfirmationAlert
758+
description=" Do you wish to save your data before continuing ?"
759+
handleSubmit={() => saveJSON({ isInSaveWarning: true })}
760+
variant="primary"
761+
title={(
762+
<div className="flex justify-center items-center mb-5">
763+
<div className="w-5 h-5 mr-3">
764+
<Icons.Warring />
765+
</div>
766+
New changes detected
767+
</div>
768+
)}
769+
isOpen={isSaveWarning}
770+
okText="Save"
771+
isLoading={isSaveLoading}
772+
handleClose={() => { changeNextEvent.current(); hideSaveWarning(); setNoChangeInTable(); }}
773+
/>
734774

735775
</>
736776
);

packages/client/src/container/CRUD/Modal/ModelList/index.js

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ import DeleteModel from '../DeleteModel';
2323
import { getModelDetail } from '../../../../redux/thunks/models';
2424

2525
export const ModelList = ({ setPanel, modelPanel }) => {
26-
const { isError, isJsonError } = useModel();
26+
const {
27+
isError, isJsonError, isChangeInTable, setChangeNextEvent, setNoChangeInTable, setSaveWarning,
28+
} = useModel();
2729
const [modalStatus, showModal, hideModal] = useBoolean(false);
2830
const modelList = useSelector((state) => state.models.modelList);
2931
const currentId = useSelector((state) => state.models.currentId);
@@ -32,6 +34,15 @@ export const ModelList = ({ setPanel, modelPanel }) => {
3234
const location = useLocation();
3335

3436
const openCreateModel = () => {
37+
if (isChangeInTable) {
38+
setChangeNextEvent(() => {
39+
setNoChangeInTable();
40+
showModal();
41+
});
42+
setSaveWarning();
43+
return;
44+
}
45+
3546
showModal();
3647
};
3748
React.useEffect(() => {
@@ -55,7 +66,23 @@ export const ModelList = ({ setPanel, modelPanel }) => {
5566
<Tabs selectedIndex={modelPanel === ModelPanel.CUSTOM.name ? ModelPanel.CUSTOM.tabIndex : ModelPanel.LIBRARY.tabIndex} className="flex-grow flex flex-col h-0" selectedTabPanelClassName="h-0 flex-grow" selectedTabClassName={TabCSs.selectTab}>
5667
<TabList className={`${TabCSs.tabHead} modelListTab`}>
5768
<Tab onClick={() => { setPanel(ModelPanel.CUSTOM.name); }} className={TabCSs.tabSmallTitle}>Custom</Tab>
58-
<Tab onClick={() => { setPanel(ModelPanel.LIBRARY.name); }} className={TabCSs.tabSmallTitle}>Library</Tab>
69+
<Tab
70+
onClick={() => {
71+
if (isChangeInTable) {
72+
setChangeNextEvent(() => {
73+
setPanel(ModelPanel.LIBRARY.name);
74+
setNoChangeInTable();
75+
});
76+
setSaveWarning();
77+
return;
78+
}
79+
setPanel(ModelPanel.LIBRARY.name);
80+
}}
81+
className={TabCSs.tabSmallTitle}
82+
>
83+
Library
84+
85+
</Tab>
5986
</TabList>
6087
<TabPanel>
6188
<div className="overflow-auto h-full">
@@ -75,6 +102,16 @@ export const ModelList = ({ setPanel, modelPanel }) => {
75102
<div
76103
className="flex items-center justify-between w-full py-1 pr-8"
77104
onClick={() => {
105+
if (isChangeInTable) {
106+
setChangeNextEvent(() => {
107+
dispatch(setCurrentModel({ currentId: d._id }));
108+
dispatch(getModelDetail(d._id));
109+
setNoChangeInTable();
110+
});
111+
setSaveWarning();
112+
return;
113+
}
114+
78115
if (d._id === currentId) return;
79116
dispatch(setCurrentModel({ currentId: d._id }));
80117
dispatch(getModelDetail(d._id));

packages/client/src/container/CRUD/Routes/AddRoutes/AddRouteProvider.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ export const RouteTabIndexName = {
1414
[ROUTE_GENERATE_TYPE.MANUAL]: {
1515
0: 'Basic',
1616
1: 'Advance',
17-
2: 'Configuration',
18-
3: 'Query builder',
17+
// 2: 'Configuration',
18+
2: 'Query builder',
1919
},
2020
[ROUTE_GENERATE_TYPE.AUTO]: {
2121
get: {

packages/client/src/container/CRUD/Routes/AddRoutes/index.js

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import { RouteTabIndexName, useAddRoute } from './AddRouteProvider';
1717
import { useAddToggle } from '../AddToggleProvider';
1818
import Basic from './Basic';
1919
import Advance from './Advance';
20-
import { Configuration } from './Configuration';
2120
import { useRoute } from '../RouteProvider';
2221
import { useBoolean } from '../../../../components/hooks';
2322
import { ModelPermission } from './ModelPermission';
@@ -119,20 +118,6 @@ export const AddRoutes = () => {
119118
<Advance />
120119
</div>
121120
</TabPanel>
122-
<TabPanel>
123-
<div className="px-5 overflow-auto h-full">
124-
<Controller
125-
control={control}
126-
name="uploads"
127-
defaultValue={editRouteData?.fileUpload?.uploads[0]}
128-
render={(controlProps) => (
129-
<Configuration
130-
{...controlProps}
131-
/>
132-
)}
133-
/>
134-
</div>
135-
</TabPanel>
136121
<TabPanel>
137122
<Controller
138123
control={control}

0 commit comments

Comments
 (0)