Skip to content

Commit 5f652a9

Browse files
committed
add loading state
1 parent aea4d1f commit 5f652a9

File tree

2 files changed

+104
-78
lines changed

2 files changed

+104
-78
lines changed

src/dashboard/Data/Config/Config.react.js

Lines changed: 82 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ class Config extends TableView {
9393
value={this.state.modalValue}
9494
masterKeyOnly={this.state.modalMasterKeyOnly}
9595
parseServerVersion={this.context.serverInfo?.parseServerVersion}
96+
loading={this.state.loading}
9697
/>
9798
);
9899
} else if (this.state.showDeleteParameterDialog) {
@@ -272,77 +273,93 @@ class Config extends TableView {
272273
}
273274

274275
async saveParam({ name, value, type, masterKeyOnly, override }) {
275-
const cachedParams = this.cacheData.get('params');
276-
const cachedValue = cachedParams.get(name);
276+
try {
277+
this.setState({ loading: true });
278+
279+
const fetchedParams = this.props.config.data.get('params');
280+
const currentValue = fetchedParams.get(name);
281+
await this.props.config.dispatch(ActionTypes.FETCH);
282+
const fetchedParamsAfter = this.props.config.data.get('params');
283+
const currentValueAfter = fetchedParamsAfter.get(name);
277284

278-
await this.props.config.dispatch(ActionTypes.FETCH);
279-
const fetchedParams = this.props.config.data.get('params');
280-
281-
if (cachedValue !== fetchedParams.get(name) && !override) {
282-
this.setState({
283-
confirmModalOpen: true,
284-
modalOpen: false,
285-
});
286-
this.confirmData = {
287-
name,
288-
value,
289-
type,
290-
masterKeyOnly,
291-
};
292-
return;
293-
}
285+
if (currentValue !== currentValueAfter && !override) {
286+
this.setState({
287+
confirmModalOpen: true,
288+
modalOpen: false,
289+
loading: false,
290+
});
291+
this.confirmData = {
292+
name,
293+
value,
294+
type,
295+
masterKeyOnly,
296+
};
297+
return;
298+
}
294299

295-
this.props.config
296-
.dispatch(ActionTypes.SET, {
300+
await this.props.config.dispatch(ActionTypes.SET, {
297301
param: name,
298302
value: value,
299303
masterKeyOnly: masterKeyOnly,
300-
})
301-
.then(
302-
() => {
303-
this.setState({ modalOpen: false });
304-
const limit = this.context.cloudConfigHistoryLimit;
305-
const applicationId = this.context.applicationId;
306-
let transformedValue = value;
307-
if (type === 'Date') {
308-
transformedValue = { __type: 'Date', iso: value };
309-
}
310-
if (type === 'File') {
311-
transformedValue = { name: value._name, url: value._url };
312-
}
313-
const configHistory = localStorage.getItem(`${applicationId}_configHistory`);
314-
if (!configHistory) {
315-
localStorage.setItem(
316-
`${applicationId}_configHistory`,
317-
JSON.stringify({
318-
[name]: [
319-
{
320-
time: new Date(),
321-
value: transformedValue,
322-
},
323-
],
324-
})
325-
);
326-
} else {
327-
const oldConfigHistory = JSON.parse(configHistory);
328-
localStorage.setItem(
329-
`${applicationId}_configHistory`,
330-
JSON.stringify({
331-
...oldConfigHistory,
332-
[name]: !oldConfigHistory[name]
333-
? [{ time: new Date(), value: transformedValue }]
334-
: [
335-
{ time: new Date(), value: transformedValue },
336-
...oldConfigHistory[name],
337-
].slice(0, limit || 100),
338-
})
339-
);
340-
}
341-
},
342-
() => {
343-
// Catch the error
344-
}
304+
});
305+
306+
// Update the cached data after successful save
307+
const params = this.cacheData.get('params');
308+
params.set(name, value);
309+
if (masterKeyOnly) {
310+
const masterKeyOnlyParams = this.cacheData.get('masterKeyOnly') || new Map();
311+
masterKeyOnlyParams.set(name, masterKeyOnly);
312+
this.cacheData.set('masterKeyOnly', masterKeyOnlyParams);
313+
}
314+
315+
this.setState({ modalOpen: false });
316+
317+
// Update config history in localStorage
318+
const limit = this.context.cloudConfigHistoryLimit;
319+
const applicationId = this.context.applicationId;
320+
let transformedValue = value;
321+
322+
if (type === 'Date') {
323+
transformedValue = { __type: 'Date', iso: value };
324+
}
325+
if (type === 'File') {
326+
transformedValue = { name: value._name, url: value._url };
327+
}
328+
329+
const configHistory = localStorage.getItem(`${applicationId}_configHistory`);
330+
const newHistoryEntry = {
331+
time: new Date(),
332+
value: transformedValue,
333+
};
334+
335+
if (!configHistory) {
336+
localStorage.setItem(
337+
`${applicationId}_configHistory`,
338+
JSON.stringify({
339+
[name]: [newHistoryEntry],
340+
})
341+
);
342+
} else {
343+
const oldConfigHistory = JSON.parse(configHistory);
344+
const updatedHistory = !oldConfigHistory[name]
345+
? [newHistoryEntry]
346+
: [newHistoryEntry, ...oldConfigHistory[name]].slice(0, limit || 100);
347+
348+
localStorage.setItem(
349+
`${applicationId}_configHistory`,
350+
JSON.stringify({
351+
...oldConfigHistory,
352+
[name]: updatedHistory,
353+
})
354+
);
355+
}
356+
} catch (error) {
357+
this.context.showError?.(
358+
`Failed to save parameter: ${error.message || 'Unknown error occurred'}`
345359
);
360+
} finally {
361+
this.setState({ loading: false });
362+
}
346363
}
347364

348365
deleteParam(name) {

src/dashboard/Data/Config/ConfigDialog.react.js

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import validateNumeric from 'lib/validateNumeric';
2121
import styles from 'dashboard/Data/Browser/Browser.scss';
2222
import semver from 'semver/preload.js';
2323
import { dateStringUTC } from 'lib/DateUtils';
24+
import LoaderContainer from 'components/LoaderContainer/LoaderContainer.react';
2425
import { CurrentApp } from 'context/currentApp';
2526

2627
const PARAM_TYPES = ['Boolean', 'String', 'Number', 'Date', 'Object', 'Array', 'GeoPoint', 'File'];
@@ -222,19 +223,8 @@ export default class ConfigDialog extends React.Component {
222223
this.setState({ selectedIndex: index, value });
223224
};
224225

225-
return (
226-
<Modal
227-
type={Modal.Types.INFO}
228-
title={newParam ? 'New parameter' : 'Edit parameter'}
229-
icon="gear-solid"
230-
iconSize={30}
231-
subtitle={'Dynamically configure parts of your app'}
232-
disabled={!this.valid()}
233-
confirmText={newParam ? 'Create' : 'Save'}
234-
cancelText="Cancel"
235-
onCancel={this.props.onCancel}
236-
onConfirm={this.submit.bind(this)}
237-
>
226+
const dialogContent = (
227+
<div>
238228
<Field
239229
label={<Label text="Parameter Name" description="A unique identifier for this value" />}
240230
input={
@@ -305,6 +295,25 @@ export default class ConfigDialog extends React.Component {
305295
className={styles.addColumnToggleWrapper}
306296
/>
307297
)}
298+
</div>
299+
);
300+
301+
return (
302+
<Modal
303+
type={Modal.Types.INFO}
304+
title={newParam ? 'New parameter' : 'Edit parameter'}
305+
icon="gear-solid"
306+
iconSize={30}
307+
subtitle={'Dynamically configure parts of your app'}
308+
disabled={!this.valid() || this.props.loading}
309+
confirmText={newParam ? 'Create' : 'Save'}
310+
cancelText="Cancel"
311+
onCancel={this.props.onCancel}
312+
onConfirm={this.submit.bind(this)}
313+
>
314+
<LoaderContainer loading={this.props.loading}>
315+
{dialogContent}
316+
</LoaderContainer>
308317
</Modal>
309318
);
310319
}

0 commit comments

Comments
 (0)