eventmodeler 0.6.12 → 0.6.14
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 +297 -129
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2630,6 +2630,7 @@ var ELEMENT_DIMENSIONS = {
|
|
|
2630
2630
|
aggregate: { width: 300, height: 200 },
|
|
2631
2631
|
actor: { width: 300, height: 200 },
|
|
2632
2632
|
chapter: { width: 800, height: 1200 },
|
|
2633
|
+
sheet: { width: 800, height: 1200 },
|
|
2633
2634
|
note: { width: 200, height: 150 },
|
|
2634
2635
|
externalEvent: { width: 160, height: 100 },
|
|
2635
2636
|
context: { width: 300, height: 200 },
|
|
@@ -2834,6 +2835,7 @@ var SliceSchema = baseContainer("sliceId").extend({
|
|
|
2834
2835
|
var AggregateSchema = baseContainer("aggregateId");
|
|
2835
2836
|
var ActorSchema = baseContainer("actorId");
|
|
2836
2837
|
var ChapterSchema = baseContainer("chapterId");
|
|
2838
|
+
var SheetSchema = baseContainer("sheetId");
|
|
2837
2839
|
var ContextSchema = baseContainer("contextId");
|
|
2838
2840
|
var LaneKindSchema = z.enum(["actor", "interaction", "swimlane", "specification"]);
|
|
2839
2841
|
var SwimLaneSchema = baseContainer("swimLaneId").extend({
|
|
@@ -2937,9 +2939,9 @@ var FlowSchema = z.object({
|
|
|
2937
2939
|
var SheetFlowSchema = z.object({
|
|
2938
2940
|
sheetFlowId: z.string().uuid().optional(),
|
|
2939
2941
|
modelId: z.string().uuid().optional(),
|
|
2940
|
-
|
|
2942
|
+
sourceSheetId: z.string().uuid(),
|
|
2941
2943
|
sourceHandle: z.string().min(1),
|
|
2942
|
-
|
|
2944
|
+
targetSheetId: z.string().uuid(),
|
|
2943
2945
|
targetHandle: z.string().min(1)
|
|
2944
2946
|
});
|
|
2945
2947
|
var CellRefSchema = z.object({
|
|
@@ -2958,6 +2960,7 @@ var SheetStructureSchema = z.object({
|
|
|
2958
2960
|
columns: z.array(z.string().uuid()),
|
|
2959
2961
|
rows: z.array(z.string().uuid()),
|
|
2960
2962
|
cells: z.record(z.string(), z.array(CellRefSchema)),
|
|
2963
|
+
columnSlices: z.record(z.string(), z.string().uuid()).optional(),
|
|
2961
2964
|
cellNotes: z.record(z.string(), z.string()).optional()
|
|
2962
2965
|
});
|
|
2963
2966
|
var SCOPE_SCHEMAS = {
|
|
@@ -2971,6 +2974,7 @@ var SCOPE_SCHEMAS = {
|
|
|
2971
2974
|
aggregates: AggregateSchema,
|
|
2972
2975
|
actors: ActorSchema,
|
|
2973
2976
|
chapters: ChapterSchema,
|
|
2977
|
+
sheets: SheetSchema,
|
|
2974
2978
|
contexts: ContextSchema,
|
|
2975
2979
|
swimLanes: SwimLaneSchema,
|
|
2976
2980
|
notes: NoteSchema,
|
|
@@ -3005,36 +3009,49 @@ var GRID_SCOPE = "grid";
|
|
|
3005
3009
|
function getGridMap(doc) {
|
|
3006
3010
|
return doc.getMap(GRID_SCOPE);
|
|
3007
3011
|
}
|
|
3008
|
-
function cellKey(
|
|
3009
|
-
return `${
|
|
3012
|
+
function cellKey(columnId, swimLaneId) {
|
|
3013
|
+
return `${columnId}:${swimLaneId}`;
|
|
3010
3014
|
}
|
|
3011
|
-
function resolveSheet(doc,
|
|
3015
|
+
function resolveSheet(doc, sheetId) {
|
|
3012
3016
|
const grid = getGridMap(doc);
|
|
3013
|
-
let sheet = grid.get(
|
|
3017
|
+
let sheet = grid.get(sheetId);
|
|
3014
3018
|
if (!sheet) {
|
|
3015
3019
|
sheet = new Y6.Map;
|
|
3016
3020
|
sheet.set("columns", new Y6.Array);
|
|
3017
3021
|
sheet.set("rows", new Y6.Array);
|
|
3018
3022
|
sheet.set("cells", new Y6.Map);
|
|
3019
|
-
|
|
3023
|
+
sheet.set("columnSlices", new Y6.Map);
|
|
3024
|
+
grid.set(sheetId, sheet);
|
|
3025
|
+
}
|
|
3026
|
+
let columnSlices = sheet.get("columnSlices");
|
|
3027
|
+
if (!columnSlices) {
|
|
3028
|
+
columnSlices = new Y6.Map;
|
|
3029
|
+
sheet.set("columnSlices", columnSlices);
|
|
3020
3030
|
}
|
|
3021
3031
|
return {
|
|
3022
3032
|
sheet,
|
|
3023
3033
|
columns: sheet.get("columns"),
|
|
3024
3034
|
rows: sheet.get("rows"),
|
|
3025
|
-
cells: sheet.get("cells")
|
|
3035
|
+
cells: sheet.get("cells"),
|
|
3036
|
+
columnSlices
|
|
3026
3037
|
};
|
|
3027
3038
|
}
|
|
3028
|
-
function ensureSheet(doc,
|
|
3039
|
+
function ensureSheet(doc, sheetId) {
|
|
3029
3040
|
doc.transact(() => {
|
|
3030
|
-
resolveSheet(doc,
|
|
3041
|
+
resolveSheet(doc, sheetId);
|
|
3031
3042
|
});
|
|
3032
3043
|
}
|
|
3033
|
-
function readSheet(doc,
|
|
3034
|
-
const sheet = getGridMap(doc).get(
|
|
3044
|
+
function readSheet(doc, sheetId) {
|
|
3045
|
+
const sheet = getGridMap(doc).get(sheetId);
|
|
3035
3046
|
if (!sheet)
|
|
3036
3047
|
return;
|
|
3037
|
-
|
|
3048
|
+
const json = sheet.toJSON();
|
|
3049
|
+
const columns = json.columns ?? [];
|
|
3050
|
+
const columnSlices = { ...json.columnSlices ?? {} };
|
|
3051
|
+
for (const c of columns)
|
|
3052
|
+
if (!(c in columnSlices))
|
|
3053
|
+
columnSlices[c] = c;
|
|
3054
|
+
return { ...json, columns, columnSlices };
|
|
3038
3055
|
}
|
|
3039
3056
|
function clampIndex(at, length) {
|
|
3040
3057
|
if (at === undefined || at > length)
|
|
@@ -3046,52 +3063,66 @@ function insertUnique(arr, value, at) {
|
|
|
3046
3063
|
return;
|
|
3047
3064
|
arr.insert(clampIndex(at, arr.length), [value]);
|
|
3048
3065
|
}
|
|
3049
|
-
function addColumn(doc,
|
|
3066
|
+
function addColumn(doc, sheetId, sliceId, at) {
|
|
3050
3067
|
doc.transact(() => {
|
|
3051
|
-
const { columns } = resolveSheet(doc,
|
|
3052
|
-
|
|
3068
|
+
const { columns, columnSlices } = resolveSheet(doc, sheetId);
|
|
3069
|
+
if (columns.toArray().includes(sliceId))
|
|
3070
|
+
return;
|
|
3071
|
+
columns.insert(clampIndex(at, columns.length), [sliceId]);
|
|
3072
|
+
columnSlices.set(sliceId, sliceId);
|
|
3053
3073
|
});
|
|
3054
3074
|
}
|
|
3055
|
-
function moveColumn(doc,
|
|
3075
|
+
function moveColumn(doc, sheetId, columnId, toIndex) {
|
|
3056
3076
|
doc.transact(() => {
|
|
3057
|
-
const { columns } = resolveSheet(doc,
|
|
3058
|
-
const from = columns.toArray().indexOf(
|
|
3077
|
+
const { columns } = resolveSheet(doc, sheetId);
|
|
3078
|
+
const from = columns.toArray().indexOf(columnId);
|
|
3059
3079
|
if (from === -1)
|
|
3060
3080
|
return;
|
|
3061
3081
|
columns.delete(from, 1);
|
|
3062
|
-
columns.insert(clampIndex(toIndex, columns.length), [
|
|
3082
|
+
columns.insert(clampIndex(toIndex, columns.length), [columnId]);
|
|
3063
3083
|
});
|
|
3064
3084
|
}
|
|
3065
|
-
function removeColumn(doc,
|
|
3085
|
+
function removeColumn(doc, sheetId, columnId) {
|
|
3066
3086
|
doc.transact(() => {
|
|
3067
|
-
const sheet = getGridMap(doc).get(
|
|
3087
|
+
const sheet = getGridMap(doc).get(sheetId);
|
|
3068
3088
|
if (!sheet)
|
|
3069
3089
|
return;
|
|
3070
3090
|
const columns = sheet.get("columns");
|
|
3071
3091
|
const cells = sheet.get("cells");
|
|
3072
3092
|
const cellNotes = sheet.get("cellNotes");
|
|
3073
|
-
const
|
|
3093
|
+
const columnSlices = sheet.get("columnSlices");
|
|
3094
|
+
const idx = columns.toArray().indexOf(columnId);
|
|
3074
3095
|
if (idx !== -1)
|
|
3075
3096
|
columns.delete(idx, 1);
|
|
3097
|
+
columnSlices?.delete(columnId);
|
|
3076
3098
|
for (const key of [...cells.keys()]) {
|
|
3077
|
-
if (key.startsWith(`${
|
|
3099
|
+
if (key.startsWith(`${columnId}:`))
|
|
3078
3100
|
cells.delete(key);
|
|
3079
3101
|
}
|
|
3080
3102
|
for (const key of [...cellNotes?.keys() ?? []]) {
|
|
3081
|
-
if (key.startsWith(`${
|
|
3103
|
+
if (key.startsWith(`${columnId}:`))
|
|
3082
3104
|
cellNotes.delete(key);
|
|
3083
3105
|
}
|
|
3084
3106
|
});
|
|
3085
3107
|
}
|
|
3086
|
-
function
|
|
3108
|
+
function ensureColumnSlices(doc, sheetId) {
|
|
3109
|
+
doc.transact(() => {
|
|
3110
|
+
const { columns, columnSlices } = resolveSheet(doc, sheetId);
|
|
3111
|
+
for (const columnId of columns.toArray()) {
|
|
3112
|
+
if (!columnSlices.has(columnId))
|
|
3113
|
+
columnSlices.set(columnId, columnId);
|
|
3114
|
+
}
|
|
3115
|
+
});
|
|
3116
|
+
}
|
|
3117
|
+
function addRow(doc, sheetId, swimLaneId, at) {
|
|
3087
3118
|
doc.transact(() => {
|
|
3088
|
-
const { rows } = resolveSheet(doc,
|
|
3119
|
+
const { rows } = resolveSheet(doc, sheetId);
|
|
3089
3120
|
insertUnique(rows, swimLaneId, at);
|
|
3090
3121
|
});
|
|
3091
3122
|
}
|
|
3092
|
-
function moveRow(doc,
|
|
3123
|
+
function moveRow(doc, sheetId, swimLaneId, toIndex) {
|
|
3093
3124
|
doc.transact(() => {
|
|
3094
|
-
const { rows } = resolveSheet(doc,
|
|
3125
|
+
const { rows } = resolveSheet(doc, sheetId);
|
|
3095
3126
|
const from = rows.toArray().indexOf(swimLaneId);
|
|
3096
3127
|
if (from === -1)
|
|
3097
3128
|
return;
|
|
@@ -3099,9 +3130,9 @@ function moveRow(doc, chapterId, swimLaneId, toIndex) {
|
|
|
3099
3130
|
rows.insert(clampIndex(toIndex, rows.length), [swimLaneId]);
|
|
3100
3131
|
});
|
|
3101
3132
|
}
|
|
3102
|
-
function removeRow(doc,
|
|
3133
|
+
function removeRow(doc, sheetId, swimLaneId) {
|
|
3103
3134
|
doc.transact(() => {
|
|
3104
|
-
const sheet = getGridMap(doc).get(
|
|
3135
|
+
const sheet = getGridMap(doc).get(sheetId);
|
|
3105
3136
|
if (!sheet)
|
|
3106
3137
|
return;
|
|
3107
3138
|
const rows = sheet.get("rows");
|
|
@@ -3137,9 +3168,9 @@ function findStickyCell(cells, stickyId) {
|
|
|
3137
3168
|
}
|
|
3138
3169
|
return;
|
|
3139
3170
|
}
|
|
3140
|
-
function placeInCell(doc,
|
|
3171
|
+
function placeInCell(doc, sheetId, sliceId, swimLaneId, ref, at) {
|
|
3141
3172
|
doc.transact(() => {
|
|
3142
|
-
const { cells } = resolveSheet(doc,
|
|
3173
|
+
const { cells } = resolveSheet(doc, sheetId);
|
|
3143
3174
|
const existing = findStickyCell(cells, ref.stickyId);
|
|
3144
3175
|
if (existing)
|
|
3145
3176
|
cells.get(existing.key).delete(existing.index, 1);
|
|
@@ -3154,9 +3185,9 @@ function placeInCell(doc, chapterId, sliceId, swimLaneId, ref, at) {
|
|
|
3154
3185
|
]);
|
|
3155
3186
|
});
|
|
3156
3187
|
}
|
|
3157
|
-
function removeSticky(doc,
|
|
3188
|
+
function removeSticky(doc, sheetId, stickyId) {
|
|
3158
3189
|
doc.transact(() => {
|
|
3159
|
-
const sheet = getGridMap(doc).get(
|
|
3190
|
+
const sheet = getGridMap(doc).get(sheetId);
|
|
3160
3191
|
if (!sheet)
|
|
3161
3192
|
return;
|
|
3162
3193
|
const cells = sheet.get("cells");
|
|
@@ -3166,8 +3197,13 @@ function removeSticky(doc, chapterId, stickyId) {
|
|
|
3166
3197
|
cells.get(loc.key).delete(loc.index, 1);
|
|
3167
3198
|
});
|
|
3168
3199
|
}
|
|
3169
|
-
function
|
|
3170
|
-
|
|
3200
|
+
function removeSheet(doc, sheetId) {
|
|
3201
|
+
doc.transact(() => {
|
|
3202
|
+
getGridMap(doc).delete(sheetId);
|
|
3203
|
+
});
|
|
3204
|
+
}
|
|
3205
|
+
function getCellNotesMap(doc, sheetId, create) {
|
|
3206
|
+
const sheet = getGridMap(doc).get(sheetId);
|
|
3171
3207
|
if (!sheet)
|
|
3172
3208
|
return;
|
|
3173
3209
|
let notes = sheet.get("cellNotes");
|
|
@@ -3177,19 +3213,98 @@ function getCellNotesMap(doc, chapterId, create) {
|
|
|
3177
3213
|
}
|
|
3178
3214
|
return notes;
|
|
3179
3215
|
}
|
|
3180
|
-
function readCellNotes(doc,
|
|
3181
|
-
const notes = getGridMap(doc).get(
|
|
3216
|
+
function readCellNotes(doc, sheetId) {
|
|
3217
|
+
const notes = getGridMap(doc).get(sheetId)?.get("cellNotes");
|
|
3182
3218
|
return notes ? notes.toJSON() : {};
|
|
3183
3219
|
}
|
|
3184
|
-
function setCellNote(doc,
|
|
3220
|
+
function setCellNote(doc, sheetId, sliceId, swimLaneId, text) {
|
|
3185
3221
|
doc.transact(() => {
|
|
3186
3222
|
const key = cellKey(sliceId, swimLaneId);
|
|
3187
3223
|
const trimmed = text.trim();
|
|
3188
3224
|
if (!trimmed) {
|
|
3189
|
-
getCellNotesMap(doc,
|
|
3225
|
+
getCellNotesMap(doc, sheetId, false)?.delete(key);
|
|
3190
3226
|
return;
|
|
3191
3227
|
}
|
|
3192
|
-
getCellNotesMap(doc,
|
|
3228
|
+
getCellNotesMap(doc, sheetId, true).set(key, trimmed);
|
|
3229
|
+
});
|
|
3230
|
+
}
|
|
3231
|
+
// ../packages/canvas-model/src/migrate.ts
|
|
3232
|
+
function migrateChaptersToSheets(doc) {
|
|
3233
|
+
const chapters = getScopeMap(doc, "chapters");
|
|
3234
|
+
const sheets = getScopeMap(doc, "sheets");
|
|
3235
|
+
const sheetFlows = getScopeMap(doc, "sheetFlows");
|
|
3236
|
+
const needsEntityMove = sheets.size === 0 && chapters.size > 0;
|
|
3237
|
+
const needsFlowRename = [...sheetFlows.values()].some((f) => f.has("sourceChapterId") || f.has("targetChapterId"));
|
|
3238
|
+
if (!needsEntityMove && !needsFlowRename)
|
|
3239
|
+
return;
|
|
3240
|
+
doc.transact(() => {
|
|
3241
|
+
if (needsEntityMove) {
|
|
3242
|
+
for (const [id, ch] of [...chapters.entries()]) {
|
|
3243
|
+
const json = ch.toJSON();
|
|
3244
|
+
delete json.chapterId;
|
|
3245
|
+
json.sheetId = id;
|
|
3246
|
+
sheets.set(id, deepToY(json));
|
|
3247
|
+
chapters.delete(id);
|
|
3248
|
+
}
|
|
3249
|
+
}
|
|
3250
|
+
for (const f of sheetFlows.values()) {
|
|
3251
|
+
if (f.has("sourceChapterId")) {
|
|
3252
|
+
f.set("sourceSheetId", f.get("sourceChapterId"));
|
|
3253
|
+
f.delete("sourceChapterId");
|
|
3254
|
+
}
|
|
3255
|
+
if (f.has("targetChapterId")) {
|
|
3256
|
+
f.set("targetSheetId", f.get("targetChapterId"));
|
|
3257
|
+
f.delete("targetChapterId");
|
|
3258
|
+
}
|
|
3259
|
+
}
|
|
3260
|
+
});
|
|
3261
|
+
}
|
|
3262
|
+
// ../packages/canvas-model/src/sheet-delete.ts
|
|
3263
|
+
var SHEETS_SCOPE = "sheets";
|
|
3264
|
+
var SLICES_SCOPE2 = "slices";
|
|
3265
|
+
var SWIM_LANES_SCOPE = "swimLanes";
|
|
3266
|
+
var SCENARIOS_SCOPE2 = "scenarios";
|
|
3267
|
+
var SHEET_FLOWS_SCOPE = "sheetFlows";
|
|
3268
|
+
function deleteSheet(doc, sheetId) {
|
|
3269
|
+
doc.transact(() => {
|
|
3270
|
+
const sheet = getGridMap(doc).get(sheetId);
|
|
3271
|
+
const removedStickies = new Set;
|
|
3272
|
+
const sliceIds = new Set;
|
|
3273
|
+
const laneIds = new Set;
|
|
3274
|
+
if (sheet) {
|
|
3275
|
+
for (const id of sheet.get("columns").toArray())
|
|
3276
|
+
sliceIds.add(id);
|
|
3277
|
+
for (const id of sheet.get("rows").toArray())
|
|
3278
|
+
laneIds.add(id);
|
|
3279
|
+
const cells = sheet.get("cells");
|
|
3280
|
+
for (const key of cells.keys()) {
|
|
3281
|
+
for (const ref of cells.get(key).toArray()) {
|
|
3282
|
+
const stickyId = ref.get("stickyId");
|
|
3283
|
+
getScopeMap(doc, ref.get("scope")).delete(stickyId);
|
|
3284
|
+
removedStickies.add(stickyId);
|
|
3285
|
+
}
|
|
3286
|
+
}
|
|
3287
|
+
}
|
|
3288
|
+
for (const id of sliceIds)
|
|
3289
|
+
getScopeMap(doc, SLICES_SCOPE2).delete(id);
|
|
3290
|
+
for (const id of laneIds)
|
|
3291
|
+
getScopeMap(doc, SWIM_LANES_SCOPE).delete(id);
|
|
3292
|
+
const scenarios = getScopeMap(doc, SCENARIOS_SCOPE2);
|
|
3293
|
+
for (const [id, sc] of scenarios.entries()) {
|
|
3294
|
+
if (sliceIds.has(sc.get("sliceId"))) {
|
|
3295
|
+
scenarios.delete(id);
|
|
3296
|
+
removedStickies.add(id);
|
|
3297
|
+
}
|
|
3298
|
+
}
|
|
3299
|
+
cascadeStickyRemoval(doc, removedStickies);
|
|
3300
|
+
const sheetFlows = getScopeMap(doc, SHEET_FLOWS_SCOPE);
|
|
3301
|
+
for (const [id, f] of sheetFlows.entries()) {
|
|
3302
|
+
if (f.get("sourceSheetId") === sheetId || f.get("targetSheetId") === sheetId) {
|
|
3303
|
+
sheetFlows.delete(id);
|
|
3304
|
+
}
|
|
3305
|
+
}
|
|
3306
|
+
removeSheet(doc, sheetId);
|
|
3307
|
+
getScopeMap(doc, SHEETS_SCOPE).delete(sheetId);
|
|
3193
3308
|
});
|
|
3194
3309
|
}
|
|
3195
3310
|
// ../packages/canvas-model/src/sheet-layout.ts
|
|
@@ -3242,8 +3357,8 @@ function cellContentSize(refs) {
|
|
|
3242
3357
|
});
|
|
3243
3358
|
return { width, height };
|
|
3244
3359
|
}
|
|
3245
|
-
function pruneOrphanCellRefs(doc,
|
|
3246
|
-
const sheet = getGridMap(doc).get(
|
|
3360
|
+
function pruneOrphanCellRefs(doc, sheetId) {
|
|
3361
|
+
const sheet = getGridMap(doc).get(sheetId);
|
|
3247
3362
|
if (!sheet)
|
|
3248
3363
|
return 0;
|
|
3249
3364
|
const cells = sheet.get("cells");
|
|
@@ -3262,19 +3377,21 @@ function pruneOrphanCellRefs(doc, chapterId) {
|
|
|
3262
3377
|
}
|
|
3263
3378
|
return pruned;
|
|
3264
3379
|
}
|
|
3265
|
-
function computeSheetLayout(doc,
|
|
3266
|
-
const structure = readSheet(doc,
|
|
3380
|
+
function computeSheetLayout(doc, sheetId, override) {
|
|
3381
|
+
const structure = readSheet(doc, sheetId);
|
|
3267
3382
|
if (!structure)
|
|
3268
3383
|
return;
|
|
3269
|
-
const
|
|
3270
|
-
const originX = snap(
|
|
3271
|
-
const originY = snap(
|
|
3384
|
+
const sheet = getEntry(doc, "sheets", sheetId);
|
|
3385
|
+
const originX = snap(sheet?.x ?? 0);
|
|
3386
|
+
const originY = snap(sheet?.y ?? 0);
|
|
3272
3387
|
const { columns, rows } = structure;
|
|
3388
|
+
const columnSlices = structure.columnSlices ?? {};
|
|
3389
|
+
const ownerOf = (columnId) => columnSlices[columnId] ?? columnId;
|
|
3273
3390
|
const cells = override ? applyLayoutOverride(structure.cells, override) : structure.cells;
|
|
3274
|
-
const colWidths = columns.map((
|
|
3391
|
+
const colWidths = columns.map((columnId) => {
|
|
3275
3392
|
let w = 0;
|
|
3276
3393
|
for (const swimLaneId of rows) {
|
|
3277
|
-
const refs = cells[cellKey(
|
|
3394
|
+
const refs = cells[cellKey(columnId, swimLaneId)] ?? [];
|
|
3278
3395
|
const c = cellContentSize(refs);
|
|
3279
3396
|
if (c.width > 0)
|
|
3280
3397
|
w = Math.max(w, c.width + SHEET_LAYOUT.cellPadX * 2);
|
|
@@ -3283,8 +3400,8 @@ function computeSheetLayout(doc, chapterId, override) {
|
|
|
3283
3400
|
});
|
|
3284
3401
|
const rowHeights = rows.map((swimLaneId) => {
|
|
3285
3402
|
let h = 0;
|
|
3286
|
-
for (const
|
|
3287
|
-
const refs = cells[cellKey(
|
|
3403
|
+
for (const columnId of columns) {
|
|
3404
|
+
const refs = cells[cellKey(columnId, swimLaneId)] ?? [];
|
|
3288
3405
|
const c = cellContentSize(refs);
|
|
3289
3406
|
if (c.height > 0)
|
|
3290
3407
|
h = Math.max(h, c.height + SHEET_LAYOUT.cellPadY * 2);
|
|
@@ -3305,14 +3422,33 @@ function computeSheetLayout(doc, chapterId, override) {
|
|
|
3305
3422
|
});
|
|
3306
3423
|
const gridWidth = SHEET_LAYOUT.headerLeft + colWidths.reduce((a, b) => a + b, 0);
|
|
3307
3424
|
const gridHeight = SHEET_LAYOUT.headerTop + rowHeights.reduce((a, b) => a + b, 0);
|
|
3308
|
-
const columnLayouts = columns.map((
|
|
3309
|
-
|
|
3425
|
+
const columnLayouts = columns.map((columnId, i) => ({
|
|
3426
|
+
columnId,
|
|
3427
|
+
sliceId: ownerOf(columnId),
|
|
3310
3428
|
index: i,
|
|
3311
3429
|
x: colX[i],
|
|
3312
3430
|
y: originY,
|
|
3313
3431
|
width: colWidths[i],
|
|
3314
3432
|
height: gridHeight
|
|
3315
3433
|
}));
|
|
3434
|
+
const sliceLayouts = [];
|
|
3435
|
+
for (const col of columnLayouts) {
|
|
3436
|
+
const last = sliceLayouts[sliceLayouts.length - 1];
|
|
3437
|
+
if (last && last.sliceId === col.sliceId) {
|
|
3438
|
+
last.columnIds.push(col.columnId);
|
|
3439
|
+
last.width += col.width;
|
|
3440
|
+
} else {
|
|
3441
|
+
sliceLayouts.push({
|
|
3442
|
+
sliceId: col.sliceId,
|
|
3443
|
+
columnIds: [col.columnId],
|
|
3444
|
+
index: sliceLayouts.length,
|
|
3445
|
+
x: col.x,
|
|
3446
|
+
y: originY,
|
|
3447
|
+
width: col.width,
|
|
3448
|
+
height: gridHeight
|
|
3449
|
+
});
|
|
3450
|
+
}
|
|
3451
|
+
}
|
|
3316
3452
|
const rowLayouts = rows.map((swimLaneId, i) => ({
|
|
3317
3453
|
swimLaneId,
|
|
3318
3454
|
index: i,
|
|
@@ -3322,9 +3458,10 @@ function computeSheetLayout(doc, chapterId, override) {
|
|
|
3322
3458
|
height: rowHeights[i]
|
|
3323
3459
|
}));
|
|
3324
3460
|
const stickies = [];
|
|
3325
|
-
columns.forEach((
|
|
3461
|
+
columns.forEach((columnId, ci) => {
|
|
3462
|
+
const sliceId = ownerOf(columnId);
|
|
3326
3463
|
rows.forEach((swimLaneId, ri) => {
|
|
3327
|
-
const refs = cells[cellKey(
|
|
3464
|
+
const refs = cells[cellKey(columnId, swimLaneId)] ?? [];
|
|
3328
3465
|
if (refs.length === 0)
|
|
3329
3466
|
return;
|
|
3330
3467
|
const content = cellContentSize(refs);
|
|
@@ -3339,6 +3476,7 @@ function computeSheetLayout(doc, chapterId, override) {
|
|
|
3339
3476
|
stickies.push({
|
|
3340
3477
|
stickyId: ref.stickyId,
|
|
3341
3478
|
scope: ref.scope,
|
|
3479
|
+
columnId,
|
|
3342
3480
|
sliceId,
|
|
3343
3481
|
swimLaneId,
|
|
3344
3482
|
x: Math.round(midX - size.width / 2),
|
|
@@ -3355,6 +3493,7 @@ function computeSheetLayout(doc, chapterId, override) {
|
|
|
3355
3493
|
stickies.push({
|
|
3356
3494
|
stickyId: ref.stickyId,
|
|
3357
3495
|
scope: ref.scope,
|
|
3496
|
+
columnId,
|
|
3358
3497
|
sliceId,
|
|
3359
3498
|
swimLaneId,
|
|
3360
3499
|
x: Math.round(cursorX),
|
|
@@ -3368,18 +3507,19 @@ function computeSheetLayout(doc, chapterId, override) {
|
|
|
3368
3507
|
});
|
|
3369
3508
|
});
|
|
3370
3509
|
return {
|
|
3371
|
-
|
|
3372
|
-
|
|
3510
|
+
sheetId,
|
|
3511
|
+
sheet: { x: originX, y: originY, width: gridWidth, height: gridHeight },
|
|
3373
3512
|
columns: columnLayouts,
|
|
3513
|
+
slices: sliceLayouts,
|
|
3374
3514
|
rows: rowLayouts,
|
|
3375
3515
|
stickies
|
|
3376
3516
|
};
|
|
3377
3517
|
}
|
|
3378
3518
|
// ../packages/canvas-model/src/reflow.ts
|
|
3379
3519
|
var REFLOW_ORIGIN = Symbol("sheet-reflow");
|
|
3380
|
-
var
|
|
3381
|
-
var
|
|
3382
|
-
var
|
|
3520
|
+
var SHEETS_SCOPE2 = "sheets";
|
|
3521
|
+
var SLICES_SCOPE3 = "slices";
|
|
3522
|
+
var SWIM_LANES_SCOPE2 = "swimLanes";
|
|
3383
3523
|
var STICKY_SCOPES = [
|
|
3384
3524
|
"commands",
|
|
3385
3525
|
"events",
|
|
@@ -3404,27 +3544,30 @@ function applyBox(m, box, size = true) {
|
|
|
3404
3544
|
}
|
|
3405
3545
|
}
|
|
3406
3546
|
function reflowAllSheets(doc, origin = REFLOW_ORIGIN) {
|
|
3407
|
-
|
|
3408
|
-
|
|
3547
|
+
migrateChaptersToSheets(doc);
|
|
3548
|
+
const sheets = getScopeMap(doc, SHEETS_SCOPE2);
|
|
3549
|
+
if (sheets.size === 0)
|
|
3409
3550
|
return;
|
|
3410
3551
|
doc.transact(() => {
|
|
3411
|
-
for (const
|
|
3412
|
-
ensureSheet(doc,
|
|
3413
|
-
|
|
3414
|
-
|
|
3552
|
+
for (const sheetId of sheets.keys()) {
|
|
3553
|
+
ensureSheet(doc, sheetId);
|
|
3554
|
+
ensureColumnSlices(doc, sheetId);
|
|
3555
|
+
}
|
|
3556
|
+
const slices = getScopeMap(doc, SLICES_SCOPE3);
|
|
3557
|
+
const lanes = getScopeMap(doc, SWIM_LANES_SCOPE2);
|
|
3415
3558
|
const stickyMaps = STICKY_SCOPES.map((s) => getScopeMap(doc, s));
|
|
3416
|
-
for (const
|
|
3417
|
-
pruneOrphanCellRefs(doc,
|
|
3418
|
-
const layout = computeSheetLayout(doc,
|
|
3559
|
+
for (const sheetId of getGridMap(doc).keys()) {
|
|
3560
|
+
pruneOrphanCellRefs(doc, sheetId);
|
|
3561
|
+
const layout = computeSheetLayout(doc, sheetId);
|
|
3419
3562
|
if (!layout)
|
|
3420
3563
|
continue;
|
|
3421
|
-
const ch =
|
|
3564
|
+
const ch = sheets.get(sheetId);
|
|
3422
3565
|
if (ch) {
|
|
3423
|
-
setIfChanged(ch, "width", layout.
|
|
3424
|
-
setIfChanged(ch, "height", layout.
|
|
3566
|
+
setIfChanged(ch, "width", layout.sheet.width);
|
|
3567
|
+
setIfChanged(ch, "height", layout.sheet.height);
|
|
3425
3568
|
}
|
|
3426
|
-
for (const
|
|
3427
|
-
applyBox(slices.get(
|
|
3569
|
+
for (const band of layout.slices)
|
|
3570
|
+
applyBox(slices.get(band.sliceId), band);
|
|
3428
3571
|
for (const row of layout.rows)
|
|
3429
3572
|
applyBox(lanes.get(row.swimLaneId), row);
|
|
3430
3573
|
const scenarioOrder = new Map;
|
|
@@ -4884,12 +5027,12 @@ function pad(s, width) {
|
|
|
4884
5027
|
return s.length >= width ? s : s + " ".repeat(width - s.length);
|
|
4885
5028
|
}
|
|
4886
5029
|
var NOTE = "†";
|
|
4887
|
-
function resolve4(doc,
|
|
4888
|
-
const structure = readSheet(doc,
|
|
5030
|
+
function resolve4(doc, sheetId) {
|
|
5031
|
+
const structure = readSheet(doc, sheetId);
|
|
4889
5032
|
if (!structure)
|
|
4890
5033
|
return;
|
|
4891
5034
|
const { columns, rows, cells } = structure;
|
|
4892
|
-
const notes = readCellNotes(doc,
|
|
5035
|
+
const notes = readCellNotes(doc, sheetId);
|
|
4893
5036
|
const cols = columns.map((sliceId, i) => ({
|
|
4894
5037
|
label: colLabel(i),
|
|
4895
5038
|
name: entityName(doc, "slices", sliceId),
|
|
@@ -4902,7 +5045,7 @@ function resolve4(doc, chapterId) {
|
|
|
4902
5045
|
const elems = columns.map((sliceId) => rows.map((swimLaneId) => (cells[cellKey(sliceId, swimLaneId)] ?? []).map((r) => elementText(doc, r))));
|
|
4903
5046
|
const cellNote = columns.map((sliceId) => rows.map((swimLaneId) => Boolean(notes[cellKey(sliceId, swimLaneId)])));
|
|
4904
5047
|
return {
|
|
4905
|
-
title: entityName(doc, "
|
|
5048
|
+
title: entityName(doc, "sheets", sheetId),
|
|
4906
5049
|
columns: cols,
|
|
4907
5050
|
rows: lanes2,
|
|
4908
5051
|
elems,
|
|
@@ -4984,9 +5127,9 @@ function renderListing(r) {
|
|
|
4984
5127
|
return lines.join(`
|
|
4985
5128
|
`).trimEnd();
|
|
4986
5129
|
}
|
|
4987
|
-
function renderSheetOverview(doc,
|
|
5130
|
+
function renderSheetOverview(doc, sheetId, options = {}) {
|
|
4988
5131
|
const opts = { ...DEFAULTS, ...options };
|
|
4989
|
-
const r = resolve4(doc,
|
|
5132
|
+
const r = resolve4(doc, sheetId);
|
|
4990
5133
|
if (!r)
|
|
4991
5134
|
return;
|
|
4992
5135
|
if (r.empty)
|
|
@@ -5020,23 +5163,23 @@ function resolveSheet2(doc, ref) {
|
|
|
5020
5163
|
const ids = [...grid2.keys()];
|
|
5021
5164
|
if (ids.length === 0)
|
|
5022
5165
|
throw new SheetAddressError("This model has no sheets.");
|
|
5023
|
-
const done = (
|
|
5166
|
+
const done = (sheetId) => ({ sheetId, structure: readSheet(doc, sheetId) });
|
|
5024
5167
|
if (ref && grid2.has(ref))
|
|
5025
5168
|
return done(ref);
|
|
5026
5169
|
if (!ref) {
|
|
5027
5170
|
if (ids.length === 1)
|
|
5028
5171
|
return done(ids[0]);
|
|
5029
|
-
const list = ids.map((id) => `"${name(doc, "
|
|
5172
|
+
const list = ids.map((id) => `"${name(doc, "sheets", id)}"`).join(", ");
|
|
5030
5173
|
throw new SheetAddressError(`Multiple sheets — name one. Available: ${list}`);
|
|
5031
5174
|
}
|
|
5032
5175
|
const lower = ref.toLowerCase();
|
|
5033
|
-
const matches = ids.filter((id) => name(doc, "
|
|
5176
|
+
const matches = ids.filter((id) => name(doc, "sheets", id).toLowerCase() === lower);
|
|
5034
5177
|
if (matches.length === 0) {
|
|
5035
|
-
const list = ids.map((id) => `"${name(doc, "
|
|
5178
|
+
const list = ids.map((id) => `"${name(doc, "sheets", id)}"`).join(", ") || "(none)";
|
|
5036
5179
|
throw new SheetAddressError(`No sheet named "${ref}". Available: ${list}`);
|
|
5037
5180
|
}
|
|
5038
5181
|
if (matches.length > 1)
|
|
5039
|
-
throw new SheetAddressError(`Ambiguous sheet name "${ref}" — pass the
|
|
5182
|
+
throw new SheetAddressError(`Ambiguous sheet name "${ref}" — pass the sheetId instead.`);
|
|
5040
5183
|
return done(matches[0]);
|
|
5041
5184
|
}
|
|
5042
5185
|
function resolveColumn(doc, s, ref) {
|
|
@@ -5240,9 +5383,9 @@ function insertColumn(doc, s, modelId, name2, at) {
|
|
|
5240
5383
|
throw new SheetAddressError(`Invalid slice: ${v.issues.join("; ")}`);
|
|
5241
5384
|
doc.transact(() => {
|
|
5242
5385
|
getScopeMap(doc, "slices").set(id, deepToY({ ...v.data, sliceId: id, modelId }));
|
|
5243
|
-
addColumn(doc, s.
|
|
5386
|
+
addColumn(doc, s.sheetId, id, at);
|
|
5244
5387
|
});
|
|
5245
|
-
const idx = readSheet(doc, s.
|
|
5388
|
+
const idx = readSheet(doc, s.sheetId).columns.indexOf(id);
|
|
5246
5389
|
return `${colLabel2(idx)} "${name2}" ${id}`;
|
|
5247
5390
|
}
|
|
5248
5391
|
function insertLane(doc, s, modelId, kind, name2, at) {
|
|
@@ -5253,9 +5396,9 @@ function insertLane(doc, s, modelId, kind, name2, at) {
|
|
|
5253
5396
|
throw new SheetAddressError(`Invalid lane: ${v.issues.join("; ")}`);
|
|
5254
5397
|
doc.transact(() => {
|
|
5255
5398
|
getScopeMap(doc, "swimLanes").set(id, deepToY({ ...v.data, swimLaneId: id, modelId }));
|
|
5256
|
-
addRow(doc, s.
|
|
5399
|
+
addRow(doc, s.sheetId, id, at);
|
|
5257
5400
|
});
|
|
5258
|
-
const idx = readSheet(doc, s.
|
|
5401
|
+
const idx = readSheet(doc, s.sheetId).rows.indexOf(id);
|
|
5259
5402
|
return `${idx + 1} "${name2}" (${kind}) ${id}`;
|
|
5260
5403
|
}
|
|
5261
5404
|
function insertElement(doc, s, modelId, type, cellArg, nameOrJson) {
|
|
@@ -5284,7 +5427,7 @@ function insertElement(doc, s, modelId, type, cellArg, nameOrJson) {
|
|
|
5284
5427
|
};
|
|
5285
5428
|
doc.transact(() => {
|
|
5286
5429
|
getScopeMap(doc, "scenarios").set(id, deepToY(entry2));
|
|
5287
|
-
placeInCell(doc, s.
|
|
5430
|
+
placeInCell(doc, s.sheetId, cell.sliceId, cell.swimLaneId, { stickyId: id, scope: "scenarios" });
|
|
5288
5431
|
});
|
|
5289
5432
|
return addressOf(doc, s, cell.sliceId, cell.swimLaneId, id, cell.address);
|
|
5290
5433
|
}
|
|
@@ -5299,12 +5442,12 @@ function insertElement(doc, s, modelId, type, cellArg, nameOrJson) {
|
|
|
5299
5442
|
const final = { ...v.data, [meta.idKey]: id, modelId };
|
|
5300
5443
|
doc.transact(() => {
|
|
5301
5444
|
getScopeMap(doc, meta.scope).set(id, deepToY(final));
|
|
5302
|
-
placeInCell(doc, s.
|
|
5445
|
+
placeInCell(doc, s.sheetId, cell.sliceId, cell.swimLaneId, { stickyId: id, scope: meta.scope });
|
|
5303
5446
|
});
|
|
5304
5447
|
return addressOf(doc, s, cell.sliceId, cell.swimLaneId, id, cell.address);
|
|
5305
5448
|
}
|
|
5306
5449
|
function addressOf(doc, s, sliceId, swimLaneId, id, cellAddr) {
|
|
5307
|
-
const refs = readSheet(doc, s.
|
|
5450
|
+
const refs = readSheet(doc, s.sheetId).cells[cellKey(sliceId, swimLaneId)] ?? [];
|
|
5308
5451
|
const ord = refs.findIndex((r) => r.stickyId === id) + 1;
|
|
5309
5452
|
return `${cellAddr}.${ord} ${id}`;
|
|
5310
5453
|
}
|
|
@@ -5315,7 +5458,7 @@ function moveElement(doc, s, elAddr, toCell) {
|
|
|
5315
5458
|
if (!laneAllows(kind, el.scope))
|
|
5316
5459
|
rejectLane(doc, dest.swimLaneId, dest.rowIndex, kind, TYPE_LABEL[el.scope] ?? el.scope);
|
|
5317
5460
|
doc.transact(() => {
|
|
5318
|
-
placeInCell(doc, s.
|
|
5461
|
+
placeInCell(doc, s.sheetId, dest.sliceId, dest.swimLaneId, { stickyId: el.stickyId, scope: el.scope });
|
|
5319
5462
|
});
|
|
5320
5463
|
return addressOf(doc, s, dest.sliceId, dest.swimLaneId, el.stickyId, dest.address);
|
|
5321
5464
|
}
|
|
@@ -5323,14 +5466,14 @@ function reorderAxis(doc, s, ref, to) {
|
|
|
5323
5466
|
const toIndex = to - 1;
|
|
5324
5467
|
if (/^\d+$/.test(ref)) {
|
|
5325
5468
|
const row = resolveRow(doc, s, ref);
|
|
5326
|
-
doc.transact(() => moveRow(doc, s.
|
|
5327
|
-
const idx = readSheet(doc, s.
|
|
5469
|
+
doc.transact(() => moveRow(doc, s.sheetId, row.swimLaneId, toIndex));
|
|
5470
|
+
const idx = readSheet(doc, s.sheetId).rows.indexOf(row.swimLaneId);
|
|
5328
5471
|
return `row → ${idx + 1}`;
|
|
5329
5472
|
}
|
|
5330
5473
|
if (colIndexFromLabel(ref) >= 0 || s.structure.columns.length > 0) {
|
|
5331
5474
|
const col = resolveColumn(doc, s, ref);
|
|
5332
|
-
doc.transact(() => moveColumn(doc, s.
|
|
5333
|
-
const idx = readSheet(doc, s.
|
|
5475
|
+
doc.transact(() => moveColumn(doc, s.sheetId, col.sliceId, toIndex));
|
|
5476
|
+
const idx = readSheet(doc, s.sheetId).columns.indexOf(col.sliceId);
|
|
5334
5477
|
return `column → ${colLabel2(idx)}`;
|
|
5335
5478
|
}
|
|
5336
5479
|
throw new SheetAddressError(`reorder takes a column letter (A) or row number (1), got "${ref}".`);
|
|
@@ -5339,7 +5482,7 @@ function removeTarget(doc, s, target) {
|
|
|
5339
5482
|
if (/^[A-Za-z]+\d+(\.\d+)?$/.test(target)) {
|
|
5340
5483
|
const el = resolveElement(doc, s, target);
|
|
5341
5484
|
doc.transact(() => {
|
|
5342
|
-
removeSticky(doc, s.
|
|
5485
|
+
removeSticky(doc, s.sheetId, el.stickyId);
|
|
5343
5486
|
getScopeMap(doc, el.scope).delete(el.stickyId);
|
|
5344
5487
|
cascadeStickyRemoval(doc, new Set([el.stickyId]));
|
|
5345
5488
|
});
|
|
@@ -5350,7 +5493,7 @@ function removeTarget(doc, s, target) {
|
|
|
5350
5493
|
const laneName = nameOf(doc, "swimLanes", row.swimLaneId);
|
|
5351
5494
|
const refs2 = s.structure.columns.flatMap((sliceId) => s.structure.cells[cellKey(sliceId, row.swimLaneId)] ?? []);
|
|
5352
5495
|
doc.transact(() => {
|
|
5353
|
-
removeRow(doc, s.
|
|
5496
|
+
removeRow(doc, s.sheetId, row.swimLaneId);
|
|
5354
5497
|
getScopeMap(doc, "swimLanes").delete(row.swimLaneId);
|
|
5355
5498
|
for (const r of refs2)
|
|
5356
5499
|
getScopeMap(doc, r.scope).delete(r.stickyId);
|
|
@@ -5362,7 +5505,7 @@ function removeTarget(doc, s, target) {
|
|
|
5362
5505
|
const sliceName = nameOf(doc, "slices", col.sliceId);
|
|
5363
5506
|
const refs = s.structure.rows.flatMap((swimLaneId) => s.structure.cells[cellKey(col.sliceId, swimLaneId)] ?? []);
|
|
5364
5507
|
doc.transact(() => {
|
|
5365
|
-
removeColumn(doc, s.
|
|
5508
|
+
removeColumn(doc, s.sheetId, col.sliceId);
|
|
5366
5509
|
getScopeMap(doc, "slices").delete(col.sliceId);
|
|
5367
5510
|
for (const r of refs)
|
|
5368
5511
|
getScopeMap(doc, r.scope).delete(r.stickyId);
|
|
@@ -5440,7 +5583,7 @@ function sheetEdgeHandle(side, dir) {
|
|
|
5440
5583
|
}
|
|
5441
5584
|
function resolveAnchor(doc, sheet, dir, col, side) {
|
|
5442
5585
|
const flag = dir === "source" ? "from" : "to";
|
|
5443
|
-
const sheetName = nameOf(doc, "
|
|
5586
|
+
const sheetName = nameOf(doc, "sheets", sheet.sheetId);
|
|
5444
5587
|
if (col !== undefined) {
|
|
5445
5588
|
const c = resolveColumn(doc, sheet, col);
|
|
5446
5589
|
const s2 = side ?? (dir === "source" ? "bottom" : "top");
|
|
@@ -5458,7 +5601,7 @@ function resolveAnchor(doc, sheet, dir, col, side) {
|
|
|
5458
5601
|
function connectSheets(doc, modelId, fromRef, toRef, opts) {
|
|
5459
5602
|
const src = resolveSheet2(doc, fromRef);
|
|
5460
5603
|
const dst = resolveSheet2(doc, toRef);
|
|
5461
|
-
if (src.
|
|
5604
|
+
if (src.sheetId === dst.sheetId) {
|
|
5462
5605
|
throw new SheetAddressError("Connect joins two different sheets — source and target are the same sheet.");
|
|
5463
5606
|
}
|
|
5464
5607
|
const from = resolveAnchor(doc, src, "source", opts.from, opts.fromSide);
|
|
@@ -5466,9 +5609,9 @@ function connectSheets(doc, modelId, fromRef, toRef, opts) {
|
|
|
5466
5609
|
const id = crypto.randomUUID();
|
|
5467
5610
|
const entry = {
|
|
5468
5611
|
sheetFlowId: id,
|
|
5469
|
-
|
|
5612
|
+
sourceSheetId: src.sheetId,
|
|
5470
5613
|
sourceHandle: from.handle,
|
|
5471
|
-
|
|
5614
|
+
targetSheetId: dst.sheetId,
|
|
5472
5615
|
targetHandle: to.handle
|
|
5473
5616
|
};
|
|
5474
5617
|
const v = validateEntry("sheetFlows", entry);
|
|
@@ -5501,7 +5644,7 @@ function copyElement(doc, s, modelId, srcAddr, toCell) {
|
|
|
5501
5644
|
const dim = FIXED_SIZE_DIM(src.scope);
|
|
5502
5645
|
doc.transact(() => {
|
|
5503
5646
|
getScopeMap(doc, src.scope).set(id, deepToY({ [meta.idKey]: id, modelId, name: "", x: 0, y: 0, width: dim.width, height: dim.height, isLinkedCopy: true, [meta.originalIdKey]: originalId }));
|
|
5504
|
-
placeInCell(doc, s.
|
|
5647
|
+
placeInCell(doc, s.sheetId, dest.sliceId, dest.swimLaneId, { stickyId: id, scope: src.scope });
|
|
5505
5648
|
});
|
|
5506
5649
|
return addressOf(doc, s, dest.sliceId, dest.swimLaneId, id, dest.address);
|
|
5507
5650
|
}
|
|
@@ -5531,7 +5674,7 @@ function noteTarget(doc, s, target, text) {
|
|
|
5531
5674
|
}
|
|
5532
5675
|
if (/^[A-Za-z]+\d+$/.test(target)) {
|
|
5533
5676
|
const cell = resolveCell(doc, s, target);
|
|
5534
|
-
setCellNote(doc, s.
|
|
5677
|
+
setCellNote(doc, s.sheetId, cell.sliceId, cell.swimLaneId, t);
|
|
5535
5678
|
return `${verb} cell ${cell.address}`;
|
|
5536
5679
|
}
|
|
5537
5680
|
if (/^\d+$/.test(target)) {
|
|
@@ -5631,12 +5774,12 @@ function buildFromSpec(doc, modelId, nameArg, spec) {
|
|
|
5631
5774
|
if (f.type && f.type !== inferred)
|
|
5632
5775
|
throw new SheetAddressError(`Flow ${f.from}→${f.to} is ${inferred}, not ${f.type}.`);
|
|
5633
5776
|
}
|
|
5634
|
-
const
|
|
5777
|
+
const sheetId = crypto.randomUUID();
|
|
5635
5778
|
const idByAddress = {};
|
|
5636
5779
|
doc.transact(() => {
|
|
5637
|
-
const cd = ELEMENT_DIMENSIONS.
|
|
5638
|
-
getScopeMap(doc, "
|
|
5639
|
-
ensureSheet(doc,
|
|
5780
|
+
const cd = ELEMENT_DIMENSIONS.sheet;
|
|
5781
|
+
getScopeMap(doc, "sheets").set(sheetId, deepToY({ sheetId, modelId, name: sheetName, x: 0, y: 0, width: cd.width, height: cd.height }));
|
|
5782
|
+
ensureSheet(doc, sheetId);
|
|
5640
5783
|
const sd = ELEMENT_DIMENSIONS.slice;
|
|
5641
5784
|
const sliceIds = cols.map((c) => {
|
|
5642
5785
|
const id = crypto.randomUUID();
|
|
@@ -5646,7 +5789,7 @@ function buildFromSpec(doc, modelId, nameArg, spec) {
|
|
|
5646
5789
|
if (c.note)
|
|
5647
5790
|
entry.note = c.note;
|
|
5648
5791
|
getScopeMap(doc, "slices").set(id, deepToY(entry));
|
|
5649
|
-
addColumn(doc,
|
|
5792
|
+
addColumn(doc, sheetId, id);
|
|
5650
5793
|
return id;
|
|
5651
5794
|
});
|
|
5652
5795
|
const ld = ELEMENT_DIMENSIONS.swimLane;
|
|
@@ -5656,7 +5799,7 @@ function buildFromSpec(doc, modelId, nameArg, spec) {
|
|
|
5656
5799
|
if (r.note)
|
|
5657
5800
|
entry.note = r.note;
|
|
5658
5801
|
getScopeMap(doc, "swimLanes").set(id, deepToY(entry));
|
|
5659
|
-
addRow(doc,
|
|
5802
|
+
addRow(doc, sheetId, id);
|
|
5660
5803
|
return id;
|
|
5661
5804
|
});
|
|
5662
5805
|
for (const op of ops) {
|
|
@@ -5678,10 +5821,10 @@ function buildFromSpec(doc, modelId, nameArg, spec) {
|
|
|
5678
5821
|
width: SCENARIO_CARD.width,
|
|
5679
5822
|
height: SCENARIO_CARD.height
|
|
5680
5823
|
}));
|
|
5681
|
-
placeInCell(doc,
|
|
5824
|
+
placeInCell(doc, sheetId, sliceIds[op.ci], laneIds[op.ri], { stickyId: id, scope: "scenarios" });
|
|
5682
5825
|
} else {
|
|
5683
5826
|
getScopeMap(doc, op.scope).set(id, deepToY({ ...op.data, [op.idKey]: id, modelId }));
|
|
5684
|
-
placeInCell(doc,
|
|
5827
|
+
placeInCell(doc, sheetId, sliceIds[op.ci], laneIds[op.ri], { stickyId: id, scope: op.scope });
|
|
5685
5828
|
}
|
|
5686
5829
|
idByAddress[op.address] = id;
|
|
5687
5830
|
}
|
|
@@ -5692,7 +5835,7 @@ function buildFromSpec(doc, modelId, nameArg, spec) {
|
|
|
5692
5835
|
const id = crypto.randomUUID();
|
|
5693
5836
|
const dim = FIXED_SIZE_DIM(op.scope);
|
|
5694
5837
|
getScopeMap(doc, op.scope).set(id, deepToY({ [meta.idKey]: id, modelId, name: "", x: 0, y: 0, width: dim.width, height: dim.height, isLinkedCopy: true, [meta.originalIdKey]: idByAddress[op.copyOf] }));
|
|
5695
|
-
placeInCell(doc,
|
|
5838
|
+
placeInCell(doc, sheetId, sliceIds[op.ci], laneIds[op.ri], { stickyId: id, scope: op.scope });
|
|
5696
5839
|
idByAddress[op.address] = id;
|
|
5697
5840
|
}
|
|
5698
5841
|
for (const f of specFlows) {
|
|
@@ -5707,13 +5850,13 @@ function buildFromSpec(doc, modelId, nameArg, spec) {
|
|
|
5707
5850
|
const ci = colIndexFromLabel(cl);
|
|
5708
5851
|
const ri = rowNum - 1;
|
|
5709
5852
|
if (ci >= 0 && ci < cols.length && ri >= 0 && ri < rows.length && text) {
|
|
5710
|
-
setCellNote(doc,
|
|
5853
|
+
setCellNote(doc, sheetId, sliceIds[ci], laneIds[ri], text);
|
|
5711
5854
|
}
|
|
5712
5855
|
}
|
|
5713
5856
|
});
|
|
5714
5857
|
reflowAllSheets(doc);
|
|
5715
5858
|
const nElems = ops.length;
|
|
5716
|
-
return `built sheet "${sheetName}" — ${cols.length} slices, ${rows.length} lanes, ${nElems} elements, ${specFlows.length} flows ${
|
|
5859
|
+
return `built sheet "${sheetName}" — ${cols.length} slices, ${rows.length} lanes, ${nElems} elements, ${specFlows.length} flows ${sheetId}`;
|
|
5717
5860
|
}
|
|
5718
5861
|
function buildSheetJson(doc, s) {
|
|
5719
5862
|
const { columns, rows, cells } = s.structure;
|
|
@@ -5725,7 +5868,7 @@ function buildSheetJson(doc, s) {
|
|
|
5725
5868
|
const e = getEntry(doc, "swimLanes", swimLaneId);
|
|
5726
5869
|
return { label: String(i + 1), name: e?.name ?? "(unnamed)", laneKind: e?.laneKind ?? null, swimLaneId, note: e?.note ?? null };
|
|
5727
5870
|
});
|
|
5728
|
-
const cellNotes = readCellNotes(doc, s.
|
|
5871
|
+
const cellNotes = readCellNotes(doc, s.sheetId);
|
|
5729
5872
|
const cellNotesByAddr = {};
|
|
5730
5873
|
for (const [k, text] of Object.entries(cellNotes)) {
|
|
5731
5874
|
const [sliceId, swimLaneId] = k.split(":");
|
|
@@ -5748,7 +5891,7 @@ function buildSheetJson(doc, s) {
|
|
|
5748
5891
|
}));
|
|
5749
5892
|
});
|
|
5750
5893
|
});
|
|
5751
|
-
return { sheet: nameOf(doc, "
|
|
5894
|
+
return { sheet: nameOf(doc, "sheets", s.sheetId), sheetId: s.sheetId, columns: columnViews, rows: rowViews, cells: cellViews, cellNotes: cellNotesByAddr };
|
|
5752
5895
|
}
|
|
5753
5896
|
function buildCellView(doc, s, cellArg) {
|
|
5754
5897
|
const { ordinal } = parseCellAddress(cellArg);
|
|
@@ -5765,7 +5908,7 @@ function buildCellView(doc, s, cellArg) {
|
|
|
5765
5908
|
const flows = getEntries(doc, "flows");
|
|
5766
5909
|
return {
|
|
5767
5910
|
cell: cell.address,
|
|
5768
|
-
note: readCellNotes(doc, s.
|
|
5911
|
+
note: readCellNotes(doc, s.sheetId)[cellKey(cell.sliceId, cell.swimLaneId)] ?? null,
|
|
5769
5912
|
slice: { label: colLabel2(cell.colIndex), name: slice?.name ?? "(unnamed)", sliceId: cell.sliceId, note: slice?.note ?? null },
|
|
5770
5913
|
lane: { label: String(cell.rowIndex + 1), name: lane?.name ?? "(unnamed)", laneKind: lane?.laneKind ?? null, swimLaneId: cell.swimLaneId, note: lane?.note ?? null },
|
|
5771
5914
|
elements: refs.map((r) => ({
|
|
@@ -5811,7 +5954,7 @@ function registerSheetCommands(program) {
|
|
|
5811
5954
|
return JSON.stringify(buildCellView(doc, s, cellArg), null, 2);
|
|
5812
5955
|
if (opts.json)
|
|
5813
5956
|
return JSON.stringify(buildSheetJson(doc, s), null, 2);
|
|
5814
|
-
return renderSheetOverview(doc, s.
|
|
5957
|
+
return renderSheetOverview(doc, s.sheetId) ?? "(empty sheet)";
|
|
5815
5958
|
});
|
|
5816
5959
|
console.log(output);
|
|
5817
5960
|
} catch (err) {
|
|
@@ -5842,13 +5985,13 @@ function registerSheetCommands(program) {
|
|
|
5842
5985
|
if (!name2)
|
|
5843
5986
|
throw new SheetAddressError("Pass a <name> (or --from <file>).");
|
|
5844
5987
|
const id = crypto.randomUUID();
|
|
5845
|
-
const d = ELEMENT_DIMENSIONS.
|
|
5846
|
-
const v = validateEntry("
|
|
5988
|
+
const d = ELEMENT_DIMENSIONS.sheet;
|
|
5989
|
+
const v = validateEntry("sheets", { name: name2, x: 0, y: 0, width: d.width, height: d.height });
|
|
5847
5990
|
if (!v.ok)
|
|
5848
5991
|
throw new SheetAddressError(`Invalid sheet: ${v.issues.join("; ")}`);
|
|
5849
5992
|
const out = await withDoc(modelId, (doc) => {
|
|
5850
5993
|
doc.transact(() => {
|
|
5851
|
-
getScopeMap(doc, "
|
|
5994
|
+
getScopeMap(doc, "sheets").set(id, deepToY({ ...v.data, sheetId: id, modelId }));
|
|
5852
5995
|
ensureSheet(doc, id);
|
|
5853
5996
|
});
|
|
5854
5997
|
reflowAllSheets(doc);
|
|
@@ -5863,13 +6006,38 @@ function registerSheetCommands(program) {
|
|
|
5863
6006
|
throw err;
|
|
5864
6007
|
}
|
|
5865
6008
|
});
|
|
6009
|
+
sheet.command("delete [sheet]").description("Delete a whole sheet and everything in it — slices, lanes, elements, scenarios, flows. Destructive; pass --yes to confirm.").option("--yes", "Confirm the deletion (required — this cannot be undone)").option("--model <id>", "Target model id").action(async (sheetRef, opts) => {
|
|
6010
|
+
const modelId = resolveModelId(opts.model);
|
|
6011
|
+
try {
|
|
6012
|
+
const out = await withDoc(modelId, (doc) => {
|
|
6013
|
+
const s = resolveSheet2(doc, sheetRef);
|
|
6014
|
+
const name2 = getEntry(doc, "sheets", s.sheetId)?.name ?? s.sheetId;
|
|
6015
|
+
const elements = Object.values(s.structure.cells).reduce((n, refs) => n + refs.length, 0);
|
|
6016
|
+
const summary = `sheet "${name2}" — ${s.structure.columns.length} slice(s), ${s.structure.rows.length} lane(s), ${elements} element(s)`;
|
|
6017
|
+
if (!opts.yes) {
|
|
6018
|
+
return `Would delete ${summary}.
|
|
6019
|
+
This cannot be undone. Re-run with --yes to confirm.`;
|
|
6020
|
+
}
|
|
6021
|
+
deleteSheet(doc, s.sheetId);
|
|
6022
|
+
reflowAllSheets(doc);
|
|
6023
|
+
return `Deleted ${summary}.`;
|
|
6024
|
+
});
|
|
6025
|
+
console.log(out);
|
|
6026
|
+
} catch (err) {
|
|
6027
|
+
if (err instanceof SheetAddressError) {
|
|
6028
|
+
console.error(err.message);
|
|
6029
|
+
process.exit(2);
|
|
6030
|
+
}
|
|
6031
|
+
throw err;
|
|
6032
|
+
}
|
|
6033
|
+
});
|
|
5866
6034
|
const insert = sheet.command("insert").description("Insert a slice (column), a lane (row), or an element into a cell");
|
|
5867
|
-
insert.command("slice <name>").description("Insert a new slice (column)").option("--at <n>", "Position (1-based); appends if omitted").option("--sheet <ref>", "Which sheet (name or
|
|
6035
|
+
insert.command("slice <name>").description("Insert a new slice (column)").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) => insertColumn(doc, s, modelId, name2, atIndex(opts.at))));
|
|
5868
6036
|
for (const kind of LANE_KINDS) {
|
|
5869
|
-
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
|
|
6037
|
+
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))));
|
|
5870
6038
|
}
|
|
5871
6039
|
for (const type of ELEMENT_TYPES) {
|
|
5872
|
-
insert.command(`${type} <cell> <element>`).description(`Insert a ${type} into a cell (e.g. B2). <element> is a name or a JSON object.`).option("--sheet <ref>", "Which sheet (name or
|
|
6040
|
+
insert.command(`${type} <cell> <element>`).description(`Insert a ${type} into a cell (e.g. B2). <element> is a name or a JSON object.`).option("--sheet <ref>", "Which sheet (name or sheetId) when the model has several").option("--model <id>", "Target model id").action((cell, element, opts) => runWrite(opts, (doc, s, modelId) => insertElement(doc, s, modelId, type, cell, element)));
|
|
5873
6041
|
}
|
|
5874
6042
|
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)));
|
|
5875
6043
|
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))));
|