eventmodeler 0.6.14 → 0.6.15
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.
- package/dist/index.js +266 -45
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2573,6 +2573,15 @@ function registerStatusCommands(program, conn) {
|
|
|
2573
2573
|
}
|
|
2574
2574
|
// ../packages/canvas-model/src/build.ts
|
|
2575
2575
|
import * as Y2 from "yjs";
|
|
2576
|
+
function buildYMap(props) {
|
|
2577
|
+
const m = new Y2.Map;
|
|
2578
|
+
for (const [k, v] of Object.entries(props)) {
|
|
2579
|
+
if (v === undefined)
|
|
2580
|
+
continue;
|
|
2581
|
+
m.set(k, v);
|
|
2582
|
+
}
|
|
2583
|
+
return m;
|
|
2584
|
+
}
|
|
2576
2585
|
function buildYArray(items) {
|
|
2577
2586
|
const arr = new Y2.Array;
|
|
2578
2587
|
if (items.length > 0)
|
|
@@ -3036,6 +3045,9 @@ function resolveSheet(doc, sheetId) {
|
|
|
3036
3045
|
columnSlices
|
|
3037
3046
|
};
|
|
3038
3047
|
}
|
|
3048
|
+
function sliceOf(columnSlices, columnId) {
|
|
3049
|
+
return columnSlices[columnId] ?? columnId;
|
|
3050
|
+
}
|
|
3039
3051
|
function ensureSheet(doc, sheetId) {
|
|
3040
3052
|
doc.transact(() => {
|
|
3041
3053
|
resolveSheet(doc, sheetId);
|
|
@@ -3053,6 +3065,23 @@ function readSheet(doc, sheetId) {
|
|
|
3053
3065
|
columnSlices[c] = c;
|
|
3054
3066
|
return { ...json, columns, columnSlices };
|
|
3055
3067
|
}
|
|
3068
|
+
function sliceOrder(structure) {
|
|
3069
|
+
const cs = structure.columnSlices ?? {};
|
|
3070
|
+
const seen = new Set;
|
|
3071
|
+
const out = [];
|
|
3072
|
+
for (const colId of structure.columns) {
|
|
3073
|
+
const sid = sliceOf(cs, colId);
|
|
3074
|
+
if (!seen.has(sid)) {
|
|
3075
|
+
seen.add(sid);
|
|
3076
|
+
out.push(sid);
|
|
3077
|
+
}
|
|
3078
|
+
}
|
|
3079
|
+
return out;
|
|
3080
|
+
}
|
|
3081
|
+
function sliceColumns(structure, sliceId) {
|
|
3082
|
+
const cs = structure.columnSlices ?? {};
|
|
3083
|
+
return structure.columns.filter((c) => sliceOf(cs, c) === sliceId);
|
|
3084
|
+
}
|
|
3056
3085
|
function clampIndex(at, length) {
|
|
3057
3086
|
if (at === undefined || at > length)
|
|
3058
3087
|
return length;
|
|
@@ -3072,6 +3101,25 @@ function addColumn(doc, sheetId, sliceId, at) {
|
|
|
3072
3101
|
columnSlices.set(sliceId, sliceId);
|
|
3073
3102
|
});
|
|
3074
3103
|
}
|
|
3104
|
+
function addColumnToSlice(doc, sheetId, sliceId, columnId, atWithin) {
|
|
3105
|
+
doc.transact(() => {
|
|
3106
|
+
const { columns, columnSlices } = resolveSheet(doc, sheetId);
|
|
3107
|
+
const arr = columns.toArray();
|
|
3108
|
+
if (arr.includes(columnId))
|
|
3109
|
+
return;
|
|
3110
|
+
const slices = columnSlices.toJSON();
|
|
3111
|
+
const flatIdxs = arr.map((c, i) => [c, i]).filter(([c]) => sliceOf(slices, c) === sliceId).map(([, i]) => i);
|
|
3112
|
+
let flat;
|
|
3113
|
+
if (flatIdxs.length === 0) {
|
|
3114
|
+
flat = columns.length;
|
|
3115
|
+
} else {
|
|
3116
|
+
const within = atWithin === undefined ? flatIdxs.length : Math.max(0, Math.min(flatIdxs.length, atWithin));
|
|
3117
|
+
flat = within < flatIdxs.length ? flatIdxs[within] : flatIdxs[flatIdxs.length - 1] + 1;
|
|
3118
|
+
}
|
|
3119
|
+
columns.insert(flat, [columnId]);
|
|
3120
|
+
columnSlices.set(columnId, sliceId);
|
|
3121
|
+
});
|
|
3122
|
+
}
|
|
3075
3123
|
function moveColumn(doc, sheetId, columnId, toIndex) {
|
|
3076
3124
|
doc.transact(() => {
|
|
3077
3125
|
const { columns } = resolveSheet(doc, sheetId);
|
|
@@ -3105,6 +3153,12 @@ function removeColumn(doc, sheetId, columnId) {
|
|
|
3105
3153
|
}
|
|
3106
3154
|
});
|
|
3107
3155
|
}
|
|
3156
|
+
function setColumnSlice(doc, sheetId, columnId, sliceId) {
|
|
3157
|
+
doc.transact(() => {
|
|
3158
|
+
const { columnSlices } = resolveSheet(doc, sheetId);
|
|
3159
|
+
columnSlices.set(columnId, sliceId);
|
|
3160
|
+
});
|
|
3161
|
+
}
|
|
3108
3162
|
function ensureColumnSlices(doc, sheetId) {
|
|
3109
3163
|
doc.transact(() => {
|
|
3110
3164
|
const { columns, columnSlices } = resolveSheet(doc, sheetId);
|
|
@@ -3228,6 +3282,62 @@ function setCellNote(doc, sheetId, sliceId, swimLaneId, text) {
|
|
|
3228
3282
|
getCellNotesMap(doc, sheetId, true).set(key, trimmed);
|
|
3229
3283
|
});
|
|
3230
3284
|
}
|
|
3285
|
+
// ../packages/canvas-model/src/slice-span.ts
|
|
3286
|
+
var SLICES_SCOPE2 = "slices";
|
|
3287
|
+
var SHEET_FLOWS_SCOPE = "sheetFlows";
|
|
3288
|
+
function sliceIdFromHandle(handleId) {
|
|
3289
|
+
if (typeof handleId !== "string")
|
|
3290
|
+
return;
|
|
3291
|
+
const parts = handleId.split(":");
|
|
3292
|
+
if (parts[0] === "sf" && parts[1] === "slice" && parts.length >= 5)
|
|
3293
|
+
return parts.slice(4).join(":");
|
|
3294
|
+
return;
|
|
3295
|
+
}
|
|
3296
|
+
function pruneSheetFlowsForSlice(doc, sliceId) {
|
|
3297
|
+
const map = getScopeMap(doc, SHEET_FLOWS_SCOPE);
|
|
3298
|
+
for (const [id, f] of [...map.entries()]) {
|
|
3299
|
+
if (sliceIdFromHandle(f.get("sourceHandle")) === sliceId || sliceIdFromHandle(f.get("targetHandle")) === sliceId) {
|
|
3300
|
+
map.delete(id);
|
|
3301
|
+
}
|
|
3302
|
+
}
|
|
3303
|
+
}
|
|
3304
|
+
function resizeSliceSpan(doc, sheetId, sliceId, targetLast) {
|
|
3305
|
+
doc.transact(() => {
|
|
3306
|
+
const structure = readSheet(doc, sheetId);
|
|
3307
|
+
if (!structure)
|
|
3308
|
+
return;
|
|
3309
|
+
const cols = structure.columns;
|
|
3310
|
+
const owned = sliceColumns(structure, sliceId);
|
|
3311
|
+
if (owned.length === 0)
|
|
3312
|
+
return;
|
|
3313
|
+
const firstFlat = cols.indexOf(owned[0]);
|
|
3314
|
+
const currentLast = cols.indexOf(owned[owned.length - 1]);
|
|
3315
|
+
const target = Math.max(firstFlat, Math.min(targetLast, cols.length - 1));
|
|
3316
|
+
if (target === currentLast)
|
|
3317
|
+
return;
|
|
3318
|
+
const owner = (c) => structure.columnSlices?.[c] ?? c;
|
|
3319
|
+
const slices = getScopeMap(doc, SLICES_SCOPE2);
|
|
3320
|
+
const modelId = getEntry(doc, SLICES_SCOPE2, sliceId)?.modelId;
|
|
3321
|
+
const d = ELEMENT_DIMENSIONS.slice;
|
|
3322
|
+
const claimed = cols.slice(firstFlat, target + 1);
|
|
3323
|
+
const prevOwners = new Set(claimed.map(owner).filter((s) => s !== sliceId));
|
|
3324
|
+
for (const colId of claimed)
|
|
3325
|
+
setColumnSlice(doc, sheetId, colId, sliceId);
|
|
3326
|
+
for (const colId of cols.slice(target + 1, currentLast + 1)) {
|
|
3327
|
+
const newSliceId = crypto.randomUUID();
|
|
3328
|
+
const base = { sliceId: newSliceId, name: "Slice", x: 0, y: 0, width: d.width, height: d.height };
|
|
3329
|
+
slices.set(newSliceId, buildYMap(modelId ? { ...base, modelId } : base));
|
|
3330
|
+
setColumnSlice(doc, sheetId, colId, newSliceId);
|
|
3331
|
+
}
|
|
3332
|
+
const after = readSheet(doc, sheetId);
|
|
3333
|
+
for (const sid of prevOwners) {
|
|
3334
|
+
if (sliceColumns(after, sid).length === 0) {
|
|
3335
|
+
slices.delete(sid);
|
|
3336
|
+
pruneSheetFlowsForSlice(doc, sid);
|
|
3337
|
+
}
|
|
3338
|
+
}
|
|
3339
|
+
});
|
|
3340
|
+
}
|
|
3231
3341
|
// ../packages/canvas-model/src/migrate.ts
|
|
3232
3342
|
function migrateChaptersToSheets(doc) {
|
|
3233
3343
|
const chapters = getScopeMap(doc, "chapters");
|
|
@@ -3261,10 +3371,10 @@ function migrateChaptersToSheets(doc) {
|
|
|
3261
3371
|
}
|
|
3262
3372
|
// ../packages/canvas-model/src/sheet-delete.ts
|
|
3263
3373
|
var SHEETS_SCOPE = "sheets";
|
|
3264
|
-
var
|
|
3374
|
+
var SLICES_SCOPE3 = "slices";
|
|
3265
3375
|
var SWIM_LANES_SCOPE = "swimLanes";
|
|
3266
3376
|
var SCENARIOS_SCOPE2 = "scenarios";
|
|
3267
|
-
var
|
|
3377
|
+
var SHEET_FLOWS_SCOPE2 = "sheetFlows";
|
|
3268
3378
|
function deleteSheet(doc, sheetId) {
|
|
3269
3379
|
doc.transact(() => {
|
|
3270
3380
|
const sheet = getGridMap(doc).get(sheetId);
|
|
@@ -3286,7 +3396,7 @@ function deleteSheet(doc, sheetId) {
|
|
|
3286
3396
|
}
|
|
3287
3397
|
}
|
|
3288
3398
|
for (const id of sliceIds)
|
|
3289
|
-
getScopeMap(doc,
|
|
3399
|
+
getScopeMap(doc, SLICES_SCOPE3).delete(id);
|
|
3290
3400
|
for (const id of laneIds)
|
|
3291
3401
|
getScopeMap(doc, SWIM_LANES_SCOPE).delete(id);
|
|
3292
3402
|
const scenarios = getScopeMap(doc, SCENARIOS_SCOPE2);
|
|
@@ -3297,7 +3407,7 @@ function deleteSheet(doc, sheetId) {
|
|
|
3297
3407
|
}
|
|
3298
3408
|
}
|
|
3299
3409
|
cascadeStickyRemoval(doc, removedStickies);
|
|
3300
|
-
const sheetFlows = getScopeMap(doc,
|
|
3410
|
+
const sheetFlows = getScopeMap(doc, SHEET_FLOWS_SCOPE2);
|
|
3301
3411
|
for (const [id, f] of sheetFlows.entries()) {
|
|
3302
3412
|
if (f.get("sourceSheetId") === sheetId || f.get("targetSheetId") === sheetId) {
|
|
3303
3413
|
sheetFlows.delete(id);
|
|
@@ -3518,7 +3628,7 @@ function computeSheetLayout(doc, sheetId, override) {
|
|
|
3518
3628
|
// ../packages/canvas-model/src/reflow.ts
|
|
3519
3629
|
var REFLOW_ORIGIN = Symbol("sheet-reflow");
|
|
3520
3630
|
var SHEETS_SCOPE2 = "sheets";
|
|
3521
|
-
var
|
|
3631
|
+
var SLICES_SCOPE4 = "slices";
|
|
3522
3632
|
var SWIM_LANES_SCOPE2 = "swimLanes";
|
|
3523
3633
|
var STICKY_SCOPES = [
|
|
3524
3634
|
"commands",
|
|
@@ -3553,7 +3663,7 @@ function reflowAllSheets(doc, origin = REFLOW_ORIGIN) {
|
|
|
3553
3663
|
ensureSheet(doc, sheetId);
|
|
3554
3664
|
ensureColumnSlices(doc, sheetId);
|
|
3555
3665
|
}
|
|
3556
|
-
const slices = getScopeMap(doc,
|
|
3666
|
+
const slices = getScopeMap(doc, SLICES_SCOPE4);
|
|
3557
3667
|
const lanes = getScopeMap(doc, SWIM_LANES_SCOPE2);
|
|
3558
3668
|
const stickyMaps = STICKY_SCOPES.map((s) => getScopeMap(doc, s));
|
|
3559
3669
|
for (const sheetId of getGridMap(doc).keys()) {
|
|
@@ -5033,19 +5143,30 @@ function resolve4(doc, sheetId) {
|
|
|
5033
5143
|
return;
|
|
5034
5144
|
const { columns, rows, cells } = structure;
|
|
5035
5145
|
const notes = readCellNotes(doc, sheetId);
|
|
5036
|
-
const cols = columns.map((
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5146
|
+
const cols = columns.map((_, i) => ({ label: colLabel(i) }));
|
|
5147
|
+
const slices = sliceOrder(structure).map((sliceId) => {
|
|
5148
|
+
const cids = sliceColumns(structure, sliceId);
|
|
5149
|
+
const firstCol = columns.indexOf(cids[0]);
|
|
5150
|
+
const lastCol = columns.indexOf(cids[cids.length - 1]);
|
|
5151
|
+
const e = getEntry(doc, "slices", sliceId);
|
|
5152
|
+
return {
|
|
5153
|
+
label: firstCol === lastCol ? colLabel(firstCol) : `${colLabel(firstCol)}–${colLabel(lastCol)}`,
|
|
5154
|
+
name: e?.name?.trim() || "(unnamed)",
|
|
5155
|
+
status: e?.status ?? "",
|
|
5156
|
+
note: Boolean(e?.note),
|
|
5157
|
+
firstCol,
|
|
5158
|
+
lastCol
|
|
5159
|
+
};
|
|
5160
|
+
});
|
|
5041
5161
|
const lanes2 = rows.map((swimLaneId, i) => {
|
|
5042
5162
|
const e = getEntry(doc, "swimLanes", swimLaneId);
|
|
5043
5163
|
return { label: String(i + 1), name: e?.name?.trim() || "(unnamed)", kind: e?.laneKind ?? "?", note: Boolean(e?.note) };
|
|
5044
5164
|
});
|
|
5045
|
-
const elems = columns.map((
|
|
5046
|
-
const cellNote = columns.map((
|
|
5165
|
+
const elems = columns.map((columnId) => rows.map((swimLaneId) => (cells[cellKey(columnId, swimLaneId)] ?? []).map((r) => elementText(doc, r))));
|
|
5166
|
+
const cellNote = columns.map((columnId) => rows.map((swimLaneId) => Boolean(notes[cellKey(columnId, swimLaneId)])));
|
|
5047
5167
|
return {
|
|
5048
5168
|
title: entityName(doc, "sheets", sheetId),
|
|
5169
|
+
slices,
|
|
5049
5170
|
columns: cols,
|
|
5050
5171
|
rows: lanes2,
|
|
5051
5172
|
elems,
|
|
@@ -5058,7 +5179,12 @@ function rowLabel(r) {
|
|
|
5058
5179
|
return r.note ? `${base} ${NOTE}` : base;
|
|
5059
5180
|
}
|
|
5060
5181
|
function header(r) {
|
|
5061
|
-
return `Sheet "${r.title}" (${r.
|
|
5182
|
+
return `Sheet "${r.title}" (${r.slices.length} slices · ${r.columns.length} columns × ${r.rows.length} lanes)`;
|
|
5183
|
+
}
|
|
5184
|
+
function bandLabel(s) {
|
|
5185
|
+
const status = s.status && s.status !== "draft" ? ` · ${s.status}` : "";
|
|
5186
|
+
const note = s.note ? ` ${NOTE}` : "";
|
|
5187
|
+
return `⟦ ${s.label} ${s.name}${status}${note} ⟧`;
|
|
5062
5188
|
}
|
|
5063
5189
|
function cellLines(elems, width, hasNote) {
|
|
5064
5190
|
const lines = elems.length === 0 ? [EMPTY] : (() => {
|
|
@@ -5069,22 +5195,27 @@ function cellLines(elems, width, hasNote) {
|
|
|
5069
5195
|
lines[lines.length - 1] = `${lines[lines.length - 1]} ${NOTE}`;
|
|
5070
5196
|
return lines;
|
|
5071
5197
|
}
|
|
5072
|
-
function
|
|
5073
|
-
|
|
5198
|
+
function spanWidth(s, colWidths) {
|
|
5199
|
+
let w = 2 * (s.lastCol - s.firstCol);
|
|
5200
|
+
for (let i = s.firstCol;i <= s.lastCol; i += 1)
|
|
5201
|
+
w += colWidths[i];
|
|
5202
|
+
return w;
|
|
5074
5203
|
}
|
|
5075
5204
|
function renderTable(r, opts) {
|
|
5076
5205
|
const gutter = Math.max(...r.rows.map(rowLabel).map((s) => s.length), 0);
|
|
5077
5206
|
const colWidths = r.columns.map((c, ci) => {
|
|
5078
|
-
const widest = Math.max(
|
|
5207
|
+
const widest = Math.max(c.label.length, ...r.elems[ci].map((cell, ri) => Math.max(0, ...cell.map((e) => e.length)) + (r.cellNote[ci][ri] ? 2 : 0)), EMPTY.length);
|
|
5079
5208
|
return Math.min(widest, opts.maxColWidth + 2);
|
|
5080
5209
|
});
|
|
5210
|
+
for (const s of r.slices) {
|
|
5211
|
+
const deficit = bandLabel(s).length - spanWidth(s, colWidths);
|
|
5212
|
+
if (deficit > 0)
|
|
5213
|
+
colWidths[s.lastCol] += deficit;
|
|
5214
|
+
}
|
|
5081
5215
|
const totalWidth = gutter + colWidths.reduce((a, w) => a + w + 2, 0);
|
|
5082
5216
|
const lines = [header(r), LEGEND, ""];
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
for (let i = 0;i < headHeight; i += 1) {
|
|
5086
|
-
lines.push(pad("", gutter) + " " + r.columns.map((_, ci) => pad(headCells[ci][i] ?? "", colWidths[ci])).join(" "));
|
|
5087
|
-
}
|
|
5217
|
+
lines.push(pad("", gutter) + " " + r.slices.map((s) => pad(bandLabel(s), spanWidth(s, colWidths))).join(" "));
|
|
5218
|
+
lines.push(pad("", gutter) + " " + r.columns.map((c, ci) => pad(c.label, colWidths[ci])).join(" "));
|
|
5088
5219
|
lines.push("─".repeat(totalWidth));
|
|
5089
5220
|
r.rows.forEach((row, ri) => {
|
|
5090
5221
|
const cellsLines = r.columns.map((_, ci) => cellLines(r.elems[ci][ri], colWidths[ci], r.cellNote[ci][ri]));
|
|
@@ -5102,24 +5233,28 @@ function renderTable(r, opts) {
|
|
|
5102
5233
|
}
|
|
5103
5234
|
function renderListing(r) {
|
|
5104
5235
|
const lines = [header(r), LEGEND, ""];
|
|
5105
|
-
r.
|
|
5106
|
-
|
|
5236
|
+
r.slices.forEach((s) => {
|
|
5237
|
+
const status = s.status && s.status !== "draft" ? ` · ${s.status}` : "";
|
|
5238
|
+
lines.push(`⟦ ${s.label} ⟧ "${s.name}"${status}${s.note ? ` ${NOTE}` : ""}`);
|
|
5107
5239
|
let any = false;
|
|
5108
|
-
|
|
5109
|
-
const
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
|
|
5117
|
-
|
|
5118
|
-
|
|
5119
|
-
|
|
5120
|
-
|
|
5121
|
-
|
|
5122
|
-
});
|
|
5240
|
+
for (let ci = s.firstCol;ci <= s.lastCol; ci += 1) {
|
|
5241
|
+
const col = r.columns[ci];
|
|
5242
|
+
r.rows.forEach((row, ri) => {
|
|
5243
|
+
const elems = r.elems[ci][ri];
|
|
5244
|
+
const noted = r.cellNote[ci][ri];
|
|
5245
|
+
if (elems.length === 0 && !noted)
|
|
5246
|
+
return;
|
|
5247
|
+
any = true;
|
|
5248
|
+
const addr = `${col.label}${row.label}`;
|
|
5249
|
+
const mark = noted ? ` ${NOTE}` : "";
|
|
5250
|
+
if (elems.length <= 1) {
|
|
5251
|
+
lines.push(` ${addr} ${elems[0] ?? EMPTY} [${row.kind}]${mark}`);
|
|
5252
|
+
} else {
|
|
5253
|
+
lines.push(` ${addr} [${row.kind}]${mark}`);
|
|
5254
|
+
elems.forEach((e, i) => lines.push(` ${addr}.${i + 1} ${e}`));
|
|
5255
|
+
}
|
|
5256
|
+
});
|
|
5257
|
+
}
|
|
5123
5258
|
if (!any)
|
|
5124
5259
|
lines.push(" (empty)");
|
|
5125
5260
|
lines.push("");
|
|
@@ -5217,6 +5352,36 @@ function resolveRow(doc, s, ref) {
|
|
|
5217
5352
|
throw new SheetAddressError(`Ambiguous row name "${ref}" — use its number instead.`);
|
|
5218
5353
|
throw new SheetAddressError(numeric ? `No row "${ref}" — not a lane name, and row ${ref} is out of range (sheet has ${rows.length} rows).` : `No row named "${ref}".`);
|
|
5219
5354
|
}
|
|
5355
|
+
function resolveSlice(doc, s, ref) {
|
|
5356
|
+
const { columns, columnSlices } = s.structure;
|
|
5357
|
+
const order = sliceOrder(s.structure);
|
|
5358
|
+
const make = (sliceId) => {
|
|
5359
|
+
const columnIds = sliceColumns(s.structure, sliceId);
|
|
5360
|
+
const firstIndex = columns.indexOf(columnIds[0]);
|
|
5361
|
+
const lastIndex = columns.indexOf(columnIds[columnIds.length - 1]);
|
|
5362
|
+
return {
|
|
5363
|
+
sliceId,
|
|
5364
|
+
columnIds,
|
|
5365
|
+
firstIndex,
|
|
5366
|
+
lastIndex,
|
|
5367
|
+
label: firstIndex === lastIndex ? labelOf(firstIndex) : `${labelOf(firstIndex)}–${labelOf(lastIndex)}`
|
|
5368
|
+
};
|
|
5369
|
+
};
|
|
5370
|
+
const lower = ref.toLowerCase();
|
|
5371
|
+
const byName = order.filter((sid) => name(doc, "slices", sid).toLowerCase() === lower);
|
|
5372
|
+
if (byName.length === 1)
|
|
5373
|
+
return make(byName[0]);
|
|
5374
|
+
if (byName.length > 1)
|
|
5375
|
+
throw new SheetAddressError(`Ambiguous slice name "${ref}" — use its leading column letter instead.`);
|
|
5376
|
+
const byLabel = colIndexFromLabel(ref);
|
|
5377
|
+
if (byLabel >= 0 && byLabel < columns.length) {
|
|
5378
|
+
const columnId = columns[byLabel];
|
|
5379
|
+
return make((columnSlices ?? {})[columnId] ?? columnId);
|
|
5380
|
+
}
|
|
5381
|
+
if (order.includes(ref))
|
|
5382
|
+
return make(ref);
|
|
5383
|
+
throw new SheetAddressError(`No slice "${ref}" — not a slice name, a leading column letter, or a sliceId.`);
|
|
5384
|
+
}
|
|
5220
5385
|
function labelOf(index) {
|
|
5221
5386
|
let n = index;
|
|
5222
5387
|
let str = "";
|
|
@@ -5375,18 +5540,58 @@ function rejectLane(doc, swimLaneId, rowIndex, kind, type) {
|
|
|
5375
5540
|
const allowed = (LANE_ELEMENT_SCOPES[kind] ?? []).map((sc) => TYPE_LABEL[sc] ?? sc).join(", ");
|
|
5376
5541
|
throw new SheetAddressError(`Lane "${nameOf(doc, "swimLanes", swimLaneId)}" (row ${rowIndex + 1}, kind=${kind}) accepts ${allowed || "(nothing)"}, not ${type}.`);
|
|
5377
5542
|
}
|
|
5378
|
-
function insertColumn(doc, s, modelId, name2, at) {
|
|
5543
|
+
function insertColumn(doc, s, modelId, name2, at, cols = 1) {
|
|
5379
5544
|
const id = crypto.randomUUID();
|
|
5380
5545
|
const d = ELEMENT_DIMENSIONS.slice;
|
|
5381
5546
|
const v = validateEntry("slices", { name: name2, x: 0, y: 0, width: d.width, height: d.height });
|
|
5382
5547
|
if (!v.ok)
|
|
5383
5548
|
throw new SheetAddressError(`Invalid slice: ${v.issues.join("; ")}`);
|
|
5549
|
+
const span = Math.max(1, cols);
|
|
5384
5550
|
doc.transact(() => {
|
|
5385
5551
|
getScopeMap(doc, "slices").set(id, deepToY({ ...v.data, sliceId: id, modelId }));
|
|
5386
5552
|
addColumn(doc, s.sheetId, id, at);
|
|
5553
|
+
for (let i = 1;i < span; i += 1)
|
|
5554
|
+
addColumnToSlice(doc, s.sheetId, id, crypto.randomUUID());
|
|
5387
5555
|
});
|
|
5388
5556
|
const idx = readSheet(doc, s.sheetId).columns.indexOf(id);
|
|
5389
|
-
|
|
5557
|
+
const note = span > 1 ? ` (${span} cols)` : "";
|
|
5558
|
+
return `${colLabel2(idx)} "${name2}"${note} ${id}`;
|
|
5559
|
+
}
|
|
5560
|
+
function spanSlice(doc, s, ref, toCol) {
|
|
5561
|
+
const slice = resolveSlice(doc, s, ref);
|
|
5562
|
+
const col = resolveColumn(doc, s, toCol);
|
|
5563
|
+
const sliceName = getEntry(doc, "slices", slice.sliceId)?.name ?? "(unnamed)";
|
|
5564
|
+
doc.transact(() => resizeSliceSpan(doc, s.sheetId, slice.sliceId, col.index));
|
|
5565
|
+
const after = resolveSlice(doc, { sheetId: s.sheetId, structure: readSheet(doc, s.sheetId) }, slice.sliceId);
|
|
5566
|
+
return `slice "${sliceName}" now spans ${after.label}`;
|
|
5567
|
+
}
|
|
5568
|
+
function splitSlice(doc, s, modelId, colRef) {
|
|
5569
|
+
const col = resolveColumn(doc, s, colRef);
|
|
5570
|
+
const columnId = col.sliceId;
|
|
5571
|
+
const owningSlice = (s.structure.columnSlices ?? {})[columnId] ?? columnId;
|
|
5572
|
+
const cols = sliceColumns(s.structure, owningSlice);
|
|
5573
|
+
const pos = cols.indexOf(columnId);
|
|
5574
|
+
if (pos <= 0)
|
|
5575
|
+
throw new SheetAddressError(`Column ${col.label} already begins its slice — nothing to split.`);
|
|
5576
|
+
const newId = crypto.randomUUID();
|
|
5577
|
+
const d = ELEMENT_DIMENSIONS.slice;
|
|
5578
|
+
doc.transact(() => {
|
|
5579
|
+
getScopeMap(doc, "slices").set(newId, deepToY({ sliceId: newId, modelId, name: "Slice", x: 0, y: 0, width: d.width, height: d.height }));
|
|
5580
|
+
for (const c of cols.slice(pos))
|
|
5581
|
+
setColumnSlice(doc, s.sheetId, c, newId);
|
|
5582
|
+
});
|
|
5583
|
+
return `split at ${col.label} — a new slice now covers ${col.label} onward ${newId}`;
|
|
5584
|
+
}
|
|
5585
|
+
function renameSlice(doc, s, ref, newName) {
|
|
5586
|
+
const slice = resolveSlice(doc, s, ref);
|
|
5587
|
+
if (!newName.trim())
|
|
5588
|
+
throw new SheetAddressError("A slice name cannot be empty.");
|
|
5589
|
+
doc.transact(() => {
|
|
5590
|
+
const e = getScopeMap(doc, "slices").get(slice.sliceId);
|
|
5591
|
+
if (e)
|
|
5592
|
+
e.set("name", newName.trim());
|
|
5593
|
+
});
|
|
5594
|
+
return `renamed slice ${slice.label} → "${newName.trim()}"`;
|
|
5390
5595
|
}
|
|
5391
5596
|
function insertLane(doc, s, modelId, kind, name2, at) {
|
|
5392
5597
|
const id = crypto.randomUUID();
|
|
@@ -5860,9 +6065,21 @@ function buildFromSpec(doc, modelId, nameArg, spec) {
|
|
|
5860
6065
|
}
|
|
5861
6066
|
function buildSheetJson(doc, s) {
|
|
5862
6067
|
const { columns, rows, cells } = s.structure;
|
|
5863
|
-
const
|
|
6068
|
+
const ownerOf = (columnId) => (s.structure.columnSlices ?? {})[columnId] ?? columnId;
|
|
6069
|
+
const columnViews = columns.map((columnId, i) => {
|
|
6070
|
+
const e = getEntry(doc, "slices", ownerOf(columnId));
|
|
6071
|
+
return { label: colLabel2(i), columnId, name: e?.name ?? "(unnamed)", status: e?.status ?? null, note: e?.note ?? null };
|
|
6072
|
+
});
|
|
6073
|
+
const slices = sliceOrder(s.structure).map((sliceId) => {
|
|
6074
|
+
const cids = sliceColumns(s.structure, sliceId);
|
|
5864
6075
|
const e = getEntry(doc, "slices", sliceId);
|
|
5865
|
-
return {
|
|
6076
|
+
return {
|
|
6077
|
+
sliceId,
|
|
6078
|
+
name: e?.name ?? "(unnamed)",
|
|
6079
|
+
status: e?.status ?? null,
|
|
6080
|
+
note: e?.note ?? null,
|
|
6081
|
+
cols: cids.map((c) => colLabel2(columns.indexOf(c)))
|
|
6082
|
+
};
|
|
5866
6083
|
});
|
|
5867
6084
|
const rowViews = rows.map((swimLaneId, i) => {
|
|
5868
6085
|
const e = getEntry(doc, "swimLanes", swimLaneId);
|
|
@@ -5891,7 +6108,7 @@ function buildSheetJson(doc, s) {
|
|
|
5891
6108
|
}));
|
|
5892
6109
|
});
|
|
5893
6110
|
});
|
|
5894
|
-
return { sheet: nameOf(doc, "sheets", s.sheetId), sheetId: s.sheetId, columns: columnViews, rows: rowViews, cells: cellViews, cellNotes: cellNotesByAddr };
|
|
6111
|
+
return { sheet: nameOf(doc, "sheets", s.sheetId), sheetId: s.sheetId, slices, columns: columnViews, rows: rowViews, cells: cellViews, cellNotes: cellNotesByAddr };
|
|
5895
6112
|
}
|
|
5896
6113
|
function buildCellView(doc, s, cellArg) {
|
|
5897
6114
|
const { ordinal } = parseCellAddress(cellArg);
|
|
@@ -6032,7 +6249,7 @@ This cannot be undone. Re-run with --yes to confirm.`;
|
|
|
6032
6249
|
}
|
|
6033
6250
|
});
|
|
6034
6251
|
const insert = sheet.command("insert").description("Insert a slice (column), a lane (row), or an element into a cell");
|
|
6035
|
-
insert.command("slice <name>").description("Insert a new slice
|
|
6252
|
+
insert.command("slice <name>").description("Insert a new slice; --cols N makes it span N contiguous columns").option("--at <n>", "Position (1-based); appends if omitted").option("--cols <n>", "How many columns the slice spans (default 1)").option("--sheet <ref>", "Which sheet (name or sheetId) when the model has several").option("--model <id>", "Target model id").action((name2, opts) => runWrite(opts, (doc, s, modelId) => insertColumn(doc, s, modelId, name2, atIndex(opts.at), opts.cols ? Math.max(1, parseInt(opts.cols, 10) || 1) : 1)));
|
|
6036
6253
|
for (const kind of LANE_KINDS) {
|
|
6037
6254
|
insert.command(`${kind} <name>`).description(`Insert a ${kind} lane (row)`).option("--at <n>", "Position (1-based); appends if omitted").option("--sheet <ref>", "Which sheet (name or sheetId) when the model has several").option("--model <id>", "Target model id").action((name2, opts) => runWrite(opts, (doc, s, modelId) => insertLane(doc, s, modelId, kind, name2, atIndex(opts.at))));
|
|
6038
6255
|
}
|
|
@@ -6041,6 +6258,10 @@ This cannot be undone. Re-run with --yes to confirm.`;
|
|
|
6041
6258
|
}
|
|
6042
6259
|
sheet.command("move <element>").description("Move an element to another cell, e.g. `move B2.1 --to C2` (keeps its id + flows)").requiredOption("--to <cell>", "Destination cell (e.g. C2)").option("--sheet <ref>", "Which sheet when the model has several").option("--model <id>", "Target model id").action((element, opts) => runWrite(opts, (doc, s) => moveElement(doc, s, element, opts.to)));
|
|
6043
6260
|
sheet.command("reorder <ref>").description("Reorder a slice (column letter) or lane (row number), e.g. `reorder A --to 3`").requiredOption("--to <n>", "New 1-based position").option("--sheet <ref>", "Which sheet when the model has several").option("--model <id>", "Target model id").action((ref, opts) => runWrite(opts, (doc, s) => reorderAxis(doc, s, ref, parseInt(opts.to, 10))));
|
|
6261
|
+
const slice = sheet.command("slice").description("Slice (work-ticket) ops: span across columns, split, rename");
|
|
6262
|
+
slice.command("span <slice>").description("Set a slice to span up to a column, e.g. `slice span A --to C` (grows or shrinks)").requiredOption("--to <col>", "The column the slice should end at (letter or name)").option("--sheet <ref>", "Which sheet when the model has several").option("--model <id>", "Target model id").action((sliceRef, opts) => runWrite(opts, (doc, s) => spanSlice(doc, s, sliceRef, opts.to)));
|
|
6263
|
+
slice.command("split <col>").description("Split a slice so <col> begins a new slice (the columns from <col> onward break off)").option("--sheet <ref>", "Which sheet when the model has several").option("--model <id>", "Target model id").action((col, opts) => runWrite(opts, (doc, s, modelId) => splitSlice(doc, s, modelId, col)));
|
|
6264
|
+
slice.command("rename <slice> <name>").description("Rename a slice (by name, leading column letter, or id)").option("--sheet <ref>", "Which sheet when the model has several").option("--model <id>", "Target model id").action((sliceRef, name2, opts) => runWrite(opts, (doc, s) => renameSlice(doc, s, sliceRef, name2)));
|
|
6044
6265
|
sheet.command("rm <target>").description("Remove an element (B2.1), a column (A), or a lane (2) — cascades to flows/scenarios").option("--sheet <ref>", "Which sheet when the model has several").option("--model <id>", "Target model id").action((target, opts) => runWrite(opts, (doc, s) => removeTarget(doc, s, target)));
|
|
6045
6266
|
sheet.command("update <address> <json>").description(`Replace an element's shape in place (e.g. \`update A2.1 '{"name":"PlaceOrderV2","fields":[…]}'\`)`).option("--sheet <ref>", "Which sheet when the model has several").option("--model <id>", "Target model id").action((address, json, opts) => runWrite(opts, (doc, s, modelId) => updateElement(doc, s, modelId, address, json)));
|
|
6046
6267
|
sheet.command("flow <from> <to>").description("Connect two elements, e.g. `flow A2.1 A3.1` (flow type inferred from the element kinds)").option("--type <flowType>", "Force a flow type (otherwise inferred)").option("--sheet <ref>", "Which sheet when the model has several").option("--model <id>", "Target model id").action((from, to, opts) => runWrite(opts, (doc, s, modelId) => flowBetween(doc, s, modelId, from, to, opts.type)));
|