Skip to content

Commit

Permalink
Prevent nesting a parent inside of its own child
Browse files Browse the repository at this point in the history
  • Loading branch information
jloleysens committed Apr 29, 2020
1 parent b60ef5f commit 61d194b
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -136,4 +136,47 @@ describe('Processors reducer', () => {
},
]);
});

it('prevents moving a parent into child list', () => {
const processor1 = { type: 'test1', options: {} };
const processor2 = { type: 'test2', options: {} };
const processor3 = { type: 'test3', options: {} };
const processor4 = { type: 'test4', options: {} };

const s1 = reducer(initialState, {
type: 'addTopLevelProcessor',
payload: { processor: processor1 },
});

const s2 = reducer(s1, {
type: 'addTopLevelProcessor',
payload: { processor: processor2 },
});

const s3 = reducer(s2, {
type: 'addOnFailureProcessor',
payload: { onFailureProcessor: processor3, targetSelector: ['1'] },
});

const s4 = reducer(s3, {
type: 'addOnFailureProcessor',
payload: { onFailureProcessor: processor4, targetSelector: ['1', 'onFailure', '0'] },
});

expect(s4.processors).toEqual([
processor1,
{ ...processor2, onFailure: [{ ...processor3, onFailure: [processor4] }] },
]);

// Move the parent into a child list
const s5 = reducer(s4, {
type: 'moveProcessor',
payload: {
source: { selector: [], index: 1 },
destination: { selector: ['1', 'onFailure', '0', 'onFailure', '0', 'onFailure'], index: 0 },
},
});

expect(s5.processors).toEqual(s4.processors);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { euiDragDropReorder } from '@elastic/eui';
import { OnFormUpdateArg } from '../../../shared_imports';

import { DeserializeResult } from './data_in';
import { getValue, setValue, unsafeProcessorMove } from './utils';
import { getValue, setValue, unsafeProcessorMove, PARENT_CHILD_NEST_ERROR } from './utils';
import { ProcessorInternal, DraggableLocation, ProcessorSelector } from './types';

type StateArg = DeserializeResult;
Expand Down Expand Up @@ -62,11 +62,17 @@ export const reducer: Reducer<State, Action> = (state, action) => {
euiDragDropReorder(getValue(path, state), source.index, destination.index)
);
} else {
return setValue(
['processors'],
state,
unsafeProcessorMove(state.processors, source, destination)
);
try {
return setValue(
['processors'],
state,
unsafeProcessorMove(state.processors, source, destination)
);
} catch (e) {
if (e.message === PARENT_CHILD_NEST_ERROR) {
return { ...state };
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ export const setValue = <Target = any, Value = any>(
return result!;
};

export const PARENT_CHILD_NEST_ERROR = 'PARENT_CHILD_NEST_ERROR';

/**
* Unsafe!
*
Expand All @@ -105,6 +107,10 @@ export const unsafeProcessorMove = (
source: DraggableLocation,
destination: DraggableLocation
) => {
const selectorToSource = source.selector.concat(String(source.index));
if (selectorToSource.every((pathSegment, idx) => pathSegment === destination.selector[idx])) {
throw new Error(PARENT_CHILD_NEST_ERROR);
}
// Start by setting up references to objects of interest using our selectors
// At this point, our selectors are consistent with the data passed in.
const sourceProcessors = getValue<ProcessorInternal[]>(source.selector, processors);
Expand Down

0 comments on commit 61d194b

Please sign in to comment.