feat: update internal control value for list and object widget whenever store changes (#933)

This commit is contained in:
Daniel Lautzenheiser 2023-10-10 10:29:31 -04:00 committed by GitHub
parent 1d4ae8ef18
commit 1ddcfbe153
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 49 additions and 224 deletions

View File

@ -3,6 +3,7 @@ import attempt from 'lodash/attempt';
import flatten from 'lodash/flatten';
import get from 'lodash/get';
import isError from 'lodash/isError';
import set from 'lodash/set';
import uniq from 'lodash/uniq';
import { dirname } from 'path';
@ -45,7 +46,6 @@ import filterEntries from './lib/util/filter.util';
import { DRAFT_MEDIA_FILES, selectMediaFilePublicPath } from './lib/util/media.util';
import { selectCustomPath, slugFromCustomPath } from './lib/util/nested.util';
import { isNullish } from './lib/util/null.util';
import { set } from './lib/util/object.util';
import { fileSearch, sortByScore } from './lib/util/search.util';
import { dateParsers, expandPath, extractTemplateVars } from './lib/widgets/stringTemplate';
import createEntry from './valueObjects/createEntry';

View File

@ -110,6 +110,15 @@ const EditorControl = ({
);
const hidden = useHidden(field, entry, listItemPath);
useEffect(() => {
if (!['list', 'object'].includes(field.widget)) {
return;
}
setInternalValue(finalStorageValue);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [finalStorageValue]);
useEffect(() => {
if (hidden) {
dispatch(changeDraftFieldValidation(path, [], i18n, isMeta));
@ -220,10 +229,7 @@ const EditorControl = ({
path,
query,
t,
value:
field.widget === 'list' || field.widget === 'object'
? finalStorageValue
: internalValue,
value: internalValue,
forList,
listItemPath,
forSingleList,

View File

@ -1,10 +1,10 @@
import get from 'lodash/get';
import set from 'lodash/set';
import { COMMIT_AUTHOR, COMMIT_DATE } from '../constants/commitProps';
import { sanitizeSlug } from './urlHelper';
import { selectIdentifier, selectInferredField } from './util/collection.util';
import { selectField } from './util/field.util';
import { set } from './util/object.util';
import { isEmpty } from './util/string.util';
import {
addFileTemplateFields,

View File

@ -1,9 +1,9 @@
import escapeRegExp from 'lodash/escapeRegExp';
import get from 'lodash/get';
import groupBy from 'lodash/groupBy';
import set from 'lodash/set';
import { fileForEntry, selectEntrySlug } from './util/collection.util';
import { set } from './util/object.util';
import type {
BaseField,

View File

@ -1,159 +0,0 @@
import { set } from '../object.util';
describe('object.util', () => {
describe('set', () => {
describe('simple object', () => {
test('existing key', () => {
const testObject = {
something: '12345',
somethingElse: 5,
};
const updatedObject = set(testObject, 'something', '54321');
expect(testObject.something).toBe('12345');
expect(updatedObject.something).toBe('54321');
});
test('new key', () => {
const testObject = {
something: '12345',
somethingElse: 5,
} as {
something: string;
somethingElse: number;
somethingNew?: string;
};
const updatedObject = set(testObject, 'somethingNew', 'aNewValue');
expect(testObject.somethingNew).toBeUndefined();
expect(updatedObject.somethingNew).toBe('aNewValue');
});
});
describe('nested object', () => {
test('existing key', () => {
const testObject = {
something: '12345',
somethingElse: {
nestedValue: 65,
},
};
const updatedObject = set(testObject, 'somethingElse.nestedValue', 125);
expect(testObject.somethingElse.nestedValue).toBe(65);
expect(updatedObject.somethingElse.nestedValue).toBe(125);
});
test('new key', () => {
const testObject = {
something: '12345',
somethingElse: {
nestedValue: 65,
},
} as {
something: string;
somethingElse: {
nestedValue: number;
};
somethingNew?: {
nestedLayer: {
anotherNestedLayer: string;
};
};
};
const updatedObject = set(
testObject,
'somethingNew.nestedLayer.anotherNestedLayer',
'aNewNestedValue',
);
expect(testObject.somethingNew?.nestedLayer.anotherNestedLayer).toBeUndefined();
expect(updatedObject.somethingNew?.nestedLayer.anotherNestedLayer).toBe('aNewNestedValue');
});
});
describe('simple array', () => {
test('existing key', () => {
const testObject = {
something: '12345',
somethingElse: [6, 5, 3],
};
const updatedObject = set(testObject, 'somethingElse.1', 13);
expect(updatedObject.somethingElse).toStrictEqual([6, 13, 3]);
});
test('new index should be ignored', () => {
const testObject = {
something: '12345',
somethingElse: [6, 5, 3],
};
const updatedObject = set(testObject, 'somethingElse.3', 84);
expect(updatedObject.somethingElse).toStrictEqual([6, 5, 3]);
});
});
describe('object array', () => {
test('existing key', () => {
const testObject = {
something: '12345',
somethingElse: [
{ name: 'one', value: '11111' },
{ name: 'two', value: '22222' },
{ name: 'three', value: '33333' },
],
};
const updatedObject = set(testObject, 'somethingElse.1.value', 'aNewValue');
expect(testObject.somethingElse[1].value).toBe('22222');
expect(updatedObject.somethingElse[1].value).toBe('aNewValue');
});
test('new index should be ignored', () => {
const testObject = {
something: '12345',
somethingElse: [
{ name: 'one', value: '11111' },
{ name: 'two', value: '22222' },
{ name: 'three', value: '33333' },
],
};
const updatedObject = set(testObject, 'somethingElse.3.value', 'valueToBeIgnored');
expect(updatedObject.somethingElse.length).toBe(3);
});
test('new key inside existing index', () => {
const testObject = {
something: '12345',
somethingElse: [
{ name: 'one', value: '11111' },
{ name: 'two', value: '22222' },
{ name: 'three', value: '33333' },
],
} as {
something: string;
somethingElse: {
name: string;
value: string;
newKey?: string;
}[];
};
const updatedObject = set(testObject, 'somethingElse.1.newKey', 'newValueToBeAdded');
expect(testObject.somethingElse[1].newKey).toBeUndefined();
expect(updatedObject.somethingElse[1].newKey).toBe('newValueToBeAdded');
});
});
});
});

View File

@ -1,45 +0,0 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
function setIn(target: any, path: (string | number)[], value: unknown): any {
if (path.length === 0) {
return value;
}
const pathSegment = path[0];
const restOfPath = path.slice(1);
if (Array.isArray(target)) {
const localTarget = [...(target ?? [])];
if (Number.isNaN(+pathSegment)) {
return localTarget;
}
const index = +pathSegment;
if (index < 0 || index >= localTarget.length) {
return localTarget;
}
localTarget[index] = setIn(localTarget[index], restOfPath, value);
return localTarget;
}
const localTarget = target ?? {};
return {
...localTarget,
[pathSegment]: setIn(localTarget[pathSegment], restOfPath, value),
};
}
export function set<T>(target: T, path: string | undefined | null, value: unknown): T;
export function set(target: any, path: string | undefined | null, value: unknown): any {
return setIn(
target,
(path ?? '').split('.').map(part => {
if (Number.isNaN(+part)) {
return part;
}
return +part;
}),
value,
);
}

View File

@ -1,4 +1,5 @@
import once from 'lodash/once';
import set from 'lodash/set';
import sortBy from 'lodash/sortBy';
import {
@ -23,7 +24,6 @@ import {
SORT_ENTRIES_SUCCESS,
} from '../constants';
import { VIEW_STYLES, VIEW_STYLE_TABLE } from '../constants/views';
import { set } from '../lib/util/object.util';
import type { EntriesAction } from '../actions/entries';
import type { SearchAction } from '../actions/search';

View File

@ -1,4 +1,6 @@
import isEqual from 'lodash/isEqual';
import set from 'lodash/set';
import cloneDeep from 'lodash/cloneDeep';
import { v4 as uuid } from 'uuid';
import {
@ -23,7 +25,6 @@ import {
import { duplicateI18nFields, getDataPath } from '../lib/i18n';
import { fileForEntry } from '../lib/util/collection.util';
import { applyDefaultsToDraftData } from '../lib/util/entry.util';
import { set } from '../lib/util/object.util';
import type { EntriesAction } from '../actions/entries';
import type { Entry, FieldsErrors } from '../interface';
@ -70,7 +71,7 @@ function entryDraftReducer(
...entry,
data: applyDefaultsToDraftData(fields, undefined, entry.data),
},
original: entry,
original: cloneDeep(entry),
fieldsErrors: {},
hasChanged: false,
key: uuid(),
@ -89,7 +90,7 @@ function entryDraftReducer(
return {
...newState,
entry,
original: entry,
original: cloneDeep(entry),
fieldsErrors: {},
hasChanged: false,
key: uuid(),
@ -115,7 +116,7 @@ function entryDraftReducer(
return {
...state,
entry,
original: entry,
original: cloneDeep(entry),
fieldsErrors: {},
hasChanged: true,
key: uuid(),
@ -135,7 +136,7 @@ function entryDraftReducer(
return {
...newState,
entry,
original: entry,
original: cloneDeep(entry),
fieldsErrors: {},
hasChanged: true,
};
@ -203,9 +204,11 @@ function entryDraftReducer(
? ['meta']
: (i18n && getDataPath(i18n.currentLocale, i18n.defaultLocale)) || ['data'];
const newEntry = cloneDeep(newState.entry);
newState = {
...newState,
entry: set(newState.entry, `${dataPath.join('.')}.${path}`, value),
entry: set(newEntry, `${dataPath.join('.')}.${path}`, value),
};
if (i18n) {
@ -213,14 +216,14 @@ function entryDraftReducer(
}
let hasChanged =
!isEqual(newState.entry?.meta, newState.original?.meta) ||
!isEqual(newState.entry?.data, newState.original?.data);
!isEqual(newEntry?.meta, newState.original?.meta) ||
!isEqual(newEntry?.data, newState.original?.data);
const i18nData = newState.entry?.i18n ?? {};
const i18nData = newEntry?.i18n ?? {};
for (const locale in i18nData) {
hasChanged =
hasChanged ||
!isEqual(newState.entry?.i18n?.[locale]?.data, newState.original?.i18n?.[locale]?.data);
!isEqual(newEntry?.i18n?.[locale]?.data, newState.original?.i18n?.[locale]?.data);
}
return {
@ -322,7 +325,7 @@ function entryDraftReducer(
...newState,
hasChanged: false,
entry,
original: entry,
original: cloneDeep(entry),
};
}
@ -343,7 +346,7 @@ function entryDraftReducer(
...newState,
hasChanged: false,
entry,
original: entry,
original: cloneDeep(entry),
};
}

View File

@ -1,5 +1,25 @@
{
"releases": [
{
"date": "2023-10-10T10:00:00.000Z",
"version": "v3.3.7",
"type": "patch"
},
{
"date": "2023-10-06T10:00:00.000Z",
"version": "v3.3.6",
"type": "patch"
},
{
"date": "2023-10-05T10:00:00.000Z",
"version": "v3.3.5",
"type": "patch"
},
{
"date": "2023-10-04T10:00:00.000Z",
"version": "v3.3.4",
"type": "patch"
},
{
"date": "2023-09-24T10:00:00.000Z",
"version": "v3.3.3",