@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.
- package/README.md +546 -404
- package/dist/bundle-4UYBQOZO.js +10 -0
- package/dist/chunk-3PMKH6IT.js +1023 -0
- package/dist/index.js +216 -448
- package/package.json +54 -49
package/dist/index.js
CHANGED
|
@@ -1,4 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
compileConfigurationDocument,
|
|
4
|
+
compileLayoutsDocument,
|
|
5
|
+
compileProfileDocument,
|
|
6
|
+
compileUsersDocument,
|
|
7
|
+
detectDocumentType,
|
|
8
|
+
isBundleDocument,
|
|
9
|
+
isConfigurationDocument,
|
|
10
|
+
isDocumentReference,
|
|
11
|
+
isLayoutsDocument,
|
|
12
|
+
isProfileDocument,
|
|
13
|
+
isUsersDocument
|
|
14
|
+
} from "./chunk-3PMKH6IT.js";
|
|
2
15
|
|
|
3
16
|
// src/index.ts
|
|
4
17
|
import { Command as Command4 } from "commander";
|
|
@@ -34,452 +47,186 @@ function hasComponent(nodes, componentType) {
|
|
|
34
47
|
}
|
|
35
48
|
return false;
|
|
36
49
|
}
|
|
37
|
-
function
|
|
50
|
+
function validateProfileSettings(settings, prefix = "") {
|
|
38
51
|
const issues = [];
|
|
39
|
-
|
|
40
|
-
|
|
52
|
+
const p = prefix ? `${prefix}: ` : "";
|
|
53
|
+
if (!settings.name?.trim()) {
|
|
54
|
+
issues.push({ type: "error", message: `${p}Profile name is required` });
|
|
41
55
|
}
|
|
42
|
-
if (!
|
|
43
|
-
issues.push({ type: "error", message:
|
|
56
|
+
if (!settings.code?.trim()) {
|
|
57
|
+
issues.push({ type: "error", message: `${p}Profile code is required` });
|
|
44
58
|
}
|
|
45
|
-
if (!
|
|
46
|
-
issues.push({ type: "error", message:
|
|
59
|
+
if (!settings.workspace || settings.workspace.length === 0) {
|
|
60
|
+
issues.push({ type: "error", message: `${p}Workspace must have at least one element` });
|
|
47
61
|
} else {
|
|
48
|
-
const componentCount = countComponents(
|
|
62
|
+
const componentCount = countComponents(settings.workspace);
|
|
49
63
|
if (componentCount === 0) {
|
|
50
|
-
issues.push({ type: "warning", message:
|
|
64
|
+
issues.push({ type: "warning", message: `${p}Workspace has no components` });
|
|
51
65
|
}
|
|
52
|
-
const hasPlanningBoard = hasComponent(
|
|
66
|
+
const hasPlanningBoard = hasComponent(settings.workspace, "planningBoard");
|
|
53
67
|
if (!hasPlanningBoard) {
|
|
54
|
-
issues.push({ type: "warning", message:
|
|
68
|
+
issues.push({ type: "warning", message: `${p}Consider adding a Planning Board component` });
|
|
55
69
|
}
|
|
56
70
|
}
|
|
57
|
-
|
|
58
|
-
profile.users.forEach((user, index) => {
|
|
59
|
-
if (!user.name?.trim()) {
|
|
60
|
-
issues.push({ type: "error", message: `User ${index + 1}: Name is required` });
|
|
61
|
-
}
|
|
62
|
-
if (!user.email?.trim()) {
|
|
63
|
-
issues.push({ type: "error", message: `User ${index + 1}: Email is required` });
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
const errors = issues.filter((i) => i.type === "error");
|
|
68
|
-
const warnings = issues.filter((i) => i.type === "warning");
|
|
69
|
-
return {
|
|
70
|
-
valid: errors.length === 0,
|
|
71
|
-
errors,
|
|
72
|
-
warnings
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// src/core/compile.ts
|
|
77
|
-
var SNAP_MODE_MAP = {
|
|
78
|
-
"none": 1,
|
|
79
|
-
"off": 1,
|
|
80
|
-
"5min": 2,
|
|
81
|
-
"5minutes": 2,
|
|
82
|
-
"10min": 3,
|
|
83
|
-
"10minutes": 3,
|
|
84
|
-
"15min": 4,
|
|
85
|
-
"15minutes": 4,
|
|
86
|
-
"30min": 5,
|
|
87
|
-
"30minutes": 5,
|
|
88
|
-
"halfhour": 5,
|
|
89
|
-
"1hour": 6,
|
|
90
|
-
"1h": 6,
|
|
91
|
-
"hour": 6,
|
|
92
|
-
"12hours": 7,
|
|
93
|
-
"12h": 7,
|
|
94
|
-
"1day": 8,
|
|
95
|
-
"1d": 8,
|
|
96
|
-
"day": 8,
|
|
97
|
-
"2hours": 9,
|
|
98
|
-
"2h": 9,
|
|
99
|
-
"4hours": 10,
|
|
100
|
-
"4h": 10
|
|
101
|
-
};
|
|
102
|
-
var RANGE_MODE_MAP = {
|
|
103
|
-
"day": 1,
|
|
104
|
-
"days": 1,
|
|
105
|
-
"hours": 1,
|
|
106
|
-
"week": 2,
|
|
107
|
-
"weeks": 2,
|
|
108
|
-
"month": 3,
|
|
109
|
-
"months": 3,
|
|
110
|
-
"custom": 4
|
|
111
|
-
};
|
|
112
|
-
var START_MODE_MAP = {
|
|
113
|
-
"today": 1,
|
|
114
|
-
"absolute": 1,
|
|
115
|
-
"startofweek": 2,
|
|
116
|
-
"relative": 2,
|
|
117
|
-
"startofmonth": 3,
|
|
118
|
-
"todayoffset": 4
|
|
119
|
-
};
|
|
120
|
-
var COMPONENT_TO_GL = {
|
|
121
|
-
"openTasks": "openTasksGridComponent",
|
|
122
|
-
"planningBoard": "schedulerComponent",
|
|
123
|
-
"mapComponent": "mapComponent",
|
|
124
|
-
"indicators": "categoriesComponent",
|
|
125
|
-
"resourceFilters": "filterComponent",
|
|
126
|
-
"plannedTasksGridComponent": "plannedTasksGridComponent",
|
|
127
|
-
"propertygridComponent": "propertygridComponent",
|
|
128
|
-
"datePickerComponent": "datePickerComponent",
|
|
129
|
-
"ganttComponent": "ganttComponent",
|
|
130
|
-
"capacityComponent": "capacityComponent",
|
|
131
|
-
"routeSequenceComponent": "routeSequenceComponent",
|
|
132
|
-
"notificationsComponent": "notificationsComponent"
|
|
133
|
-
};
|
|
134
|
-
var COMPONENT_TO_CONTEXT = {
|
|
135
|
-
"planningBoard": "scheduler",
|
|
136
|
-
"openTasks": "unplannedTasksGrid",
|
|
137
|
-
"plannedTasksGridComponent": "plannedTasksGrid",
|
|
138
|
-
"notificationsComponent": "notificationsGrid",
|
|
139
|
-
"propertygridComponent": "detailsGrid",
|
|
140
|
-
"capacityComponent": "pivotGrid",
|
|
141
|
-
"ganttComponent": "gantt",
|
|
142
|
-
"routeSequenceComponent": "routeSequenceGrid"
|
|
143
|
-
};
|
|
144
|
-
var VIEW_PRESET_MAP = {
|
|
145
|
-
"day": "1",
|
|
146
|
-
"1": "1",
|
|
147
|
-
"week": "2",
|
|
148
|
-
"2": "2",
|
|
149
|
-
"workweek": "3",
|
|
150
|
-
"workWeek": "3",
|
|
151
|
-
"work_week": "3",
|
|
152
|
-
"3": "3",
|
|
153
|
-
"month": "4",
|
|
154
|
-
"4": "4"
|
|
155
|
-
};
|
|
156
|
-
var ROW_HEIGHT_MAP = {
|
|
157
|
-
"1row": 25,
|
|
158
|
-
"1rows": 25,
|
|
159
|
-
"1": 25,
|
|
160
|
-
"25": 25,
|
|
161
|
-
"2rows": 38,
|
|
162
|
-
"2row": 38,
|
|
163
|
-
"2": 38,
|
|
164
|
-
"38": 38,
|
|
165
|
-
"3rows": 50,
|
|
166
|
-
"3row": 50,
|
|
167
|
-
"3": 50,
|
|
168
|
-
"50": 50,
|
|
169
|
-
"4rows": 63,
|
|
170
|
-
"4row": 63,
|
|
171
|
-
"4": 63,
|
|
172
|
-
"63": 63
|
|
173
|
-
};
|
|
174
|
-
function mapSnapMode(mode) {
|
|
175
|
-
if (!mode) return 6;
|
|
176
|
-
return SNAP_MODE_MAP[mode.toLowerCase()] ?? 6;
|
|
177
|
-
}
|
|
178
|
-
function mapRangeMode(mode) {
|
|
179
|
-
if (!mode) return 2;
|
|
180
|
-
return RANGE_MODE_MAP[mode.toLowerCase()] ?? 2;
|
|
71
|
+
return issues;
|
|
181
72
|
}
|
|
182
|
-
function
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
const v = unit.toLowerCase();
|
|
189
|
-
if (["km", "kilometer", "kilometers"].includes(v)) return "Kilometers";
|
|
190
|
-
if (["mi", "mile", "miles"].includes(v)) return "Miles";
|
|
191
|
-
return unit;
|
|
192
|
-
}
|
|
193
|
-
function componentToGlName(name) {
|
|
194
|
-
return COMPONENT_TO_GL[name] ?? name;
|
|
195
|
-
}
|
|
196
|
-
function componentToContext(name) {
|
|
197
|
-
return COMPONENT_TO_CONTEXT[name] ?? name.toLowerCase();
|
|
198
|
-
}
|
|
199
|
-
function mapViewPreset(value) {
|
|
200
|
-
if (value === void 0 || value === null) return "2";
|
|
201
|
-
const v = String(value).toLowerCase().replace(/[\s_-]+/g, "");
|
|
202
|
-
return VIEW_PRESET_MAP[v] ?? String(value);
|
|
203
|
-
}
|
|
204
|
-
function mapRowHeight(value) {
|
|
205
|
-
if (value === void 0 || value === null) return 38;
|
|
206
|
-
const v = String(value).toLowerCase().replace(/[\s_-]+/g, "");
|
|
207
|
-
if (ROW_HEIGHT_MAP[v] !== void 0) return ROW_HEIGHT_MAP[v];
|
|
208
|
-
const parsed = parseInt(String(value), 10);
|
|
209
|
-
return isNaN(parsed) ? 38 : parsed;
|
|
210
|
-
}
|
|
211
|
-
function workspaceNodeToGL(node) {
|
|
212
|
-
const gl = { type: node.type };
|
|
213
|
-
if ("width" in node && node.width !== void 0) {
|
|
214
|
-
gl.width = node.width;
|
|
215
|
-
}
|
|
216
|
-
if ("height" in node && node.height !== void 0) {
|
|
217
|
-
gl.height = node.height;
|
|
218
|
-
}
|
|
219
|
-
if (node.type === "row" || node.type === "column" || node.type === "stack") {
|
|
220
|
-
gl.isClosable = true;
|
|
221
|
-
gl.reorderEnabled = true;
|
|
222
|
-
gl.title = "";
|
|
223
|
-
if ("content" in node && node.content) {
|
|
224
|
-
gl.content = node.content.map(workspaceNodeToGL);
|
|
73
|
+
function validateUsers(users, prefix = "") {
|
|
74
|
+
const issues = [];
|
|
75
|
+
const p = prefix ? `${prefix} ` : "";
|
|
76
|
+
users.forEach((user, index) => {
|
|
77
|
+
if (!user.name?.trim()) {
|
|
78
|
+
issues.push({ type: "error", message: `${p}User ${index + 1}: Name is required` });
|
|
225
79
|
}
|
|
226
|
-
if (
|
|
227
|
-
|
|
80
|
+
if (!user.email?.trim()) {
|
|
81
|
+
issues.push({ type: "error", message: `${p}User ${index + 1}: Email is required` });
|
|
228
82
|
}
|
|
229
|
-
|
|
83
|
+
});
|
|
84
|
+
return issues;
|
|
85
|
+
}
|
|
86
|
+
function validateProfile(doc) {
|
|
87
|
+
const issues = [];
|
|
88
|
+
if (!doc || typeof doc !== "object") {
|
|
89
|
+
issues.push({ type: "error", message: "Invalid document: expected an object" });
|
|
90
|
+
return { valid: false, errors: issues, warnings: [] };
|
|
230
91
|
}
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
92
|
+
const obj = doc;
|
|
93
|
+
const docType = obj.type;
|
|
94
|
+
switch (docType) {
|
|
95
|
+
case "profile": {
|
|
96
|
+
if (!obj.payload || typeof obj.payload !== "object") {
|
|
97
|
+
issues.push({ type: "error", message: 'Profile document must have a "payload" property' });
|
|
98
|
+
} else {
|
|
99
|
+
issues.push(...validateProfileSettings(obj.payload));
|
|
100
|
+
}
|
|
101
|
+
break;
|
|
235
102
|
}
|
|
236
|
-
|
|
237
|
-
|
|
103
|
+
case "users": {
|
|
104
|
+
if (!Array.isArray(obj.payload)) {
|
|
105
|
+
issues.push({ type: "error", message: 'Users document must have a "payload" array' });
|
|
106
|
+
} else {
|
|
107
|
+
issues.push(...validateUsers(obj.payload));
|
|
108
|
+
}
|
|
109
|
+
break;
|
|
238
110
|
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
gl.id = compId;
|
|
245
|
-
compState.id = compId;
|
|
246
|
-
} else if (compName === "schedulerComponent") {
|
|
247
|
-
gl.id = "schedulerContainer";
|
|
248
|
-
compState.id = "scheduler";
|
|
111
|
+
case "layouts": {
|
|
112
|
+
if (!Array.isArray(obj.payload)) {
|
|
113
|
+
issues.push({ type: "error", message: 'Layouts document must have a "payload" array' });
|
|
114
|
+
}
|
|
115
|
+
break;
|
|
249
116
|
}
|
|
250
|
-
|
|
251
|
-
|
|
117
|
+
case "bundle": {
|
|
118
|
+
if (!obj.name?.toString().trim()) {
|
|
119
|
+
issues.push({ type: "error", message: "Bundle name is required" });
|
|
120
|
+
}
|
|
121
|
+
if (!Array.isArray(obj.documents)) {
|
|
122
|
+
issues.push({ type: "error", message: 'Bundle must have a "documents" array' });
|
|
123
|
+
} else {
|
|
124
|
+
const documents = obj.documents;
|
|
125
|
+
let profileCount = 0;
|
|
126
|
+
documents.forEach((item, index) => {
|
|
127
|
+
if ("$ref" in item) {
|
|
128
|
+
if (typeof item.$ref !== "string") {
|
|
129
|
+
issues.push({ type: "error", message: `Document ${index + 1}: $ref must be a string` });
|
|
130
|
+
}
|
|
131
|
+
} else if (item.type === "profile") {
|
|
132
|
+
profileCount++;
|
|
133
|
+
if (item.payload && typeof item.payload === "object") {
|
|
134
|
+
const profileName = item.payload.name || `Profile ${profileCount}`;
|
|
135
|
+
issues.push(...validateProfileSettings(item.payload, profileName));
|
|
136
|
+
} else {
|
|
137
|
+
issues.push({ type: "error", message: `Document ${index + 1}: Profile must have a "payload" property` });
|
|
138
|
+
}
|
|
139
|
+
} else if (item.type === "users") {
|
|
140
|
+
if (Array.isArray(item.payload)) {
|
|
141
|
+
issues.push(...validateUsers(item.payload));
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
if (profileCount === 0) {
|
|
146
|
+
issues.push({ type: "warning", message: "Bundle contains no profile documents" });
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
break;
|
|
252
150
|
}
|
|
253
|
-
|
|
254
|
-
|
|
151
|
+
default: {
|
|
152
|
+
issues.push(...validateProfileSettings({
|
|
153
|
+
name: obj.name,
|
|
154
|
+
code: obj.code,
|
|
155
|
+
workspace: obj.workspace
|
|
156
|
+
}));
|
|
157
|
+
if (Array.isArray(obj.users)) {
|
|
158
|
+
issues.push(...validateUsers(obj.users));
|
|
159
|
+
}
|
|
255
160
|
}
|
|
256
|
-
return gl;
|
|
257
161
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
function workspaceToGoldenLayout(workspace) {
|
|
162
|
+
const errors = issues.filter((i) => i.type === "error");
|
|
163
|
+
const warnings = issues.filter((i) => i.type === "warning");
|
|
261
164
|
return {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
reorderEnabled: true,
|
|
266
|
-
selectionEnabled: true,
|
|
267
|
-
popoutWholeStack: false,
|
|
268
|
-
blockedPopoutsThrowError: true,
|
|
269
|
-
closePopoutsOnUnload: true,
|
|
270
|
-
showPopoutIcon: false,
|
|
271
|
-
showMaximiseIcon: true,
|
|
272
|
-
showCloseIcon: true,
|
|
273
|
-
responsiveMode: "onload",
|
|
274
|
-
tabOverlapAllowance: 0,
|
|
275
|
-
reorderOnTabMenuClick: true,
|
|
276
|
-
tabControlOffset: 10
|
|
277
|
-
},
|
|
278
|
-
dimensions: {
|
|
279
|
-
borderWidth: 5,
|
|
280
|
-
borderGrabWidth: 15,
|
|
281
|
-
minItemHeight: 10,
|
|
282
|
-
minItemWidth: 10,
|
|
283
|
-
headerHeight: 20,
|
|
284
|
-
dragProxyWidth: 300,
|
|
285
|
-
dragProxyHeight: 200
|
|
286
|
-
},
|
|
287
|
-
labels: {
|
|
288
|
-
close: "Close",
|
|
289
|
-
maximise: "Maximize",
|
|
290
|
-
minimise: "Minimize",
|
|
291
|
-
popout: "open in new window",
|
|
292
|
-
popin: "pop in",
|
|
293
|
-
tabDropdown: "Additional Tabs"
|
|
294
|
-
},
|
|
295
|
-
content: [
|
|
296
|
-
{
|
|
297
|
-
type: "row",
|
|
298
|
-
isClosable: true,
|
|
299
|
-
reorderEnabled: true,
|
|
300
|
-
title: "",
|
|
301
|
-
content: workspace.map(workspaceNodeToGL)
|
|
302
|
-
}
|
|
303
|
-
],
|
|
304
|
-
isClosable: true,
|
|
305
|
-
reorderEnabled: true,
|
|
306
|
-
title: "",
|
|
307
|
-
openPopouts: [],
|
|
308
|
-
maximisedItemId: null
|
|
165
|
+
valid: errors.length === 0,
|
|
166
|
+
errors,
|
|
167
|
+
warnings
|
|
309
168
|
};
|
|
310
169
|
}
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
id: layout.grouper.id || layout.grouper.property
|
|
321
|
-
};
|
|
322
|
-
}
|
|
323
|
-
const filters = (layout.filters || []).map((f) => ({
|
|
324
|
-
operator: f.operator || "like",
|
|
325
|
-
value: f.value || "",
|
|
326
|
-
property: f.property,
|
|
327
|
-
exactMatch: f.exactMatch ?? false
|
|
328
|
-
}));
|
|
329
|
-
const lockedGridWidth = layout.lockedGridWidth || layout.resourcesGridWidth || null;
|
|
330
|
-
const fitToScreen = typeof layout.fitToScreen === "boolean" ? layout.fitToScreen : layout.fitToScreen === "true";
|
|
331
|
-
const ignoreCalendars = typeof layout.ignoreCalendars === "boolean" ? layout.ignoreCalendars : layout.ignoreCalendars === "true";
|
|
332
|
-
const pageSize = layout.pageSize !== void 0 ? typeof layout.pageSize === "number" ? layout.pageSize : parseInt(String(layout.pageSize), 10) : 50;
|
|
333
|
-
const state = {
|
|
334
|
-
columns,
|
|
335
|
-
storeState: grouper ? { grouper } : {},
|
|
336
|
-
filters,
|
|
337
|
-
viewPreset: layout.viewPreset !== void 0 ? mapViewPreset(layout.viewPreset) : null,
|
|
338
|
-
Id: layout.id || gridName,
|
|
339
|
-
lockedGridWidth,
|
|
340
|
-
pageSize: isNaN(pageSize) ? 50 : pageSize,
|
|
341
|
-
fitToScreen,
|
|
342
|
-
rowHeight: mapRowHeight(layout.rowHeight),
|
|
343
|
-
ignoreCalendars
|
|
170
|
+
|
|
171
|
+
// src/core/compile/index.ts
|
|
172
|
+
function compileToApiPayload(doc) {
|
|
173
|
+
const result = {
|
|
174
|
+
profiles: [],
|
|
175
|
+
layouts: [],
|
|
176
|
+
profileLayouts: [],
|
|
177
|
+
users: [],
|
|
178
|
+
configuration: []
|
|
344
179
|
};
|
|
345
|
-
if (
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
function collectLayouts(nodes) {
|
|
373
|
-
const acc = [];
|
|
374
|
-
for (const node of nodes) {
|
|
375
|
-
if (node.type === "row" || node.type === "column" || node.type === "stack") {
|
|
376
|
-
if ("content" in node && node.content) {
|
|
377
|
-
acc.push(...collectLayouts(node.content));
|
|
180
|
+
if (isProfileDocument(doc)) {
|
|
181
|
+
const compiled = compileProfileDocument(doc);
|
|
182
|
+
result.profiles = compiled.payload.profiles;
|
|
183
|
+
result.layouts = compiled.payload.layouts;
|
|
184
|
+
result.profileLayouts = compiled.payload.profileLayouts;
|
|
185
|
+
result.owner = compiled.payload.owner;
|
|
186
|
+
result.notificationEmail = compiled.payload.notificationEmail;
|
|
187
|
+
} else if (isUsersDocument(doc)) {
|
|
188
|
+
const compiled = compileUsersDocument(doc);
|
|
189
|
+
result.users = compiled.payload.users;
|
|
190
|
+
result.owner = compiled.payload.owner;
|
|
191
|
+
result.notificationEmail = compiled.payload.notificationEmail;
|
|
192
|
+
} else if (isLayoutsDocument(doc)) {
|
|
193
|
+
const compiled = compileLayoutsDocument(doc);
|
|
194
|
+
result.layouts = compiled.payload.layouts;
|
|
195
|
+
result.owner = compiled.payload.owner;
|
|
196
|
+
result.notificationEmail = compiled.payload.notificationEmail;
|
|
197
|
+
} else if (isConfigurationDocument(doc)) {
|
|
198
|
+
const compiled = compileConfigurationDocument(doc);
|
|
199
|
+
result.configuration = compiled.payload.configuration;
|
|
200
|
+
result.owner = compiled.payload.owner;
|
|
201
|
+
result.notificationEmail = compiled.payload.notificationEmail;
|
|
202
|
+
} else if (isBundleDocument(doc)) {
|
|
203
|
+
const bundle = doc;
|
|
204
|
+
for (const item of bundle.documents) {
|
|
205
|
+
if (isDocumentReference(item)) {
|
|
206
|
+
throw new Error("Bundle contains $ref items. Use compileToApiPayloadAsync instead.");
|
|
378
207
|
}
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
layoutCode = gridName.toUpperCase().replace(/-/g, "_");
|
|
394
|
-
}
|
|
395
|
-
acc.push({
|
|
396
|
-
context,
|
|
397
|
-
grid: gridName,
|
|
398
|
-
value: buildLayoutState(layoutItem, gridName),
|
|
399
|
-
name: layoutName,
|
|
400
|
-
code: layoutCode || gridName.toUpperCase(),
|
|
401
|
-
componentId: gridName,
|
|
402
|
-
default: layoutItem.default ?? false,
|
|
403
|
-
public: layoutItem.shared?.public ?? false,
|
|
404
|
-
userGroup: layoutItem.shared?.userGroup
|
|
405
|
-
});
|
|
208
|
+
if (isProfileDocument(item)) {
|
|
209
|
+
const compiled = compileProfileDocument(item);
|
|
210
|
+
result.profiles.push(...compiled.payload.profiles);
|
|
211
|
+
result.layouts.push(...compiled.payload.layouts);
|
|
212
|
+
result.profileLayouts.push(...compiled.payload.profileLayouts);
|
|
213
|
+
} else if (isUsersDocument(item)) {
|
|
214
|
+
const compiled = compileUsersDocument(item);
|
|
215
|
+
result.users.push(...compiled.payload.users);
|
|
216
|
+
} else if (isLayoutsDocument(item)) {
|
|
217
|
+
const compiled = compileLayoutsDocument(item);
|
|
218
|
+
result.layouts.push(...compiled.payload.layouts);
|
|
219
|
+
} else if (isConfigurationDocument(item)) {
|
|
220
|
+
const compiled = compileConfigurationDocument(item);
|
|
221
|
+
result.configuration.push(...compiled.payload.configuration);
|
|
406
222
|
}
|
|
407
223
|
}
|
|
224
|
+
result.owner = bundle.owner;
|
|
225
|
+
result.notificationEmail = bundle.notificationEmail;
|
|
226
|
+
} else {
|
|
227
|
+
throw new Error("Unknown document type. Expected profile, users, layouts, configuration, or bundle at root.");
|
|
408
228
|
}
|
|
409
|
-
return
|
|
410
|
-
}
|
|
411
|
-
function buildLayoutDtos(workspace) {
|
|
412
|
-
const layouts = collectLayouts(workspace);
|
|
413
|
-
return layouts.map((L) => ({
|
|
414
|
-
context: L.context,
|
|
415
|
-
grid: L.grid,
|
|
416
|
-
value: JSON.stringify(L.value),
|
|
417
|
-
default: L.default,
|
|
418
|
-
public: L.public,
|
|
419
|
-
userGroup: L.userGroup,
|
|
420
|
-
isOwner: true,
|
|
421
|
-
isNew: true,
|
|
422
|
-
name: L.name,
|
|
423
|
-
code: L.code
|
|
424
|
-
}));
|
|
425
|
-
}
|
|
426
|
-
function buildProfileLayoutDtos(workspace, profileCode) {
|
|
427
|
-
const layouts = collectLayouts(workspace);
|
|
428
|
-
return layouts.filter((L) => L.default && L.code).map((L) => ({
|
|
429
|
-
profileCode,
|
|
430
|
-
layoutCode: L.code,
|
|
431
|
-
default: true,
|
|
432
|
-
public: false,
|
|
433
|
-
name: L.componentId
|
|
434
|
-
}));
|
|
435
|
-
}
|
|
436
|
-
function compileProfile(profile) {
|
|
437
|
-
const theme = profile.theme || { color: "default", scheme: "sdtd" };
|
|
438
|
-
const shared = profile.shared || { global: false, userGroup: "" };
|
|
439
|
-
const route = profile.route || {
|
|
440
|
-
profile: "default",
|
|
441
|
-
calculateRoutes: true,
|
|
442
|
-
showSequenceIndicators: true,
|
|
443
|
-
unitOfDistance: "km"
|
|
444
|
-
};
|
|
445
|
-
const planning = profile.planning || {
|
|
446
|
-
snapInterval: { mode: "1hour", value: 0 },
|
|
447
|
-
range: { mode: "week", value: 0 },
|
|
448
|
-
start: { mode: "startOfWeek", value: 2 },
|
|
449
|
-
hours: { start: 8, end: 18 }
|
|
450
|
-
};
|
|
451
|
-
const workspace = profile.workspace || [];
|
|
452
|
-
const goldenLayout = workspaceToGoldenLayout(workspace);
|
|
453
|
-
const layouts = buildLayoutDtos(workspace);
|
|
454
|
-
const profileLayouts = buildProfileLayoutDtos(workspace, profile.code || "");
|
|
455
|
-
return {
|
|
456
|
-
profile: {
|
|
457
|
-
name: profile.name || "",
|
|
458
|
-
code: profile.code || "",
|
|
459
|
-
color: theme.color || "default",
|
|
460
|
-
theme: theme.scheme || "sdtd",
|
|
461
|
-
public: shared.global ?? false,
|
|
462
|
-
userGroup: shared.userGroup || "",
|
|
463
|
-
snapMode: mapSnapMode(planning.snapInterval?.mode),
|
|
464
|
-
snapValue: planning.snapInterval?.value ?? null,
|
|
465
|
-
rangeMode: mapRangeMode(planning.range?.mode),
|
|
466
|
-
rangeValue: planning.range?.value ?? null,
|
|
467
|
-
startMode: mapStartMode(planning.start?.mode),
|
|
468
|
-
startValue: planning.start?.value ?? null,
|
|
469
|
-
startTime: planning.hours?.start ?? 8,
|
|
470
|
-
endTime: planning.hours?.end ?? 18,
|
|
471
|
-
unitOfDistance: mapUnitOfDistance(route.unitOfDistance),
|
|
472
|
-
autoRouteCalculation: route.calculateRoutes ?? true,
|
|
473
|
-
showSequenceIndicators: route.showSequenceIndicators ?? true,
|
|
474
|
-
routeProfile: route.profile || "default",
|
|
475
|
-
layout: JSON.stringify(goldenLayout)
|
|
476
|
-
},
|
|
477
|
-
layouts,
|
|
478
|
-
profileLayouts,
|
|
479
|
-
users: profile.users || [],
|
|
480
|
-
owner: profile.owner,
|
|
481
|
-
notificationEmail: profile.notificationEmail
|
|
482
|
-
};
|
|
229
|
+
return result;
|
|
483
230
|
}
|
|
484
231
|
|
|
485
232
|
// src/commands/validate.ts
|
|
@@ -487,9 +234,9 @@ var validateCommand = new Command("validate").description("Validate a configurat
|
|
|
487
234
|
try {
|
|
488
235
|
const filePath = resolve(normalize(file));
|
|
489
236
|
const content = readFileSync(filePath, "utf-8");
|
|
490
|
-
let
|
|
237
|
+
let doc;
|
|
491
238
|
try {
|
|
492
|
-
|
|
239
|
+
doc = JSON5.parse(content);
|
|
493
240
|
} catch {
|
|
494
241
|
if (options.json) {
|
|
495
242
|
console.log(JSON.stringify({ valid: false, errors: [{ type: "error", message: "Invalid JSON5 syntax" }], warnings: [] }));
|
|
@@ -498,7 +245,7 @@ var validateCommand = new Command("validate").description("Validate a configurat
|
|
|
498
245
|
}
|
|
499
246
|
process.exit(1);
|
|
500
247
|
}
|
|
501
|
-
const result = validateProfile(
|
|
248
|
+
const result = validateProfile(doc);
|
|
502
249
|
if (options.json) {
|
|
503
250
|
console.log(JSON.stringify(result, null, 2));
|
|
504
251
|
} else {
|
|
@@ -543,15 +290,20 @@ var compileCommand = new Command2("compile").description("Compile a JSON5 config
|
|
|
543
290
|
try {
|
|
544
291
|
const filePath = resolve2(normalize2(file));
|
|
545
292
|
const content = readFileSync2(filePath, "utf-8");
|
|
546
|
-
let
|
|
293
|
+
let doc;
|
|
547
294
|
try {
|
|
548
|
-
|
|
295
|
+
doc = JSON52.parse(content);
|
|
549
296
|
} catch {
|
|
550
297
|
console.error(pc2.red("Error:"), "Invalid JSON5 syntax in", file);
|
|
551
298
|
process.exit(1);
|
|
552
299
|
}
|
|
300
|
+
const docType = detectDocumentType(doc);
|
|
301
|
+
if (!docType) {
|
|
302
|
+
console.error(pc2.red("Error:"), "Unknown document type. Expected profile, users, layouts, or bundle at root.");
|
|
303
|
+
process.exit(1);
|
|
304
|
+
}
|
|
553
305
|
if (!options.skipValidation) {
|
|
554
|
-
const validation = validateProfile(
|
|
306
|
+
const validation = validateProfile(doc);
|
|
555
307
|
if (!validation.valid) {
|
|
556
308
|
console.error(pc2.red("Error:"), "Configuration has validation errors:");
|
|
557
309
|
for (const error of validation.errors) {
|
|
@@ -562,8 +314,8 @@ var compileCommand = new Command2("compile").description("Compile a JSON5 config
|
|
|
562
314
|
process.exit(1);
|
|
563
315
|
}
|
|
564
316
|
}
|
|
565
|
-
const
|
|
566
|
-
const jsonOutput = JSON.stringify(
|
|
317
|
+
const result = compileToApiPayload(doc);
|
|
318
|
+
const jsonOutput = JSON.stringify(result, null, 2);
|
|
567
319
|
if (options.stdout) {
|
|
568
320
|
console.log(jsonOutput);
|
|
569
321
|
} else {
|
|
@@ -572,7 +324,7 @@ var compileCommand = new Command2("compile").description("Compile a JSON5 config
|
|
|
572
324
|
const outputPath = resolve2(outputDir, `${inputBasename}.json`);
|
|
573
325
|
mkdirSync(outputDir, { recursive: true });
|
|
574
326
|
writeFileSync(outputPath, jsonOutput, "utf-8");
|
|
575
|
-
console.log(pc2.green("\u2713"),
|
|
327
|
+
console.log(pc2.green("\u2713"), `Compiled ${docType} document to`, outputPath);
|
|
576
328
|
}
|
|
577
329
|
process.exit(0);
|
|
578
330
|
} catch (err) {
|
|
@@ -605,7 +357,7 @@ async function confirm(message) {
|
|
|
605
357
|
});
|
|
606
358
|
});
|
|
607
359
|
}
|
|
608
|
-
async function deployToApi(
|
|
360
|
+
async function deployToApi(result, docType, url, apiKey) {
|
|
609
361
|
try {
|
|
610
362
|
const response = await fetch(`${url}/import/setup`, {
|
|
611
363
|
method: "POST",
|
|
@@ -613,10 +365,10 @@ async function deployToApi(payload, url, apiKey) {
|
|
|
613
365
|
"Content-Type": "application/json",
|
|
614
366
|
"X-API-KEY": apiKey
|
|
615
367
|
},
|
|
616
|
-
body: JSON.stringify(
|
|
368
|
+
body: JSON.stringify(result)
|
|
617
369
|
});
|
|
618
370
|
if (response.ok) {
|
|
619
|
-
return { success: true, message:
|
|
371
|
+
return { success: true, message: `${docType} document deployed successfully` };
|
|
620
372
|
} else {
|
|
621
373
|
const text = await response.text();
|
|
622
374
|
return { success: false, message: `HTTP ${response.status}`, error: text };
|
|
@@ -648,9 +400,9 @@ var deployCommand = new Command3("deploy").description("Deploy a configuration t
|
|
|
648
400
|
process.exit(1);
|
|
649
401
|
}
|
|
650
402
|
const apiUrl = ENVIRONMENT_URLS[options.env];
|
|
651
|
-
let
|
|
403
|
+
let doc;
|
|
652
404
|
try {
|
|
653
|
-
|
|
405
|
+
doc = JSON53.parse(content);
|
|
654
406
|
} catch {
|
|
655
407
|
if (options.json) {
|
|
656
408
|
console.log(JSON.stringify({ success: false, error: "Invalid JSON5 syntax" }));
|
|
@@ -659,8 +411,17 @@ var deployCommand = new Command3("deploy").description("Deploy a configuration t
|
|
|
659
411
|
}
|
|
660
412
|
process.exit(1);
|
|
661
413
|
}
|
|
662
|
-
|
|
663
|
-
|
|
414
|
+
const docType = detectDocumentType(doc);
|
|
415
|
+
if (!docType) {
|
|
416
|
+
if (options.json) {
|
|
417
|
+
console.log(JSON.stringify({ success: false, error: "Unknown document type. Expected profile, users, or layouts at root." }));
|
|
418
|
+
} else {
|
|
419
|
+
console.error(pc3.red("Error:"), "Unknown document type. Expected profile, users, or layouts at root.");
|
|
420
|
+
}
|
|
421
|
+
process.exit(1);
|
|
422
|
+
}
|
|
423
|
+
if (!options.skipValidation && isProfileDocument(doc)) {
|
|
424
|
+
const validation = validateProfile(doc);
|
|
664
425
|
if (!validation.valid) {
|
|
665
426
|
if (options.json) {
|
|
666
427
|
console.log(JSON.stringify({ success: false, error: "Validation failed", details: validation.errors }));
|
|
@@ -673,12 +434,12 @@ var deployCommand = new Command3("deploy").description("Deploy a configuration t
|
|
|
673
434
|
process.exit(1);
|
|
674
435
|
}
|
|
675
436
|
}
|
|
676
|
-
const
|
|
437
|
+
const result = compileToApiPayload(doc);
|
|
677
438
|
if (options.dryRun) {
|
|
678
439
|
if (options.json) {
|
|
679
|
-
console.log(JSON.stringify({ success: true, message: "Dry run successful",
|
|
440
|
+
console.log(JSON.stringify({ success: true, message: "Dry run successful", result }));
|
|
680
441
|
} else {
|
|
681
|
-
console.log(pc3.green("\u2713"),
|
|
442
|
+
console.log(pc3.green("\u2713"), `Dry run successful - ${docType} document is valid and compiled`);
|
|
682
443
|
console.log(pc3.dim(" Would deploy to:"), apiUrl);
|
|
683
444
|
}
|
|
684
445
|
process.exit(0);
|
|
@@ -686,7 +447,10 @@ var deployCommand = new Command3("deploy").description("Deploy a configuration t
|
|
|
686
447
|
if (!options.yes && !options.json) {
|
|
687
448
|
console.log();
|
|
688
449
|
console.log(pc3.bold("Deploy Summary:"));
|
|
689
|
-
console.log(`
|
|
450
|
+
console.log(` Document type: ${pc3.cyan(docType)}`);
|
|
451
|
+
if (isProfileDocument(doc)) {
|
|
452
|
+
console.log(` Profile: ${pc3.cyan(doc.payload.name || "unnamed")} (${doc.payload.code || "no code"})`);
|
|
453
|
+
}
|
|
690
454
|
console.log(` Environment: ${pc3.yellow(options.env)}`);
|
|
691
455
|
console.log(` Target: ${pc3.dim(apiUrl)}`);
|
|
692
456
|
console.log();
|
|
@@ -699,20 +463,20 @@ var deployCommand = new Command3("deploy").description("Deploy a configuration t
|
|
|
699
463
|
if (!options.json) {
|
|
700
464
|
console.log(pc3.dim("Deploying..."));
|
|
701
465
|
}
|
|
702
|
-
const
|
|
466
|
+
const deployResult = await deployToApi(result, docType, apiUrl, apiKey);
|
|
703
467
|
if (options.json) {
|
|
704
|
-
console.log(JSON.stringify(
|
|
468
|
+
console.log(JSON.stringify(deployResult));
|
|
705
469
|
} else {
|
|
706
|
-
if (
|
|
707
|
-
console.log(pc3.green("\u2713"),
|
|
470
|
+
if (deployResult.success) {
|
|
471
|
+
console.log(pc3.green("\u2713"), deployResult.message);
|
|
708
472
|
} else {
|
|
709
|
-
console.error(pc3.red("\u2717"),
|
|
710
|
-
if (
|
|
711
|
-
console.error(pc3.dim(" "),
|
|
473
|
+
console.error(pc3.red("\u2717"), deployResult.message);
|
|
474
|
+
if (deployResult.error) {
|
|
475
|
+
console.error(pc3.dim(" "), deployResult.error);
|
|
712
476
|
}
|
|
713
477
|
}
|
|
714
478
|
}
|
|
715
|
-
process.exit(
|
|
479
|
+
process.exit(deployResult.success ? 0 : 2);
|
|
716
480
|
} catch (err) {
|
|
717
481
|
if (options.json) {
|
|
718
482
|
console.log(JSON.stringify({ success: false, error: String(err) }));
|
|
@@ -725,8 +489,12 @@ var deployCommand = new Command3("deploy").description("Deploy a configuration t
|
|
|
725
489
|
|
|
726
490
|
// src/index.ts
|
|
727
491
|
var program = new Command4();
|
|
728
|
-
program.name("dimescheduler-setup").description("CLI tool to validate, compile, and deploy Dime.Scheduler configurations").version("0.1.
|
|
492
|
+
program.name("dimescheduler-setup").description("CLI tool to validate, compile, and deploy Dime.Scheduler configurations").version("0.1.3");
|
|
729
493
|
program.addCommand(validateCommand);
|
|
730
494
|
program.addCommand(compileCommand);
|
|
731
495
|
program.addCommand(deployCommand);
|
|
496
|
+
if (process.argv.length <= 2) {
|
|
497
|
+
program.outputHelp();
|
|
498
|
+
process.exit(0);
|
|
499
|
+
}
|
|
732
500
|
program.parse();
|