@dimescheduler/setup 0.1.2 → 0.11.4

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.
@@ -0,0 +1,1023 @@
1
+ // src/core/compile/bundle.ts
2
+ import { readFile } from "fs/promises";
3
+ import { dirname, resolve } from "path";
4
+ import JSON5 from "json5";
5
+
6
+ // src/core/types.ts
7
+ function isProfileDocument(doc) {
8
+ return typeof doc === "object" && doc !== null && doc.type === "profile";
9
+ }
10
+ function isUsersDocument(doc) {
11
+ return typeof doc === "object" && doc !== null && doc.type === "users";
12
+ }
13
+ function isLayoutsDocument(doc) {
14
+ return typeof doc === "object" && doc !== null && doc.type === "layouts";
15
+ }
16
+ function isConfigurationDocument(doc) {
17
+ return typeof doc === "object" && doc !== null && doc.type === "configuration";
18
+ }
19
+ function isBundleDocument(doc) {
20
+ return typeof doc === "object" && doc !== null && doc.type === "bundle";
21
+ }
22
+ function isDocumentReference(item) {
23
+ return "$ref" in item;
24
+ }
25
+ function detectDocumentType(doc) {
26
+ if (typeof doc !== "object" || doc === null) return null;
27
+ const type = doc.type;
28
+ if (type === "profile" || type === "users" || type === "layouts" || type === "configuration" || type === "bundle") {
29
+ return type;
30
+ }
31
+ return null;
32
+ }
33
+
34
+ // src/core/compile/merge.ts
35
+ function hasConflicts(a, b, key) {
36
+ const aKeys = new Set(a.map((item) => item[key]));
37
+ return b.some((item) => aKeys.has(item[key]));
38
+ }
39
+ function mergeLayouts(existing, incoming, strategy = "append") {
40
+ if (strategy === "replace") {
41
+ return [...incoming];
42
+ }
43
+ if (strategy === "error" && hasConflicts(existing, incoming, "code")) {
44
+ const existingCodes = new Set(existing.map((l) => l.code));
45
+ const conflicts = incoming.filter((l) => existingCodes.has(l.code)).map((l) => l.code);
46
+ throw new Error(`Layout code conflict detected: ${conflicts.join(", ")}`);
47
+ }
48
+ const merged = [...existing];
49
+ for (const layout of incoming) {
50
+ const existingIndex = merged.findIndex((l) => l.code === layout.code);
51
+ if (existingIndex >= 0) {
52
+ merged[existingIndex] = layout;
53
+ } else {
54
+ merged.push(layout);
55
+ }
56
+ }
57
+ return merged;
58
+ }
59
+ function mergeUsers(existing, incoming, strategy = "append") {
60
+ if (strategy === "replace") {
61
+ return [...incoming];
62
+ }
63
+ if (strategy === "error" && hasConflicts(existing, incoming, "email")) {
64
+ const existingEmails = new Set(existing.map((u) => u.email));
65
+ const conflicts = incoming.filter((u) => existingEmails.has(u.email)).map((u) => u.email);
66
+ throw new Error(`User email conflict detected: ${conflicts.join(", ")}`);
67
+ }
68
+ const merged = [...existing];
69
+ for (const user of incoming) {
70
+ const existingIndex = merged.findIndex((u) => u.email === user.email);
71
+ if (existingIndex >= 0) {
72
+ merged[existingIndex] = user;
73
+ } else {
74
+ merged.push(user);
75
+ }
76
+ }
77
+ return merged;
78
+ }
79
+ function deepMerge(target, source) {
80
+ const result = { ...target };
81
+ for (const key of Object.keys(source)) {
82
+ const sourceValue = source[key];
83
+ const targetValue = result[key];
84
+ if (sourceValue === void 0) {
85
+ continue;
86
+ }
87
+ if (Array.isArray(sourceValue)) {
88
+ if (Array.isArray(targetValue)) {
89
+ result[key] = [...targetValue, ...sourceValue];
90
+ } else {
91
+ result[key] = [...sourceValue];
92
+ }
93
+ } else if (typeof sourceValue === "object" && sourceValue !== null && typeof targetValue === "object" && targetValue !== null && !Array.isArray(targetValue)) {
94
+ result[key] = deepMerge(
95
+ targetValue,
96
+ sourceValue
97
+ );
98
+ } else {
99
+ result[key] = sourceValue;
100
+ }
101
+ }
102
+ return result;
103
+ }
104
+ function setPath(obj, path, value) {
105
+ const parts = path.split(".");
106
+ let current = obj;
107
+ for (let i = 0; i < parts.length - 1; i++) {
108
+ const part = parts[i];
109
+ if (!(part in current) || typeof current[part] !== "object" || current[part] === null) {
110
+ current[part] = {};
111
+ }
112
+ current = current[part];
113
+ }
114
+ const lastPart = parts[parts.length - 1];
115
+ if (Array.isArray(value) && Array.isArray(current[lastPart])) {
116
+ current[lastPart] = [...current[lastPart], ...value];
117
+ } else if (typeof value === "object" && value !== null && !Array.isArray(value) && typeof current[lastPart] === "object" && current[lastPart] !== null && !Array.isArray(current[lastPart])) {
118
+ current[lastPart] = deepMerge(
119
+ current[lastPart],
120
+ value
121
+ );
122
+ } else {
123
+ current[lastPart] = value;
124
+ }
125
+ }
126
+ function applyMergeOverrides(doc, mergeOverrides) {
127
+ const result = JSON.parse(JSON.stringify(doc));
128
+ for (const [path, value] of Object.entries(mergeOverrides)) {
129
+ setPath(result, path, value);
130
+ }
131
+ return result;
132
+ }
133
+
134
+ // src/core/compile/mappers.ts
135
+ var SNAP_MODE_MAP = {
136
+ "none": 1,
137
+ "off": 1,
138
+ "5min": 2,
139
+ "5minutes": 2,
140
+ "10min": 3,
141
+ "10minutes": 3,
142
+ "15min": 4,
143
+ "15minutes": 4,
144
+ "30min": 5,
145
+ "30minutes": 5,
146
+ "halfhour": 5,
147
+ "1hour": 6,
148
+ "1h": 6,
149
+ "hour": 6,
150
+ "12hours": 7,
151
+ "12h": 7,
152
+ "1day": 8,
153
+ "1d": 8,
154
+ "day": 8,
155
+ "2hours": 9,
156
+ "2h": 9,
157
+ "4hours": 10,
158
+ "4h": 10,
159
+ // Numeric string mappings
160
+ "1": 1,
161
+ "2": 2,
162
+ "3": 3,
163
+ "4": 4,
164
+ "5": 5,
165
+ "6": 6,
166
+ "7": 7,
167
+ "8": 8,
168
+ "9": 9,
169
+ "10": 10
170
+ };
171
+ function mapSnapMode(mode) {
172
+ if (mode === void 0 || mode === null) return 6;
173
+ return SNAP_MODE_MAP[String(mode).toLowerCase()] ?? 6;
174
+ }
175
+ var RANGE_MODE_MAP = {
176
+ "day": 1,
177
+ "days": 1,
178
+ "hours": 1,
179
+ "week": 2,
180
+ "weeks": 2,
181
+ "month": 3,
182
+ "months": 3,
183
+ "custom": 4,
184
+ // Numeric string mappings
185
+ "1": 1,
186
+ "2": 2,
187
+ "3": 3,
188
+ "4": 4
189
+ };
190
+ function mapRangeMode(mode) {
191
+ if (mode === void 0 || mode === null) return 2;
192
+ return RANGE_MODE_MAP[String(mode).toLowerCase()] ?? 2;
193
+ }
194
+ var START_MODE_MAP = {
195
+ "today": 1,
196
+ "absolute": 1,
197
+ "startofweek": 2,
198
+ "relative": 2,
199
+ "startofmonth": 3,
200
+ "todayoffset": 4,
201
+ // Numeric string mappings
202
+ "1": 1,
203
+ "2": 2,
204
+ "3": 3,
205
+ "4": 4
206
+ };
207
+ function mapStartMode(mode) {
208
+ if (mode === void 0 || mode === null) return 2;
209
+ return START_MODE_MAP[String(mode).toLowerCase().replace(/\s+/g, "")] ?? 2;
210
+ }
211
+ function mapUnitOfDistance(unit) {
212
+ if (!unit) return "Kilometers";
213
+ const v = unit.toLowerCase();
214
+ if (["km", "kilometer", "kilometers"].includes(v)) return "Kilometers";
215
+ if (["mi", "mile", "miles"].includes(v)) return "Miles";
216
+ return unit;
217
+ }
218
+ var COMPONENT_TO_GL = {
219
+ // Friendly names (user-facing DSL names)
220
+ "openTasks": "openTasksGridComponent",
221
+ "planningBoard": "schedulerComponent",
222
+ "map": "mapComponent",
223
+ "indicators": "categoriesComponent",
224
+ "resourceFilters": "filterComponent",
225
+ "plannedTasks": "plannedTasksGridComponent",
226
+ "details": "propertygridComponent",
227
+ "datePicker": "datePickerComponent",
228
+ "gantt": "ganttComponent",
229
+ "capacity": "capacityComponent",
230
+ "routeSequence": "routeSequenceComponent",
231
+ "notifications": "notificationsComponent",
232
+ // Internal names (for backwards compatibility)
233
+ "mapComponent": "mapComponent",
234
+ "plannedTasksGridComponent": "plannedTasksGridComponent",
235
+ "propertygridComponent": "propertygridComponent",
236
+ "datePickerComponent": "datePickerComponent",
237
+ "ganttComponent": "ganttComponent",
238
+ "capacityComponent": "capacityComponent",
239
+ "routeSequenceComponent": "routeSequenceComponent",
240
+ "notificationsComponent": "notificationsComponent"
241
+ };
242
+ var CONTEXT_TO_API_CONTEXT = {
243
+ "planningBoard": "scheduler",
244
+ "openTasks": "unplannedTasksGrid",
245
+ "plannedTasks": "plannedTasksGrid",
246
+ "notifications": "notificationsGrid",
247
+ "details": "detailsGrid",
248
+ "capacity": "pivotGrid",
249
+ "gantt": "gantt",
250
+ "routeSequence": "routeSequenceGrid"
251
+ };
252
+ function componentToGlName(name) {
253
+ return COMPONENT_TO_GL[name] ?? name;
254
+ }
255
+ function contextToApiContext(context) {
256
+ return CONTEXT_TO_API_CONTEXT[context] ?? context;
257
+ }
258
+ var VIEW_PRESET_MAP = {
259
+ "day": "1",
260
+ "1": "1",
261
+ "week": "2",
262
+ "2": "2",
263
+ "workweek": "3",
264
+ "workWeek": "3",
265
+ "work_week": "3",
266
+ "3": "3",
267
+ "month": "4",
268
+ "4": "4"
269
+ };
270
+ function mapViewPreset(value) {
271
+ if (value === void 0 || value === null) return "2";
272
+ const v = String(value).toLowerCase().replace(/[\s_-]+/g, "");
273
+ return VIEW_PRESET_MAP[v] ?? String(value);
274
+ }
275
+ var ROW_HEIGHT_MAP = {
276
+ "1row": 25,
277
+ "1rows": 25,
278
+ "1": 25,
279
+ "25": 25,
280
+ "2rows": 38,
281
+ "2row": 38,
282
+ "2": 38,
283
+ "38": 38,
284
+ "3rows": 50,
285
+ "3row": 50,
286
+ "3": 50,
287
+ "50": 50,
288
+ "4rows": 63,
289
+ "4row": 63,
290
+ "4": 63,
291
+ "63": 63
292
+ };
293
+ function mapRowHeight(value) {
294
+ if (value === void 0 || value === null) return 38;
295
+ const v = String(value).toLowerCase().replace(/[\s_-]+/g, "");
296
+ if (ROW_HEIGHT_MAP[v] !== void 0) return ROW_HEIGHT_MAP[v];
297
+ const parsed = parseInt(String(value), 10);
298
+ return isNaN(parsed) ? 38 : parsed;
299
+ }
300
+ function mapRouteProfile(value) {
301
+ if (!value || value === "default") return "car";
302
+ return value;
303
+ }
304
+
305
+ // src/core/compile/goldenLayout.ts
306
+ function workspaceNodeToGL(node) {
307
+ const gl = { type: node.type };
308
+ if ("width" in node && node.width !== void 0) {
309
+ gl.width = node.width;
310
+ }
311
+ if ("height" in node && node.height !== void 0) {
312
+ gl.height = node.height;
313
+ }
314
+ if (node.type === "row" || node.type === "column" || node.type === "stack") {
315
+ gl.isClosable = true;
316
+ gl.reorderEnabled = true;
317
+ gl.title = "";
318
+ if ("content" in node && node.content) {
319
+ gl.content = node.content.map(workspaceNodeToGL);
320
+ }
321
+ if (node.type === "stack") {
322
+ gl.activeItemIndex = 0;
323
+ }
324
+ return gl;
325
+ }
326
+ if (node.type === "component") {
327
+ const compName = componentToGlName(node.component);
328
+ if (compName) {
329
+ gl.componentName = compName;
330
+ }
331
+ if (node.title !== void 0) {
332
+ gl.title = node.title;
333
+ }
334
+ gl.isClosable = true;
335
+ gl.reorderEnabled = true;
336
+ const compState = {};
337
+ const compId = node.id;
338
+ if (compId) {
339
+ gl.id = compId;
340
+ compState.id = compId;
341
+ } else if (compName === "schedulerComponent") {
342
+ gl.id = "schedulerContainer";
343
+ compState.id = "scheduler";
344
+ }
345
+ if (compName === "datePickerComponent" && compId) {
346
+ compState.wrapperId = compId;
347
+ }
348
+ if (Object.keys(compState).length > 0) {
349
+ gl.componentState = compState;
350
+ }
351
+ return gl;
352
+ }
353
+ return gl;
354
+ }
355
+ function detectRootType(workspace) {
356
+ if (workspace.length === 0) return "row";
357
+ let heightCount = 0;
358
+ let widthCount = 0;
359
+ for (const node of workspace) {
360
+ if ("height" in node && node.height !== void 0) heightCount++;
361
+ if ("width" in node && node.width !== void 0) widthCount++;
362
+ }
363
+ if (heightCount > widthCount) {
364
+ return "column";
365
+ }
366
+ return "row";
367
+ }
368
+ function workspaceToGoldenLayout(workspace) {
369
+ const rootType = detectRootType(workspace);
370
+ return {
371
+ settings: {
372
+ hasHeaders: true,
373
+ constrainDragToContainer: false,
374
+ reorderEnabled: true,
375
+ selectionEnabled: true,
376
+ popoutWholeStack: false,
377
+ blockedPopoutsThrowError: true,
378
+ closePopoutsOnUnload: true,
379
+ showPopoutIcon: false,
380
+ showMaximiseIcon: true,
381
+ showCloseIcon: true,
382
+ responsiveMode: "onload",
383
+ tabOverlapAllowance: 0,
384
+ reorderOnTabMenuClick: true,
385
+ tabControlOffset: 10
386
+ },
387
+ dimensions: {
388
+ borderWidth: 5,
389
+ borderGrabWidth: 15,
390
+ minItemHeight: 10,
391
+ minItemWidth: 10,
392
+ headerHeight: 20,
393
+ dragProxyWidth: 300,
394
+ dragProxyHeight: 200
395
+ },
396
+ labels: {
397
+ close: "Close",
398
+ maximise: "Maximize",
399
+ minimise: "Minimize",
400
+ popout: "open in new window",
401
+ popin: "pop in",
402
+ tabDropdown: "Additional Tabs"
403
+ },
404
+ content: [
405
+ {
406
+ type: rootType,
407
+ isClosable: true,
408
+ reorderEnabled: true,
409
+ title: "",
410
+ content: workspace.map(workspaceNodeToGL)
411
+ }
412
+ ],
413
+ isClosable: true,
414
+ reorderEnabled: true,
415
+ title: "",
416
+ openPopouts: [],
417
+ maximisedItemId: null
418
+ };
419
+ }
420
+
421
+ // src/core/compile/layoutBuilders/base.ts
422
+ function buildBaseLayoutState(layout, gridName) {
423
+ const columns = (layout.columns || []).filter((c) => c.property).map((c) => ({ dataIndex: c.property }));
424
+ const sorters = (layout.sorters || []).filter((s) => s.property && s.direction).map((s) => ({ direction: s.direction, property: s.property }));
425
+ let grouper;
426
+ if (layout.grouper && layout.grouper.property && layout.grouper.direction) {
427
+ grouper = {
428
+ root: "data",
429
+ property: layout.grouper.property,
430
+ direction: layout.grouper.direction,
431
+ id: layout.grouper.id || layout.grouper.property
432
+ };
433
+ }
434
+ const filters = (layout.filters || []).map((f) => ({
435
+ operator: f.operator || "like",
436
+ value: f.value || "",
437
+ property: f.property,
438
+ exactMatch: f.exactMatch ?? false
439
+ }));
440
+ const pageSize = layout.pageSize !== void 0 ? typeof layout.pageSize === "number" ? layout.pageSize : parseInt(String(layout.pageSize), 10) : 50;
441
+ const state = {
442
+ columns,
443
+ storeState: grouper ? { grouper } : {},
444
+ filters,
445
+ Id: layout.id || gridName,
446
+ pageSize: isNaN(pageSize) ? 50 : pageSize
447
+ };
448
+ if (sorters.length > 0) {
449
+ state.sorters = sorters;
450
+ }
451
+ if (layout.default) {
452
+ state.default = true;
453
+ }
454
+ if (layout.name) {
455
+ state.name = layout.name;
456
+ }
457
+ return state;
458
+ }
459
+
460
+ // src/core/compile/layoutBuilders/scheduler.ts
461
+ function buildSchedulerLayoutState(layout, gridName) {
462
+ const base = buildBaseLayoutState(layout, gridName);
463
+ const lockedGridWidth = layout.lockedGridWidth || layout.resourcesGridWidth || null;
464
+ const fitToScreen = typeof layout.fitToScreen === "boolean" ? layout.fitToScreen : layout.fitToScreen === "true";
465
+ const ignoreCalendars = typeof layout.ignoreCalendars === "boolean" ? layout.ignoreCalendars : layout.ignoreCalendars === "true";
466
+ return {
467
+ ...base,
468
+ viewPreset: layout.viewPreset !== void 0 ? mapViewPreset(layout.viewPreset) : null,
469
+ lockedGridWidth,
470
+ fitToScreen,
471
+ rowHeight: mapRowHeight(layout.rowHeight),
472
+ ignoreCalendars
473
+ };
474
+ }
475
+
476
+ // src/core/compile/layoutBuilders/capacity.ts
477
+ function buildCapacityLayoutState(layout, gridName) {
478
+ const base = buildBaseLayoutState(layout, gridName);
479
+ const state = { ...base };
480
+ if (layout.viewLayoutType !== void 0) state.viewLayoutType = layout.viewLayoutType;
481
+ if (layout.startRowGroupsCollapsed !== void 0) state.startRowGroupsCollapsed = layout.startRowGroupsCollapsed;
482
+ if (layout.startColGroupsCollapsed !== void 0) state.startColGroupsCollapsed = layout.startColGroupsCollapsed;
483
+ if (layout.enableColumnSort !== void 0) state.enableColumnSort = layout.enableColumnSort;
484
+ if (layout.expandedItems !== void 0) state.expandedItems = layout.expandedItems;
485
+ if (layout.matrix !== void 0) state.matrix = layout.matrix;
486
+ if (layout.pivotcolumns !== void 0) state.pivotcolumns = layout.pivotcolumns;
487
+ if (layout.collapsed !== void 0) state.collapsed = layout.collapsed;
488
+ return state;
489
+ }
490
+
491
+ // src/core/compile/layoutBuilders/gantt.ts
492
+ function buildGanttLayoutState(layout, gridName) {
493
+ const base = buildBaseLayoutState(layout, gridName);
494
+ const state = { ...base };
495
+ if (layout.viewPreset !== void 0) {
496
+ state.viewPreset = mapViewPreset(layout.viewPreset);
497
+ }
498
+ return state;
499
+ }
500
+
501
+ // src/core/compile/layoutBuilders/grid.ts
502
+ function buildGridLayoutState(layout, gridName) {
503
+ const base = buildBaseLayoutState(layout, gridName);
504
+ const state = { ...base };
505
+ if (layout.hideEmptyRows !== void 0) {
506
+ state.hideEmptyRows = layout.hideEmptyRows;
507
+ }
508
+ return state;
509
+ }
510
+
511
+ // src/core/compile/layoutBuilders/index.ts
512
+ function buildLayoutState(layout, gridName) {
513
+ const context = layout.context;
514
+ switch (context) {
515
+ case "planningBoard":
516
+ return buildSchedulerLayoutState(layout, gridName);
517
+ case "capacity":
518
+ return buildCapacityLayoutState(layout, gridName);
519
+ case "gantt":
520
+ return buildGanttLayoutState(layout, gridName);
521
+ case "openTasks":
522
+ case "plannedTasks":
523
+ case "notifications":
524
+ case "details":
525
+ case "routeSequence":
526
+ return buildGridLayoutState(layout, gridName);
527
+ default:
528
+ return buildBaseLayoutState(layout, gridName);
529
+ }
530
+ }
531
+
532
+ // src/core/compile/layoutBuilder.ts
533
+ function collectLayouts(layouts) {
534
+ return layouts.map((layout) => {
535
+ const gridName = layout.id || layout.code;
536
+ return {
537
+ context: layout.context,
538
+ grid: gridName,
539
+ value: buildLayoutState(layout, gridName),
540
+ name: layout.name || layout.code,
541
+ code: layout.code,
542
+ componentId: gridName,
543
+ default: layout.default ?? false,
544
+ public: layout.shared?.public ?? false,
545
+ userGroup: layout.shared?.userGroup
546
+ };
547
+ });
548
+ }
549
+ function buildLayoutDtos(layouts) {
550
+ if (!layouts || layouts.length === 0) return [];
551
+ return collectLayouts(layouts).map((L) => ({
552
+ context: contextToApiContext(L.context),
553
+ grid: L.grid,
554
+ value: JSON.stringify(L.value),
555
+ default: L.default,
556
+ public: L.public,
557
+ userGroup: L.userGroup,
558
+ isOwner: true,
559
+ isNew: true,
560
+ name: L.name,
561
+ code: L.code
562
+ }));
563
+ }
564
+ var PANEL_COMPONENTS = /* @__PURE__ */ new Set([
565
+ "planningBoard",
566
+ "scheduler",
567
+ "openTasks",
568
+ "tasks",
569
+ "plannedTasks",
570
+ "details",
571
+ "gantt",
572
+ "indicators",
573
+ "categories",
574
+ "capacity",
575
+ "pivot",
576
+ "notifications",
577
+ "routeSequence"
578
+ ]);
579
+ function buildProfileLayoutDtos(workspace, profileCode) {
580
+ if (!workspace || workspace.length === 0) return [];
581
+ const profileLayouts = [];
582
+ function traverse(nodes) {
583
+ for (const node of nodes) {
584
+ if (node.type === "row" || node.type === "column" || node.type === "stack") {
585
+ if ("content" in node && node.content) {
586
+ traverse(node.content);
587
+ }
588
+ } else if (node.type === "component") {
589
+ if (node.layoutRef) {
590
+ const refs = Array.isArray(node.layoutRef) ? node.layoutRef : [node.layoutRef];
591
+ const needsPanel = PANEL_COMPONENTS.has(node.component);
592
+ for (const code of refs) {
593
+ profileLayouts.push({
594
+ profileCode,
595
+ layoutCode: code,
596
+ default: true,
597
+ public: false,
598
+ name: node.id ? needsPanel ? `${node.id}_panel` : node.id : ""
599
+ });
600
+ }
601
+ }
602
+ }
603
+ }
604
+ }
605
+ traverse(workspace);
606
+ return profileLayouts;
607
+ }
608
+
609
+ // src/core/compile/profile.ts
610
+ var SNAP_MODE_VALUE = {
611
+ 1: 0,
612
+ // none
613
+ 2: 3e5,
614
+ // 5 min
615
+ 3: 6e5,
616
+ // 10 min
617
+ 4: 9e5,
618
+ // 15 min
619
+ 5: 18e5,
620
+ // 30 min
621
+ 6: 36e5,
622
+ // 1 hour
623
+ 7: 432e5,
624
+ // 12 hours
625
+ 8: 864e5,
626
+ // 1 day
627
+ 9: 72e5,
628
+ // 2 hours
629
+ 10: 144e5
630
+ // 4 hours
631
+ };
632
+ function getSnapMode(snapInterval) {
633
+ if (!snapInterval) return void 0;
634
+ if (typeof snapInterval === "string") return snapInterval;
635
+ return snapInterval.mode;
636
+ }
637
+ function getSnapValue(snapInterval, snapMode) {
638
+ if (typeof snapInterval === "object" && snapInterval?.value !== void 0 && snapInterval.value !== null) {
639
+ return snapInterval.value;
640
+ }
641
+ return SNAP_MODE_VALUE[snapMode] ?? 36e5;
642
+ }
643
+ function compileProfileDocument(doc) {
644
+ const profile = doc.payload;
645
+ const theme = profile.theme || { color: "default", scheme: "sdtd" };
646
+ const shared = profile.shared || { global: false, userGroup: "" };
647
+ const route = profile.route || {
648
+ profile: "default",
649
+ calculateRoutes: true,
650
+ showSequenceIndicators: true,
651
+ unitOfDistance: "km"
652
+ };
653
+ const planning = profile.planning || {
654
+ snapInterval: { mode: "1hour", value: 0 },
655
+ range: { mode: "week", value: 0 },
656
+ start: { mode: "startOfWeek", value: 2 },
657
+ hours: { start: 8, end: 18 }
658
+ };
659
+ const workspace = profile.workspace;
660
+ const goldenLayout = workspace && workspace.length > 0 ? workspaceToGoldenLayout(workspace) : null;
661
+ const layouts = [];
662
+ const profileLayouts = buildProfileLayoutDtos(workspace, profile.code || "");
663
+ const snapMode = mapSnapMode(getSnapMode(planning.snapInterval));
664
+ const snapValue = getSnapValue(planning.snapInterval, snapMode);
665
+ return {
666
+ id: "profile",
667
+ payload: {
668
+ profiles: [{
669
+ name: profile.name || "",
670
+ code: profile.code || "",
671
+ color: theme.color || "default",
672
+ theme: theme.scheme || "sdtd",
673
+ public: shared.global ?? false,
674
+ userGroup: shared.userGroup || "",
675
+ snapMode,
676
+ snapValue,
677
+ rangeMode: mapRangeMode(planning.range?.mode),
678
+ rangeValue: planning.range?.value ?? null,
679
+ startMode: mapStartMode(planning.start?.mode),
680
+ startValue: planning.start?.value ?? null,
681
+ startTime: planning.hours?.start ?? 8,
682
+ endTime: planning.hours?.end ?? 18,
683
+ unitOfDistance: mapUnitOfDistance(route.unitOfDistance),
684
+ autoRouteCalculation: route.calculateRoutes ?? true,
685
+ showSequenceIndicators: route.showSequenceIndicators ?? true,
686
+ routeProfile: mapRouteProfile(route.profile),
687
+ layout: goldenLayout ? JSON.stringify(goldenLayout) : ""
688
+ }],
689
+ layouts,
690
+ profileLayouts,
691
+ owner: doc.owner,
692
+ notificationEmail: doc.notificationEmail
693
+ }
694
+ };
695
+ }
696
+
697
+ // src/core/compile/users.ts
698
+ function compileUsersDocument(doc) {
699
+ return {
700
+ id: "users",
701
+ payload: {
702
+ users: doc.payload,
703
+ owner: doc.owner,
704
+ notificationEmail: doc.notificationEmail
705
+ }
706
+ };
707
+ }
708
+
709
+ // src/core/compile/layouts.ts
710
+ function compileLayoutsDocument(doc) {
711
+ return {
712
+ id: "layouts",
713
+ payload: {
714
+ layouts: buildLayoutDtos(doc.payload),
715
+ owner: doc.owner,
716
+ notificationEmail: doc.notificationEmail
717
+ }
718
+ };
719
+ }
720
+
721
+ // src/core/compile/configuration.ts
722
+ var CONFIG_KEY_TO_INTERNAL = {
723
+ CompanyName: "AppSetup_CompanyName",
724
+ CompanyAddress: "AppSetup_CompanyAddress",
725
+ CompanyAddressCountry: "AppSetup_CompanyAddress_Country",
726
+ DurationFormat: "AppSetup_DurationFormat",
727
+ EnableAppointmentContainers: "AppSetup_EnableAppointmentContainers",
728
+ EnablePlanningBoardTooltip: "AppSetup_EnablePlanningBoardTooltip",
729
+ ApplyRequestedDates: "AppSetup_ApplyRequestedDates",
730
+ ApplyRequestedTimes: "AppSetup_ApplyRequestedTimes",
731
+ RespectAllowedDateConstraints: "AppSetup_RespectAllowedDateConstraints",
732
+ MultiDayCapacityDistributionMode: "AppSetup_MultiDayCapacityDistributionMode",
733
+ RenderCategoryInBackground: "AppSetup_RenderCategoryInBackground",
734
+ AlternateRows: "AppSetup_AlternateRows",
735
+ EnableResourceCalendarsVisualisation: "AppSetup_EnableResourceCalendarsVisualisation",
736
+ ResourceZonesColor: "AppSetup_ResourceZonesColor",
737
+ ResourceCalendarRecalculationMode: "AppSetup_ResourceCalendarRecalculationMode",
738
+ RouteReschedulingMode: "AppSetup_RouteReschedulingMode",
739
+ DoNotCountAssignment: "AppSetup_DoNotCountAssignment",
740
+ DisableTaskDurationCalculation: "AppSetup_DisableTaskDurationCalculation",
741
+ CalculateRouteAndTravelTime: "AppSetup_CalculateRouteAndTravelTime",
742
+ DistanceUnit: "AppSetup_DistanceUnit",
743
+ RouteProfile: "AppSetup_RouteProfile",
744
+ ShowWaypoints: "AppSetup_ShowWaypoints",
745
+ MobileVisibilityModeForLockedAppointments: "AppSetup_MobileVisibilityModeForLockedAppointments",
746
+ SolverApiKey: "AppSetup_SolverApiKey",
747
+ EnableRouteModel: "AppSetup_EnableRouteModel",
748
+ EnableFieldServiceModel: "AppSetup_EnableFieldServiceModel",
749
+ Chat: "AppSetup_Chat",
750
+ OpenAiApiKey: "AppSetup_OpenAiApiKey",
751
+ ExchangeClientId: "AppSetup_Exchange_ClientId",
752
+ ExchangeClientSecret: "AppSetup_Exchange_ClientSecret",
753
+ ExchangeClientTenant: "AppSetup_Exchange_ClientTenant",
754
+ ExchangeEnableTwoWaySync: "AppSetup_Exchange_EnableTwoWaySync",
755
+ ExchangeDeltaStart: "AppSetup_Exchange_DeltaStart",
756
+ ExchangeDeltaEnd: "AppSetup_Exchange_DeltaEnd",
757
+ ExchangeResourcePreferencesEnabled: "AppSetup_Exchange_ResourcePreferences_Enabled",
758
+ ExchangeDefaultShowAs: "AppSetup_Exchange_ResourcePreferences_DefaultShowAs",
759
+ ExchangeDefaultSensitivity: "AppSetup_Exchange_ResourcePreferences_DefaultSensitivity",
760
+ ExchangeCategoryPreset: "AppSetup_Exchange_CategoryPreset",
761
+ ExchangeUseCategory: "AppSetup_Exchange_UseCategory"
762
+ };
763
+ var ENUM_CONVERSIONS = {
764
+ "AppSetup_DurationFormat": {
765
+ "Decimal": 0,
766
+ "HoursMinutes": 1,
767
+ "DaysDecimal": 2,
768
+ "DaysHours": 3
769
+ },
770
+ "AppSetup_ResourceCalendarRecalculationMode": {
771
+ "None": 0,
772
+ "ExtendDuration": 1,
773
+ "UpdatePlanningQuantity": 2
774
+ },
775
+ "AppSetup_DistanceUnit": {
776
+ "km": 0,
777
+ "mi": 1
778
+ },
779
+ "AppSetup_MobileVisibilityModeForLockedAppointments": {
780
+ "Locked": 0,
781
+ "Hidden": 1
782
+ },
783
+ "AppSetup_MultiDayCapacityDistributionMode": {
784
+ "None": 0,
785
+ "Constant": 1,
786
+ "Even": 2
787
+ },
788
+ "AppSetup_RouteReschedulingMode": {
789
+ "DoNothing": 0,
790
+ "UpdateTravelTime": 1,
791
+ "Optimize": 2
792
+ }
793
+ };
794
+ var SHOW_AS_TO_ID = {
795
+ "Free": 1,
796
+ "Tentative": 2,
797
+ "Office": 3,
798
+ "OutOfOffice": 4,
799
+ "WorkingElsewhere": 5,
800
+ "Unknown": 6
801
+ };
802
+ var SENSITIVITY_TO_ID = {
803
+ "Normal": 1,
804
+ "Personal": 2,
805
+ "Private": 3,
806
+ "Confidential": 4
807
+ };
808
+ function convertConfigurationItem(item) {
809
+ const internalKey = CONFIG_KEY_TO_INTERNAL[item.key] || item.key;
810
+ let value = item.value;
811
+ if (internalKey === "AppSetup_Exchange_ResourcePreferences_DefaultShowAs" && Array.isArray(item.value)) {
812
+ const ids = item.value.map((v) => SHOW_AS_TO_ID[v]).filter(Boolean);
813
+ value = ids.sort((a, b) => a - b).join(";");
814
+ } else if (internalKey === "AppSetup_Exchange_ResourcePreferences_DefaultSensitivity" && Array.isArray(item.value)) {
815
+ const ids = item.value.map((v) => SENSITIVITY_TO_ID[v]).filter(Boolean);
816
+ value = ids.sort((a, b) => a - b).join(";");
817
+ } else if (typeof value === "string" && ENUM_CONVERSIONS[internalKey]?.[value] !== void 0) {
818
+ value = ENUM_CONVERSIONS[internalKey][value];
819
+ }
820
+ return {
821
+ key: internalKey,
822
+ value
823
+ };
824
+ }
825
+ function compileConfigurationDocument(doc) {
826
+ const configuration = (doc.payload || []).map(convertConfigurationItem);
827
+ return {
828
+ id: "configuration",
829
+ payload: {
830
+ configuration,
831
+ owner: doc.owner,
832
+ notificationEmail: doc.notificationEmail
833
+ }
834
+ };
835
+ }
836
+ function mergeConfiguration(existing, incoming) {
837
+ const merged = /* @__PURE__ */ new Map();
838
+ for (const item of existing) {
839
+ merged.set(item.key, item);
840
+ }
841
+ for (const item of incoming) {
842
+ merged.set(item.key, item);
843
+ }
844
+ return Array.from(merged.values());
845
+ }
846
+
847
+ // src/core/compile/bundle.ts
848
+ async function resolveBundle(bundle, basePath) {
849
+ const result = {
850
+ profiles: [],
851
+ users: [],
852
+ layouts: [],
853
+ configuration: []
854
+ };
855
+ const strategy = bundle.mergeStrategy ?? {};
856
+ for (const item of bundle.documents) {
857
+ let doc;
858
+ if (isDocumentReference(item)) {
859
+ const refPath = resolve(dirname(basePath), item.$ref);
860
+ const content = await readFile(refPath, "utf-8");
861
+ const parsed = JSON5.parse(content);
862
+ if (!isProfileDocument(parsed) && !isUsersDocument(parsed) && !isLayoutsDocument(parsed) && !isConfigurationDocument(parsed)) {
863
+ throw new Error(`Referenced document at ${item.$ref} is not a valid document type (profile, users, layouts, or configuration)`);
864
+ }
865
+ doc = parsed;
866
+ if (item.$merge) {
867
+ doc = applyMergeOverrides(doc, item.$merge);
868
+ }
869
+ } else if (isProfileDocument(item) || isUsersDocument(item) || isLayoutsDocument(item) || isConfigurationDocument(item)) {
870
+ doc = item;
871
+ } else {
872
+ continue;
873
+ }
874
+ if (isProfileDocument(doc)) {
875
+ result.profiles.push(doc);
876
+ } else if (isUsersDocument(doc)) {
877
+ result.users = mergeUsers(result.users, doc.payload ?? [], strategy.users);
878
+ } else if (isLayoutsDocument(doc)) {
879
+ result.layouts = mergeLayouts(result.layouts, doc.payload ?? [], strategy.layouts);
880
+ } else if (isConfigurationDocument(doc)) {
881
+ result.configuration = mergeConfiguration(result.configuration, doc.payload ?? []);
882
+ }
883
+ }
884
+ return result;
885
+ }
886
+ async function compileBundleDocument(bundle, basePath) {
887
+ const resolved = await resolveBundle(bundle, basePath);
888
+ const payloads = [];
889
+ const strategy = bundle.mergeStrategy ?? {};
890
+ if (resolved.profiles.length > 0) {
891
+ let profilesForCompile;
892
+ if (strategy.profiles === "error" && resolved.profiles.length > 1) {
893
+ throw new Error(`Multiple profiles found in bundle and mergeStrategy.profiles is 'error'`);
894
+ } else if (strategy.profiles === "first-wins") {
895
+ profilesForCompile = [resolved.profiles[0]];
896
+ } else {
897
+ profilesForCompile = [resolved.profiles[resolved.profiles.length - 1]];
898
+ }
899
+ for (const profile of profilesForCompile) {
900
+ payloads.push(compileProfileDocument(profile));
901
+ }
902
+ if (resolved.layouts.length > 0) {
903
+ const layoutsDoc = {
904
+ type: "layouts",
905
+ payload: resolved.layouts
906
+ };
907
+ payloads.push(compileLayoutsDocument(layoutsDoc));
908
+ }
909
+ }
910
+ if (resolved.profiles.length === 0) {
911
+ if (resolved.users.length > 0) {
912
+ const usersDoc = {
913
+ type: "users",
914
+ payload: resolved.users
915
+ };
916
+ payloads.push(compileUsersDocument(usersDoc));
917
+ }
918
+ if (resolved.layouts.length > 0) {
919
+ const layoutsDoc = {
920
+ type: "layouts",
921
+ payload: resolved.layouts
922
+ };
923
+ payloads.push(compileLayoutsDocument(layoutsDoc));
924
+ }
925
+ } else {
926
+ if (resolved.users.length > 0) {
927
+ const usersDoc = {
928
+ type: "users",
929
+ payload: resolved.users
930
+ };
931
+ payloads.push(compileUsersDocument(usersDoc));
932
+ }
933
+ }
934
+ if (resolved.configuration.length > 0) {
935
+ const configDoc = {
936
+ type: "configuration",
937
+ payload: resolved.configuration
938
+ };
939
+ payloads.push(compileConfigurationDocument(configDoc));
940
+ }
941
+ return {
942
+ id: "bundle",
943
+ payloads
944
+ };
945
+ }
946
+ function compileBundleDocumentSync(bundle) {
947
+ for (const item of bundle.documents) {
948
+ if (isDocumentReference(item)) {
949
+ throw new Error("Bundle contains $ref items. Use compileBundleDocument (async) instead.");
950
+ }
951
+ }
952
+ const result = {
953
+ profiles: [],
954
+ users: [],
955
+ layouts: [],
956
+ configuration: []
957
+ };
958
+ const strategy = bundle.mergeStrategy ?? {};
959
+ for (const item of bundle.documents) {
960
+ if (isProfileDocument(item)) {
961
+ result.profiles.push(item);
962
+ } else if (isUsersDocument(item)) {
963
+ result.users = mergeUsers(result.users, item.payload ?? [], strategy.users);
964
+ } else if (isLayoutsDocument(item)) {
965
+ result.layouts = mergeLayouts(result.layouts, item.payload ?? [], strategy.layouts);
966
+ } else if (isConfigurationDocument(item)) {
967
+ result.configuration = mergeConfiguration(result.configuration, item.payload ?? []);
968
+ }
969
+ }
970
+ const payloads = [];
971
+ if (result.profiles.length > 0) {
972
+ let profilesForCompile;
973
+ if (strategy.profiles === "error" && result.profiles.length > 1) {
974
+ throw new Error(`Multiple profiles found in bundle and mergeStrategy.profiles is 'error'`);
975
+ } else if (strategy.profiles === "first-wins") {
976
+ profilesForCompile = [result.profiles[0]];
977
+ } else {
978
+ profilesForCompile = [result.profiles[result.profiles.length - 1]];
979
+ }
980
+ for (const profile of profilesForCompile) {
981
+ payloads.push(compileProfileDocument(profile));
982
+ }
983
+ if (result.layouts.length > 0) {
984
+ payloads.push(compileLayoutsDocument({ type: "layouts", payload: result.layouts }));
985
+ }
986
+ }
987
+ if (result.profiles.length === 0) {
988
+ if (result.users.length > 0) {
989
+ payloads.push(compileUsersDocument({ type: "users", payload: result.users }));
990
+ }
991
+ if (result.layouts.length > 0) {
992
+ payloads.push(compileLayoutsDocument({ type: "layouts", payload: result.layouts }));
993
+ }
994
+ } else {
995
+ if (result.users.length > 0) {
996
+ payloads.push(compileUsersDocument({ type: "users", payload: result.users }));
997
+ }
998
+ }
999
+ if (result.configuration.length > 0) {
1000
+ payloads.push(compileConfigurationDocument({ type: "configuration", payload: result.configuration }));
1001
+ }
1002
+ return {
1003
+ id: "bundle",
1004
+ payloads
1005
+ };
1006
+ }
1007
+
1008
+ export {
1009
+ isProfileDocument,
1010
+ isUsersDocument,
1011
+ isLayoutsDocument,
1012
+ isConfigurationDocument,
1013
+ isBundleDocument,
1014
+ isDocumentReference,
1015
+ detectDocumentType,
1016
+ compileProfileDocument,
1017
+ compileUsersDocument,
1018
+ compileLayoutsDocument,
1019
+ compileConfigurationDocument,
1020
+ resolveBundle,
1021
+ compileBundleDocument,
1022
+ compileBundleDocumentSync
1023
+ };