Skip to content

Commit 2da6c4e

Browse files
fix: drag-drop card reorder now persists in SA Data Contract
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 1ab60cf commit 2da6c4e

3 files changed

Lines changed: 51 additions & 5 deletions

File tree

app/src/lib/adapters/standalone-adapter.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ export function createStandaloneAdapter(callbacks: {
4444
onSetPatternOverride?: (patternId: string, override: ContractPatternOverride) => void;
4545
/** Optional: remove a pattern override (revert to static defaults for that pattern). */
4646
onDeletePatternOverride?: (patternId: string) => void;
47+
/** Optional: reorder an item within its containing array. Called when the
48+
* shared CanvasSection drag-drop emits `properties.order` updates. */
49+
onReorderItem?: (sourceId: string, newOrder: number) => void;
4750
}): DataAdapter {
4851
function getSnapshot() {
4952
return contractToContextPlane(callbacks.getModel());
@@ -159,10 +162,18 @@ export function createStandaloneAdapter(callbacks: {
159162
if (updates.description !== undefined) nameOrDesc.description = updates.description;
160163
if (Object.keys(nameOrDesc).length > 0) callbacks.onUpdateNode(sourceId, nameOrDesc);
161164

162-
if (updates.properties && callbacks.onUpdateItemProperties) {
163-
// Strip out non-editable system properties
164-
const { canvas: _c, sourceId: _s, order: _o, ...rest } = updates.properties as Record<string, unknown>;
165-
if (Object.keys(rest).length > 0) callbacks.onUpdateItemProperties(sourceId, rest);
165+
if (updates.properties) {
166+
const props = updates.properties as Record<string, unknown>;
167+
// Drag-drop reorder: shared CanvasSection emits per-card
168+
// `properties.order` updates with the new 1-based slot.
169+
if (typeof props.order === 'number' && callbacks.onReorderItem) {
170+
callbacks.onReorderItem(sourceId, props.order);
171+
}
172+
if (callbacks.onUpdateItemProperties) {
173+
// Strip system properties + `order` (handled above) before forwarding.
174+
const { canvas: _c, sourceId: _s, order: _o, ...rest } = props;
175+
if (Object.keys(rest).length > 0) callbacks.onUpdateItemProperties(sourceId, rest);
176+
}
166177
}
167178
}
168179

app/src/lib/stores/contract.svelte.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,6 +1073,33 @@ export function setExampleData(rows: ExampleDataRow[]) {
10731073
// adapter routes those calls into these mutators so the changes land on the
10741074
// model and survive page reload.
10751075

1076+
/**
1077+
* Move an item to a new position within its containing array, given its raw
1078+
* ContractItem id and the new 1-based order. Used by the shared
1079+
* CanvasSection's drag-drop reorder. The converter emits `order: i + 1` per
1080+
* item, so reorder requests come in 1-based — we splice to slot `order - 1`.
1081+
*
1082+
* Searches all known array fields for the item; no entity-label mapping
1083+
* needed. No-op if the item isn't found or the slot doesn't change.
1084+
*/
1085+
export function reorderItem(itemId: string, newOrder: number) {
1086+
const arrays: (keyof ContractModel)[] = [
1087+
'team', 'personas', 'columns', 'glossaryTerms',
1088+
'deliveryTypes', 'trustRules', 'dataSyncs', 'lineage'
1089+
];
1090+
for (const field of arrays) {
1091+
const arr = store.model[field] as ContractItem[];
1092+
const fromIdx = arr.findIndex((i) => i.id === itemId);
1093+
if (fromIdx === -1) continue;
1094+
const toIdx = Math.max(0, Math.min(arr.length - 1, newOrder - 1));
1095+
if (fromIdx === toIdx) return;
1096+
const [moved] = arr.splice(fromIdx, 1);
1097+
arr.splice(toIdx, 0, moved);
1098+
markDirty();
1099+
return;
1100+
}
1101+
}
1102+
10761103
/** Replace the per-contract list of pattern types. `null` = use static defaults. */
10771104
export function setPatternTypes(types: ContractPatternType[] | null) {
10781105
store.model.patternTypes = types;

app/src/routes/+page.svelte

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
migrateModel,
1919
setPatternTypes,
2020
setPatternOverride,
21-
deletePatternOverride
21+
deletePatternOverride,
22+
reorderItem
2223
} from '$lib/stores/contract.svelte';
2324
import { contractToContextPlane, contextPlaneToContract } from '$lib/converters/context-plane';
2425
import { seedDemoIfEmpty } from '$lib/stores/demo-seed';
@@ -108,6 +109,13 @@
108109
deletePatternOverride(patternId);
109110
clearTimeout(orderSaveTimer);
110111
orderSaveTimer = setTimeout(() => saveModel(), 300);
112+
},
113+
onReorderItem: (sourceId, newOrder) => {
114+
reorderItem(sourceId, newOrder);
115+
// Drag-drop fires N updateNode calls in sequence (one per affected
116+
// card). Debounce so we save once after the whole reorder lands.
117+
clearTimeout(orderSaveTimer);
118+
orderSaveTimer = setTimeout(() => saveModel(), 300);
111119
}
112120
});
113121
setContext('dataAdapter', adapter);

0 commit comments

Comments
 (0)