mirror of
https://github.com/strapi/strapi.git
synced 2025-09-21 06:22:30 +00:00
Merge pull request #15818 from strapi/feat/relations-diffing-fe
This commit is contained in:
commit
14d5597a8f
@ -75,7 +75,7 @@ module.exports = {
|
|||||||
'<rootDir>/fileTransformer.js',
|
'<rootDir>/fileTransformer.js',
|
||||||
},
|
},
|
||||||
transformIgnorePatterns: [
|
transformIgnorePatterns: [
|
||||||
'node_modules/(?!(react-dnd|dnd-core|react-dnd-html5-backend|@strapi/design-system|@strapi/icons)/)',
|
'node_modules/(?!(react-dnd|dnd-core|react-dnd-html5-backend|@strapi/design-system|@strapi/icons|fractional-indexing)/)',
|
||||||
],
|
],
|
||||||
testMatch: ['/**/tests/**/?(*.)+(spec|test).[jt]s?(x)'],
|
testMatch: ['/**/tests/**/?(*.)+(spec|test).[jt]s?(x)'],
|
||||||
testEnvironmentOptions: {
|
testEnvironmentOptions: {
|
||||||
|
@ -8,6 +8,7 @@ import uniqBy from 'lodash/uniqBy';
|
|||||||
import merge from 'lodash/merge';
|
import merge from 'lodash/merge';
|
||||||
import castArray from 'lodash/castArray';
|
import castArray from 'lodash/castArray';
|
||||||
import isNil from 'lodash/isNil';
|
import isNil from 'lodash/isNil';
|
||||||
|
import { generateNKeysBetween } from 'fractional-indexing';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
findLeafByPathAndReplace,
|
findLeafByPathAndReplace,
|
||||||
@ -155,17 +156,33 @@ const reducer = (state, action) =>
|
|||||||
const initialDataRelations = get(state, initialDataPath);
|
const initialDataRelations = get(state, initialDataPath);
|
||||||
const modifiedDataRelations = get(state, modifiedDataPath);
|
const modifiedDataRelations = get(state, modifiedDataPath);
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the values we're loading are already in initial
|
|
||||||
* data if they are then we don't need to load them at all
|
|
||||||
*/
|
|
||||||
const valuesToLoad = value.filter((relation) => {
|
const valuesToLoad = value.filter((relation) => {
|
||||||
return !initialDataRelations.some((initialDataRelation) => {
|
return !initialDataRelations.some((initialDataRelation) => {
|
||||||
return initialDataRelation.id === relation.id;
|
return initialDataRelation.id === relation.id;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
set(draftState, initialDataPath, uniqBy([...valuesToLoad, ...initialDataRelations], 'id'));
|
const keys = generateNKeysBetween(
|
||||||
|
null,
|
||||||
|
modifiedDataRelations[0]?.__temp_key__,
|
||||||
|
valuesToLoad.length
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the values we're loading are already in initial
|
||||||
|
* data if they are then we don't need to load them at all
|
||||||
|
*/
|
||||||
|
|
||||||
|
const valuesWithKeys = valuesToLoad.map((relation, index) => ({
|
||||||
|
...relation,
|
||||||
|
__temp_key__: keys[index],
|
||||||
|
}));
|
||||||
|
|
||||||
|
set(
|
||||||
|
draftState,
|
||||||
|
initialDataPath,
|
||||||
|
uniqBy([...valuesWithKeys, ...initialDataRelations], 'id')
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We need to set the value also on modifiedData, because initialData
|
* We need to set the value also on modifiedData, because initialData
|
||||||
@ -175,7 +192,7 @@ const reducer = (state, action) =>
|
|||||||
set(
|
set(
|
||||||
draftState,
|
draftState,
|
||||||
modifiedDataPath,
|
modifiedDataPath,
|
||||||
uniqBy([...valuesToLoad, ...modifiedDataRelations], 'id')
|
uniqBy([...valuesWithKeys, ...modifiedDataRelations], 'id')
|
||||||
);
|
);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -192,7 +209,9 @@ const reducer = (state, action) =>
|
|||||||
set(draftState, path, [value]);
|
set(draftState, path, [value]);
|
||||||
} else {
|
} else {
|
||||||
const modifiedDataRelations = get(state, path);
|
const modifiedDataRelations = get(state, path);
|
||||||
const newRelations = [...modifiedDataRelations, value];
|
const [key] = generateNKeysBetween(modifiedDataRelations.at(-1)?.__temp_key__, null, 1);
|
||||||
|
|
||||||
|
const newRelations = [...modifiedDataRelations, { ...value, __temp_key__: key }];
|
||||||
set(draftState, path, newRelations);
|
set(draftState, path, newRelations);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,8 +238,19 @@ const reducer = (state, action) =>
|
|||||||
|
|
||||||
const newRelations = [...modifiedDataRelations];
|
const newRelations = [...modifiedDataRelations];
|
||||||
|
|
||||||
|
if (action.type === 'REORDER_RELATION') {
|
||||||
|
const [newKey] = generateNKeysBetween(
|
||||||
|
modifiedDataRelations[newIndex - 1]?.__temp_key__,
|
||||||
|
modifiedDataRelations[newIndex]?.__temp_key__,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
|
||||||
|
newRelations.splice(oldIndex, 1);
|
||||||
|
newRelations.splice(newIndex, 0, { ...currentItem, __temp_key__: newKey });
|
||||||
|
} else {
|
||||||
newRelations.splice(oldIndex, 1);
|
newRelations.splice(oldIndex, 1);
|
||||||
newRelations.splice(newIndex, 0, currentItem);
|
newRelations.splice(newIndex, 0, currentItem);
|
||||||
|
}
|
||||||
|
|
||||||
set(draftState, path, newRelations);
|
set(draftState, path, newRelations);
|
||||||
|
|
||||||
|
@ -869,7 +869,7 @@ describe('CONTENT MANAGER | COMPONENTS | EditViewDataManagerProvider | reducer',
|
|||||||
componentsDataStructure: {},
|
componentsDataStructure: {},
|
||||||
initialData: {},
|
initialData: {},
|
||||||
modifiedData: {
|
modifiedData: {
|
||||||
relation: [{ id: 1 }],
|
relation: [{ id: 1, __temp_key__: 'a0' }],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -882,6 +882,74 @@ describe('CONTENT MANAGER | COMPONENTS | EditViewDataManagerProvider | reducer',
|
|||||||
expect(reducer(state, action)).toEqual(expected);
|
expect(reducer(state, action)).toEqual(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should set a temp key every time a relation is connected', () => {
|
||||||
|
const state = {
|
||||||
|
...initialState,
|
||||||
|
|
||||||
|
initialData: {
|
||||||
|
relation: [
|
||||||
|
{ id: 1, __temp_key__: 'a0' },
|
||||||
|
{ id: 2, __temp_key__: 'a1' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
modifiedData: {
|
||||||
|
relation: [
|
||||||
|
{ id: 1, __temp_key__: 'a0' },
|
||||||
|
{ id: 2, __temp_key__: 'a1' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const nextState = reducer(state, {
|
||||||
|
type: 'CONNECT_RELATION',
|
||||||
|
keys: ['relation'],
|
||||||
|
value: { id: 3 },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(nextState).toStrictEqual({
|
||||||
|
...initialState,
|
||||||
|
componentsDataStructure: {},
|
||||||
|
initialData: {
|
||||||
|
relation: [
|
||||||
|
{ id: 1, __temp_key__: 'a0' },
|
||||||
|
{ id: 2, __temp_key__: 'a1' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
modifiedData: {
|
||||||
|
relation: [
|
||||||
|
{ id: 1, __temp_key__: 'a0' },
|
||||||
|
{ id: 2, __temp_key__: 'a1' },
|
||||||
|
{ id: 3, __temp_key__: 'a2' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(
|
||||||
|
reducer(nextState, {
|
||||||
|
type: 'CONNECT_RELATION',
|
||||||
|
keys: ['relation'],
|
||||||
|
value: { id: 4 },
|
||||||
|
})
|
||||||
|
).toStrictEqual({
|
||||||
|
...initialState,
|
||||||
|
componentsDataStructure: {},
|
||||||
|
initialData: {
|
||||||
|
relation: [
|
||||||
|
{ id: 1, __temp_key__: 'a0' },
|
||||||
|
{ id: 2, __temp_key__: 'a1' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
modifiedData: {
|
||||||
|
relation: [
|
||||||
|
{ id: 1, __temp_key__: 'a0' },
|
||||||
|
{ id: 2, __temp_key__: 'a1' },
|
||||||
|
{ id: 3, __temp_key__: 'a2' },
|
||||||
|
{ id: 4, __temp_key__: 'a3' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should overwrite existing data, when toOneRelation is set to true', () => {
|
it('should overwrite existing data, when toOneRelation is set to true', () => {
|
||||||
const state = {
|
const state = {
|
||||||
...initialState,
|
...initialState,
|
||||||
@ -953,10 +1021,10 @@ describe('CONTENT MANAGER | COMPONENTS | EditViewDataManagerProvider | reducer',
|
|||||||
expect(nextState).toStrictEqual({
|
expect(nextState).toStrictEqual({
|
||||||
...initialState,
|
...initialState,
|
||||||
initialData: {
|
initialData: {
|
||||||
relation: [{ id: 1 }],
|
relation: [{ id: 1, __temp_key__: 'a0' }],
|
||||||
},
|
},
|
||||||
modifiedData: {
|
modifiedData: {
|
||||||
relation: [{ id: 1 }],
|
relation: [{ id: 1, __temp_key__: 'a0' }],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -970,10 +1038,16 @@ describe('CONTENT MANAGER | COMPONENTS | EditViewDataManagerProvider | reducer',
|
|||||||
).toStrictEqual({
|
).toStrictEqual({
|
||||||
...initialState,
|
...initialState,
|
||||||
initialData: {
|
initialData: {
|
||||||
relation: [{ id: 2 }, { id: 1 }],
|
relation: [
|
||||||
|
{ id: 2, __temp_key__: 'Zz' },
|
||||||
|
{ id: 1, __temp_key__: 'a0' },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
modifiedData: {
|
modifiedData: {
|
||||||
relation: [{ id: 2 }, { id: 1 }],
|
relation: [
|
||||||
|
{ id: 2, __temp_key__: 'Zz' },
|
||||||
|
{ id: 1, __temp_key__: 'a0' },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -1002,10 +1076,10 @@ describe('CONTENT MANAGER | COMPONENTS | EditViewDataManagerProvider | reducer',
|
|||||||
expect(nextState).toStrictEqual({
|
expect(nextState).toStrictEqual({
|
||||||
...initialState,
|
...initialState,
|
||||||
initialData: {
|
initialData: {
|
||||||
relation: [{ id: 1 }],
|
relation: [{ id: 1, __temp_key__: 'a0' }],
|
||||||
},
|
},
|
||||||
modifiedData: {
|
modifiedData: {
|
||||||
relation: [{ id: 1 }],
|
relation: [{ id: 1, __temp_key__: 'a0' }],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1019,10 +1093,103 @@ describe('CONTENT MANAGER | COMPONENTS | EditViewDataManagerProvider | reducer',
|
|||||||
).toStrictEqual({
|
).toStrictEqual({
|
||||||
...initialState,
|
...initialState,
|
||||||
initialData: {
|
initialData: {
|
||||||
relation: [{ id: 1 }],
|
relation: [{ id: 1, __temp_key__: 'a0' }],
|
||||||
},
|
},
|
||||||
modifiedData: {
|
modifiedData: {
|
||||||
relation: [{ id: 1 }],
|
relation: [{ id: 1, __temp_key__: 'a0' }],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add a temp key for all the relations added', () => {
|
||||||
|
const state = {
|
||||||
|
...initialState,
|
||||||
|
initialData: {
|
||||||
|
relation: [],
|
||||||
|
},
|
||||||
|
modifiedData: {
|
||||||
|
relation: [],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const initialDataPath = ['initialData', 'relation'];
|
||||||
|
const modifiedDataPath = ['modifiedData', 'relation'];
|
||||||
|
|
||||||
|
let nextState = reducer(state, {
|
||||||
|
type: 'LOAD_RELATION',
|
||||||
|
initialDataPath,
|
||||||
|
modifiedDataPath,
|
||||||
|
value: [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 5 }],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(nextState).toStrictEqual({
|
||||||
|
...initialState,
|
||||||
|
initialData: {
|
||||||
|
relation: [
|
||||||
|
{ id: 1, __temp_key__: 'a0' },
|
||||||
|
{ id: 2, __temp_key__: 'a1' },
|
||||||
|
{ id: 3, __temp_key__: 'a2' },
|
||||||
|
{ id: 4, __temp_key__: 'a3' },
|
||||||
|
{ id: 5, __temp_key__: 'a4' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
modifiedData: {
|
||||||
|
relation: [
|
||||||
|
{ id: 1, __temp_key__: 'a0' },
|
||||||
|
{ id: 2, __temp_key__: 'a1' },
|
||||||
|
{ id: 3, __temp_key__: 'a2' },
|
||||||
|
{ id: 4, __temp_key__: 'a3' },
|
||||||
|
{ id: 5, __temp_key__: 'a4' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add a temp key working backwards on every new load because of how relations are shown in the UI', () => {
|
||||||
|
const state = {
|
||||||
|
...initialState,
|
||||||
|
initialData: {
|
||||||
|
relation: [],
|
||||||
|
},
|
||||||
|
modifiedData: {
|
||||||
|
relation: [],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const initialDataPath = ['initialData', 'relation'];
|
||||||
|
const modifiedDataPath = ['modifiedData', 'relation'];
|
||||||
|
|
||||||
|
let nextState = reducer(state, {
|
||||||
|
type: 'LOAD_RELATION',
|
||||||
|
initialDataPath,
|
||||||
|
modifiedDataPath,
|
||||||
|
value: [{ id: 1 }, { id: 2 }],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(
|
||||||
|
reducer(nextState, {
|
||||||
|
type: 'LOAD_RELATION',
|
||||||
|
initialDataPath,
|
||||||
|
modifiedDataPath,
|
||||||
|
value: [{ id: 3 }, { id: 4 }],
|
||||||
|
})
|
||||||
|
).toStrictEqual({
|
||||||
|
...initialState,
|
||||||
|
initialData: {
|
||||||
|
relation: [
|
||||||
|
{ id: 3, __temp_key__: 'Zy' },
|
||||||
|
{ id: 4, __temp_key__: 'Zz' },
|
||||||
|
{ id: 1, __temp_key__: 'a0' },
|
||||||
|
{ id: 2, __temp_key__: 'a1' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
modifiedData: {
|
||||||
|
relation: [
|
||||||
|
{ id: 3, __temp_key__: 'Zy' },
|
||||||
|
{ id: 4, __temp_key__: 'Zz' },
|
||||||
|
{ id: 1, __temp_key__: 'a0' },
|
||||||
|
{ id: 2, __temp_key__: 'a1' },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -2397,10 +2564,10 @@ describe('CONTENT MANAGER | COMPONENTS | EditViewDataManagerProvider | reducer',
|
|||||||
field1: {
|
field1: {
|
||||||
field2: {
|
field2: {
|
||||||
relation: [
|
relation: [
|
||||||
{ name: 'first' },
|
{ name: 'first', __temp_key__: 'a0' },
|
||||||
{ name: 'second' },
|
{ name: 'second', __temp_key__: 'a1' },
|
||||||
{ name: 'third' },
|
{ name: 'third', __temp_key__: 'a2' },
|
||||||
{ name: 'fourth' },
|
{ name: 'fourth', __temp_key__: 'a3' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -2421,10 +2588,10 @@ describe('CONTENT MANAGER | COMPONENTS | EditViewDataManagerProvider | reducer',
|
|||||||
field1: {
|
field1: {
|
||||||
field2: {
|
field2: {
|
||||||
relation: [
|
relation: [
|
||||||
{ name: 'first' },
|
{ name: 'first', __temp_key__: 'a0' },
|
||||||
{ name: 'fourth' },
|
{ name: 'fourth', __temp_key__: 'a0V' },
|
||||||
{ name: 'second' },
|
{ name: 'second', __temp_key__: 'a1' },
|
||||||
{ name: 'third' },
|
{ name: 'third', __temp_key__: 'a2' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -2433,6 +2600,89 @@ describe('CONTENT MANAGER | COMPONENTS | EditViewDataManagerProvider | reducer',
|
|||||||
|
|
||||||
expect(reducer(state, action)).toEqual(expected);
|
expect(reducer(state, action)).toEqual(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should move many components many times and have the correct temp keys', () => {
|
||||||
|
const state = {
|
||||||
|
...initialState,
|
||||||
|
modifiedData: {
|
||||||
|
relation: [
|
||||||
|
{ name: 'first', __temp_key__: 'a0' },
|
||||||
|
{ name: 'second', __temp_key__: 'a1' },
|
||||||
|
{ name: 'third', __temp_key__: 'a2' },
|
||||||
|
{ name: 'fourth', __temp_key__: 'a3' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateAction = (newIndex, oldIndex) => ({
|
||||||
|
type: 'REORDER_RELATION',
|
||||||
|
newIndex,
|
||||||
|
oldIndex,
|
||||||
|
keys: ['relation'],
|
||||||
|
});
|
||||||
|
|
||||||
|
const generateExpected = (relation = []) => ({
|
||||||
|
...initialState,
|
||||||
|
modifiedData: {
|
||||||
|
relation,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const nextState1 = reducer(state, generateAction(1, 3));
|
||||||
|
|
||||||
|
expect(nextState1).toEqual(
|
||||||
|
generateExpected([
|
||||||
|
{ name: 'first', __temp_key__: 'a0' },
|
||||||
|
{ name: 'fourth', __temp_key__: 'a0V' },
|
||||||
|
{ name: 'second', __temp_key__: 'a1' },
|
||||||
|
{ name: 'third', __temp_key__: 'a2' },
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
const nextState2 = reducer(nextState1, generateAction(1, 2));
|
||||||
|
|
||||||
|
expect(nextState2).toEqual(
|
||||||
|
generateExpected([
|
||||||
|
{ name: 'first', __temp_key__: 'a0' },
|
||||||
|
{ name: 'second', __temp_key__: 'a0G' },
|
||||||
|
{ name: 'fourth', __temp_key__: 'a0V' },
|
||||||
|
{ name: 'third', __temp_key__: 'a2' },
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
const nextState3 = reducer(nextState2, generateAction(0, 3));
|
||||||
|
|
||||||
|
expect(nextState3).toEqual(
|
||||||
|
generateExpected([
|
||||||
|
{ name: 'third', __temp_key__: 'Zz' },
|
||||||
|
{ name: 'first', __temp_key__: 'a0' },
|
||||||
|
{ name: 'second', __temp_key__: 'a0G' },
|
||||||
|
{ name: 'fourth', __temp_key__: 'a0V' },
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
const nextState4 = reducer(nextState3, generateAction(3, 1));
|
||||||
|
|
||||||
|
expect(nextState4).toEqual(
|
||||||
|
generateExpected([
|
||||||
|
{ name: 'third', __temp_key__: 'Zz' },
|
||||||
|
{ name: 'second', __temp_key__: 'a0G' },
|
||||||
|
{ name: 'fourth', __temp_key__: 'a0V' },
|
||||||
|
{ name: 'first', __temp_key__: 'a0O' },
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
const nextState5 = reducer(nextState4, generateAction(1, 2));
|
||||||
|
|
||||||
|
expect(nextState5).toEqual(
|
||||||
|
generateExpected([
|
||||||
|
{ name: 'third', __temp_key__: 'Zz' },
|
||||||
|
{ name: 'fourth', __temp_key__: 'a0' },
|
||||||
|
{ name: 'second', __temp_key__: 'a0G' },
|
||||||
|
{ name: 'first', __temp_key__: 'a0O' },
|
||||||
|
])
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('SET_DEFAULT_DATA_STRUCTURES', () => {
|
describe('SET_DEFAULT_DATA_STRUCTURES', () => {
|
||||||
|
@ -95,28 +95,22 @@ const cleanData = ({ browserState, serverState }, currentSchema, componentsSchem
|
|||||||
*/
|
*/
|
||||||
let actualOldValue = get(rootServerState, trueInitialDataPath, []);
|
let actualOldValue = get(rootServerState, trueInitialDataPath, []);
|
||||||
|
|
||||||
const valuesWithPositions = value.map((relation, index, allRelations) => {
|
|
||||||
const nextRelation = allRelations[index + 1];
|
|
||||||
|
|
||||||
if (nextRelation) {
|
|
||||||
return { ...relation, position: { before: nextRelation.id } };
|
|
||||||
}
|
|
||||||
|
|
||||||
return { ...relation, position: { end: true } };
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instead of the full relation object, we only want to send its ID
|
* Instead of the full relation object, we only want to send its ID
|
||||||
* connectedRelations are the items that are in the browserState
|
* connectedRelations are the items that are in the browserState
|
||||||
* array but not in the serverState
|
* array but not in the serverState
|
||||||
*/
|
*/
|
||||||
const connectedRelations = valuesWithPositions.reduce((acc, relation, currentIndex) => {
|
const connectedRelations = value.reduce((acc, relation, currentIndex, array) => {
|
||||||
const indexOfRelationOnServer = actualOldValue.findIndex(
|
const relationOnServer = actualOldValue.find(
|
||||||
(oldRelation) => oldRelation.id === relation.id
|
(oldRelation) => oldRelation.id === relation.id
|
||||||
);
|
);
|
||||||
|
|
||||||
if (indexOfRelationOnServer === -1 || indexOfRelationOnServer !== currentIndex) {
|
const relationInFront = array[currentIndex + 1];
|
||||||
return [...acc, { id: relation.id, position: relation.position }];
|
|
||||||
|
if (!relationOnServer || relationOnServer.__temp_key__ !== relation.__temp_key__) {
|
||||||
|
const position = relationInFront ? { before: relationInFront.id } : { end: true };
|
||||||
|
|
||||||
|
return [...acc, { id: relation.id, position }];
|
||||||
}
|
}
|
||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
@ -127,7 +121,7 @@ const cleanData = ({ browserState, serverState }, currentSchema, componentsSchem
|
|||||||
* are no longer in the browserState
|
* are no longer in the browserState
|
||||||
*/
|
*/
|
||||||
const disconnectedRelations = actualOldValue.reduce((acc, relation) => {
|
const disconnectedRelations = actualOldValue.reduce((acc, relation) => {
|
||||||
if (!valuesWithPositions.find((newRelation) => newRelation.id === relation.id)) {
|
if (!value.find((newRelation) => newRelation.id === relation.id)) {
|
||||||
return [...acc, { id: relation.id }];
|
return [...acc, { id: relation.id }];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,10 +407,10 @@ describe('CM || components || EditViewDataManagerProvider || utils || cleanData'
|
|||||||
const result = cleanData(
|
const result = cleanData(
|
||||||
{
|
{
|
||||||
browserState: {
|
browserState: {
|
||||||
relation: [{ id: 1, something: true }],
|
relation: [{ id: 1, __temp_key__: 'a1', something: true }],
|
||||||
},
|
},
|
||||||
serverState: {
|
serverState: {
|
||||||
relation: [{ id: 2, something: true }],
|
relation: [{ id: 2, __temp_key__: 'a0', something: true }],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
schema,
|
schema,
|
||||||
@ -429,7 +429,7 @@ describe('CM || components || EditViewDataManagerProvider || utils || cleanData'
|
|||||||
const result = cleanData(
|
const result = cleanData(
|
||||||
{
|
{
|
||||||
browserState: {
|
browserState: {
|
||||||
relation: [{ id: 1, something: true }],
|
relation: [{ id: 1, __temp_key__: 'a0', something: true }],
|
||||||
},
|
},
|
||||||
serverState: {
|
serverState: {
|
||||||
relation: [],
|
relation: [],
|
||||||
@ -454,7 +454,7 @@ describe('CM || components || EditViewDataManagerProvider || utils || cleanData'
|
|||||||
relation: [],
|
relation: [],
|
||||||
},
|
},
|
||||||
serverState: {
|
serverState: {
|
||||||
relation: [{ id: 1, something: true }],
|
relation: [{ id: 1, __temp_key__: 'a0', something: true }],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
schema,
|
schema,
|
||||||
@ -477,13 +477,13 @@ describe('CM || components || EditViewDataManagerProvider || utils || cleanData'
|
|||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
relation_component: {
|
relation_component: {
|
||||||
relation: [{ id: 1 }],
|
relation: [{ id: 1, __temp_key__: 'a0' }],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
relation_component: {
|
relation_component: {
|
||||||
relation: [{ id: 2 }],
|
relation: [{ id: 2, __temp_key__: 'a0' }],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -541,7 +541,7 @@ describe('CM || components || EditViewDataManagerProvider || utils || cleanData'
|
|||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
relation_component: {
|
relation_component: {
|
||||||
relation: [{ id: 2 }],
|
relation: [{ id: 2, __temp_key__: 'a0' }],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -551,13 +551,13 @@ describe('CM || components || EditViewDataManagerProvider || utils || cleanData'
|
|||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
relation_component: {
|
relation_component: {
|
||||||
relation: [{ id: 1 }],
|
relation: [{ id: 1, __temp_key__: 'a0' }],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
relation_component: {
|
relation_component: {
|
||||||
relation: [{ id: 2 }],
|
relation: [{ id: 2, __temp_key__: 'a0' }],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -599,13 +599,13 @@ describe('CM || components || EditViewDataManagerProvider || utils || cleanData'
|
|||||||
{
|
{
|
||||||
__component: 'basic.relation',
|
__component: 'basic.relation',
|
||||||
id: 1,
|
id: 1,
|
||||||
relation: [{ id: 1 }],
|
relation: [{ id: 1, __temp_key__: 'a0' }],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
__component: 'basic.nested-relation',
|
__component: 'basic.nested-relation',
|
||||||
id: 2,
|
id: 2,
|
||||||
relation_component: {
|
relation_component: {
|
||||||
relation: [{ id: 2 }],
|
relation: [{ id: 2, __temp_key__: 'a0' }],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -615,7 +615,7 @@ describe('CM || components || EditViewDataManagerProvider || utils || cleanData'
|
|||||||
{
|
{
|
||||||
__component: 'basic.relation',
|
__component: 'basic.relation',
|
||||||
id: 1,
|
id: 1,
|
||||||
relation: [{ id: 3 }],
|
relation: [{ id: 3, __temp_key__: 'a0' }],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -715,7 +715,7 @@ describe('CM || components || EditViewDataManagerProvider || utils || cleanData'
|
|||||||
{
|
{
|
||||||
__component: 'basic.relation',
|
__component: 'basic.relation',
|
||||||
id: 1,
|
id: 1,
|
||||||
relation: [{ id: 3 }],
|
relation: [{ id: 3, __temp_key__: 'a0' }],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
__component: 'basic.relation',
|
__component: 'basic.relation',
|
||||||
@ -731,13 +731,13 @@ describe('CM || components || EditViewDataManagerProvider || utils || cleanData'
|
|||||||
{
|
{
|
||||||
__component: 'basic.relation',
|
__component: 'basic.relation',
|
||||||
id: 1,
|
id: 1,
|
||||||
relation: [{ id: 1 }],
|
relation: [{ id: 1, __temp_key__: 'a0' }],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
__component: 'basic.nested-relation',
|
__component: 'basic.nested-relation',
|
||||||
id: 2,
|
id: 2,
|
||||||
relation_component: {
|
relation_component: {
|
||||||
relation: [{ id: 2 }],
|
relation: [{ id: 2, __temp_key__: 'a0' }],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -747,12 +747,12 @@ describe('CM || components || EditViewDataManagerProvider || utils || cleanData'
|
|||||||
{
|
{
|
||||||
__component: 'basic.relation',
|
__component: 'basic.relation',
|
||||||
id: 1,
|
id: 1,
|
||||||
relation: [{ id: 3 }],
|
relation: [{ id: 3, __temp_key__: 'a0' }],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
__component: 'basic.relation',
|
__component: 'basic.relation',
|
||||||
id: 2,
|
id: 2,
|
||||||
relation: [{ id: 4 }],
|
relation: [{ id: 4, __temp_key__: 'a0' }],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -813,10 +813,16 @@ describe('CM || components || EditViewDataManagerProvider || utils || cleanData'
|
|||||||
const result = cleanData(
|
const result = cleanData(
|
||||||
{
|
{
|
||||||
browserState: {
|
browserState: {
|
||||||
relation: [{ id: 1 }, { id: 2 }],
|
relation: [
|
||||||
|
{ id: 1, __temp_key__: 'Zz' },
|
||||||
|
{ id: 2, __temp_key__: 'a0' },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
serverState: {
|
serverState: {
|
||||||
relation: [{ id: 2 }, { id: 1 }],
|
relation: [
|
||||||
|
{ id: 2, __temp_key__: 'a0' },
|
||||||
|
{ id: 1, __temp_key__: 'a1' },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
schema,
|
schema,
|
||||||
@ -825,10 +831,7 @@ describe('CM || components || EditViewDataManagerProvider || utils || cleanData'
|
|||||||
|
|
||||||
expect(result).toStrictEqual({
|
expect(result).toStrictEqual({
|
||||||
relation: {
|
relation: {
|
||||||
connect: [
|
connect: [{ id: 1, position: { before: 2 } }],
|
||||||
{ id: 2, position: { end: true } },
|
|
||||||
{ id: 1, position: { before: 2 } },
|
|
||||||
],
|
|
||||||
disconnect: [],
|
disconnect: [],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -838,10 +841,17 @@ describe('CM || components || EditViewDataManagerProvider || utils || cleanData'
|
|||||||
const result = cleanData(
|
const result = cleanData(
|
||||||
{
|
{
|
||||||
browserState: {
|
browserState: {
|
||||||
relation: [{ id: 3 }, { id: 1 }, { id: 2 }],
|
relation: [
|
||||||
|
{ id: 3, __temp_key__: 'Zz' },
|
||||||
|
{ id: 1, __temp_key__: 'a0' },
|
||||||
|
{ id: 2, __temp_key__: 'a1' },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
serverState: {
|
serverState: {
|
||||||
relation: [{ id: 1 }, { id: 2 }],
|
relation: [
|
||||||
|
{ id: 1, __temp_key__: 'a0' },
|
||||||
|
{ id: 2, __temp_key__: 'a1' },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
schema,
|
schema,
|
||||||
@ -851,8 +861,6 @@ describe('CM || components || EditViewDataManagerProvider || utils || cleanData'
|
|||||||
expect(result).toStrictEqual({
|
expect(result).toStrictEqual({
|
||||||
relation: {
|
relation: {
|
||||||
connect: [
|
connect: [
|
||||||
{ id: 2, position: { end: true } },
|
|
||||||
{ id: 1, position: { before: 2 } },
|
|
||||||
{
|
{
|
||||||
id: 3,
|
id: 3,
|
||||||
position: { before: 1 },
|
position: { before: 1 },
|
||||||
@ -867,10 +875,18 @@ describe('CM || components || EditViewDataManagerProvider || utils || cleanData'
|
|||||||
const result = cleanData(
|
const result = cleanData(
|
||||||
{
|
{
|
||||||
browserState: {
|
browserState: {
|
||||||
relation: [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }],
|
relation: [
|
||||||
|
{ id: 1, __temp_key__: 'a0' },
|
||||||
|
{ id: 2, __temp_key__: 'a1' },
|
||||||
|
{ id: 3, __temp_key__: 'a2' },
|
||||||
|
{ id: 4, __temp_key__: 'a3' },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
serverState: {
|
serverState: {
|
||||||
relation: [{ id: 1 }, { id: 2 }],
|
relation: [
|
||||||
|
{ id: 1, __temp_key__: 'a0' },
|
||||||
|
{ id: 2, __temp_key__: 'a1' },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
schema,
|
schema,
|
||||||
@ -893,5 +909,255 @@ describe('CM || components || EditViewDataManagerProvider || utils || cleanData'
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('given a complicated list of reorderd relations it should only contain the items that moved', () => {
|
||||||
|
const result = cleanData(
|
||||||
|
{
|
||||||
|
browserState: {
|
||||||
|
relation: [
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
__temp_key__: 'Zw',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
__temp_key__: 'Zx',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
__temp_key__: 'Zwl',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
__temp_key__: 'ZwV',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
__temp_key__: 'Zy',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 7,
|
||||||
|
__temp_key__: 'Zz',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 10,
|
||||||
|
__temp_key__: 'ZzV',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
|
__temp_key__: 'a0',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 9,
|
||||||
|
__temp_key__: 'a0G',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 8,
|
||||||
|
__temp_key__: 'a0V',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
serverState: {
|
||||||
|
relation: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
__temp_key__: 'Zv',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
__temp_key__: 'Zw',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
__temp_key__: 'Zx',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
__temp_key__: 'Zy',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
__temp_key__: 'Zz',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
|
__temp_key__: 'a0',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 7,
|
||||||
|
__temp_key__: 'a1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 8,
|
||||||
|
__temp_key__: 'a2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 9,
|
||||||
|
__temp_key__: 'a3',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 10,
|
||||||
|
__temp_key__: 'a4',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
schema,
|
||||||
|
componentsSchema
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result).toStrictEqual({
|
||||||
|
relation: {
|
||||||
|
connect: [
|
||||||
|
{
|
||||||
|
id: 8,
|
||||||
|
position: {
|
||||||
|
end: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 9,
|
||||||
|
position: {
|
||||||
|
before: 8,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 10,
|
||||||
|
position: {
|
||||||
|
before: 6,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 7,
|
||||||
|
position: {
|
||||||
|
before: 10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
position: {
|
||||||
|
before: 5,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
position: {
|
||||||
|
before: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
disconnect: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('given a long list of relations and i move the first to the last, only that item should be in the payload', () => {
|
||||||
|
const result = cleanData(
|
||||||
|
{
|
||||||
|
browserState: {
|
||||||
|
relation: [
|
||||||
|
{
|
||||||
|
id: 10,
|
||||||
|
__temp_key__: 'Zu',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
__temp_key__: 'Zv',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
__temp_key__: 'Zw',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
__temp_key__: 'Zx',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
__temp_key__: 'Zy',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
__temp_key__: 'Zz',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
|
__temp_key__: 'a0',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 7,
|
||||||
|
__temp_key__: 'a1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 8,
|
||||||
|
__temp_key__: 'a2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 9,
|
||||||
|
__temp_key__: 'a3',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
serverState: {
|
||||||
|
relation: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
__temp_key__: 'Zv',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
__temp_key__: 'Zw',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
__temp_key__: 'Zx',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
__temp_key__: 'Zy',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
__temp_key__: 'Zz',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
|
__temp_key__: 'a0',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 7,
|
||||||
|
__temp_key__: 'a1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 8,
|
||||||
|
__temp_key__: 'a2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 9,
|
||||||
|
__temp_key__: 'a3',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 10,
|
||||||
|
__temp_key__: 'a4',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
schema,
|
||||||
|
componentsSchema
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result).toStrictEqual({
|
||||||
|
relation: {
|
||||||
|
connect: [
|
||||||
|
{
|
||||||
|
id: 10,
|
||||||
|
position: { before: 1 },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
disconnect: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -73,6 +73,7 @@
|
|||||||
"find-root": "1.1.0",
|
"find-root": "1.1.0",
|
||||||
"fork-ts-checker-webpack-plugin": "7.2.1",
|
"fork-ts-checker-webpack-plugin": "7.2.1",
|
||||||
"formik": "^2.2.6",
|
"formik": "^2.2.6",
|
||||||
|
"fractional-indexing": "3.2.0",
|
||||||
"fs-extra": "10.0.0",
|
"fs-extra": "10.0.0",
|
||||||
"highlight.js": "^10.4.1",
|
"highlight.js": "^10.4.1",
|
||||||
"history": "^4.9.0",
|
"history": "^4.9.0",
|
||||||
|
@ -12013,6 +12013,11 @@ forwarded@0.2.0:
|
|||||||
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
|
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
|
||||||
integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
|
integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
|
||||||
|
|
||||||
|
fractional-indexing@3.2.0:
|
||||||
|
version "3.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/fractional-indexing/-/fractional-indexing-3.2.0.tgz#1193e63d54ff4e0cbe0c79a9ed6cfbab25d91628"
|
||||||
|
integrity sha512-PcOxmqwYCW7O2ovKRU8OoQQj2yqTfEB/yeTYk4gPid6dN5ODRfU1hXd9tTVZzax/0NkO7AxpHykvZnT1aYp/BQ==
|
||||||
|
|
||||||
fragment-cache@^0.2.1:
|
fragment-cache@^0.2.1:
|
||||||
version "0.2.1"
|
version "0.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19"
|
resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19"
|
||||||
@ -17862,6 +17867,8 @@ path-case@^2.1.0:
|
|||||||
version "2.1.1"
|
version "2.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/path-case/-/path-case-2.1.1.tgz#94b8037c372d3fe2906e465bb45e25d226e8eea5"
|
resolved "https://registry.yarnpkg.com/path-case/-/path-case-2.1.1.tgz#94b8037c372d3fe2906e465bb45e25d226e8eea5"
|
||||||
integrity sha1-lLgDfDctP+KQbkZbtF4l0ibo7qU=
|
integrity sha1-lLgDfDctP+KQbkZbtF4l0ibo7qU=
|
||||||
|
dependencies:
|
||||||
|
no-case "^2.2.0"
|
||||||
|
|
||||||
path-dirname@^1.0.0:
|
path-dirname@^1.0.0:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user