Prevent racing condition in fast subsequent field reorders

This commit is contained in:
rijkvanzanten
2020-09-08 11:42:29 -04:00
parent 972b86cba2
commit 5b1cd7b2bb

View File

@@ -8,6 +8,7 @@ import notify from '@/utils/notify';
import { useRelationsStore } from '@/stores/';
import { Relation, FieldRaw, Field } from '@/types';
import { merge } from 'lodash';
import { nanoid } from 'nanoid';
const fakeFilesField: Field = {
collection: 'directus_files',
@@ -36,6 +37,15 @@ const fakeFilesField: Field = {
},
};
/**
* @NOTE
* This keeps track of what update is the last one that's in progress. After every update, the store
* gets flushed with the updated values, which means that you can have racing conditions if you do
* multiple updates at the same time. By keeping track which one is the last one that's fired, we
* can ensure that only the last update gets used to flush the store with.
*/
let currentUpdate: string;
export const useFieldsStore = createStore({
id: 'fieldsStore',
state: () => ({
@@ -165,8 +175,11 @@ export const useFieldsStore = createStore({
}
},
async updateFields(collectionKey: string, updates: Partial<Field>[]) {
const updateID = nanoid();
const stateClone = [...this.state.fields];
currentUpdate = updateID;
// Update locally first, so the changes are visible immediately
this.state.fields = this.state.fields.map((field) => {
if (field.collection === collectionKey) {
@@ -185,16 +198,18 @@ export const useFieldsStore = createStore({
// API
const response = await api.patch(`/fields/${collectionKey}`, updates);
this.state.fields = this.state.fields.map((field) => {
if (field.collection === collectionKey) {
const newDataForField = response.data.data.find(
(update: Field) => update.field === field.field
);
if (newDataForField) return this.parseField(newDataForField);
}
if (currentUpdate === updateID) {
this.state.fields = this.state.fields.map((field) => {
if (field.collection === collectionKey) {
const newDataForField = response.data.data.find(
(update: Field) => update.field === field.field
);
if (newDataForField) return this.parseField(newDataForField);
}
return field;
});
return field;
});
}
notify({
title: i18n.t('fields_update_success'),