@sqlrooms/canvas 0.28.0 → 0.29.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +5 -95
  2. package/dist/Canvas.d.ts.map +1 -1
  3. package/dist/Canvas.js +72 -14
  4. package/dist/Canvas.js.map +1 -1
  5. package/dist/CanvasSlice.d.ts +42 -93
  6. package/dist/CanvasSlice.d.ts.map +1 -1
  7. package/dist/CanvasSlice.js +183 -305
  8. package/dist/CanvasSlice.js.map +1 -1
  9. package/dist/crdt.d.ts +5 -16
  10. package/dist/crdt.d.ts.map +1 -1
  11. package/dist/crdt.js +41 -28
  12. package/dist/crdt.js.map +1 -1
  13. package/dist/edgeUtils.d.ts +3 -0
  14. package/dist/edgeUtils.d.ts.map +1 -0
  15. package/dist/edgeUtils.js +7 -0
  16. package/dist/edgeUtils.js.map +1 -0
  17. package/dist/index.d.ts +1 -1
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +1 -1
  20. package/dist/index.js.map +1 -1
  21. package/dist/nodes/AddNodePopover.d.ts.map +1 -1
  22. package/dist/nodes/AddNodePopover.js +16 -9
  23. package/dist/nodes/AddNodePopover.js.map +1 -1
  24. package/dist/nodes/CanvasNodeContainer.d.ts.map +1 -1
  25. package/dist/nodes/CanvasNodeContainer.js +5 -9
  26. package/dist/nodes/CanvasNodeContainer.js.map +1 -1
  27. package/package.json +8 -10
  28. package/dist/CanvasAssistantDrawer.d.ts +0 -3
  29. package/dist/CanvasAssistantDrawer.d.ts.map +0 -1
  30. package/dist/CanvasAssistantDrawer.js +0 -14
  31. package/dist/CanvasAssistantDrawer.js.map +0 -1
  32. package/dist/dag.d.ts +0 -53
  33. package/dist/dag.d.ts.map +0 -1
  34. package/dist/dag.js +0 -124
  35. package/dist/dag.js.map +0 -1
  36. package/dist/nodes/SqlNode.d.ts +0 -11
  37. package/dist/nodes/SqlNode.d.ts.map +0 -1
  38. package/dist/nodes/SqlNode.js +0 -52
  39. package/dist/nodes/SqlNode.js.map +0 -1
  40. package/dist/nodes/VegaNode.d.ts +0 -11
  41. package/dist/nodes/VegaNode.d.ts.map +0 -1
  42. package/dist/nodes/VegaNode.js +0 -12
  43. package/dist/nodes/VegaNode.js.map +0 -1
@@ -1,338 +1,216 @@
1
1
  import { createId } from '@paralleldrive/cuid2';
2
- import { createAiSlice, createDefaultAiInstructions, createDefaultAiTools, } from '@sqlrooms/ai';
3
- import { escapeId } from '@sqlrooms/duckdb';
4
- import { createSlice, useBaseRoomStore, } from '@sqlrooms/room-shell';
5
- import { createVegaChartTool } from '@sqlrooms/vega';
6
- import { addEdge, applyEdgeChanges, applyNodeChanges, } from '@xyflow/react';
2
+ import { getSheetsByType } from '@sqlrooms/cells';
3
+ import { createSlice, useBaseRoomStore, } from '@sqlrooms/room-store';
4
+ import { generateUniqueName } from '@sqlrooms/utils';
5
+ import { applyNodeChanges, } from '@xyflow/react';
7
6
  import { produce } from 'immer';
8
7
  import { z } from 'zod';
9
- import { findNodeById, topoSortAll, topoSortDownstream } from './dag';
10
8
  const DEFAULT_NODE_WIDTH = 800;
11
9
  const DEFAULT_NODE_HEIGHT = 600;
12
10
  const CANVAS_SCHEMA_NAME = 'canvas';
13
- export const CanvasNodeTypes = z.enum(['sql', 'vega']);
14
- export const CanvasNodeData = z.discriminatedUnion('type', [
15
- z.object({
16
- title: z.string().default('Untitled'),
17
- type: z.literal('sql'),
18
- sql: z.string().optional(),
19
- }),
20
- z.object({
21
- title: z.string().default('Untitled'),
22
- type: z.literal('vega'),
23
- sql: z.string().optional(),
24
- vegaSpec: z.any().optional(),
25
- }),
26
- ]);
27
- function isSqlData(data) {
28
- return data.type === 'sql';
29
- }
30
- function getUniqueSqlTitle(nodes, baseTitle, excludeNodeId) {
31
- const existing = new Set(nodes
32
- .filter((n) => n.type === 'sql' && n.id !== (excludeNodeId || ''))
33
- .map((n) => n.data.title || ''));
34
- if (!existing.has(baseTitle))
35
- return baseTitle;
36
- let counter = 1;
37
- while (existing.has(`${baseTitle} ${counter}`))
38
- counter += 1;
39
- return `${baseTitle} ${counter}`;
40
- }
41
- export const CanvasNodeSchema = z.object({
11
+ const VIEWPORT_EPSILON = 0.1;
12
+ /** View metadata for a single node on the canvas */
13
+ export const CanvasNodeMeta = z.object({
42
14
  id: z.string(),
43
15
  position: z.object({ x: z.number(), y: z.number() }),
44
- type: CanvasNodeTypes,
45
- data: CanvasNodeData,
46
- width: z.number(),
47
- height: z.number(),
48
- });
49
- export const CanvasEdgeSchema = z.object({
50
- id: z.string(),
51
- source: z.string(),
52
- target: z.string(),
16
+ width: z.number().default(DEFAULT_NODE_WIDTH),
17
+ height: z.number().default(DEFAULT_NODE_HEIGHT),
18
+ data: z.record(z.string(), z.any()).default({}), // Required by ReactFlow NodeBase
53
19
  });
54
- export const CanvasSliceConfig = z.object({
20
+ /** View metadata for a sheet (canvas view) */
21
+ export const CanvasSheetMeta = z.object({
55
22
  viewport: z.object({
56
23
  x: z.number(),
57
24
  y: z.number(),
58
25
  zoom: z.number(),
59
26
  }),
60
- nodes: z.array(CanvasNodeSchema).default([]),
61
- edges: z.array(CanvasEdgeSchema).default([]),
27
+ nodeOrder: z.array(z.string()).default([]),
28
+ });
29
+ export const CanvasSliceConfig = z.object({
30
+ sheets: z
31
+ .record(z.string(), z.object({
32
+ id: z.string(),
33
+ nodes: z.record(z.string(), CanvasNodeMeta).default({}),
34
+ meta: CanvasSheetMeta,
35
+ }))
36
+ .default({}),
62
37
  });
38
+ function getSheet(config, sheetId) {
39
+ return config.sheets[sheetId];
40
+ }
41
+ function ensureCanvasSheetMeta(config, sheetId, viewport = { x: 0, y: 0, zoom: 1 }) {
42
+ let sheet = config.sheets[sheetId];
43
+ if (!sheet) {
44
+ sheet = {
45
+ id: sheetId,
46
+ nodes: {},
47
+ meta: {
48
+ viewport,
49
+ nodeOrder: [],
50
+ },
51
+ };
52
+ config.sheets[sheetId] = sheet;
53
+ }
54
+ return sheet;
55
+ }
56
+ function isSameViewport(a, b) {
57
+ return (Math.abs(a.x - b.x) < VIEWPORT_EPSILON &&
58
+ Math.abs(a.y - b.y) < VIEWPORT_EPSILON &&
59
+ Math.abs(a.zoom - b.zoom) < VIEWPORT_EPSILON);
60
+ }
63
61
  export function createDefaultCanvasConfig(props) {
64
- return {
65
- viewport: { x: 0, y: 0, zoom: 1 },
66
- nodes: [],
67
- edges: [],
68
- ...props,
62
+ const base = {
63
+ sheets: {},
69
64
  };
65
+ return { ...base, ...props };
70
66
  }
71
- export function createCanvasSlice(props) {
72
- return createSlice((set, get, store) => ({
73
- ...createAiSlice({
74
- getInstructions: () => {
75
- return createDefaultAiInstructions(store);
76
- },
77
- tools: {
78
- ...createDefaultAiTools(store),
79
- chart: createVegaChartTool(),
80
- ...props.ai?.tools,
81
- },
82
- ...props.ai,
83
- })(set, get, store),
84
- canvas: {
85
- config: createDefaultCanvasConfig(props.config),
86
- isAssistantOpen: false,
87
- sqlResults: {},
88
- setConfig: (config) => {
89
- set((state) => produce(state, (draft) => {
90
- draft.canvas.config = config;
91
- }));
92
- },
93
- setAssistantOpen: (isAssistantOpen) => {
94
- set((state) => produce(state, (draft) => {
95
- draft.canvas.isAssistantOpen = isAssistantOpen;
96
- }));
97
- },
98
- async initialize() {
99
- // Execute SQL nodes in topological order based on edges
100
- const nodes = get().canvas.config.nodes;
101
- const edges = get().canvas.config.edges;
102
- const order = topoSortAll(nodes, edges);
103
- // Execute SQL nodes sequentially to ensure parents finish before children
104
- for (const nodeId of order) {
105
- const node = findNodeById(get().canvas.config.nodes, nodeId);
106
- if (!node || !isSqlData(node.data))
107
- continue;
108
- const sqlText = node.data.sql || '';
109
- if (!sqlText.trim())
110
- continue;
111
- // Await ensures table creation completes before children execute
112
- await get().canvas.executeSqlNodeQuery(nodeId, { cascade: false });
113
- }
114
- await get().db.refreshTableSchemas();
115
- },
116
- addNode: ({ parentId, nodeType = 'sql', initialPosition, }) => {
117
- const newId = createId();
118
- set((state) => produce(state, (draft) => {
119
- const parent = parentId
120
- ? findNodeById(draft.canvas.config.nodes, parentId)
121
- : undefined;
122
- const position = initialPosition
123
- ? initialPosition
124
- : parent
125
- ? {
126
- x: parent.position.x + parent.width + 100,
127
- y: parent.position.y,
128
- }
129
- : {
130
- x: draft.canvas.config.viewport.x + 100,
131
- y: draft.canvas.config.viewport.y + 100,
132
- };
133
- const firstTable = draft.db.tables.find((t) => t.table.schema === 'main');
134
- const getInitialSqlForNewSqlNode = () => {
135
- if (parent && isSqlData(parent.data)) {
136
- const parentResults = draft.canvas.sqlResults[parent.id];
137
- const parentTitle = parent.data.title || 'Query';
138
- const fallbackParentTable = `${CANVAS_SCHEMA_NAME}.${escapeId(parentTitle)}`;
139
- const parentTableName = parentResults && parentResults.status === 'success'
140
- ? parentResults.tableName
141
- : fallbackParentTable;
142
- return `SELECT * FROM ${parentTableName}`;
143
- }
144
- return firstTable
145
- ? `SELECT * FROM ${firstTable.table.table}`
146
- : `SELECT 1`;
147
- };
148
- const newSqlTitle = getUniqueSqlTitle(draft.canvas.config.nodes, 'Query');
149
- const initialSql = getInitialSqlForNewSqlNode();
150
- draft.canvas.config.nodes.push({
151
- id: newId,
152
- position,
153
- width: DEFAULT_NODE_WIDTH,
154
- height: DEFAULT_NODE_HEIGHT,
155
- type: nodeType,
156
- data: (nodeType === 'sql'
157
- ? {
158
- title: newSqlTitle,
159
- type: 'sql',
160
- sql: initialSql,
161
- }
162
- : {
163
- title: 'Chart',
164
- type: 'vega',
165
- }),
67
+ export function createCanvasSlice(props = {}) {
68
+ return createSlice((set, get, store) => {
69
+ return {
70
+ canvas: {
71
+ config: createDefaultCanvasConfig(props.config),
72
+ setConfig: (config) => {
73
+ set((state) => produce(state, (draft) => {
74
+ draft.canvas.config = config;
75
+ }));
76
+ },
77
+ getCanvasSheets: () => getSheetsByType(get(), 'canvas'),
78
+ async initialize() {
79
+ const sheetId = get().cells.config.currentSheetId ||
80
+ get().cells.config.sheetOrder[0];
81
+ if (!sheetId)
82
+ return;
83
+ // don't await this - it will block the UI
84
+ get().cells.runAllCellsCascade(sheetId);
85
+ },
86
+ addNode: async ({ sheetId, nodeType = 'sql', initialPosition, parentId, }) => {
87
+ const newId = createId();
88
+ const registry = get().cells.cellRegistry;
89
+ const reg = registry[nodeType];
90
+ if (!reg)
91
+ return newId;
92
+ // 1. Create the cell in CellsSlice
93
+ const cell = reg.createCell(newId);
94
+ const existingTitles = Object.values(get().cells.config.data).map((c) => {
95
+ const title = c.data.title;
96
+ return typeof title === 'string' ? title : '';
166
97
  });
98
+ cell.data.title = generateUniqueName(`${reg.title} 1`, existingTitles, ' ');
99
+ await get().cells.addCell(sheetId, cell);
100
+ // 2. If parent exists, add an edge in CellsSlice
167
101
  if (parentId) {
168
- draft.canvas.config.edges.push({
169
- id: `${parentId}-${newId}`,
170
- source: parentId,
171
- target: newId,
172
- });
102
+ get().cells.addEdge(sheetId, { source: parentId, target: newId });
173
103
  }
174
- }));
175
- return newId;
176
- },
177
- executeDownstreamFrom: async (nodeId) => {
178
- const allNodes = get().canvas.config.nodes;
179
- const allEdges = get().canvas.config.edges;
180
- const downstreamOrder = topoSortDownstream(nodeId, allNodes, allEdges);
181
- for (const childId of downstreamOrder) {
182
- const child = findNodeById(allNodes, childId);
183
- if (!child || !isSqlData(child.data))
184
- continue;
185
- const text = child.data.sql || '';
186
- if (!text.trim())
187
- continue;
188
- await get().canvas.executeSqlNodeQuery(childId, { cascade: false });
189
- }
190
- await get().db.refreshTableSchemas();
191
- },
192
- addEdge: (connection) => {
193
- set((state) => produce(state, (draft) => {
194
- draft.canvas.config.edges = addEdge(connection, draft.canvas.config.edges);
195
- }));
196
- },
197
- updateNode: (nodeId, updater) => {
198
- set((state) => produce(state, (draft) => {
199
- const node = findNodeById(draft.canvas.config.nodes, nodeId);
200
- if (node) {
201
- node.data = updater(node.data);
202
- }
203
- }));
204
- },
205
- renameNode: async (nodeId, newTitle) => {
206
- const node = findNodeById(get().canvas.config.nodes, nodeId);
207
- if (!node)
208
- throw new Error('Node not found');
209
- if (!isSqlData(node.data)) {
104
+ // 3. Update view-specific metadata
210
105
  set((state) => produce(state, (draft) => {
211
- const dnode = findNodeById(draft.canvas.config.nodes, nodeId);
212
- if (dnode)
213
- dnode.data.title = newTitle;
106
+ let sheet = getSheet(draft.canvas.config, sheetId);
107
+ sheet = ensureCanvasSheetMeta(draft.canvas.config, sheetId);
108
+ const parentNode = parentId ? sheet.nodes[parentId] : undefined;
109
+ const position = initialPosition
110
+ ? initialPosition
111
+ : parentNode
112
+ ? {
113
+ x: parentNode.position.x + parentNode.width + 100,
114
+ y: parentNode.position.y,
115
+ }
116
+ : {
117
+ x: sheet.meta.viewport.x + 100,
118
+ y: sheet.meta.viewport.y + 100,
119
+ };
120
+ sheet.nodes[newId] = {
121
+ id: newId,
122
+ position,
123
+ width: DEFAULT_NODE_WIDTH,
124
+ height: DEFAULT_NODE_HEIGHT,
125
+ data: {},
126
+ };
127
+ sheet.meta.nodeOrder.push(newId);
214
128
  }));
215
- return;
216
- }
217
- const prevTitle = node.data.title || 'result';
218
- if (prevTitle === newTitle)
219
- return;
220
- // Ensure title uniqueness among SQL nodes by adjusting to a unique variant
221
- const uniqueTitle = getUniqueSqlTitle(get().canvas.config.nodes, newTitle, nodeId);
222
- const connector = await get().db.getConnector();
223
- await connector.query(`CREATE SCHEMA IF NOT EXISTS ${CANVAS_SCHEMA_NAME}`);
224
- const result = get().canvas.sqlResults[nodeId];
225
- const oldTableName = result && result.status === 'success'
226
- ? result.tableName
227
- : `${CANVAS_SCHEMA_NAME}.${escapeId(prevTitle)}`;
228
- await connector.query(`ALTER TABLE ${oldTableName} RENAME TO ${escapeId(uniqueTitle)}`);
229
- const newQualified = `${CANVAS_SCHEMA_NAME}.${escapeId(uniqueTitle)}`;
230
- set((state) => produce(state, (draft) => {
231
- const dnode = findNodeById(draft.canvas.config.nodes, nodeId);
232
- if (dnode)
233
- dnode.data.title = uniqueTitle;
234
- const r = draft.canvas.sqlResults[nodeId];
235
- if (r && r.status === 'success')
236
- r.tableName = newQualified;
237
- }));
238
- await get().db.refreshTableSchemas();
239
- // Recompute children since upstream table name changed
240
- await get().canvas.executeDownstreamFrom(nodeId);
241
- },
242
- deleteNode: (nodeId) => {
243
- const current = get();
244
- const node = findNodeById(current.canvas.config.nodes, nodeId);
245
- let tableToDrop;
246
- if (node && isSqlData(node.data)) {
247
- const title = node.data.title || 'result';
248
- const res = current.canvas.sqlResults[nodeId];
249
- tableToDrop =
250
- res && res.status === 'success'
251
- ? res.tableName
252
- : `${CANVAS_SCHEMA_NAME}.${escapeId(title)}`;
253
- }
254
- set((state) => produce(state, (draft) => {
255
- draft.canvas.config.nodes = draft.canvas.config.nodes.filter((n) => n.id !== nodeId);
256
- draft.canvas.config.edges = draft.canvas.config.edges.filter((e) => e.source !== nodeId && e.target !== nodeId);
257
- // Clear stored result for the node
258
- delete draft.canvas.sqlResults[nodeId];
259
- if (draft.canvas.config.nodes.length === 0) {
260
- draft.canvas.config.viewport.x = 0;
261
- draft.canvas.config.viewport.y = 0;
262
- }
263
- }));
264
- if (tableToDrop) {
265
- (async () => {
266
- try {
267
- const connector = await get().db.getConnector();
268
- await connector.query(`DROP TABLE IF EXISTS ${tableToDrop}`);
269
- await get().db.refreshTableSchemas();
270
- }
271
- catch (e) {
272
- console.warn('[canvas.deleteNode] Failed to drop table for node', nodeId, e);
129
+ return newId;
130
+ },
131
+ renameNode: async (nodeId, newTitle) => {
132
+ await get().cells.updateCell(nodeId, (c) => produce(c, (draft) => {
133
+ draft.data.title = newTitle;
134
+ }));
135
+ },
136
+ updateNode: async (nodeId, updater) => {
137
+ await get().cells.updateCell(nodeId, updater);
138
+ },
139
+ deleteNode: (nodeId) => {
140
+ get().cells.removeCell(nodeId);
141
+ set((state) => produce(state, (draft) => {
142
+ for (const sheet of Object.values(draft.canvas.config.sheets)) {
143
+ delete sheet.nodes[nodeId];
144
+ sheet.meta.nodeOrder = sheet.meta.nodeOrder.filter((id) => id !== nodeId);
273
145
  }
274
- })();
275
- }
276
- },
277
- applyNodeChanges: (changes) => {
278
- set((state) => produce(state, (draft) => {
279
- draft.canvas.config.nodes = applyNodeChanges(changes, draft.canvas.config.nodes);
280
- }));
281
- },
282
- applyEdgeChanges: (changes) => {
283
- set((state) => produce(state, (draft) => {
284
- draft.canvas.config.edges = applyEdgeChanges(changes, draft.canvas.config.edges);
285
- }));
286
- },
287
- setViewport: (viewport) => {
288
- set((state) => produce(state, (draft) => {
289
- draft.canvas.config.viewport = viewport;
290
- }));
291
- },
292
- executeSqlNodeQuery: async (nodeId, opts) => {
293
- const node = findNodeById(get().canvas.config.nodes, nodeId);
294
- if (!node || !isSqlData(node.data))
295
- return;
296
- const sql = node.data.sql || '';
297
- const title = node.data.title || 'result';
298
- set((state) => produce(state, (draft) => {
299
- draft.canvas.sqlResults[nodeId] = { status: 'loading' };
300
- }));
301
- try {
302
- // Validate it's a single select
303
- const parsed = await get().db.sqlSelectToJson(sql);
304
- if (parsed.error) {
305
- throw new Error(parsed.error_message || 'Not a valid SELECT statement');
306
- }
307
- // Create schema and table
308
- const connector = await get().db.getConnector();
309
- await connector.query(`CREATE SCHEMA IF NOT EXISTS ${CANVAS_SCHEMA_NAME}`);
310
- const tableName = `${CANVAS_SCHEMA_NAME}.${escapeId(title)}`;
311
- await connector.query(`CREATE OR REPLACE TABLE ${tableName} AS ${sql}`);
146
+ }));
147
+ },
148
+ applyNodeChanges: (changes) => {
312
149
  set((state) => produce(state, (draft) => {
313
- draft.canvas.sqlResults[nodeId] = {
314
- status: 'success',
315
- tableName,
316
- lastQueryStatement: sql,
317
- };
150
+ const sheetId = draft.cells.config.currentSheetId;
151
+ if (!sheetId)
152
+ return;
153
+ const sheet = ensureCanvasSheetMeta(draft.canvas.config, sheetId);
154
+ // Ensure all cells from CellsSlice have a node entry in CanvasSlice
155
+ const cellsSheet = draft.cells.config.sheets[sheetId];
156
+ if (cellsSheet) {
157
+ for (const cellId of cellsSheet.cellIds) {
158
+ if (!sheet.nodes[cellId]) {
159
+ sheet.nodes[cellId] = {
160
+ id: cellId,
161
+ position: { x: 100, y: 100 },
162
+ width: DEFAULT_NODE_WIDTH,
163
+ height: DEFAULT_NODE_HEIGHT,
164
+ data: {},
165
+ };
166
+ sheet.meta.nodeOrder.push(cellId);
167
+ }
168
+ }
169
+ }
170
+ const nodesArray = sheet.meta.nodeOrder
171
+ .map((id) => sheet.nodes[id])
172
+ .filter(Boolean);
173
+ const updated = applyNodeChanges(changes, nodesArray);
174
+ sheet.nodes = updated.reduce((acc, node) => {
175
+ acc[node.id] = node;
176
+ return acc;
177
+ }, {});
178
+ sheet.meta.nodeOrder = updated.map((n) => n.id);
318
179
  }));
319
- // Cascade execution to downstream SQL nodes (topologically) unless disabled
320
- if (opts?.cascade !== false) {
321
- await get().canvas.executeDownstreamFrom(nodeId);
180
+ },
181
+ applyEdgeChanges: (changes) => {
182
+ // Canvas edge editing is intentionally disabled for now.
183
+ // Compatibility no-op: keep API stable until edge kinds are introduced.
184
+ void changes;
185
+ },
186
+ addEdge: (connection) => {
187
+ // Canvas edge editing is intentionally disabled for now.
188
+ // Compatibility no-op: dependency edges are derived from graph cache.
189
+ void connection;
190
+ },
191
+ setViewport: (viewport) => {
192
+ const sheetId = get().cells.config.currentSheetId;
193
+ if (!sheetId)
194
+ return;
195
+ const existing = get().canvas.config.sheets[sheetId];
196
+ if (existing && isSameViewport(existing.meta.viewport, viewport)) {
197
+ return;
322
198
  }
323
- }
324
- catch (e) {
325
- const message = e instanceof Error ? e.message : String(e);
326
199
  set((state) => produce(state, (draft) => {
327
- draft.canvas.sqlResults[nodeId] = {
328
- status: 'error',
329
- error: message,
330
- };
200
+ let sheet = getSheet(draft.canvas.config, sheetId);
201
+ sheet = ensureCanvasSheetMeta(draft.canvas.config, sheetId, viewport);
202
+ sheet.meta.viewport = viewport;
331
203
  }));
332
- }
204
+ },
205
+ executeSqlNodeQuery: async (nodeId, opts) => {
206
+ await get().cells.runCell(nodeId, {
207
+ ...opts,
208
+ schemaName: CANVAS_SCHEMA_NAME,
209
+ });
210
+ },
333
211
  },
334
- },
335
- }));
212
+ };
213
+ });
336
214
  }
337
215
  export function useStoreWithCanvas(selector) {
338
216
  return useBaseRoomStore((state) => selector(state));
@@ -1 +1 @@
1
- {"version":3,"file":"CanvasSlice.js","sourceRoot":"","sources":["../src/CanvasSlice.ts"],"names":[],"mappings":"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","sourcesContent":["import {createId} from '@paralleldrive/cuid2';\nimport {\n AiSliceState,\n createAiSlice,\n createDefaultAiInstructions,\n createDefaultAiTools,\n} from '@sqlrooms/ai';\nimport {DuckDbSliceState, escapeId} from '@sqlrooms/duckdb';\nimport {\n BaseRoomStoreState,\n createSlice,\n useBaseRoomStore,\n} from '@sqlrooms/room-shell';\nimport {createVegaChartTool} from '@sqlrooms/vega';\nimport type {Viewport, XYPosition} from '@xyflow/react';\nimport {\n addEdge,\n applyEdgeChanges,\n applyNodeChanges,\n Connection,\n type EdgeChange,\n type NodeChange,\n} from '@xyflow/react';\nimport {produce} from 'immer';\nimport {z} from 'zod';\nimport {findNodeById, topoSortAll, topoSortDownstream} from './dag';\n\nconst DEFAULT_NODE_WIDTH = 800;\nconst DEFAULT_NODE_HEIGHT = 600;\nconst CANVAS_SCHEMA_NAME = 'canvas';\n\nexport const CanvasNodeTypes = z.enum(['sql', 'vega']);\nexport type CanvasNodeTypes = z.infer<typeof CanvasNodeTypes>;\n\nexport const CanvasNodeData = z.discriminatedUnion('type', [\n z.object({\n title: z.string().default('Untitled'),\n type: z.literal('sql'),\n sql: z.string().optional(),\n }),\n z.object({\n title: z.string().default('Untitled'),\n type: z.literal('vega'),\n sql: z.string().optional(),\n vegaSpec: z.any().optional(),\n }),\n]);\nexport type CanvasNodeData = z.infer<typeof CanvasNodeData>;\n\ntype SqlData = Extract<CanvasNodeData, {type: 'sql'}>;\nfunction isSqlData(data: CanvasNodeData): data is SqlData {\n return data.type === 'sql';\n}\n\nfunction getUniqueSqlTitle(\n nodes: CanvasNodeSchema[],\n baseTitle: string,\n excludeNodeId?: string,\n): string {\n const existing = new Set(\n nodes\n .filter((n) => n.type === 'sql' && n.id !== (excludeNodeId || ''))\n .map((n) => n.data.title || ''),\n );\n if (!existing.has(baseTitle)) return baseTitle;\n let counter = 1;\n while (existing.has(`${baseTitle} ${counter}`)) counter += 1;\n return `${baseTitle} ${counter}`;\n}\n\nexport const CanvasNodeSchema = z.object({\n id: z.string(),\n position: z.object({x: z.number(), y: z.number()}),\n type: CanvasNodeTypes,\n data: CanvasNodeData,\n width: z.number(),\n height: z.number(),\n});\nexport type CanvasNodeSchema = z.infer<typeof CanvasNodeSchema>;\n\nexport const CanvasEdgeSchema = z.object({\n id: z.string(),\n source: z.string(),\n target: z.string(),\n});\nexport type CanvasEdgeSchema = z.infer<typeof CanvasEdgeSchema>;\n\nexport type SqlNodeQueryResult =\n | {status: 'idle'}\n | {status: 'loading'}\n | {status: 'error'; error: string}\n | {status: 'success'; tableName: string; lastQueryStatement: string};\n\nexport const CanvasSliceConfig = z.object({\n viewport: z.object({\n x: z.number(),\n y: z.number(),\n zoom: z.number(),\n }),\n nodes: z.array(CanvasNodeSchema).default([]),\n edges: z.array(CanvasEdgeSchema).default([]),\n});\nexport type CanvasSliceConfig = z.infer<typeof CanvasSliceConfig>;\n\nexport type CanvasSliceState = AiSliceState & {\n canvas: {\n config: CanvasSliceConfig;\n isAssistantOpen: boolean;\n sqlResults: Record<string, SqlNodeQueryResult>;\n initialize: () => Promise<void>;\n setConfig: (config: CanvasSliceConfig) => void;\n setViewport: (viewport: Viewport) => void;\n setAssistantOpen: (isAssistantOpen: boolean) => void;\n addNode: (params: {\n parentId?: string;\n nodeType?: CanvasNodeTypes;\n initialPosition?: XYPosition;\n }) => string;\n executeDownstreamFrom: (nodeId: string) => Promise<void>;\n renameNode: (nodeId: string, newTitle: string) => Promise<void>;\n updateNode: (\n nodeId: string,\n updater: (data: CanvasNodeData) => CanvasNodeData,\n ) => void;\n deleteNode: (nodeId: string) => void;\n applyNodeChanges: (changes: NodeChange<CanvasNodeSchema>[]) => void;\n applyEdgeChanges: (changes: EdgeChange<CanvasEdgeSchema>[]) => void;\n addEdge: (edge: Connection) => void;\n executeSqlNodeQuery: (\n nodeId: string,\n opts?: {cascade?: boolean},\n ) => Promise<void>;\n };\n};\n\nexport function createDefaultCanvasConfig(\n props?: Partial<CanvasSliceConfig>,\n): CanvasSliceConfig {\n return {\n viewport: {x: 0, y: 0, zoom: 1},\n nodes: [],\n edges: [],\n ...props,\n };\n}\n\nexport function createCanvasSlice(props: {\n config?: Partial<CanvasSliceConfig>;\n ai?: Partial<Parameters<typeof createAiSlice>[0]>;\n}) {\n return createSlice<\n CanvasSliceState,\n BaseRoomStoreState & DuckDbSliceState & CanvasSliceState\n >((set, get, store) => ({\n ...createAiSlice({\n getInstructions: () => {\n return createDefaultAiInstructions(store);\n },\n tools: {\n ...createDefaultAiTools(store),\n chart: createVegaChartTool(),\n ...props.ai?.tools,\n },\n ...props.ai,\n })(set, get, store),\n canvas: {\n config: createDefaultCanvasConfig(props.config),\n isAssistantOpen: false,\n sqlResults: {},\n setConfig: (config) => {\n set((state) =>\n produce(state, (draft) => {\n draft.canvas.config = config;\n }),\n );\n },\n setAssistantOpen: (isAssistantOpen) => {\n set((state) =>\n produce(state, (draft) => {\n draft.canvas.isAssistantOpen = isAssistantOpen;\n }),\n );\n },\n\n async initialize() {\n // Execute SQL nodes in topological order based on edges\n const nodes = get().canvas.config.nodes;\n const edges = get().canvas.config.edges;\n\n const order = topoSortAll(nodes, edges);\n\n // Execute SQL nodes sequentially to ensure parents finish before children\n for (const nodeId of order) {\n const node = findNodeById(get().canvas.config.nodes, nodeId);\n if (!node || !isSqlData(node.data)) continue;\n const sqlText = node.data.sql || '';\n if (!sqlText.trim()) continue;\n // Await ensures table creation completes before children execute\n await get().canvas.executeSqlNodeQuery(nodeId, {cascade: false});\n }\n\n await get().db.refreshTableSchemas();\n },\n\n addNode: ({\n parentId,\n nodeType = 'sql',\n initialPosition,\n }: {\n parentId?: string;\n nodeType?: CanvasNodeTypes;\n initialPosition?: XYPosition;\n }) => {\n const newId = createId();\n set((state) =>\n produce(state, (draft) => {\n const parent = parentId\n ? findNodeById(draft.canvas.config.nodes, parentId)\n : undefined;\n const position: XYPosition = initialPosition\n ? initialPosition\n : parent\n ? {\n x: parent.position.x + parent.width + 100,\n y: parent.position.y,\n }\n : {\n x: draft.canvas.config.viewport.x + 100,\n y: draft.canvas.config.viewport.y + 100,\n };\n const firstTable = draft.db.tables.find(\n (t) => t.table.schema === 'main',\n );\n\n const getInitialSqlForNewSqlNode = () => {\n if (parent && isSqlData(parent.data)) {\n const parentResults = draft.canvas.sqlResults[parent.id];\n const parentTitle = parent.data.title || 'Query';\n const fallbackParentTable = `${CANVAS_SCHEMA_NAME}.${escapeId(parentTitle)}`;\n const parentTableName =\n parentResults && parentResults.status === 'success'\n ? parentResults.tableName\n : fallbackParentTable;\n return `SELECT * FROM ${parentTableName}`;\n }\n return firstTable\n ? `SELECT * FROM ${firstTable.table.table}`\n : `SELECT 1`;\n };\n\n const newSqlTitle = getUniqueSqlTitle(\n draft.canvas.config.nodes,\n 'Query',\n );\n const initialSql = getInitialSqlForNewSqlNode();\n\n draft.canvas.config.nodes.push({\n id: newId,\n position,\n width: DEFAULT_NODE_WIDTH,\n height: DEFAULT_NODE_HEIGHT,\n type: nodeType,\n data: (nodeType === 'sql'\n ? {\n title: newSqlTitle,\n type: 'sql',\n sql: initialSql,\n }\n : {\n title: 'Chart',\n type: 'vega',\n }) as CanvasNodeData,\n });\n if (parentId) {\n draft.canvas.config.edges.push({\n id: `${parentId}-${newId}`,\n source: parentId,\n target: newId,\n });\n }\n }),\n );\n return newId;\n },\n\n executeDownstreamFrom: async (nodeId: string) => {\n const allNodes = get().canvas.config.nodes;\n const allEdges = get().canvas.config.edges;\n const downstreamOrder = topoSortDownstream(nodeId, allNodes, allEdges);\n for (const childId of downstreamOrder) {\n const child = findNodeById(allNodes, childId);\n if (!child || !isSqlData(child.data)) continue;\n const text = child.data.sql || '';\n if (!text.trim()) continue;\n await get().canvas.executeSqlNodeQuery(childId, {cascade: false});\n }\n await get().db.refreshTableSchemas();\n },\n\n addEdge: (connection) => {\n set((state) =>\n produce(state, (draft) => {\n draft.canvas.config.edges = addEdge(\n connection,\n draft.canvas.config.edges,\n );\n }),\n );\n },\n\n updateNode: (nodeId, updater) => {\n set((state) =>\n produce(state, (draft) => {\n const node = findNodeById(draft.canvas.config.nodes, nodeId);\n if (node) {\n node.data = updater(node.data as CanvasNodeData);\n }\n }),\n );\n },\n\n renameNode: async (nodeId: string, newTitle: string) => {\n const node = findNodeById(get().canvas.config.nodes, nodeId);\n if (!node) throw new Error('Node not found');\n if (!isSqlData(node.data)) {\n set((state) =>\n produce(state, (draft) => {\n const dnode = findNodeById(draft.canvas.config.nodes, nodeId);\n if (dnode) dnode.data.title = newTitle;\n }),\n );\n return;\n }\n\n const prevTitle = node.data.title || 'result';\n if (prevTitle === newTitle) return;\n\n // Ensure title uniqueness among SQL nodes by adjusting to a unique variant\n const uniqueTitle = getUniqueSqlTitle(\n get().canvas.config.nodes,\n newTitle,\n nodeId,\n );\n\n const connector = await get().db.getConnector();\n await connector.query(\n `CREATE SCHEMA IF NOT EXISTS ${CANVAS_SCHEMA_NAME}`,\n );\n\n const result = get().canvas.sqlResults[nodeId];\n const oldTableName =\n result && result.status === 'success'\n ? result.tableName\n : `${CANVAS_SCHEMA_NAME}.${escapeId(prevTitle)}`;\n\n await connector.query(\n `ALTER TABLE ${oldTableName} RENAME TO ${escapeId(uniqueTitle)}`,\n );\n\n const newQualified = `${CANVAS_SCHEMA_NAME}.${escapeId(uniqueTitle)}`;\n set((state) =>\n produce(state, (draft) => {\n const dnode = findNodeById(draft.canvas.config.nodes, nodeId);\n if (dnode) dnode.data.title = uniqueTitle;\n const r = draft.canvas.sqlResults[nodeId];\n if (r && r.status === 'success') r.tableName = newQualified;\n }),\n );\n\n await get().db.refreshTableSchemas();\n\n // Recompute children since upstream table name changed\n await get().canvas.executeDownstreamFrom(nodeId);\n },\n\n deleteNode: (nodeId) => {\n const current = get();\n const node = findNodeById(current.canvas.config.nodes, nodeId);\n let tableToDrop: string | undefined;\n if (node && isSqlData(node.data)) {\n const title = node.data.title || 'result';\n const res = current.canvas.sqlResults[nodeId];\n tableToDrop =\n res && res.status === 'success'\n ? res.tableName\n : `${CANVAS_SCHEMA_NAME}.${escapeId(title)}`;\n }\n\n set((state) =>\n produce(state, (draft) => {\n draft.canvas.config.nodes = draft.canvas.config.nodes.filter(\n (n) => n.id !== nodeId,\n );\n draft.canvas.config.edges = draft.canvas.config.edges.filter(\n (e) => e.source !== nodeId && e.target !== nodeId,\n );\n // Clear stored result for the node\n delete draft.canvas.sqlResults[nodeId];\n if (draft.canvas.config.nodes.length === 0) {\n draft.canvas.config.viewport.x = 0;\n draft.canvas.config.viewport.y = 0;\n }\n }),\n );\n\n if (tableToDrop) {\n (async () => {\n try {\n const connector = await get().db.getConnector();\n await connector.query(`DROP TABLE IF EXISTS ${tableToDrop}`);\n await get().db.refreshTableSchemas();\n } catch (e) {\n console.warn(\n '[canvas.deleteNode] Failed to drop table for node',\n nodeId,\n e,\n );\n }\n })();\n }\n },\n\n applyNodeChanges: (changes) => {\n set((state) =>\n produce(state, (draft) => {\n draft.canvas.config.nodes = applyNodeChanges(\n changes,\n draft.canvas.config.nodes,\n );\n }),\n );\n },\n\n applyEdgeChanges: (changes) => {\n set((state) =>\n produce(state, (draft) => {\n draft.canvas.config.edges = applyEdgeChanges(\n changes,\n draft.canvas.config.edges,\n );\n }),\n );\n },\n\n setViewport: (viewport) => {\n set((state) =>\n produce(state, (draft) => {\n draft.canvas.config.viewport = viewport;\n }),\n );\n },\n\n executeSqlNodeQuery: async (\n nodeId: string,\n opts?: {cascade?: boolean},\n ) => {\n const node = findNodeById(get().canvas.config.nodes, nodeId);\n if (!node || !isSqlData(node.data)) return;\n const sql = node.data.sql || '';\n const title = node.data.title || 'result';\n\n set((state) =>\n produce(state, (draft) => {\n draft.canvas.sqlResults[nodeId] = {status: 'loading'};\n }),\n );\n\n try {\n // Validate it's a single select\n const parsed = await get().db.sqlSelectToJson(sql);\n if (parsed.error) {\n throw new Error(\n parsed.error_message || 'Not a valid SELECT statement',\n );\n }\n\n // Create schema and table\n const connector = await get().db.getConnector();\n await connector.query(\n `CREATE SCHEMA IF NOT EXISTS ${CANVAS_SCHEMA_NAME}`,\n );\n\n const tableName = `${CANVAS_SCHEMA_NAME}.${escapeId(title)}`;\n await connector.query(\n `CREATE OR REPLACE TABLE ${tableName} AS ${sql}`,\n );\n\n set((state) =>\n produce(state, (draft) => {\n draft.canvas.sqlResults[nodeId] = {\n status: 'success',\n tableName,\n lastQueryStatement: sql,\n };\n }),\n );\n\n // Cascade execution to downstream SQL nodes (topologically) unless disabled\n if (opts?.cascade !== false) {\n await get().canvas.executeDownstreamFrom(nodeId);\n }\n } catch (e) {\n const message = e instanceof Error ? e.message : String(e);\n set((state) =>\n produce(state, (draft) => {\n draft.canvas.sqlResults[nodeId] = {\n status: 'error',\n error: message,\n };\n }),\n );\n }\n },\n },\n }));\n}\n\nexport type DuckDbSliceStateWithCanvas = DuckDbSliceState & CanvasSliceState;\n\nexport function useStoreWithCanvas<T>(\n selector: (state: DuckDbSliceStateWithCanvas) => T,\n): T {\n return useBaseRoomStore<BaseRoomStoreState, T>((state) =>\n selector(state as unknown as DuckDbSliceStateWithCanvas),\n );\n}\n"]}
1
+ {"version":3,"file":"CanvasSlice.js","sourceRoot":"","sources":["../src/CanvasSlice.ts"],"names":[],"mappings":"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","sourcesContent":["import {createId} from '@paralleldrive/cuid2';\nimport {type Cell, type CellsRootState, getSheetsByType} from '@sqlrooms/cells';\nimport {DuckDbSliceState} from '@sqlrooms/duckdb';\nimport {\n BaseRoomStoreState,\n createSlice,\n useBaseRoomStore,\n} from '@sqlrooms/room-store';\nimport {generateUniqueName} from '@sqlrooms/utils';\nimport type {Viewport, XYPosition} from '@xyflow/react';\nimport {\n applyNodeChanges,\n Connection,\n type EdgeChange,\n type NodeChange,\n} from '@xyflow/react';\nimport {produce} from 'immer';\nimport {z} from 'zod';\n\nconst DEFAULT_NODE_WIDTH = 800;\nconst DEFAULT_NODE_HEIGHT = 600;\nconst CANVAS_SCHEMA_NAME = 'canvas';\nconst VIEWPORT_EPSILON = 0.1;\n\n/** View metadata for a single node on the canvas */\nexport const CanvasNodeMeta = z.object({\n id: z.string(),\n position: z.object({x: z.number(), y: z.number()}),\n width: z.number().default(DEFAULT_NODE_WIDTH),\n height: z.number().default(DEFAULT_NODE_HEIGHT),\n data: z.record(z.string(), z.any()).default({}), // Required by ReactFlow NodeBase\n});\nexport type CanvasNodeMeta = z.infer<typeof CanvasNodeMeta>;\n\n/** View metadata for a sheet (canvas view) */\nexport const CanvasSheetMeta = z.object({\n viewport: z.object({\n x: z.number(),\n y: z.number(),\n zoom: z.number(),\n }),\n nodeOrder: z.array(z.string()).default([]),\n});\nexport type CanvasSheetMeta = z.infer<typeof CanvasSheetMeta>;\n\nexport const CanvasSliceConfig = z.object({\n sheets: z\n .record(\n z.string(),\n z.object({\n id: z.string(),\n nodes: z.record(z.string(), CanvasNodeMeta).default({}),\n meta: CanvasSheetMeta,\n }),\n )\n .default({}),\n});\nexport type CanvasSliceConfig = z.infer<typeof CanvasSliceConfig>;\n\nexport type CanvasSliceState = {\n canvas: {\n config: CanvasSliceConfig;\n initialize: () => Promise<void>;\n setConfig: (config: CanvasSliceConfig) => void;\n setViewport: (viewport: Viewport) => void;\n getCanvasSheets: () => Record<string, import('@sqlrooms/cells').Sheet>;\n\n addNode: (params: {\n sheetId: string;\n nodeType?: string;\n initialPosition?: XYPosition;\n parentId?: string;\n }) => Promise<string>;\n\n renameNode: (nodeId: string, newTitle: string) => Promise<void>;\n updateNode: (\n nodeId: string,\n updater: (cell: Cell) => Cell,\n ) => Promise<void>;\n deleteNode: (nodeId: string) => void;\n\n applyNodeChanges: (changes: NodeChange<CanvasNodeMeta>[]) => void;\n applyEdgeChanges: (changes: EdgeChange<any>[]) => void;\n addEdge: (edge: Connection) => void;\n\n executeSqlNodeQuery: (\n nodeId: string,\n opts?: {cascade?: boolean},\n ) => Promise<void>;\n };\n};\n\nfunction getSheet(config: CanvasSliceConfig, sheetId: string) {\n return config.sheets[sheetId];\n}\n\nfunction ensureCanvasSheetMeta(\n config: CanvasSliceConfig,\n sheetId: string,\n viewport: Viewport = {x: 0, y: 0, zoom: 1},\n) {\n let sheet = config.sheets[sheetId];\n if (!sheet) {\n sheet = {\n id: sheetId,\n nodes: {},\n meta: {\n viewport,\n nodeOrder: [],\n },\n };\n config.sheets[sheetId] = sheet;\n }\n return sheet;\n}\n\nfunction isSameViewport(a: Viewport, b: Viewport) {\n return (\n Math.abs(a.x - b.x) < VIEWPORT_EPSILON &&\n Math.abs(a.y - b.y) < VIEWPORT_EPSILON &&\n Math.abs(a.zoom - b.zoom) < VIEWPORT_EPSILON\n );\n}\n\nexport function createDefaultCanvasConfig(\n props?: Partial<CanvasSliceConfig>,\n): CanvasSliceConfig {\n const base: CanvasSliceConfig = {\n sheets: {},\n };\n\n return {...base, ...props};\n}\n\nexport function createCanvasSlice(\n props: {config?: Partial<CanvasSliceConfig>} = {},\n) {\n type CanvasRootState = BaseRoomStoreState &\n DuckDbSliceState &\n CanvasSliceState &\n CellsRootState;\n\n return createSlice<CanvasSliceState, CanvasRootState>((set, get, store) => {\n return {\n canvas: {\n config: createDefaultCanvasConfig(props.config),\n setConfig: (config: CanvasSliceConfig) => {\n set((state: CanvasRootState) =>\n produce(state, (draft: CanvasRootState) => {\n draft.canvas.config = config;\n }),\n );\n },\n\n getCanvasSheets: () => getSheetsByType(get(), 'canvas'),\n\n async initialize() {\n const sheetId =\n get().cells.config.currentSheetId ||\n get().cells.config.sheetOrder[0];\n if (!sheetId) return;\n // don't await this - it will block the UI\n get().cells.runAllCellsCascade(sheetId);\n },\n\n addNode: async ({\n sheetId,\n nodeType = 'sql',\n initialPosition,\n parentId,\n }: {\n sheetId: string;\n nodeType?: string;\n initialPosition?: XYPosition;\n parentId?: string;\n }) => {\n const newId = createId();\n const registry = get().cells.cellRegistry;\n const reg = registry[nodeType];\n if (!reg) return newId;\n\n // 1. Create the cell in CellsSlice\n const cell = reg.createCell(newId) as Cell;\n\n const existingTitles = Object.values(get().cells.config.data).map(\n (c) => {\n const title = (c.data as Record<string, unknown>).title;\n return typeof title === 'string' ? title : '';\n },\n );\n (cell.data as Record<string, unknown>).title = generateUniqueName(\n `${reg.title} 1`,\n existingTitles,\n ' ',\n );\n\n await get().cells.addCell(sheetId, cell);\n\n // 2. If parent exists, add an edge in CellsSlice\n if (parentId) {\n get().cells.addEdge(sheetId, {source: parentId, target: newId});\n }\n\n // 3. Update view-specific metadata\n set((state: CanvasRootState) =>\n produce(state, (draft: CanvasRootState) => {\n let sheet = getSheet(draft.canvas.config, sheetId);\n sheet = ensureCanvasSheetMeta(draft.canvas.config, sheetId);\n\n const parentNode = parentId ? sheet.nodes[parentId] : undefined;\n const position: XYPosition = initialPosition\n ? initialPosition\n : parentNode\n ? {\n x: parentNode.position.x + parentNode.width + 100,\n y: parentNode.position.y,\n }\n : {\n x: sheet.meta.viewport.x + 100,\n y: sheet.meta.viewport.y + 100,\n };\n\n sheet.nodes[newId] = {\n id: newId,\n position,\n width: DEFAULT_NODE_WIDTH,\n height: DEFAULT_NODE_HEIGHT,\n data: {},\n };\n sheet.meta.nodeOrder.push(newId);\n }),\n );\n return newId;\n },\n\n renameNode: async (nodeId: string, newTitle: string) => {\n await get().cells.updateCell(nodeId, (c) =>\n produce(c, (draft) => {\n (draft.data as Record<string, unknown>).title = newTitle;\n }),\n );\n },\n\n updateNode: async (nodeId: string, updater: (cell: Cell) => Cell) => {\n await get().cells.updateCell(nodeId, updater);\n },\n\n deleteNode: (nodeId: string) => {\n get().cells.removeCell(nodeId);\n set((state: CanvasRootState) =>\n produce(state, (draft: CanvasRootState) => {\n for (const sheet of Object.values(draft.canvas.config.sheets)) {\n delete sheet.nodes[nodeId];\n sheet.meta.nodeOrder = sheet.meta.nodeOrder.filter(\n (id) => id !== nodeId,\n );\n }\n }),\n );\n },\n\n applyNodeChanges: (changes: NodeChange<CanvasNodeMeta>[]) => {\n set((state: CanvasRootState) =>\n produce(state, (draft: CanvasRootState) => {\n const sheetId = draft.cells.config.currentSheetId;\n if (!sheetId) return;\n const sheet = ensureCanvasSheetMeta(draft.canvas.config, sheetId);\n\n // Ensure all cells from CellsSlice have a node entry in CanvasSlice\n const cellsSheet = draft.cells.config.sheets[sheetId];\n if (cellsSheet) {\n for (const cellId of cellsSheet.cellIds) {\n if (!sheet.nodes[cellId]) {\n sheet.nodes[cellId] = {\n id: cellId,\n position: {x: 100, y: 100},\n width: DEFAULT_NODE_WIDTH,\n height: DEFAULT_NODE_HEIGHT,\n data: {},\n };\n sheet.meta.nodeOrder.push(cellId);\n }\n }\n }\n\n const nodesArray = sheet.meta.nodeOrder\n .map((id) => sheet.nodes[id])\n .filter(Boolean) as CanvasNodeMeta[];\n const updated = applyNodeChanges(changes, nodesArray);\n sheet.nodes = updated.reduce<Record<string, CanvasNodeMeta>>(\n (acc, node) => {\n acc[node.id] = node;\n return acc;\n },\n {},\n );\n sheet.meta.nodeOrder = updated.map((n) => n.id);\n }),\n );\n },\n\n applyEdgeChanges: (changes: EdgeChange<any>[]) => {\n // Canvas edge editing is intentionally disabled for now.\n // Compatibility no-op: keep API stable until edge kinds are introduced.\n void changes;\n },\n\n addEdge: (connection: Connection) => {\n // Canvas edge editing is intentionally disabled for now.\n // Compatibility no-op: dependency edges are derived from graph cache.\n void connection;\n },\n\n setViewport: (viewport: Viewport) => {\n const sheetId = get().cells.config.currentSheetId;\n if (!sheetId) return;\n const existing = get().canvas.config.sheets[sheetId];\n if (existing && isSameViewport(existing.meta.viewport, viewport)) {\n return;\n }\n set((state: CanvasRootState) =>\n produce(state, (draft: CanvasRootState) => {\n let sheet = getSheet(draft.canvas.config, sheetId);\n sheet = ensureCanvasSheetMeta(\n draft.canvas.config,\n sheetId,\n viewport,\n );\n sheet.meta.viewport = viewport;\n }),\n );\n },\n\n executeSqlNodeQuery: async (\n nodeId: string,\n opts?: {cascade?: boolean},\n ) => {\n await get().cells.runCell(nodeId, {\n ...opts,\n schemaName: CANVAS_SCHEMA_NAME,\n });\n },\n },\n };\n });\n}\n\nexport type DuckDbSliceStateWithCanvas = DuckDbSliceState &\n CanvasSliceState &\n CellsRootState;\n\nexport function useStoreWithCanvas<T>(\n selector: (state: DuckDbSliceStateWithCanvas) => T,\n): T {\n return useBaseRoomStore<BaseRoomStoreState, T>((state) =>\n selector(state as unknown as DuckDbSliceStateWithCanvas),\n );\n}\n"]}