fix: prevent nesting groups

This commit is contained in:
Carlos Valente
2025-07-27 17:05:15 +02:00
committed by Carlos Valente
parent 9ab54edbf5
commit 524721002a
4 changed files with 33 additions and 14 deletions
@@ -693,6 +693,7 @@ export const useEntryActions = () => {
await reorderEntryMutation(reorderObject);
} catch (error) {
logAxiosError('Error re-ordering event', error);
throw error; // rethrow to handle in the component
}
},
[reorderEntryMutation],
+16 -7
View File
@@ -44,7 +44,7 @@ import QuickAddButtons from './entry-editor/quick-add-buttons/QuickAddButtons';
import QuickAddInline from './entry-editor/quick-add-cursor/QuickAddInline';
import BlockEnd from './rundown-block/BlockEnd';
import RundownBlock from './rundown-block/RundownBlock';
import { makeRundownMetadata, makeSortableList } from './rundown.utils';
import { canDrop, makeRundownMetadata, makeSortableList } from './rundown.utils';
import RundownEmpty from './RundownEmpty';
import { useEventSelection } from './useEventSelection';
@@ -335,14 +335,14 @@ export default function Rundown({ data }: RundownProps) {
return;
}
// prevent dropping a group inside another
if (active.data.current?.type === 'block' && !canDrop(over.data.current?.type, over.data.current?.parent)) {
return;
}
const fromIndex = active.data.current?.sortable.index;
const toIndex = over.data.current?.sortable.index;
// we keep a copy of the state as a hack to handle inconsistencies between dnd-kit and async store updates
setSortableData((currentEntries) => {
return reorderArray(currentEntries, fromIndex, toIndex);
});
let destinationId = over.id as EntryId;
let order: 'before' | 'after' | 'insert' = fromIndex < toIndex ? 'after' : 'before';
@@ -368,7 +368,16 @@ export default function Rundown({ data }: RundownProps) {
}
}
}
reorderEntry(active.id as EntryId, destinationId, order);
// keep copy of the current state in case we need to revert
const currentEntries = structuredClone(sortableData);
// we keep a copy of the state as a hack to handle inconsistencies between dnd-kit and async store updates
setSortableData((currentEntries) => {
return reorderArray(currentEntries, fromIndex, toIndex);
});
reorderEntry(active.id as EntryId, destinationId, order).catch((_) => {
setSortableData(currentEntries);
});
};
/**
@@ -17,6 +17,9 @@ export default function BlockEnd({ id, colour }: BlockEndProps) {
transition,
} = useSortable({
id,
data: {
type: 'end-block',
},
animateLayoutChanges: () => false,
disabled: true, // we do not want to drag end blocks
});
@@ -158,15 +158,21 @@ export function makeSortableList(order: EntryId[], entries: RundownEntries): Ent
/**
* Checks whether a drop operation is valid
* Currently only used for validating dropping blocks
* Currently only used for validating dropping groups
*/
export function canDrop(targetType?: SupportedEntry, targetParent?: EntryId | null): boolean {
if (targetType === 'event' || targetType === 'delay') {
return targetParent === null;
export function canDrop(targetType?: SupportedEntry & 'end-block', targetParent?: EntryId | null): boolean {
// this would mean inserting a group inside another
if (targetType === 'end-block') {
return false;
}
// remaining events will be block or end-block
// we can swap places with other blocks
return targetType == 'block';
// this means swapping places with another group
if (targetType === 'block') {
return true;
}
// for all other cases, we just need to check if we are inside a group
return targetParent === null;
}
/**