@masterteam/task-schedule 0.0.1 → 0.0.3
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 +119 -101
- package/fesm2022/masterteam-task-schedule.mjs +621 -147
- package/fesm2022/masterteam-task-schedule.mjs.map +1 -1
- package/package.json +4 -4
- package/types/masterteam-task-schedule.d.ts +45 -32
|
@@ -74,6 +74,30 @@ function normalizeTaskScheduleModelType(modelType) {
|
|
|
74
74
|
|
|
75
75
|
const TASK_SCHEDULE_DATA_ADAPTER = new InjectionToken('TASK_SCHEDULE_DATA_ADAPTER');
|
|
76
76
|
const DEFAULT_CUSTOM_PROPERTIES = [];
|
|
77
|
+
const SCHEDULE_NATIVE_KEYS = new Set([
|
|
78
|
+
'name',
|
|
79
|
+
'status',
|
|
80
|
+
'plannedStart',
|
|
81
|
+
'plannedFinish',
|
|
82
|
+
'actualStart',
|
|
83
|
+
'actualFinish',
|
|
84
|
+
'baselineStart',
|
|
85
|
+
'baselineFinish',
|
|
86
|
+
'duration',
|
|
87
|
+
'progress',
|
|
88
|
+
'predecessor',
|
|
89
|
+
'predecessors',
|
|
90
|
+
'assignedTo',
|
|
91
|
+
'resources',
|
|
92
|
+
'order',
|
|
93
|
+
'parentId',
|
|
94
|
+
'phaseGate',
|
|
95
|
+
'criticalPath',
|
|
96
|
+
'type',
|
|
97
|
+
'details',
|
|
98
|
+
'id',
|
|
99
|
+
'levelDataId',
|
|
100
|
+
]);
|
|
77
101
|
class TaskScheduleBackendAdapter {
|
|
78
102
|
http = inject(HttpClient, { optional: true });
|
|
79
103
|
load(modelType, context) {
|
|
@@ -81,21 +105,11 @@ class TaskScheduleBackendAdapter {
|
|
|
81
105
|
return this.backendError('TaskScheduleBackendAdapter requires HttpClient. Configure provideHttpClient() in the host app.');
|
|
82
106
|
}
|
|
83
107
|
const normalizedModel = normalizeTaskScheduleModelType(modelType);
|
|
84
|
-
const treeRouteTemplate = this.resolveTreeRouteTemplate(context, normalizedModel);
|
|
85
108
|
const levelId = this.readId(context.levelId);
|
|
86
109
|
if (!levelId) {
|
|
87
110
|
return this.backendError('TaskSchedule context requires levelId for backend calls.');
|
|
88
111
|
}
|
|
89
|
-
|
|
90
|
-
if (!treeRouteParams) {
|
|
91
|
-
return this.backendError('TaskSchedule context is missing required identifiers for the selected schedule endpoint.');
|
|
92
|
-
}
|
|
93
|
-
const treeUrl = this.resolveApiUrl(context, treeRouteTemplate, treeRouteParams);
|
|
94
|
-
return this.http
|
|
95
|
-
.get(treeUrl, {
|
|
96
|
-
headers: this.readHeaders(context),
|
|
97
|
-
})
|
|
98
|
-
.pipe(map((response) => this.unwrapResponse(response, 'Failed to load schedule tree.')), map((payload) => ({
|
|
112
|
+
return this.resolveReadPayload(context, normalizedModel).pipe(map((payload) => ({
|
|
99
113
|
payload,
|
|
100
114
|
rows: this.extractTaskArray(payload),
|
|
101
115
|
})), map(({ payload, rows }) => ({
|
|
@@ -153,16 +167,231 @@ class TaskScheduleBackendAdapter {
|
|
|
153
167
|
}));
|
|
154
168
|
}));
|
|
155
169
|
}
|
|
170
|
+
resolveReadPayload(context, modelType) {
|
|
171
|
+
if (modelType === 'phaseGate') {
|
|
172
|
+
return this.loadLegacyPhaseGatePayload(context);
|
|
173
|
+
}
|
|
174
|
+
if (modelType === 'resources') {
|
|
175
|
+
return this.loadScheduleUtilityPayload(context, 'levels/{levelId}/{levelDataId}/schedule/by-resource', 'Failed to load schedule resources.');
|
|
176
|
+
}
|
|
177
|
+
if (modelType === 'unscheduled') {
|
|
178
|
+
return this.loadScheduleUtilityPayload(context, 'levels/{levelId}/{levelDataId}/schedule/unscheduled', 'Failed to load unscheduled schedule items.');
|
|
179
|
+
}
|
|
180
|
+
if (modelType === 'baseline') {
|
|
181
|
+
return this.loadScheduleUtilityPayload(context, 'levels/{levelId}/{levelDataId}/schedule/baselines/latest', 'Failed to load schedule baseline.');
|
|
182
|
+
}
|
|
183
|
+
return this.loadScheduleQueryPayload(context);
|
|
184
|
+
}
|
|
185
|
+
loadScheduleQueryPayload(context) {
|
|
186
|
+
if (!this.http) {
|
|
187
|
+
return this.backendError('Task schedule query loading requires HttpClient.');
|
|
188
|
+
}
|
|
189
|
+
const levelId = this.readId(context.levelId);
|
|
190
|
+
const levelDataId = this.readId(context.levelDataId);
|
|
191
|
+
if (!levelId || !levelDataId) {
|
|
192
|
+
return this.backendError('TaskSchedule context requires levelId and levelDataId for schedule reads.');
|
|
193
|
+
}
|
|
194
|
+
const endpoint = this.resolveApiUrl(context, 'levels/{levelId}/{levelDataId}/schedule/query', {
|
|
195
|
+
levelId,
|
|
196
|
+
levelDataId,
|
|
197
|
+
});
|
|
198
|
+
return this.http
|
|
199
|
+
.post(endpoint, {
|
|
200
|
+
projection: 'Tree',
|
|
201
|
+
}, {
|
|
202
|
+
headers: this.readHeaders(context),
|
|
203
|
+
})
|
|
204
|
+
.pipe(map((response) => this.unwrapResponse(response, 'Failed to load schedule records.')), map((data) => this.composeFetchPayload(data)));
|
|
205
|
+
}
|
|
206
|
+
loadScheduleUtilityPayload(context, template, fallbackMessage) {
|
|
207
|
+
if (!this.http) {
|
|
208
|
+
return this.backendError(fallbackMessage);
|
|
209
|
+
}
|
|
210
|
+
const levelId = this.readId(context.levelId);
|
|
211
|
+
const levelDataId = this.readId(context.levelDataId);
|
|
212
|
+
if (!levelId || !levelDataId) {
|
|
213
|
+
return this.backendError('TaskSchedule context requires levelId and levelDataId for schedule utility reads.');
|
|
214
|
+
}
|
|
215
|
+
const url = this.resolveApiUrl(context, template, {
|
|
216
|
+
levelId,
|
|
217
|
+
levelDataId,
|
|
218
|
+
});
|
|
219
|
+
return this.http
|
|
220
|
+
.get(url, {
|
|
221
|
+
headers: this.readHeaders(context),
|
|
222
|
+
})
|
|
223
|
+
.pipe(map((response) => this.unwrapResponse(response, fallbackMessage)));
|
|
224
|
+
}
|
|
225
|
+
loadLegacyPhaseGatePayload(context) {
|
|
226
|
+
if (!this.http) {
|
|
227
|
+
return this.backendError('Failed to load phase gate schedule tree.');
|
|
228
|
+
}
|
|
229
|
+
const treeRouteTemplate = this.resolveTreeRouteTemplate(context, 'phaseGate');
|
|
230
|
+
const treeRouteParams = this.buildTreeRouteParams(context, treeRouteTemplate);
|
|
231
|
+
if (!treeRouteParams) {
|
|
232
|
+
return this.backendError('TaskSchedule context is missing required identifiers for phase gate mode.');
|
|
233
|
+
}
|
|
234
|
+
const treeUrl = this.resolveApiUrl(context, treeRouteTemplate, treeRouteParams);
|
|
235
|
+
return this.http
|
|
236
|
+
.get(treeUrl, {
|
|
237
|
+
headers: this.readHeaders(context),
|
|
238
|
+
})
|
|
239
|
+
.pipe(map((response) => this.unwrapResponse(response, 'Failed to load phase gate schedule tree.')));
|
|
240
|
+
}
|
|
241
|
+
composeFetchPayload(data) {
|
|
242
|
+
const schemaMap = this.toFetchSchemaMap(data.schemas ?? []);
|
|
243
|
+
const tasks = this.mapFetchRecords(this.resolveFetchRootRecords(data.records ?? [], data.projectionMeta?.rootIds ?? []), schemaMap);
|
|
244
|
+
const customProperties = this.mergeFetchCustomProperties(this.mapFetchCustomProperties(data.catalog?.properties ?? []));
|
|
245
|
+
return {
|
|
246
|
+
tasks,
|
|
247
|
+
customProperties,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
resolveFetchRootRecords(records, rootIds) {
|
|
251
|
+
if (!rootIds.length) {
|
|
252
|
+
return records;
|
|
253
|
+
}
|
|
254
|
+
const byId = new Map(records.map((record) => [String(record.id), record]));
|
|
255
|
+
return rootIds
|
|
256
|
+
.map((id) => byId.get(String(id)))
|
|
257
|
+
.filter((record) => record != null);
|
|
258
|
+
}
|
|
259
|
+
toFetchSchemaMap(schemas) {
|
|
260
|
+
return new Map(schemas
|
|
261
|
+
.filter((schema) => this.readId(schema.id) != null)
|
|
262
|
+
.map((schema) => [String(schema.id), schema]));
|
|
263
|
+
}
|
|
264
|
+
mapFetchRecords(records, schemaMap) {
|
|
265
|
+
return records.map((record, index) => this.mapFetchRecord(record, index + 1, schemaMap));
|
|
266
|
+
}
|
|
267
|
+
mapFetchRecord(record, fallbackOrder, schemaMap) {
|
|
268
|
+
const values = record.values ?? {};
|
|
269
|
+
const schema = this.readId(record.schemaId)
|
|
270
|
+
? schemaMap.get(String(record.schemaId))
|
|
271
|
+
: undefined;
|
|
272
|
+
const type = this.readFetchCellDisplay(values['type']) ??
|
|
273
|
+
this.toNullableString(this.readFetchCellValue(values['type'])) ??
|
|
274
|
+
this.toNullableString(schema?.key) ??
|
|
275
|
+
'Task';
|
|
276
|
+
const subtasks = (record.children ?? []).map((child, index) => this.mapFetchRecord(child, index + 1, schemaMap));
|
|
277
|
+
return {
|
|
278
|
+
id: record.id,
|
|
279
|
+
title: record.name ??
|
|
280
|
+
this.readFetchCellDisplay(values['name']) ??
|
|
281
|
+
`Task ${String(record.id)}`,
|
|
282
|
+
name: record.name ??
|
|
283
|
+
this.readFetchCellDisplay(values['name']) ??
|
|
284
|
+
`Task ${String(record.id)}`,
|
|
285
|
+
startDate: this.readFetchCellValue(values['plannedStart']),
|
|
286
|
+
finishDate: this.readFetchCellValue(values['plannedFinish']),
|
|
287
|
+
baselineStartDate: this.readFetchCellValue(values['baselineStart']),
|
|
288
|
+
baselineEndDate: this.readFetchCellValue(values['baselineFinish']),
|
|
289
|
+
actualStartDate: this.readFetchCellValue(values['actualStart']),
|
|
290
|
+
actualFinishDate: this.readFetchCellValue(values['actualFinish']),
|
|
291
|
+
predecessor: this.readFetchCellDisplay(values['predecessor']) ??
|
|
292
|
+
this.readFetchCellDisplay(values['predecessors']) ??
|
|
293
|
+
this.toNullableString(this.readFetchCellValue(values['predecessor'])) ??
|
|
294
|
+
this.toNullableString(this.readFetchCellValue(values['predecessors'])),
|
|
295
|
+
duration: this.readFetchCellValue(values['duration']),
|
|
296
|
+
progress: this.readFetchCellValue(values['progress']),
|
|
297
|
+
details: this.readFetchCellDisplay(values['details']) ??
|
|
298
|
+
this.toNullableString(this.readFetchCellValue(values['details'])),
|
|
299
|
+
status: this.readFetchCellValue(values['status']),
|
|
300
|
+
type,
|
|
301
|
+
typeLabel: this.toNullableString(schema?.name) ?? type,
|
|
302
|
+
typeLable: this.toNullableString(schema?.name) ?? type,
|
|
303
|
+
assignedTo: this.readFetchCellValue(values['assignedTo']),
|
|
304
|
+
resources: this.readFetchCellValue(values['resources']),
|
|
305
|
+
phaseGate: this.readFetchCellDisplay(values['phaseGate']) ??
|
|
306
|
+
this.toNullableString(this.readFetchCellValue(values['phaseGate'])),
|
|
307
|
+
criticalPath: Boolean(this.readFetchCellValue(values['criticalPath'])),
|
|
308
|
+
order: this.readFetchOrder(values['order']) ?? fallbackOrder,
|
|
309
|
+
props: this.readFetchCustomProps(values),
|
|
310
|
+
subtasks,
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
readFetchCustomProps(values) {
|
|
314
|
+
return Object.entries(values)
|
|
315
|
+
.filter(([key]) => !SCHEDULE_NATIVE_KEYS.has(key))
|
|
316
|
+
.map(([key, cell]) => ({
|
|
317
|
+
id: 0,
|
|
318
|
+
key,
|
|
319
|
+
rawValue: this.readFetchCellRaw(cell),
|
|
320
|
+
value: this.readFetchCellValue(cell),
|
|
321
|
+
}));
|
|
322
|
+
}
|
|
323
|
+
mapFetchCustomProperties(properties) {
|
|
324
|
+
return properties
|
|
325
|
+
.filter((property) => !SCHEDULE_NATIVE_KEYS.has(property.normalizedKey))
|
|
326
|
+
.sort((left, right) => (left.order ?? 0) - (right.order ?? 0))
|
|
327
|
+
.map((property) => ({
|
|
328
|
+
id: property.id,
|
|
329
|
+
key: property.normalizedKey,
|
|
330
|
+
name: property.label,
|
|
331
|
+
viewType: property.viewType,
|
|
332
|
+
normalizedKey: property.normalizedKey,
|
|
333
|
+
isRequired: !!property.isRequired,
|
|
334
|
+
isCalculated: !!property.isCalculated,
|
|
335
|
+
configuration: property.configuration ?? null,
|
|
336
|
+
}));
|
|
337
|
+
}
|
|
338
|
+
mergeFetchCustomProperties(properties) {
|
|
339
|
+
const byKey = new Map();
|
|
340
|
+
properties.forEach((property) => {
|
|
341
|
+
if (!byKey.has(property.key)) {
|
|
342
|
+
byKey.set(property.key, property);
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
return Array.from(byKey.values());
|
|
346
|
+
}
|
|
347
|
+
readFetchCellRaw(cell) {
|
|
348
|
+
if (!cell || typeof cell !== 'object') {
|
|
349
|
+
return cell;
|
|
350
|
+
}
|
|
351
|
+
const row = cell;
|
|
352
|
+
if ('raw' in row || 'value' in row || 'display' in row) {
|
|
353
|
+
return row['raw'] ?? row['value'] ?? row['display'] ?? null;
|
|
354
|
+
}
|
|
355
|
+
return cell;
|
|
356
|
+
}
|
|
357
|
+
readFetchCellValue(cell) {
|
|
358
|
+
if (!cell || typeof cell !== 'object') {
|
|
359
|
+
return cell;
|
|
360
|
+
}
|
|
361
|
+
const row = cell;
|
|
362
|
+
if ('raw' in row || 'value' in row || 'display' in row) {
|
|
363
|
+
return row['value'] ?? row['raw'] ?? row['display'] ?? null;
|
|
364
|
+
}
|
|
365
|
+
return cell;
|
|
366
|
+
}
|
|
367
|
+
readFetchCellDisplay(cell) {
|
|
368
|
+
if (!cell || typeof cell !== 'object') {
|
|
369
|
+
return this.toNullableString(cell);
|
|
370
|
+
}
|
|
371
|
+
const row = cell;
|
|
372
|
+
if ('display' in row || 'value' in row || 'raw' in row) {
|
|
373
|
+
return (this.toNullableString(row['display']) ??
|
|
374
|
+
this.toNullableString(row['value']) ??
|
|
375
|
+
this.toNullableString(row['raw']));
|
|
376
|
+
}
|
|
377
|
+
return this.toNullableString(cell);
|
|
378
|
+
}
|
|
379
|
+
readFetchOrder(cell) {
|
|
380
|
+
return this.toNullableNumber(this.readFetchCellValue(cell));
|
|
381
|
+
}
|
|
156
382
|
createTask(context, payload) {
|
|
157
383
|
if (!this.http) {
|
|
158
384
|
return this.backendError('Task create requires HttpClient.');
|
|
159
385
|
}
|
|
160
|
-
const endpoint = this.resolveTaskMutationEndpoint(context, 'createTask', 'tasks/{levelId}/create', 'tasks/{schemaId}/{levelId}/create');
|
|
386
|
+
const endpoint = this.resolveTaskMutationEndpoint(context, 'createTask', 'levels/{levelId}/{levelDataId}/schedule', 'tasks/{levelId}/create', 'tasks/{schemaId}/{levelId}/create');
|
|
161
387
|
if (!endpoint) {
|
|
162
388
|
return this.backendError('Task create endpoint requires a valid levelId.');
|
|
163
389
|
}
|
|
390
|
+
const requestBody = endpoint.mode === 'runtime'
|
|
391
|
+
? this.mapRuntimeMutationPayload(payload)
|
|
392
|
+
: payload;
|
|
164
393
|
return this.http
|
|
165
|
-
.post(endpoint,
|
|
394
|
+
.post(endpoint.url, requestBody, {
|
|
166
395
|
headers: this.readHeaders(context, 'task-create'),
|
|
167
396
|
})
|
|
168
397
|
.pipe(map((response) => this.unwrapResponse(response, 'Failed to create task.')));
|
|
@@ -171,12 +400,15 @@ class TaskScheduleBackendAdapter {
|
|
|
171
400
|
if (!this.http) {
|
|
172
401
|
return this.backendError('Task update requires HttpClient.');
|
|
173
402
|
}
|
|
174
|
-
const endpoint = this.resolveTaskMutationEndpoint(context, 'updateTask', 'tasks/{levelId}/update/{taskId}', 'tasks/{schemaId}/{levelId}/update/{taskId}', { taskId: this.readId(taskId) ?? '' });
|
|
403
|
+
const endpoint = this.resolveTaskMutationEndpoint(context, 'updateTask', 'levels/{levelId}/{levelDataId}/schedule/{taskId}', 'tasks/{levelId}/update/{taskId}', 'tasks/{schemaId}/{levelId}/update/{taskId}', { taskId: this.readId(taskId) ?? '' });
|
|
175
404
|
if (!endpoint) {
|
|
176
405
|
return this.backendError('Task update endpoint requires a valid levelId.');
|
|
177
406
|
}
|
|
407
|
+
const requestBody = endpoint.mode === 'runtime'
|
|
408
|
+
? this.mapRuntimeMutationPayload(payload)
|
|
409
|
+
: payload;
|
|
178
410
|
return this.http
|
|
179
|
-
.put(endpoint,
|
|
411
|
+
.put(endpoint.url, requestBody, {
|
|
180
412
|
headers: this.readHeaders(context, 'task-update'),
|
|
181
413
|
})
|
|
182
414
|
.pipe(map((response) => this.unwrapResponse(response, 'Failed to update task.')));
|
|
@@ -185,12 +417,12 @@ class TaskScheduleBackendAdapter {
|
|
|
185
417
|
if (!this.http) {
|
|
186
418
|
return this.backendError('Task delete requires HttpClient.');
|
|
187
419
|
}
|
|
188
|
-
const endpoint = this.resolveTaskMutationEndpoint(context, 'deleteTask', 'tasks/{levelId}/delete/{taskId}', 'tasks/{schemaId}/{levelId}/delete/{taskId}', { taskId: this.readId(taskId) ?? '' });
|
|
420
|
+
const endpoint = this.resolveTaskMutationEndpoint(context, 'deleteTask', 'levels/{levelId}/{levelDataId}/schedule/{taskId}', 'tasks/{levelId}/delete/{taskId}', 'tasks/{schemaId}/{levelId}/delete/{taskId}', { taskId: this.readId(taskId) ?? '' });
|
|
189
421
|
if (!endpoint) {
|
|
190
422
|
return this.backendError('Task delete endpoint requires a valid levelId.');
|
|
191
423
|
}
|
|
192
424
|
return this.http
|
|
193
|
-
.delete(endpoint, {
|
|
425
|
+
.delete(endpoint.url, {
|
|
194
426
|
headers: this.readHeaders(context, 'task-delete'),
|
|
195
427
|
})
|
|
196
428
|
.pipe(map((response) => this.unwrapResponse(response, 'Failed to delete task.')));
|
|
@@ -199,12 +431,15 @@ class TaskScheduleBackendAdapter {
|
|
|
199
431
|
if (!this.http) {
|
|
200
432
|
return this.backendError('Task bulk update requires HttpClient.');
|
|
201
433
|
}
|
|
202
|
-
const endpoint = this.resolveTaskMutationEndpoint(context, 'updateBulkTasks', 'tasks/{levelId}/bulkUpdate', 'tasks/{schemaId}/{levelId}/bulkUpdate');
|
|
434
|
+
const endpoint = this.resolveTaskMutationEndpoint(context, 'updateBulkTasks', 'levels/{levelId}/{levelDataId}/schedule/bulk-update', 'tasks/{levelId}/bulkUpdate', 'tasks/{schemaId}/{levelId}/bulkUpdate');
|
|
203
435
|
if (!endpoint) {
|
|
204
436
|
return this.backendError('Task bulk update endpoint requires a valid levelId.');
|
|
205
437
|
}
|
|
438
|
+
const requestBody = endpoint.mode === 'runtime'
|
|
439
|
+
? this.mapRuntimeBulkUpdatePayload(payload)
|
|
440
|
+
: { data: payload };
|
|
206
441
|
return this.http
|
|
207
|
-
.put(endpoint,
|
|
442
|
+
.put(endpoint.url, requestBody, {
|
|
208
443
|
headers: this.readHeaders(context, 'task-bulk-update'),
|
|
209
444
|
})
|
|
210
445
|
.pipe(map((response) => this.unwrapResponse(response, 'Failed to update linked tasks.')));
|
|
@@ -213,12 +448,12 @@ class TaskScheduleBackendAdapter {
|
|
|
213
448
|
if (!this.http) {
|
|
214
449
|
return this.backendError('Task parent update requires HttpClient.');
|
|
215
450
|
}
|
|
216
|
-
const endpoint = this.resolveTaskMutationEndpoint(context, 'updateParent', 'tasks/{levelId}/updateParent/{taskId}', 'tasks/{schemaId}/{levelId}/updateParent/{taskId}', { taskId: this.readId(taskId) ?? '' });
|
|
451
|
+
const endpoint = this.resolveTaskMutationEndpoint(context, 'updateParent', 'levels/{levelId}/{levelDataId}/schedule/{taskId}', 'tasks/{levelId}/updateParent/{taskId}', 'tasks/{schemaId}/{levelId}/updateParent/{taskId}', { taskId: this.readId(taskId) ?? '' });
|
|
217
452
|
if (!endpoint) {
|
|
218
453
|
return this.backendError('Task parent update endpoint requires a valid levelId.');
|
|
219
454
|
}
|
|
220
455
|
return this.http
|
|
221
|
-
.put(endpoint, { parentId }, {
|
|
456
|
+
.put(endpoint.url, { parentId }, {
|
|
222
457
|
headers: this.readHeaders(context, 'task-update-parent'),
|
|
223
458
|
})
|
|
224
459
|
.pipe(map((response) => this.unwrapResponse(response, 'Failed to update task parent.')));
|
|
@@ -227,12 +462,15 @@ class TaskScheduleBackendAdapter {
|
|
|
227
462
|
if (!this.http) {
|
|
228
463
|
return this.backendError('Task reorder requires HttpClient.');
|
|
229
464
|
}
|
|
230
|
-
const endpoint = this.resolveTaskMutationEndpoint(context, 'updateOrder', 'tasks/{levelId}/reorder', 'tasks/{schemaId}/{levelId}/reorder');
|
|
465
|
+
const endpoint = this.resolveTaskMutationEndpoint(context, 'updateOrder', 'levels/{levelId}/{levelDataId}/schedule/reorder', 'tasks/{levelId}/reorder', 'tasks/{schemaId}/{levelId}/reorder');
|
|
231
466
|
if (!endpoint) {
|
|
232
467
|
return this.backendError('Task reorder endpoint requires a valid levelId.');
|
|
233
468
|
}
|
|
469
|
+
const requestBody = endpoint.mode === 'runtime'
|
|
470
|
+
? this.mapRuntimeOrderUpdatePayload(payload)
|
|
471
|
+
: { data: payload };
|
|
234
472
|
return this.http
|
|
235
|
-
.put(endpoint,
|
|
473
|
+
.put(endpoint.url, requestBody, {
|
|
236
474
|
headers: this.readHeaders(context, 'task-update-order'),
|
|
237
475
|
})
|
|
238
476
|
.pipe(map((response) => this.unwrapResponse(response, 'Failed to update task order.')));
|
|
@@ -241,16 +479,19 @@ class TaskScheduleBackendAdapter {
|
|
|
241
479
|
if (!this.http) {
|
|
242
480
|
return this.backendError('Task progress update requires HttpClient.');
|
|
243
481
|
}
|
|
244
|
-
const endpoint = this.resolveTaskMutationEndpoint(context, 'updateProgress', 'tasks/{levelId}/updatePlanningModuleProgress', 'tasks/{schemaId}/{levelId}/updatePlanningModuleProgress');
|
|
482
|
+
const endpoint = this.resolveTaskMutationEndpoint(context, 'updateProgress', 'levels/{levelId}/{levelDataId}/schedule/{taskId}/progress', 'tasks/{levelId}/updatePlanningModuleProgress', 'tasks/{schemaId}/{levelId}/updatePlanningModuleProgress', { taskId: this.readId(taskId) ?? '' });
|
|
245
483
|
if (!endpoint) {
|
|
246
484
|
return this.backendError('Task progress update endpoint requires a valid levelId.');
|
|
247
485
|
}
|
|
486
|
+
const requestBody = endpoint.mode === 'runtime'
|
|
487
|
+
? { progress: this.toNullableNumber(payload.progress) ?? 0 }
|
|
488
|
+
: {
|
|
489
|
+
...payload,
|
|
490
|
+
id: taskId,
|
|
491
|
+
ModuleType: payload.type ?? 'Task',
|
|
492
|
+
};
|
|
248
493
|
return this.http
|
|
249
|
-
.put(endpoint, {
|
|
250
|
-
...payload,
|
|
251
|
-
id: taskId,
|
|
252
|
-
ModuleType: payload.type ?? 'Task',
|
|
253
|
-
}, {
|
|
494
|
+
.put(endpoint.url, requestBody, {
|
|
254
495
|
headers: this.readHeaders(context, 'task-update-progress'),
|
|
255
496
|
})
|
|
256
497
|
.pipe(map((response) => this.unwrapResponse(response, 'Failed to update task progress.')));
|
|
@@ -263,14 +504,21 @@ class TaskScheduleBackendAdapter {
|
|
|
263
504
|
if (!levelId) {
|
|
264
505
|
return this.backendError('Task import endpoint requires a valid levelId.');
|
|
265
506
|
}
|
|
507
|
+
const levelDataId = this.readId(context.levelDataId);
|
|
266
508
|
const schemaId = this.readId(context.schemaId);
|
|
267
|
-
const
|
|
509
|
+
const customTemplate = this.readEndpoint(context.endpoints, 'importTasks');
|
|
510
|
+
const template = customTemplate ?? 'tasks/mmp/import';
|
|
511
|
+
const endpoint = this.resolveApiUrl(context, template, {
|
|
268
512
|
levelId,
|
|
513
|
+
...(levelDataId ? { levelDataId } : {}),
|
|
269
514
|
...(schemaId ? { schemaId } : {}),
|
|
270
515
|
});
|
|
271
516
|
const formData = new FormData();
|
|
272
517
|
formData.append('file', file, file.name);
|
|
273
518
|
formData.append('levelId', levelId);
|
|
519
|
+
if (levelDataId) {
|
|
520
|
+
formData.append('levelDataId', levelDataId);
|
|
521
|
+
}
|
|
274
522
|
return this.http
|
|
275
523
|
.post(endpoint, formData, {
|
|
276
524
|
headers: this.readHeaders(context, 'task-import'),
|
|
@@ -280,7 +528,9 @@ class TaskScheduleBackendAdapter {
|
|
|
280
528
|
const tasks = rows
|
|
281
529
|
.map((item, index) => this.mapRuntimeTask(item, index + 1))
|
|
282
530
|
.filter((item) => !!item);
|
|
283
|
-
const payload = raw && typeof raw === 'object'
|
|
531
|
+
const payload = raw && typeof raw === 'object'
|
|
532
|
+
? raw
|
|
533
|
+
: {};
|
|
284
534
|
return {
|
|
285
535
|
fileName: this.toNullableString(payload['fileName']) ??
|
|
286
536
|
this.toNullableString(payload['name']) ??
|
|
@@ -312,13 +562,19 @@ class TaskScheduleBackendAdapter {
|
|
|
312
562
|
if (!levelId) {
|
|
313
563
|
return this.backendError('Set baseline endpoint requires a valid levelId.');
|
|
314
564
|
}
|
|
565
|
+
const levelDataId = this.readId(context.levelDataId);
|
|
315
566
|
const schemaId = this.readId(context.schemaId);
|
|
316
|
-
const
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
567
|
+
const customTemplate = this.readEndpoint(context.endpoints, 'setBaseline');
|
|
568
|
+
const template = customTemplate
|
|
569
|
+
? customTemplate
|
|
570
|
+
: levelDataId
|
|
571
|
+
? 'levels/{levelId}/{levelDataId}/schedule/baselines'
|
|
572
|
+
: schemaId
|
|
573
|
+
? 'levels/{schemaId}/{levelId}/tasks/setBaseline'
|
|
574
|
+
: 'levels/{levelId}/tasks/setBaseline';
|
|
320
575
|
const endpoint = this.resolveApiUrl(context, template, {
|
|
321
576
|
levelId,
|
|
577
|
+
...(levelDataId ? { levelDataId } : {}),
|
|
322
578
|
...(schemaId ? { schemaId } : {}),
|
|
323
579
|
});
|
|
324
580
|
return this.http
|
|
@@ -335,10 +591,17 @@ class TaskScheduleBackendAdapter {
|
|
|
335
591
|
if (!levelId) {
|
|
336
592
|
return this.backendError('Task export endpoint requires a valid levelId.');
|
|
337
593
|
}
|
|
594
|
+
const levelDataId = this.readId(context.levelDataId);
|
|
338
595
|
const schemaId = this.readId(context.schemaId);
|
|
339
|
-
const
|
|
340
|
-
|
|
596
|
+
const customTemplate = this.readEndpoint(context.endpoints, 'exportTasks');
|
|
597
|
+
const template = customTemplate
|
|
598
|
+
? customTemplate
|
|
599
|
+
: levelDataId
|
|
600
|
+
? 'levels/{levelId}/{levelDataId}/schedule/mpp'
|
|
601
|
+
: 'tasks/levels/{levelId}/export';
|
|
602
|
+
const endpoint = this.resolveApiUrl(context, template, {
|
|
341
603
|
levelId,
|
|
604
|
+
...(levelDataId ? { levelDataId } : {}),
|
|
342
605
|
...(schemaId ? { schemaId } : {}),
|
|
343
606
|
});
|
|
344
607
|
return this.http.get(endpoint, {
|
|
@@ -346,6 +609,60 @@ class TaskScheduleBackendAdapter {
|
|
|
346
609
|
responseType: 'blob',
|
|
347
610
|
});
|
|
348
611
|
}
|
|
612
|
+
mapRuntimeMutationPayload(payload) {
|
|
613
|
+
const mapped = { ...payload };
|
|
614
|
+
if (payload.startDate !== undefined) {
|
|
615
|
+
mapped['plannedStart'] = payload.startDate;
|
|
616
|
+
}
|
|
617
|
+
if (payload.finishDate !== undefined) {
|
|
618
|
+
mapped['plannedFinish'] = payload.finishDate;
|
|
619
|
+
}
|
|
620
|
+
return mapped;
|
|
621
|
+
}
|
|
622
|
+
mapRuntimeBulkUpdatePayload(payload) {
|
|
623
|
+
const items = payload.map((item) => {
|
|
624
|
+
const mapped = this.mapRuntimeMutationPayload(item);
|
|
625
|
+
const id = this.toTaskId(item['id']);
|
|
626
|
+
if (id !== null) {
|
|
627
|
+
mapped['id'] = id;
|
|
628
|
+
}
|
|
629
|
+
return mapped;
|
|
630
|
+
});
|
|
631
|
+
const type = this.resolveRuntimeScheduleItemType(payload[0]?.['type']);
|
|
632
|
+
return {
|
|
633
|
+
...(type === null ? {} : { type }),
|
|
634
|
+
items,
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
mapRuntimeOrderUpdatePayload(payload) {
|
|
638
|
+
return {
|
|
639
|
+
items: payload.map((item) => ({
|
|
640
|
+
id: item.taskId,
|
|
641
|
+
order: item.order,
|
|
642
|
+
})),
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
resolveRuntimeScheduleItemType(value) {
|
|
646
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
647
|
+
return value;
|
|
648
|
+
}
|
|
649
|
+
const normalized = String(value ?? '')
|
|
650
|
+
.trim()
|
|
651
|
+
.toLowerCase();
|
|
652
|
+
if (!normalized) {
|
|
653
|
+
return null;
|
|
654
|
+
}
|
|
655
|
+
if (normalized === 'task') {
|
|
656
|
+
return 0;
|
|
657
|
+
}
|
|
658
|
+
if (normalized === 'milestone') {
|
|
659
|
+
return 1;
|
|
660
|
+
}
|
|
661
|
+
if (normalized === 'deliverable') {
|
|
662
|
+
return 2;
|
|
663
|
+
}
|
|
664
|
+
return null;
|
|
665
|
+
}
|
|
349
666
|
loadCustomColumns(context) {
|
|
350
667
|
if (Array.isArray(context.customColumns)) {
|
|
351
668
|
return of(context.customColumns);
|
|
@@ -380,7 +697,8 @@ class TaskScheduleBackendAdapter {
|
|
|
380
697
|
})
|
|
381
698
|
.pipe(map((response) => this.unwrapResponse(response, 'Failed to load schedule views.')));
|
|
382
699
|
if (scheduleViewKey) {
|
|
383
|
-
return views$.pipe(map((views) => views.find((view) => String(view.key ?? '').toLowerCase() ===
|
|
700
|
+
return views$.pipe(map((views) => views.find((view) => String(view.key ?? '').toLowerCase() ===
|
|
701
|
+
scheduleViewKey.toLowerCase())), map((view) => this.mapScheduleColumns(view?.columns ?? [], context.langCode ?? 'en')));
|
|
384
702
|
}
|
|
385
703
|
const settingsEndpoint = this.resolveScheduleManagerEndpoint(context, 'scheduleSettingsByLevel', '{scheduleManagerBase}/{levelId}/settings', { levelId });
|
|
386
704
|
return this.http
|
|
@@ -398,38 +716,16 @@ class TaskScheduleBackendAdapter {
|
|
|
398
716
|
null);
|
|
399
717
|
}))), map((view) => this.mapScheduleColumns(view?.columns ?? [], context.langCode ?? 'en')));
|
|
400
718
|
}
|
|
401
|
-
resolveTreeRouteTemplate(context,
|
|
402
|
-
const
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
baseline: 'scheduleTreeBaseline',
|
|
406
|
-
criticalPath: 'scheduleTreeCriticalPath',
|
|
407
|
-
resources: 'scheduleTreeResources',
|
|
408
|
-
unscheduled: 'scheduleTreeUnscheduled',
|
|
409
|
-
phaseGate: 'scheduleTreePhaseGate',
|
|
410
|
-
custom: 'scheduleTreeCustom',
|
|
411
|
-
};
|
|
412
|
-
const modeSpecificRoute = this.readEndpoint(context.endpoints, modeEndpointKeyByModel[modelType]);
|
|
413
|
-
if (modeSpecificRoute) {
|
|
414
|
-
return modeSpecificRoute;
|
|
719
|
+
resolveTreeRouteTemplate(context, _modelType) {
|
|
720
|
+
const phaseGateRoute = this.readEndpoint(context.endpoints, 'scheduleTreePhaseGate');
|
|
721
|
+
if (phaseGateRoute) {
|
|
722
|
+
return phaseGateRoute;
|
|
415
723
|
}
|
|
416
724
|
const customTreeRoute = this.readEndpoint(context.endpoints, 'scheduleTree');
|
|
417
725
|
if (customTreeRoute) {
|
|
418
726
|
return customTreeRoute;
|
|
419
727
|
}
|
|
420
|
-
|
|
421
|
-
if (modelType === 'baseline') {
|
|
422
|
-
return 'tasks/{levelId}/GetAllBaseLine';
|
|
423
|
-
}
|
|
424
|
-
if (modelType === 'unscheduled') {
|
|
425
|
-
return 'tasks/{levelId}/unscheduled';
|
|
426
|
-
}
|
|
427
|
-
if (modelType === 'phaseGate') {
|
|
428
|
-
return 'tasks/{levelId}/GetAll?RenderMode=PhaseGate';
|
|
429
|
-
}
|
|
430
|
-
return 'tasks/{levelId}/GetAll';
|
|
431
|
-
}
|
|
432
|
-
return 'levels/{levelId}/{levelDataId}/schedule/tree';
|
|
728
|
+
return 'levels/{levelId}/{levelDataId}/schedule/tree?renderMode=PhaseGate';
|
|
433
729
|
}
|
|
434
730
|
buildTreeRouteParams(context, treeRouteTemplate) {
|
|
435
731
|
const levelId = this.readId(context.levelId);
|
|
@@ -453,19 +749,40 @@ class TaskScheduleBackendAdapter {
|
|
|
453
749
|
}
|
|
454
750
|
return params;
|
|
455
751
|
}
|
|
456
|
-
resolveTaskMutationEndpoint(context, endpointKey,
|
|
752
|
+
resolveTaskMutationEndpoint(context, endpointKey, runtimeTemplate, legacyTemplate, legacyTemplateWithSchema, extraParams) {
|
|
457
753
|
const levelId = this.readId(context.levelId);
|
|
458
754
|
if (!levelId) {
|
|
459
755
|
return null;
|
|
460
756
|
}
|
|
757
|
+
const levelDataId = this.readId(context.levelDataId);
|
|
461
758
|
const schemaId = this.readId(context.schemaId);
|
|
462
|
-
const
|
|
463
|
-
|
|
464
|
-
return this.resolveApiUrl(context, template, {
|
|
759
|
+
const customTemplate = this.readEndpoint(context.endpoints, endpointKey);
|
|
760
|
+
const params = {
|
|
465
761
|
levelId,
|
|
762
|
+
...(levelDataId ? { levelDataId } : {}),
|
|
466
763
|
...(schemaId ? { schemaId } : {}),
|
|
467
764
|
...extraParams,
|
|
468
|
-
}
|
|
765
|
+
};
|
|
766
|
+
if (customTemplate) {
|
|
767
|
+
const normalizedTemplate = customTemplate.replace(/\\/g, '/');
|
|
768
|
+
const isRuntimeTemplate = customTemplate.includes('{levelDataId}') ||
|
|
769
|
+
(levelDataId !== null &&
|
|
770
|
+
/levels\/\{levelId\}\/.+\/(schedule|tasks|milestones|deliverables)/i.test(normalizedTemplate));
|
|
771
|
+
return {
|
|
772
|
+
url: this.resolveApiUrl(context, customTemplate, params),
|
|
773
|
+
mode: isRuntimeTemplate ? 'runtime' : 'legacy',
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
if (levelDataId) {
|
|
777
|
+
return {
|
|
778
|
+
url: this.resolveApiUrl(context, runtimeTemplate, params),
|
|
779
|
+
mode: 'runtime',
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
return {
|
|
783
|
+
url: this.resolveApiUrl(context, schemaId ? legacyTemplateWithSchema : legacyTemplate, params),
|
|
784
|
+
mode: 'legacy',
|
|
785
|
+
};
|
|
469
786
|
}
|
|
470
787
|
resolveApplyImportedTasksEndpoint(context) {
|
|
471
788
|
const levelId = this.readId(context.levelId);
|
|
@@ -474,14 +791,18 @@ class TaskScheduleBackendAdapter {
|
|
|
474
791
|
}
|
|
475
792
|
const custom = this.readEndpoint(context.endpoints, 'applyImportedTasks');
|
|
476
793
|
if (custom) {
|
|
794
|
+
const levelDataId = this.readId(context.levelDataId);
|
|
477
795
|
const schemaId = this.readId(context.schemaId);
|
|
478
796
|
return this.resolveApiUrl(context, custom, {
|
|
479
797
|
levelId,
|
|
798
|
+
...(levelDataId ? { levelDataId } : {}),
|
|
480
799
|
...(schemaId ? { schemaId } : {}),
|
|
481
800
|
});
|
|
482
801
|
}
|
|
483
802
|
const schemaId = this.readId(context.schemaId);
|
|
484
|
-
const template = schemaId
|
|
803
|
+
const template = schemaId
|
|
804
|
+
? 'tasks/{schemaId}/{levelId}'
|
|
805
|
+
: 'tasks/{levelId}/import';
|
|
485
806
|
return this.resolveApiUrl(context, template, {
|
|
486
807
|
levelId,
|
|
487
808
|
...(schemaId ? { schemaId } : {}),
|
|
@@ -535,7 +856,8 @@ class TaskScheduleBackendAdapter {
|
|
|
535
856
|
return headers;
|
|
536
857
|
}
|
|
537
858
|
buildIdempotencyKey(seed) {
|
|
538
|
-
if (typeof crypto !== 'undefined' &&
|
|
859
|
+
if (typeof crypto !== 'undefined' &&
|
|
860
|
+
typeof crypto.randomUUID === 'function') {
|
|
539
861
|
return `${seed}-${crypto.randomUUID()}`;
|
|
540
862
|
}
|
|
541
863
|
return `${seed}-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
|
|
@@ -555,7 +877,7 @@ class TaskScheduleBackendAdapter {
|
|
|
555
877
|
}
|
|
556
878
|
extractTaskArray(payload) {
|
|
557
879
|
if (Array.isArray(payload)) {
|
|
558
|
-
return payload;
|
|
880
|
+
return this.normalizeTaskRows(payload);
|
|
559
881
|
}
|
|
560
882
|
if (!payload || typeof payload !== 'object') {
|
|
561
883
|
return [];
|
|
@@ -571,7 +893,7 @@ class TaskScheduleBackendAdapter {
|
|
|
571
893
|
];
|
|
572
894
|
for (const candidate of candidates) {
|
|
573
895
|
if (Array.isArray(candidate)) {
|
|
574
|
-
return candidate;
|
|
896
|
+
return this.normalizeTaskRows(candidate);
|
|
575
897
|
}
|
|
576
898
|
}
|
|
577
899
|
if (source['id'] !== undefined || source['Id'] !== undefined) {
|
|
@@ -579,6 +901,145 @@ class TaskScheduleBackendAdapter {
|
|
|
579
901
|
}
|
|
580
902
|
return [];
|
|
581
903
|
}
|
|
904
|
+
normalizeTaskRows(rows) {
|
|
905
|
+
const resourceRows = this.flattenResourceGroups(rows);
|
|
906
|
+
return resourceRows ?? rows;
|
|
907
|
+
}
|
|
908
|
+
flattenResourceGroups(rows) {
|
|
909
|
+
const mergedById = new Map();
|
|
910
|
+
const unmatchedRows = [];
|
|
911
|
+
let hasResourceGroups = false;
|
|
912
|
+
rows.forEach((row) => {
|
|
913
|
+
if (!row || typeof row !== 'object') {
|
|
914
|
+
return;
|
|
915
|
+
}
|
|
916
|
+
const group = row;
|
|
917
|
+
const groupItems = this.firstDefined(group, ['items', 'Items']);
|
|
918
|
+
if (!Array.isArray(groupItems)) {
|
|
919
|
+
return;
|
|
920
|
+
}
|
|
921
|
+
const isResourceGroup = group['userId'] !== undefined ||
|
|
922
|
+
group['UserId'] !== undefined ||
|
|
923
|
+
group['displayName'] !== undefined ||
|
|
924
|
+
group['DisplayName'] !== undefined;
|
|
925
|
+
if (!isResourceGroup) {
|
|
926
|
+
return;
|
|
927
|
+
}
|
|
928
|
+
hasResourceGroups = true;
|
|
929
|
+
const groupUserId = this.toTaskId(this.firstDefined(group, ['userId', 'UserId']));
|
|
930
|
+
const groupDisplayName = this.toNullableString(this.firstDefined(group, [
|
|
931
|
+
'displayName',
|
|
932
|
+
'DisplayName',
|
|
933
|
+
'name',
|
|
934
|
+
'Name',
|
|
935
|
+
]));
|
|
936
|
+
groupItems.forEach((item) => {
|
|
937
|
+
if (!item || typeof item !== 'object') {
|
|
938
|
+
return;
|
|
939
|
+
}
|
|
940
|
+
const taskRow = { ...item };
|
|
941
|
+
this.attachGroupResource(taskRow, groupUserId, groupDisplayName);
|
|
942
|
+
const id = this.toTaskId(this.firstDefined(taskRow, ['id', 'Id', 'taskId', 'TaskId']));
|
|
943
|
+
if (id === null) {
|
|
944
|
+
unmatchedRows.push(taskRow);
|
|
945
|
+
return;
|
|
946
|
+
}
|
|
947
|
+
const key = String(id);
|
|
948
|
+
const existing = mergedById.get(key);
|
|
949
|
+
if (!existing) {
|
|
950
|
+
mergedById.set(key, taskRow);
|
|
951
|
+
return;
|
|
952
|
+
}
|
|
953
|
+
this.mergeTaskResources(existing, taskRow);
|
|
954
|
+
if (existing['assignedTo'] === undefined &&
|
|
955
|
+
taskRow['assignedTo'] !== undefined) {
|
|
956
|
+
existing['assignedTo'] = taskRow['assignedTo'];
|
|
957
|
+
}
|
|
958
|
+
if (existing['AssignedTo'] === undefined &&
|
|
959
|
+
taskRow['AssignedTo'] !== undefined) {
|
|
960
|
+
existing['AssignedTo'] = taskRow['AssignedTo'];
|
|
961
|
+
}
|
|
962
|
+
});
|
|
963
|
+
});
|
|
964
|
+
if (!hasResourceGroups) {
|
|
965
|
+
return null;
|
|
966
|
+
}
|
|
967
|
+
return [...mergedById.values(), ...unmatchedRows];
|
|
968
|
+
}
|
|
969
|
+
attachGroupResource(taskRow, groupUserId, groupDisplayName) {
|
|
970
|
+
if (groupUserId === null) {
|
|
971
|
+
return;
|
|
972
|
+
}
|
|
973
|
+
const existingResourcesCandidate = this.firstDefined(taskRow, [
|
|
974
|
+
'resources',
|
|
975
|
+
'Resources',
|
|
976
|
+
]);
|
|
977
|
+
const existingResources = Array.isArray(existingResourcesCandidate)
|
|
978
|
+
? [...existingResourcesCandidate]
|
|
979
|
+
: [];
|
|
980
|
+
const hasResource = existingResources.some((resource) => this.resolveResourceIdentity(resource) === String(groupUserId));
|
|
981
|
+
if (!hasResource) {
|
|
982
|
+
existingResources.push({
|
|
983
|
+
resourceId: groupUserId,
|
|
984
|
+
resourceName: groupDisplayName ?? String(groupUserId),
|
|
985
|
+
});
|
|
986
|
+
}
|
|
987
|
+
taskRow['resources'] = existingResources;
|
|
988
|
+
if (taskRow['assignedTo'] === undefined &&
|
|
989
|
+
taskRow['AssignedTo'] === undefined) {
|
|
990
|
+
taskRow['assignedTo'] = groupUserId;
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
mergeTaskResources(target, source) {
|
|
994
|
+
const targetResourcesCandidate = this.firstDefined(target, [
|
|
995
|
+
'resources',
|
|
996
|
+
'Resources',
|
|
997
|
+
]);
|
|
998
|
+
const sourceResourcesCandidate = this.firstDefined(source, [
|
|
999
|
+
'resources',
|
|
1000
|
+
'Resources',
|
|
1001
|
+
]);
|
|
1002
|
+
const targetResources = Array.isArray(targetResourcesCandidate)
|
|
1003
|
+
? [...targetResourcesCandidate]
|
|
1004
|
+
: [];
|
|
1005
|
+
const sourceResources = Array.isArray(sourceResourcesCandidate)
|
|
1006
|
+
? sourceResourcesCandidate
|
|
1007
|
+
: [];
|
|
1008
|
+
sourceResources.forEach((resource) => {
|
|
1009
|
+
const sourceId = this.resolveResourceIdentity(resource);
|
|
1010
|
+
if (!sourceId) {
|
|
1011
|
+
return;
|
|
1012
|
+
}
|
|
1013
|
+
const exists = targetResources.some((targetResource) => this.resolveResourceIdentity(targetResource) === sourceId);
|
|
1014
|
+
if (!exists) {
|
|
1015
|
+
targetResources.push(resource);
|
|
1016
|
+
}
|
|
1017
|
+
});
|
|
1018
|
+
if (targetResources.length) {
|
|
1019
|
+
target['resources'] = targetResources;
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
resolveResourceIdentity(resource) {
|
|
1023
|
+
if (resource === null || resource === undefined) {
|
|
1024
|
+
return null;
|
|
1025
|
+
}
|
|
1026
|
+
if (typeof resource === 'string' || typeof resource === 'number') {
|
|
1027
|
+
return String(resource);
|
|
1028
|
+
}
|
|
1029
|
+
if (typeof resource !== 'object') {
|
|
1030
|
+
return null;
|
|
1031
|
+
}
|
|
1032
|
+
const row = resource;
|
|
1033
|
+
const id = this.toTaskId(this.firstDefined(row, [
|
|
1034
|
+
'resourceId',
|
|
1035
|
+
'ResourceId',
|
|
1036
|
+
'userId',
|
|
1037
|
+
'UserId',
|
|
1038
|
+
'id',
|
|
1039
|
+
'Id',
|
|
1040
|
+
]));
|
|
1041
|
+
return id === null ? null : String(id);
|
|
1042
|
+
}
|
|
582
1043
|
mapRuntimeTask(payload, fallbackOrder) {
|
|
583
1044
|
if (!payload || typeof payload !== 'object') {
|
|
584
1045
|
return null;
|
|
@@ -588,9 +1049,20 @@ class TaskScheduleBackendAdapter {
|
|
|
588
1049
|
if (id === null) {
|
|
589
1050
|
return null;
|
|
590
1051
|
}
|
|
591
|
-
const type = String(this.firstDefined(source, [
|
|
592
|
-
'
|
|
593
|
-
|
|
1052
|
+
const type = String(this.firstDefined(source, [
|
|
1053
|
+
'type',
|
|
1054
|
+
'Type',
|
|
1055
|
+
'typeLable',
|
|
1056
|
+
'TypeLable',
|
|
1057
|
+
'typeLabel',
|
|
1058
|
+
'TypeLabel',
|
|
1059
|
+
]) ?? 'Task');
|
|
1060
|
+
const assignee = this.extractAssignee(this.firstDefined(source, [
|
|
1061
|
+
'assignedTo',
|
|
1062
|
+
'AssignedTo',
|
|
1063
|
+
'createdBy',
|
|
1064
|
+
'CreatedBy',
|
|
1065
|
+
]));
|
|
594
1066
|
const resources = this.extractTaskResources(this.firstDefined(source, ['resources', 'Resources']), assignee);
|
|
595
1067
|
const subtasksRaw = this.firstDefined(source, [
|
|
596
1068
|
'subtasks',
|
|
@@ -645,9 +1117,24 @@ class TaskScheduleBackendAdapter {
|
|
|
645
1117
|
'baselineFinish',
|
|
646
1118
|
'BaselineFinish',
|
|
647
1119
|
])),
|
|
648
|
-
actualStartDate: this.extractDate(this.firstDefined(source, [
|
|
649
|
-
|
|
650
|
-
|
|
1120
|
+
actualStartDate: this.extractDate(this.firstDefined(source, [
|
|
1121
|
+
'actualStartDate',
|
|
1122
|
+
'ActualStartDate',
|
|
1123
|
+
'actualStart',
|
|
1124
|
+
'ActualStart',
|
|
1125
|
+
])),
|
|
1126
|
+
actualFinishDate: this.extractDate(this.firstDefined(source, [
|
|
1127
|
+
'actualFinishDate',
|
|
1128
|
+
'ActualFinishDate',
|
|
1129
|
+
'actualFinish',
|
|
1130
|
+
'ActualFinish',
|
|
1131
|
+
])),
|
|
1132
|
+
predecessor: this.toNullableString(this.firstDefined(source, [
|
|
1133
|
+
'predecessor',
|
|
1134
|
+
'Predecessor',
|
|
1135
|
+
'predecessors',
|
|
1136
|
+
'Predecessors',
|
|
1137
|
+
])),
|
|
651
1138
|
duration: this.toNullableNumber(this.firstDefined(source, ['duration', 'Duration'])),
|
|
652
1139
|
progress: this.extractProgress(this.firstDefined(source, ['progress', 'Progress'])),
|
|
653
1140
|
details: this.toNullableString(this.firstDefined(source, ['details', 'Details', 'description'])),
|
|
@@ -801,8 +1288,7 @@ class TaskScheduleBackendAdapter {
|
|
|
801
1288
|
id: typeof id === 'number' || typeof id === 'string' ? id : String(id),
|
|
802
1289
|
key,
|
|
803
1290
|
name: this.toNullableString(row['name'] ?? row['displayName'] ?? row['Name']) ?? key,
|
|
804
|
-
viewType: this.toNullableString(row['viewType'] ?? row['type'] ?? row['ViewType']) ??
|
|
805
|
-
'Text',
|
|
1291
|
+
viewType: this.toNullableString(row['viewType'] ?? row['type'] ?? row['ViewType']) ?? 'Text',
|
|
806
1292
|
normalizedKey: this.toNullableString(row['normalizedKey'] ?? row['NormalizedKey']) ??
|
|
807
1293
|
undefined,
|
|
808
1294
|
isRequired: Boolean(row['isRequired'] ?? row['required']),
|
|
@@ -824,11 +1310,7 @@ class TaskScheduleBackendAdapter {
|
|
|
824
1310
|
return;
|
|
825
1311
|
}
|
|
826
1312
|
const row = item;
|
|
827
|
-
const optionValue = row['value'] ??
|
|
828
|
-
row['id'] ??
|
|
829
|
-
row['key'] ??
|
|
830
|
-
row['name'] ??
|
|
831
|
-
row['text'];
|
|
1313
|
+
const optionValue = row['value'] ?? row['id'] ?? row['key'] ?? row['name'] ?? row['text'];
|
|
832
1314
|
const optionText = this.toNullableString(row['text'] ?? row['name'] ?? row['displayName'] ?? row['label']);
|
|
833
1315
|
if (optionValue === undefined || optionValue === null || !optionText) {
|
|
834
1316
|
return;
|
|
@@ -902,7 +1384,10 @@ class TaskScheduleBackendAdapter {
|
|
|
902
1384
|
}
|
|
903
1385
|
if (value && typeof value === 'object') {
|
|
904
1386
|
const row = value;
|
|
905
|
-
return this.toNullableString(row['displayName'] ??
|
|
1387
|
+
return this.toNullableString(row['displayName'] ??
|
|
1388
|
+
row['resourceName'] ??
|
|
1389
|
+
row['userName'] ??
|
|
1390
|
+
row['name']);
|
|
906
1391
|
}
|
|
907
1392
|
return null;
|
|
908
1393
|
};
|
|
@@ -922,10 +1407,7 @@ class TaskScheduleBackendAdapter {
|
|
|
922
1407
|
return;
|
|
923
1408
|
}
|
|
924
1409
|
const obj = resource;
|
|
925
|
-
const id = obj['resourceId'] ??
|
|
926
|
-
obj['id'] ??
|
|
927
|
-
obj['userId'] ??
|
|
928
|
-
obj['value'];
|
|
1410
|
+
const id = obj['resourceId'] ?? obj['id'] ?? obj['userId'] ?? obj['value'];
|
|
929
1411
|
if (id === undefined || id === null) {
|
|
930
1412
|
return;
|
|
931
1413
|
}
|
|
@@ -1018,7 +1500,8 @@ class TaskScheduleBackendAdapter {
|
|
|
1018
1500
|
}
|
|
1019
1501
|
return {
|
|
1020
1502
|
resourceId,
|
|
1021
|
-
unit: this.toNullableNumber(row['unit'] ?? row['resourceUnit']) ??
|
|
1503
|
+
unit: this.toNullableNumber(row['unit'] ?? row['resourceUnit']) ??
|
|
1504
|
+
undefined,
|
|
1022
1505
|
};
|
|
1023
1506
|
})
|
|
1024
1507
|
.filter((item) => item !== null);
|
|
@@ -1872,11 +2355,11 @@ class TaskScheduleTaskbarTemplate {
|
|
|
1872
2355
|
data = input.required(...(ngDevMode ? [{ debugName: "data" }] : []));
|
|
1873
2356
|
langCode = input('en', ...(ngDevMode ? [{ debugName: "langCode" }] : []));
|
|
1874
2357
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: TaskScheduleTaskbarTemplate, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1875
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: TaskScheduleTaskbarTemplate, isStandalone: true, selector: "mt-task-schedule-taskbar-template", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, langCode: { classPropertyName: "langCode", publicName: "langCode", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div>\n <div\n class=\"e-gantt-child-taskbar-inner-div e-gantt-child-taskbar gantt-child-taskbar\"\n [style.width.px]=\"data().ganttProperties?.width\"\n tabindex=\"-1\"\n >\n <div\n class=\"e-gantt-child-progressbar-inner-div e-gantt-child-progressbar gantt-child-progressbar\"\n [style.width.px]=\"data().ganttProperties?.progressWidth\"\n >\n <span class=\"e-task-label gantt-task-label\"></span>\n </div>\n </div>\n\n @if (data().taskData?.type === 'Milestone') {\n <div\n class=\"e-gantt-milestone gantt-milestone\"\n [class.diamond-left]=\"langCode() === 'en'\"\n [class.diamond-right]=\"langCode() === 'ar'\"\n tabindex=\"-1\"\n ></div>\n }\n</div>", styles: [".gantt-child-taskbar{height:22px!important;margin-top:-1px!important}.gantt-child-progressbar{border-style:solid!important;height:100%!important;border-top-right-radius:0;border-bottom-right-radius:0}.gantt-task-label{line-height:21px!important;text-align:left;display:inline-block;width:122px!important;height:22px!important}.gantt-milestone{width:16px!important;height:16px!important;position:absolute!important;transform:rotate(45deg)}.diamond-left{left:calc(100% + .5rem)}.diamond-right{right:calc(100% + .5rem)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
2358
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: TaskScheduleTaskbarTemplate, isStandalone: true, selector: "mt-task-schedule-taskbar-template", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, langCode: { classPropertyName: "langCode", publicName: "langCode", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div>\r\n <div\r\n class=\"e-gantt-child-taskbar-inner-div e-gantt-child-taskbar gantt-child-taskbar\"\r\n [style.width.px]=\"data().ganttProperties?.width\"\r\n tabindex=\"-1\"\r\n >\r\n <div\r\n class=\"e-gantt-child-progressbar-inner-div e-gantt-child-progressbar gantt-child-progressbar\"\r\n [style.width.px]=\"data().ganttProperties?.progressWidth\"\r\n >\r\n <span class=\"e-task-label gantt-task-label\"></span>\r\n </div>\r\n </div>\r\n\r\n @if (data().taskData?.type === 'Milestone') {\r\n <div\r\n class=\"e-gantt-milestone gantt-milestone\"\r\n [class.diamond-left]=\"langCode() === 'en'\"\r\n [class.diamond-right]=\"langCode() === 'ar'\"\r\n tabindex=\"-1\"\r\n ></div>\r\n }\r\n</div>", styles: [".gantt-child-taskbar{height:22px!important;margin-top:-1px!important}.gantt-child-progressbar{border-style:solid!important;height:100%!important;border-top-right-radius:0;border-bottom-right-radius:0}.gantt-task-label{line-height:21px!important;text-align:left;display:inline-block;width:122px!important;height:22px!important}.gantt-milestone{width:16px!important;height:16px!important;position:absolute!important;transform:rotate(45deg)}.diamond-left{left:calc(100% + .5rem)}.diamond-right{right:calc(100% + .5rem)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
1876
2359
|
}
|
|
1877
2360
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: TaskScheduleTaskbarTemplate, decorators: [{
|
|
1878
2361
|
type: Component,
|
|
1879
|
-
args: [{ selector: 'mt-task-schedule-taskbar-template', standalone: true, imports: [CommonModule], template: "<div>\n <div\n class=\"e-gantt-child-taskbar-inner-div e-gantt-child-taskbar gantt-child-taskbar\"\n [style.width.px]=\"data().ganttProperties?.width\"\n tabindex=\"-1\"\n >\n <div\n class=\"e-gantt-child-progressbar-inner-div e-gantt-child-progressbar gantt-child-progressbar\"\n [style.width.px]=\"data().ganttProperties?.progressWidth\"\n >\n <span class=\"e-task-label gantt-task-label\"></span>\n </div>\n </div>\n\n @if (data().taskData?.type === 'Milestone') {\n <div\n class=\"e-gantt-milestone gantt-milestone\"\n [class.diamond-left]=\"langCode() === 'en'\"\n [class.diamond-right]=\"langCode() === 'ar'\"\n tabindex=\"-1\"\n ></div>\n }\n</div>", styles: [".gantt-child-taskbar{height:22px!important;margin-top:-1px!important}.gantt-child-progressbar{border-style:solid!important;height:100%!important;border-top-right-radius:0;border-bottom-right-radius:0}.gantt-task-label{line-height:21px!important;text-align:left;display:inline-block;width:122px!important;height:22px!important}.gantt-milestone{width:16px!important;height:16px!important;position:absolute!important;transform:rotate(45deg)}.diamond-left{left:calc(100% + .5rem)}.diamond-right{right:calc(100% + .5rem)}\n"] }]
|
|
2362
|
+
args: [{ selector: 'mt-task-schedule-taskbar-template', standalone: true, imports: [CommonModule], template: "<div>\r\n <div\r\n class=\"e-gantt-child-taskbar-inner-div e-gantt-child-taskbar gantt-child-taskbar\"\r\n [style.width.px]=\"data().ganttProperties?.width\"\r\n tabindex=\"-1\"\r\n >\r\n <div\r\n class=\"e-gantt-child-progressbar-inner-div e-gantt-child-progressbar gantt-child-progressbar\"\r\n [style.width.px]=\"data().ganttProperties?.progressWidth\"\r\n >\r\n <span class=\"e-task-label gantt-task-label\"></span>\r\n </div>\r\n </div>\r\n\r\n @if (data().taskData?.type === 'Milestone') {\r\n <div\r\n class=\"e-gantt-milestone gantt-milestone\"\r\n [class.diamond-left]=\"langCode() === 'en'\"\r\n [class.diamond-right]=\"langCode() === 'ar'\"\r\n tabindex=\"-1\"\r\n ></div>\r\n }\r\n</div>", styles: [".gantt-child-taskbar{height:22px!important;margin-top:-1px!important}.gantt-child-progressbar{border-style:solid!important;height:100%!important;border-top-right-radius:0;border-bottom-right-radius:0}.gantt-task-label{line-height:21px!important;text-align:left;display:inline-block;width:122px!important;height:22px!important}.gantt-milestone{width:16px!important;height:16px!important;position:absolute!important;transform:rotate(45deg)}.diamond-left{left:calc(100% + .5rem)}.diamond-right{right:calc(100% + .5rem)}\n"] }]
|
|
1880
2363
|
}], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }], langCode: [{ type: i0.Input, args: [{ isSignal: true, alias: "langCode", required: false }] }] } });
|
|
1881
2364
|
|
|
1882
2365
|
const EMPTY_RESULT = { tasks: [] };
|
|
@@ -1907,14 +2390,7 @@ class TaskSchedule {
|
|
|
1907
2390
|
operationSub = new Subscription();
|
|
1908
2391
|
contextAddTask = signal('', ...(ngDevMode ? [{ debugName: "contextAddTask" }] : []));
|
|
1909
2392
|
customProperties = signal([], ...(ngDevMode ? [{ debugName: "customProperties" }] : []));
|
|
1910
|
-
modelType = input('default', ...(ngDevMode ? [{ debugName: "modelType" }] : []));
|
|
1911
2393
|
context = input(null, ...(ngDevMode ? [{ debugName: "context" }] : []));
|
|
1912
|
-
dateFormat = input('dd/MM/yyyy', ...(ngDevMode ? [{ debugName: "dateFormat" }] : []));
|
|
1913
|
-
height = input('760px', ...(ngDevMode ? [{ debugName: "height" }] : []));
|
|
1914
|
-
langCode = input(null, ...(ngDevMode ? [{ debugName: "langCode" }] : []));
|
|
1915
|
-
pdfFontData = input(null, ...(ngDevMode ? [{ debugName: "pdfFontData" }] : []));
|
|
1916
|
-
pdfRtlFontData = input(null, ...(ngDevMode ? [{ debugName: "pdfRtlFontData" }] : []));
|
|
1917
|
-
pdfFontSize = input(11, ...(ngDevMode ? [{ debugName: "pdfFontSize" }] : []));
|
|
1918
2394
|
toolbarAction = output();
|
|
1919
2395
|
actionBegin = output();
|
|
1920
2396
|
actionCompleted = output();
|
|
@@ -1925,8 +2401,11 @@ class TaskSchedule {
|
|
|
1925
2401
|
dataSource = signal([], ...(ngDevMode ? [{ debugName: "dataSource" }] : []));
|
|
1926
2402
|
ganttConfig = signal(createGanttConfig('default', EMPTY_RESULT, 'dd/MM/yyyy', 'en'), ...(ngDevMode ? [{ debugName: "ganttConfig" }] : []));
|
|
1927
2403
|
ganttId = `mtTaskScheduleGantt-${Math.random().toString(36).slice(2, 10)}`;
|
|
1928
|
-
|
|
1929
|
-
|
|
2404
|
+
resolvedModelTypeInput = computed(() => this.context()?.modelType ?? 'default', ...(ngDevMode ? [{ debugName: "resolvedModelTypeInput" }] : []));
|
|
2405
|
+
resolvedDateFormat = computed(() => this.context()?.dateFormat ?? 'dd/MM/yyyy', ...(ngDevMode ? [{ debugName: "resolvedDateFormat" }] : []));
|
|
2406
|
+
resolvedHeight = computed(() => this.context()?.height ?? '760px', ...(ngDevMode ? [{ debugName: "resolvedHeight" }] : []));
|
|
2407
|
+
resolvedModelType = computed(() => normalizeTaskScheduleModelType(this.resolvedModelTypeInput()), ...(ngDevMode ? [{ debugName: "resolvedModelType" }] : []));
|
|
2408
|
+
resolvedLangCode = computed(() => resolveTaskScheduleLanguage(this.context()?.langCode), ...(ngDevMode ? [{ debugName: "resolvedLangCode" }] : []));
|
|
1930
2409
|
isEditMode = computed(() => this.resolvedModelType() === 'edit', ...(ngDevMode ? [{ debugName: "isEditMode" }] : []));
|
|
1931
2410
|
editTaskTypes = computed(() => resolveEditTaskTypes(this.resolvedLangCode()), ...(ngDevMode ? [{ debugName: "editTaskTypes" }] : []));
|
|
1932
2411
|
enableRtl = computed(() => this.resolvedLangCode() === 'ar' ||
|
|
@@ -1954,7 +2433,7 @@ class TaskSchedule {
|
|
|
1954
2433
|
return;
|
|
1955
2434
|
}
|
|
1956
2435
|
const langCode = this.resolvedLangCode();
|
|
1957
|
-
this.loadSchedule(this.
|
|
2436
|
+
this.loadSchedule(this.resolvedModelTypeInput(), context, this.resolvedDateFormat(), langCode);
|
|
1958
2437
|
}, { ...(ngDevMode ? { debugName: "loadEffect" } : {}), injector: this.injector });
|
|
1959
2438
|
const refreshSub = this.queueService.refreshTasks$.subscribe(() => {
|
|
1960
2439
|
this.reloadSchedule();
|
|
@@ -2038,7 +2517,7 @@ class TaskSchedule {
|
|
|
2038
2517
|
onActionComplete(args) {
|
|
2039
2518
|
const context = this.context();
|
|
2040
2519
|
if (context) {
|
|
2041
|
-
this.queueService.reorderColumn(args, this.
|
|
2520
|
+
this.queueService.reorderColumn(args, this.resolvedModelTypeInput(), context);
|
|
2042
2521
|
}
|
|
2043
2522
|
if (this.isEditMode()) {
|
|
2044
2523
|
if (args?.requestType === 'openEditDialog' ||
|
|
@@ -2142,7 +2621,7 @@ class TaskSchedule {
|
|
|
2142
2621
|
dependsOn: property.dependsOn,
|
|
2143
2622
|
};
|
|
2144
2623
|
if (property.viewType === 'Date') {
|
|
2145
|
-
column['format'] = { type: 'date', format: this.
|
|
2624
|
+
column['format'] = { type: 'date', format: this.resolvedDateFormat() };
|
|
2146
2625
|
column['type'] = 'date';
|
|
2147
2626
|
}
|
|
2148
2627
|
if (property.viewType === 'Lookup') {
|
|
@@ -2413,7 +2892,7 @@ class TaskSchedule {
|
|
|
2413
2892
|
if (!context) {
|
|
2414
2893
|
return;
|
|
2415
2894
|
}
|
|
2416
|
-
this.loadSchedule(this.
|
|
2895
|
+
this.loadSchedule(this.resolvedModelTypeInput(), context, this.resolvedDateFormat(), this.resolvedLangCode());
|
|
2417
2896
|
}
|
|
2418
2897
|
normalizeTasks(tasks, customProps) {
|
|
2419
2898
|
return [...tasks]
|
|
@@ -2740,15 +3219,10 @@ class TaskSchedule {
|
|
|
2740
3219
|
resolvePdfExportFont() {
|
|
2741
3220
|
const contextFonts = this.context()?.pdfFonts;
|
|
2742
3221
|
const fontData = (this.enableRtl()
|
|
2743
|
-
?
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
: this.pdfFontData() ??
|
|
2748
|
-
contextFonts?.regular ??
|
|
2749
|
-
this.pdfRtlFontData() ??
|
|
2750
|
-
contextFonts?.arabic) ?? TASK_SCHEDULE_DEFAULT_PDF_FONT;
|
|
2751
|
-
return this.createEmbeddedPdfFont(fontData, contextFonts?.size ?? this.pdfFontSize());
|
|
3222
|
+
? contextFonts?.arabic ?? contextFonts?.regular
|
|
3223
|
+
: contextFonts?.regular ?? contextFonts?.arabic) ??
|
|
3224
|
+
TASK_SCHEDULE_DEFAULT_PDF_FONT;
|
|
3225
|
+
return this.createEmbeddedPdfFont(fontData, contextFonts?.size ?? 11);
|
|
2752
3226
|
}
|
|
2753
3227
|
createEmbeddedPdfFont(base64FontData, size) {
|
|
2754
3228
|
try {
|
|
@@ -2885,7 +3359,7 @@ class TaskSchedule {
|
|
|
2885
3359
|
}).format(date);
|
|
2886
3360
|
}
|
|
2887
3361
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: TaskSchedule, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2888
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: TaskSchedule, isStandalone: true, selector: "mt-task-schedule", inputs: {
|
|
3362
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: TaskSchedule, isStandalone: true, selector: "mt-task-schedule", inputs: { context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { toolbarAction: "toolbarAction", actionBegin: "actionBegin", actionCompleted: "actionCompleted", loaded: "loaded", loadError: "loadError" }, host: { classAttribute: "block" }, providers: [
|
|
2889
3363
|
DayMarkersService,
|
|
2890
3364
|
EditService,
|
|
2891
3365
|
ExcelExportService,
|
|
@@ -2897,7 +3371,7 @@ class TaskSchedule {
|
|
|
2897
3371
|
ToolbarService,
|
|
2898
3372
|
ContextMenuService,
|
|
2899
3373
|
ResizeService,
|
|
2900
|
-
], viewQueries: [{ propertyName: "ganttObj", first: true, predicate: ["ganttObj"], descendants: true }], ngImport: i0, template: "@if (!loading()) {\n <ejs-gantt\n #ganttObj\n [id]=\"ganttId\"\n [enableVirtualization]=\"true\"\n [enableTimelineVirtualization]=\"true\"\n [enableVirtualMaskRow]=\"false\"\n [allowResizing]=\"true\"\n [enableRtl]=\"enableRtl()\"\n [locale]=\"locale()\"\n [height]=\"
|
|
3374
|
+
], viewQueries: [{ propertyName: "ganttObj", first: true, predicate: ["ganttObj"], descendants: true }], ngImport: i0, template: "@if (!loading()) {\r\n <ejs-gantt\r\n #ganttObj\r\n [id]=\"ganttId\"\r\n [enableVirtualization]=\"true\"\r\n [enableTimelineVirtualization]=\"true\"\r\n [enableVirtualMaskRow]=\"false\"\n [allowResizing]=\"true\"\n [enableRtl]=\"enableRtl()\"\n [locale]=\"locale()\"\n [height]=\"resolvedHeight()\"\n [dataSource]=\"dataSource()\"\r\n [taskFields]=\"ganttConfig().taskFields\"\r\n [columns]=\"ganttConfig().columns\"\r\n [renderBaseline]=\"ganttConfig().renderBaseline\"\r\n [enableCriticalPath]=\"ganttConfig().enableCriticalPath\"\r\n [allowSelection]=\"true\"\r\n [labelSettings]=\"ganttConfig().labelSettings\"\r\n [treeColumnIndex]=\"1\"\r\n [workWeek]=\"ganttConfig().workWeek\"\r\n [highlightWeekends]=\"true\"\r\n [enablePredecessorValidation]=\"true\"\r\n [splitterSettings]=\"ganttConfig().splitterSettings\"\r\n [gridLines]=\"ganttConfig().gridLines\"\r\n [toolbar]=\"ganttConfig().toolbar\"\r\n [allowExcelExport]=\"ganttConfig().allowExcelExport\"\r\n [allowPdfExport]=\"ganttConfig().allowPdfExport\"\r\n [enableContextMenu]=\"ganttConfig().enableContextMenu\"\r\n [contextMenuItems]=\"ganttConfig().contextMenuItems\"\r\n [timelineSettings]=\"ganttConfig().timelineSettings\"\r\n [editSettings]=\"ganttConfig().editSettings\"\r\n [addDialogFields]=\"ganttConfig().addDialogFields\"\r\n [editDialogFields]=\"ganttConfig().editDialogFields\"\r\n [resourceFields]=\"ganttConfig().resourceFields\"\r\n [resources]=\"ganttConfig().resources\"\r\n [viewType]=\"ganttConfig().viewType\"\r\n [showOverAllocation]=\"ganttConfig().showOverAllocation\"\r\n [allowUnscheduledTasks]=\"ganttConfig().allowUnscheduledTasks\"\r\n [eventMarkers]=\"ganttConfig().eventMarkers\"\r\n [projectStartDate]=\"ganttConfig().projectStartDate\"\r\n [projectEndDate]=\"ganttConfig().projectEndDate\"\r\n [autoCalculateDateScheduling]=\"false\"\r\n [dateFormat]=\"resolvedDateFormat()\"\n [allowSorting]=\"true\"\r\n [holidays]=\"ganttConfig().holidays\"\r\n [enableWBS]=\"true\"\r\n [enableAutoWbsUpdate]=\"true\"\r\n [allowReordering]=\"true\"\r\n (toolbarClick)=\"onToolbarClick($event)\"\r\n (contextMenuOpen)=\"onContextMenuOpen($event)\"\r\n (contextMenuClick)=\"onContextMenuClick($event)\"\r\n (actionBegin)=\"onActionBegin($event)\"\r\n (actionComplete)=\"onActionComplete($event)\"\r\n (cellEdit)=\"onCellEdit($event)\"\r\n (queryTaskbarInfo)=\"onQueryTaskbarInfo($event)\"\r\n (dataBound)=\"onDataBound()\"\r\n >\r\n <ng-template #tooltipSettingsTaskbar let-data>\r\n <div class=\"px-2 py-1 text-xs\">\r\n <div class=\"font-medium\">{{ data?.title ?? '-' }}</div>\r\n <div>\r\n {{ tooltipTranslations().startsOn }}:\r\n {{ formatDateValue(data?.startDate) }}\r\n </div>\r\n <div>\r\n {{ tooltipTranslations().endsOn }}:\r\n {{ formatDateValue(data?.finishDate) }}\r\n </div>\r\n @if (data?.baselineStartDate) {\r\n <div>\r\n {{ tooltipTranslations().plannedStart }}:\r\n {{ formatDateValue(data?.baselineStartDate) }}\r\n </div>\r\n }\r\n @if (data?.baselineEndDate) {\r\n <div>\r\n {{ tooltipTranslations().plannedEnd }}:\r\n {{ formatDateValue(data?.baselineEndDate) }}\r\n </div>\r\n }\r\n <div>{{ tooltipTranslations().progress }}: {{ data?.progress ?? 0 }}</div>\r\n </div>\r\n </ng-template>\r\n\r\n <ng-template #taskbarTemplate let-data>\r\n <mt-task-schedule-taskbar-template [data]=\"data\" [langCode]=\"resolvedLangCode()\" />\r\n </ng-template>\r\n </ejs-gantt>\r\n} @else {\r\n <div class=\"task-schedule-loader\">\r\n <div class=\"task-schedule-loader__spinner\" aria-label=\"Loading\"></div>\r\n </div>\r\n}\r\n", styles: [":host{display:block}:host ::ng-deep .e-headercell .e-headercelldiv{height:auto;display:flex!important}:host ::ng-deep .e-custom-holiday{background-color:#0a0f32}:host ::ng-deep .e-gantt .e-gantt-chart .e-baseline-bar{height:7px!important;border-radius:3px}:host ::ng-deep .e-gantt .e-gantt-chart .e-gantt-child-taskbar-inner-div{height:17px!important}:host ::ng-deep .e-row{cursor:pointer!important}.task-schedule-loader{display:grid;place-items:center;min-height:18rem}.task-schedule-loader__spinner{width:2.25rem;height:2.25rem;border-radius:9999px;border:3px solid rgba(148,163,184,.3);border-top-color:#334155;animation:task-schedule-spin .8s linear infinite}@keyframes task-schedule-spin{to{transform:rotate(360deg)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: GanttModule }, { kind: "component", type: i1.GanttComponent, selector: "ejs-gantt", inputs: ["addDialogFields", "allowExcelExport", "allowFiltering", "allowKeyboard", "allowParentDependency", "allowPdfExport", "allowReordering", "allowResizing", "allowRowDragAndDrop", "allowSelection", "allowSorting", "allowTaskbarDragAndDrop", "allowTaskbarOverlap", "allowUnscheduledTasks", "autoCalculateDateScheduling", "autoFocusTasks", "baselineColor", "calendarSettings", "collapseAllParentTasks", "columnMenuItems", "columns", "connectorLineBackground", "connectorLineWidth", "contextMenuItems", "dataSource", "dateFormat", "dayWorkingTime", "disableHtmlEncode", "durationUnit", "editDialogFields", "editSettings", "emptyRecordTemplate", "enableAdaptiveUI", "enableAutoWbsUpdate", "enableContextMenu", "enableCriticalPath", "enableHover", "enableHtmlSanitizer", "enableImmutableMode", "enableMultiTaskbar", "enablePersistence", "enablePredecessorValidation", "enableRtl", "enableTimelineVirtualization", "enableUndoRedo", "enableVirtualMaskRow", "enableVirtualization", "enableWBS", "eventMarkers", "filterSettings", "frozenColumns", "gridLines", "height", "highlightWeekends", "holidays", "includeWeekend", "labelSettings", "loadChildOnDemand", "loadingIndicator", "locale", "milestoneTemplate", "parentTaskbarTemplate", "projectEndDate", "projectStartDate", "query", "readOnly", "renderBaseline", "resourceFields", "resourceIDMapping", "resourceNameMapping", "resources", "rowHeight", "searchSettings", "segmentData", "selectedRowIndex", "selectionSettings", "showColumnMenu", "showInlineNotes", "showOverAllocation", "sortSettings", "splitterSettings", "taskFields", "taskMode", "taskType", "taskbarHeight", "taskbarTemplate", "timelineSettings", "timelineTemplate", "timezone", "toolbar", "tooltipSettings", "treeColumnIndex", "undoRedoActions", "undoRedoStepsCount", "updateOffsetOnTaskbarEdit", "validateManualTasksOnLinking", "viewType", "weekWorkingTime", "width", "workUnit", "workWeek", "zoomingLevels"], outputs: ["actionBegin", "actionComplete", "actionFailure", "beforeDataBound", "beforeExcelExport", "beforePdfExport", "beforeTooltipRender", "cellDeselected", "cellDeselecting", "cellEdit", "cellSave", "cellSelected", "cellSelecting", "collapsed", "collapsing", "columnDrag", "columnDragStart", "columnDrop", "columnMenuClick", "columnMenuOpen", "contextMenuClick", "contextMenuOpen", "created", "dataBound", "dataStateChange", "destroyed", "endEdit", "excelExportComplete", "excelHeaderQueryCellInfo", "excelQueryCellInfo", "expanded", "expanding", "headerCellInfo", "load", "onMouseMove", "onTaskbarClick", "pdfColumnHeaderQueryCellInfo", "pdfExportComplete", "pdfQueryCellInfo", "pdfQueryTaskbarInfo", "pdfQueryTimelineCellInfo", "queryCellInfo", "queryTaskbarInfo", "recordDoubleClick", "resizeStart", "resizeStop", "resizing", "rowDataBound", "rowDeselected", "rowDeselecting", "rowDrag", "rowDragStart", "rowDragStartHelper", "rowDrop", "rowSelected", "rowSelecting", "splitterResizeStart", "splitterResized", "splitterResizing", "taskbarEdited", "taskbarEditing", "toolbarClick", "dataSourceChange"] }, { kind: "component", type: TaskScheduleTaskbarTemplate, selector: "mt-task-schedule-taskbar-template", inputs: ["data", "langCode"] }] });
|
|
2901
3375
|
}
|
|
2902
3376
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: TaskSchedule, decorators: [{
|
|
2903
3377
|
type: Component,
|
|
@@ -2913,18 +3387,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
|
|
|
2913
3387
|
ToolbarService,
|
|
2914
3388
|
ContextMenuService,
|
|
2915
3389
|
ResizeService,
|
|
2916
|
-
], template: "@if (!loading()) {\n <ejs-gantt\n #ganttObj\n [id]=\"ganttId\"\n [enableVirtualization]=\"true\"\n [enableTimelineVirtualization]=\"true\"\n [enableVirtualMaskRow]=\"false\"\n [allowResizing]=\"true\"\n [enableRtl]=\"enableRtl()\"\n [locale]=\"locale()\"\n [height]=\"
|
|
3390
|
+
], template: "@if (!loading()) {\r\n <ejs-gantt\r\n #ganttObj\r\n [id]=\"ganttId\"\r\n [enableVirtualization]=\"true\"\r\n [enableTimelineVirtualization]=\"true\"\r\n [enableVirtualMaskRow]=\"false\"\n [allowResizing]=\"true\"\n [enableRtl]=\"enableRtl()\"\n [locale]=\"locale()\"\n [height]=\"resolvedHeight()\"\n [dataSource]=\"dataSource()\"\r\n [taskFields]=\"ganttConfig().taskFields\"\r\n [columns]=\"ganttConfig().columns\"\r\n [renderBaseline]=\"ganttConfig().renderBaseline\"\r\n [enableCriticalPath]=\"ganttConfig().enableCriticalPath\"\r\n [allowSelection]=\"true\"\r\n [labelSettings]=\"ganttConfig().labelSettings\"\r\n [treeColumnIndex]=\"1\"\r\n [workWeek]=\"ganttConfig().workWeek\"\r\n [highlightWeekends]=\"true\"\r\n [enablePredecessorValidation]=\"true\"\r\n [splitterSettings]=\"ganttConfig().splitterSettings\"\r\n [gridLines]=\"ganttConfig().gridLines\"\r\n [toolbar]=\"ganttConfig().toolbar\"\r\n [allowExcelExport]=\"ganttConfig().allowExcelExport\"\r\n [allowPdfExport]=\"ganttConfig().allowPdfExport\"\r\n [enableContextMenu]=\"ganttConfig().enableContextMenu\"\r\n [contextMenuItems]=\"ganttConfig().contextMenuItems\"\r\n [timelineSettings]=\"ganttConfig().timelineSettings\"\r\n [editSettings]=\"ganttConfig().editSettings\"\r\n [addDialogFields]=\"ganttConfig().addDialogFields\"\r\n [editDialogFields]=\"ganttConfig().editDialogFields\"\r\n [resourceFields]=\"ganttConfig().resourceFields\"\r\n [resources]=\"ganttConfig().resources\"\r\n [viewType]=\"ganttConfig().viewType\"\r\n [showOverAllocation]=\"ganttConfig().showOverAllocation\"\r\n [allowUnscheduledTasks]=\"ganttConfig().allowUnscheduledTasks\"\r\n [eventMarkers]=\"ganttConfig().eventMarkers\"\r\n [projectStartDate]=\"ganttConfig().projectStartDate\"\r\n [projectEndDate]=\"ganttConfig().projectEndDate\"\r\n [autoCalculateDateScheduling]=\"false\"\r\n [dateFormat]=\"resolvedDateFormat()\"\n [allowSorting]=\"true\"\r\n [holidays]=\"ganttConfig().holidays\"\r\n [enableWBS]=\"true\"\r\n [enableAutoWbsUpdate]=\"true\"\r\n [allowReordering]=\"true\"\r\n (toolbarClick)=\"onToolbarClick($event)\"\r\n (contextMenuOpen)=\"onContextMenuOpen($event)\"\r\n (contextMenuClick)=\"onContextMenuClick($event)\"\r\n (actionBegin)=\"onActionBegin($event)\"\r\n (actionComplete)=\"onActionComplete($event)\"\r\n (cellEdit)=\"onCellEdit($event)\"\r\n (queryTaskbarInfo)=\"onQueryTaskbarInfo($event)\"\r\n (dataBound)=\"onDataBound()\"\r\n >\r\n <ng-template #tooltipSettingsTaskbar let-data>\r\n <div class=\"px-2 py-1 text-xs\">\r\n <div class=\"font-medium\">{{ data?.title ?? '-' }}</div>\r\n <div>\r\n {{ tooltipTranslations().startsOn }}:\r\n {{ formatDateValue(data?.startDate) }}\r\n </div>\r\n <div>\r\n {{ tooltipTranslations().endsOn }}:\r\n {{ formatDateValue(data?.finishDate) }}\r\n </div>\r\n @if (data?.baselineStartDate) {\r\n <div>\r\n {{ tooltipTranslations().plannedStart }}:\r\n {{ formatDateValue(data?.baselineStartDate) }}\r\n </div>\r\n }\r\n @if (data?.baselineEndDate) {\r\n <div>\r\n {{ tooltipTranslations().plannedEnd }}:\r\n {{ formatDateValue(data?.baselineEndDate) }}\r\n </div>\r\n }\r\n <div>{{ tooltipTranslations().progress }}: {{ data?.progress ?? 0 }}</div>\r\n </div>\r\n </ng-template>\r\n\r\n <ng-template #taskbarTemplate let-data>\r\n <mt-task-schedule-taskbar-template [data]=\"data\" [langCode]=\"resolvedLangCode()\" />\r\n </ng-template>\r\n </ejs-gantt>\r\n} @else {\r\n <div class=\"task-schedule-loader\">\r\n <div class=\"task-schedule-loader__spinner\" aria-label=\"Loading\"></div>\r\n </div>\r\n}\r\n", styles: [":host{display:block}:host ::ng-deep .e-headercell .e-headercelldiv{height:auto;display:flex!important}:host ::ng-deep .e-custom-holiday{background-color:#0a0f32}:host ::ng-deep .e-gantt .e-gantt-chart .e-baseline-bar{height:7px!important;border-radius:3px}:host ::ng-deep .e-gantt .e-gantt-chart .e-gantt-child-taskbar-inner-div{height:17px!important}:host ::ng-deep .e-row{cursor:pointer!important}.task-schedule-loader{display:grid;place-items:center;min-height:18rem}.task-schedule-loader__spinner{width:2.25rem;height:2.25rem;border-radius:9999px;border:3px solid rgba(148,163,184,.3);border-top-color:#334155;animation:task-schedule-spin .8s linear infinite}@keyframes task-schedule-spin{to{transform:rotate(360deg)}}\n"] }]
|
|
2917
3391
|
}], propDecorators: { ganttObj: [{
|
|
2918
3392
|
type: ViewChild,
|
|
2919
3393
|
args: ['ganttObj']
|
|
2920
|
-
}],
|
|
3394
|
+
}], context: [{ type: i0.Input, args: [{ isSignal: true, alias: "context", required: false }] }], toolbarAction: [{ type: i0.Output, args: ["toolbarAction"] }], actionBegin: [{ type: i0.Output, args: ["actionBegin"] }], actionCompleted: [{ type: i0.Output, args: ["actionCompleted"] }], loaded: [{ type: i0.Output, args: ["loaded"] }], loadError: [{ type: i0.Output, args: ["loadError"] }] } });
|
|
2921
3395
|
|
|
2922
3396
|
class TaskScheduleImportModal {
|
|
2923
3397
|
adapter = inject(TASK_SCHEDULE_DATA_ADAPTER, { optional: true }) ??
|
|
2924
3398
|
inject(TaskScheduleBackendAdapter);
|
|
2925
3399
|
visible = input(true, ...(ngDevMode ? [{ debugName: "visible" }] : []));
|
|
2926
3400
|
context = input(null, ...(ngDevMode ? [{ debugName: "context" }] : []));
|
|
2927
|
-
langCode = input(null, ...(ngDevMode ? [{ debugName: "langCode" }] : []));
|
|
2928
3401
|
title = input(null, ...(ngDevMode ? [{ debugName: "title" }] : []));
|
|
2929
3402
|
maxRows = input(400, ...(ngDevMode ? [{ debugName: "maxRows" }] : []));
|
|
2930
3403
|
closed = output();
|
|
@@ -2936,7 +3409,7 @@ class TaskScheduleImportModal {
|
|
|
2936
3409
|
loadingApply = signal(false, ...(ngDevMode ? [{ debugName: "loadingApply" }] : []));
|
|
2937
3410
|
importResult = signal(null, ...(ngDevMode ? [{ debugName: "importResult" }] : []));
|
|
2938
3411
|
selectedTaskKeys = signal(new Set(), ...(ngDevMode ? [{ debugName: "selectedTaskKeys" }] : []));
|
|
2939
|
-
resolvedLangCode = computed(() => resolveTaskScheduleLanguage(this.
|
|
3412
|
+
resolvedLangCode = computed(() => resolveTaskScheduleLanguage(this.context()?.langCode), ...(ngDevMode ? [{ debugName: "resolvedLangCode" }] : []));
|
|
2940
3413
|
isRtl = computed(() => this.resolvedLangCode() === 'ar', ...(ngDevMode ? [{ debugName: "isRtl" }] : []));
|
|
2941
3414
|
labels = computed(() => this.resolvedLangCode() === 'ar'
|
|
2942
3415
|
? {
|
|
@@ -3501,12 +3974,12 @@ class TaskScheduleImportModal {
|
|
|
3501
3974
|
this.failed.emit(message);
|
|
3502
3975
|
}
|
|
3503
3976
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: TaskScheduleImportModal, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3504
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: TaskScheduleImportModal, isStandalone: true, selector: "mt-task-schedule-import-modal", inputs: { visible: { classPropertyName: "visible", publicName: "visible", isSignal: true, isRequired: false, transformFunction: null }, context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: false, transformFunction: null }, langCode: { classPropertyName: "langCode", publicName: "langCode", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, maxRows: { classPropertyName: "maxRows", publicName: "maxRows", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed", imported: "imported", applied: "applied", failed: "failed" }, ngImport: i0, template: "@if (visible()) {\n <div class=\"fixed inset-0 z-[1000] grid place-items-center bg-slate-900/40 p-4\">\n <section\n class=\"w-full max-w-6xl overflow-hidden rounded-2xl bg-white shadow-2xl ring-1 ring-slate-200\"\n [attr.dir]=\"isRtl() ? 'rtl' : 'ltr'\"\n >\n <header class=\"flex items-center justify-between border-b border-slate-200 px-5 py-4\">\n <h2 class=\"text-base font-semibold text-slate-900\">\n {{ title() || labels().title }}\n </h2>\n\n <mt-button\n [label]=\"labels().cancel\"\n severity=\"secondary\"\n [text]=\"true\"\n (onClick)=\"close()\"\n />\n </header>\n\n <div class=\"space-y-4 p-5\">\n <div class=\"rounded-xl border border-slate-200 bg-slate-50 p-4\">\n <div class=\"flex flex-wrap items-center gap-3\">\n <label\n class=\"inline-flex cursor-pointer items-center rounded-lg border border-dashed border-slate-300 bg-white px-4 py-2 text-sm text-slate-700 hover:border-slate-400\"\n >\n <span>{{ labels().selectFile }}</span>\n <input\n class=\"hidden\"\n type=\"file\"\n accept=\".mpp,.xer\"\n (change)=\"onFileChanged($event)\"\n />\n </label>\n\n <span class=\"max-w-[22rem] truncate text-sm text-slate-500\">\n {{ selectedFile()?.name || '-' }}\n </span>\n\n <mt-button\n [label]=\"labels().startImport\"\n [disabled]=\"!canImport()\"\n [loading]=\"loadingImport()\"\n (onClick)=\"importFile()\"\n />\n </div>\n </div>\n\n @if (importResult(); as result) {\n @if (!previewRows().length) {\n <div class=\"rounded-lg border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-800\">\n {{ labels().noTasks }}\n </div>\n } @else {\n <div class=\"overflow-hidden rounded-xl border border-slate-200\">\n <div class=\"grid min-w-[1180px] grid-cols-[40px_minmax(220px,2fr)_minmax(130px,1fr)_minmax(130px,1fr)_minmax(130px,1fr)_minmax(130px,1fr)_minmax(190px,1.1fr)_minmax(120px,0.8fr)] border-b border-slate-200 bg-slate-100 px-3 py-2 text-xs font-semibold uppercase tracking-wide text-slate-600\">\n <label class=\"inline-flex items-center justify-center\">\n <input\n type=\"checkbox\"\n [checked]=\"allSelected()\"\n (change)=\"selectAllRows($any($event.target).checked)\"\n />\n </label>\n <div>{{ labels().task }}</div>\n <div>{{ labels().startDate }}</div>\n <div>{{ labels().finishDate }}</div>\n <div>{{ labels().actualStartDate }}</div>\n <div>{{ labels().actualFinishDate }}</div>\n <div>{{ labels().assignedTo }}</div>\n <div>{{ labels().progress }}</div>\n </div>\n\n <div class=\"max-h-[28rem] overflow-auto\">\n @for (row of previewRows(); track trackByRow($index, row)) {\n <div class=\"grid min-w-[1180px] grid-cols-[40px_minmax(220px,2fr)_minmax(130px,1fr)_minmax(130px,1fr)_minmax(130px,1fr)_minmax(130px,1fr)_minmax(190px,1.1fr)_minmax(120px,0.8fr)] items-center gap-x-2 border-b border-slate-100 px-3 py-2 text-sm\">\n <label class=\"inline-flex items-center justify-center\">\n <input\n type=\"checkbox\"\n [checked]=\"selectedTaskKeys().has(row.key)\"\n (change)=\"toggleRowSelection(row.key, $any($event.target).checked)\"\n />\n </label>\n\n <div class=\"min-w-0\" [style.paddingInlineStart.px]=\"row.depth * 18\">\n <input\n class=\"w-full rounded-md border border-slate-300 px-2 py-1 text-sm text-slate-700 outline-none focus:border-slate-400\"\n type=\"text\"\n [value]=\"row.task.title || row.task.name || ''\"\n (input)=\"onTaskTitleChanged(row.key, $any($event.target).value)\"\n />\n </div>\n\n <div>\n <input\n class=\"w-full rounded-md border border-slate-300 px-2 py-1 text-sm text-slate-700 outline-none focus:border-slate-400\"\n type=\"date\"\n [value]=\"toDateInputValue(row.task.startDate)\"\n (change)=\"onTaskDateChanged(row.key, 'startDate', $any($event.target).value)\"\n />\n </div>\n\n <div>\n <input\n class=\"w-full rounded-md border border-slate-300 px-2 py-1 text-sm text-slate-700 outline-none focus:border-slate-400\"\n type=\"date\"\n [value]=\"toDateInputValue(row.task.finishDate)\"\n (change)=\"onTaskDateChanged(row.key, 'finishDate', $any($event.target).value)\"\n />\n </div>\n\n <div>\n <input\n class=\"w-full rounded-md border border-slate-300 px-2 py-1 text-sm text-slate-700 outline-none focus:border-slate-400\"\n type=\"date\"\n [value]=\"toDateInputValue(row.task.actualStartDate || row.task.actualStart)\"\n (change)=\"onTaskDateChanged(row.key, 'actualStartDate', $any($event.target).value)\"\n />\n </div>\n\n <div>\n <input\n class=\"w-full rounded-md border border-slate-300 px-2 py-1 text-sm text-slate-700 outline-none focus:border-slate-400\"\n type=\"date\"\n [value]=\"toDateInputValue(row.task.actualFinishDate || row.task.actualFinish)\"\n (change)=\"onTaskDateChanged(row.key, 'actualFinishDate', $any($event.target).value)\"\n />\n </div>\n\n <div class=\"min-w-0\">\n @if (resourceOptions().length) {\n <div class=\"space-y-1\">\n <select\n class=\"w-full rounded-md border border-slate-300 px-2 py-1 text-sm text-slate-700 outline-none focus:border-slate-400\"\n [value]=\"resolveAssignedValue(row.task)\"\n (change)=\"onTaskAssignedToChanged(row.key, $any($event.target).value)\"\n >\n <option value=\"\">-</option>\n @for (option of resourceOptions(); track option.id) {\n <option [value]=\"option.id\">{{ option.label }}</option>\n }\n </select>\n @if (row.task.assignedTo) {\n <mt-entity-preview [data]=\"toAssignedEntity(row.task)\" />\n }\n </div>\n } @else if (row.task.assignedTo) {\n <mt-entity-preview [data]=\"toAssignedEntity(row.task)\" />\n } @else {\n <span class=\"text-slate-400\">-</span>\n }\n </div>\n\n <div>\n <div class=\"space-y-1\">\n <input\n class=\"w-full rounded-md border border-slate-300 px-2 py-1 text-sm text-slate-700 outline-none focus:border-slate-400\"\n type=\"number\"\n min=\"0\"\n max=\"100\"\n [value]=\"normalizeProgress(row.task.progress)\"\n (input)=\"onTaskProgressChanged(row.key, $any($event.target).value)\"\n />\n <mt-entity-preview [data]=\"toProgressEntity(row.task)\" />\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n\n @if (isTruncated()) {\n <p class=\"text-xs text-slate-500\">{{ labels().rowsLimited }}</p>\n }\n }\n }\n </div>\n\n <footer class=\"flex flex-wrap items-center justify-end gap-2 border-t border-slate-200 px-5 py-4\">\n <mt-button\n [label]=\"labels().cancel\"\n severity=\"secondary\"\n [outlined]=\"true\"\n (onClick)=\"close()\"\n />\n\n <mt-button\n [label]=\"labels().replace\"\n [disabled]=\"!canApply()\"\n [loading]=\"loadingApply()\"\n (onClick)=\"applyImport(true)\"\n />\n\n <mt-button\n [label]=\"labels().append\"\n severity=\"secondary\"\n [disabled]=\"!canApply()\"\n [loading]=\"loadingApply()\"\n (onClick)=\"applyImport(false)\"\n />\n </footer>\n </section>\n </div>\n}\r\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: EntityPreview, selector: "mt-entity-preview", inputs: ["data"] }] });
|
|
3977
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: TaskScheduleImportModal, isStandalone: true, selector: "mt-task-schedule-import-modal", inputs: { visible: { classPropertyName: "visible", publicName: "visible", isSignal: true, isRequired: false, transformFunction: null }, context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, maxRows: { classPropertyName: "maxRows", publicName: "maxRows", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed", imported: "imported", applied: "applied", failed: "failed" }, ngImport: i0, template: "@if (visible()) {\r\n <div class=\"fixed inset-0 z-[1000] grid place-items-center bg-slate-900/40 p-4\">\r\n <section\r\n class=\"w-full max-w-6xl overflow-hidden rounded-2xl bg-white shadow-2xl ring-1 ring-slate-200\"\r\n [attr.dir]=\"isRtl() ? 'rtl' : 'ltr'\"\r\n >\r\n <header class=\"flex items-center justify-between border-b border-slate-200 px-5 py-4\">\r\n <h2 class=\"text-base font-semibold text-slate-900\">\r\n {{ title() || labels().title }}\r\n </h2>\r\n\r\n <mt-button\r\n [label]=\"labels().cancel\"\r\n severity=\"secondary\"\r\n [text]=\"true\"\r\n (onClick)=\"close()\"\r\n />\r\n </header>\r\n\r\n <div class=\"space-y-4 p-5\">\r\n <div class=\"rounded-xl border border-slate-200 bg-slate-50 p-4\">\r\n <div class=\"flex flex-wrap items-center gap-3\">\r\n <label\r\n class=\"inline-flex cursor-pointer items-center rounded-lg border border-dashed border-slate-300 bg-white px-4 py-2 text-sm text-slate-700 hover:border-slate-400\"\r\n >\r\n <span>{{ labels().selectFile }}</span>\r\n <input\r\n class=\"hidden\"\r\n type=\"file\"\r\n accept=\".mpp,.xer\"\r\n (change)=\"onFileChanged($event)\"\r\n />\r\n </label>\r\n\r\n <span class=\"max-w-[22rem] truncate text-sm text-slate-500\">\r\n {{ selectedFile()?.name || '-' }}\r\n </span>\r\n\r\n <mt-button\r\n [label]=\"labels().startImport\"\r\n [disabled]=\"!canImport()\"\r\n [loading]=\"loadingImport()\"\r\n (onClick)=\"importFile()\"\r\n />\r\n </div>\r\n </div>\r\n\r\n @if (importResult(); as result) {\r\n @if (!previewRows().length) {\r\n <div class=\"rounded-lg border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-800\">\r\n {{ labels().noTasks }}\r\n </div>\r\n } @else {\r\n <div class=\"overflow-hidden rounded-xl border border-slate-200\">\r\n <div class=\"grid min-w-[1180px] grid-cols-[40px_minmax(220px,2fr)_minmax(130px,1fr)_minmax(130px,1fr)_minmax(130px,1fr)_minmax(130px,1fr)_minmax(190px,1.1fr)_minmax(120px,0.8fr)] border-b border-slate-200 bg-slate-100 px-3 py-2 text-xs font-semibold uppercase tracking-wide text-slate-600\">\r\n <label class=\"inline-flex items-center justify-center\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"allSelected()\"\r\n (change)=\"selectAllRows($any($event.target).checked)\"\r\n />\r\n </label>\r\n <div>{{ labels().task }}</div>\r\n <div>{{ labels().startDate }}</div>\r\n <div>{{ labels().finishDate }}</div>\r\n <div>{{ labels().actualStartDate }}</div>\r\n <div>{{ labels().actualFinishDate }}</div>\r\n <div>{{ labels().assignedTo }}</div>\r\n <div>{{ labels().progress }}</div>\r\n </div>\r\n\r\n <div class=\"max-h-[28rem] overflow-auto\">\r\n @for (row of previewRows(); track trackByRow($index, row)) {\r\n <div class=\"grid min-w-[1180px] grid-cols-[40px_minmax(220px,2fr)_minmax(130px,1fr)_minmax(130px,1fr)_minmax(130px,1fr)_minmax(130px,1fr)_minmax(190px,1.1fr)_minmax(120px,0.8fr)] items-center gap-x-2 border-b border-slate-100 px-3 py-2 text-sm\">\r\n <label class=\"inline-flex items-center justify-center\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"selectedTaskKeys().has(row.key)\"\r\n (change)=\"toggleRowSelection(row.key, $any($event.target).checked)\"\r\n />\r\n </label>\r\n\r\n <div class=\"min-w-0\" [style.paddingInlineStart.px]=\"row.depth * 18\">\r\n <input\r\n class=\"w-full rounded-md border border-slate-300 px-2 py-1 text-sm text-slate-700 outline-none focus:border-slate-400\"\r\n type=\"text\"\r\n [value]=\"row.task.title || row.task.name || ''\"\r\n (input)=\"onTaskTitleChanged(row.key, $any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n <div>\r\n <input\r\n class=\"w-full rounded-md border border-slate-300 px-2 py-1 text-sm text-slate-700 outline-none focus:border-slate-400\"\r\n type=\"date\"\r\n [value]=\"toDateInputValue(row.task.startDate)\"\r\n (change)=\"onTaskDateChanged(row.key, 'startDate', $any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n <div>\r\n <input\r\n class=\"w-full rounded-md border border-slate-300 px-2 py-1 text-sm text-slate-700 outline-none focus:border-slate-400\"\r\n type=\"date\"\r\n [value]=\"toDateInputValue(row.task.finishDate)\"\r\n (change)=\"onTaskDateChanged(row.key, 'finishDate', $any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n <div>\r\n <input\r\n class=\"w-full rounded-md border border-slate-300 px-2 py-1 text-sm text-slate-700 outline-none focus:border-slate-400\"\r\n type=\"date\"\r\n [value]=\"toDateInputValue(row.task.actualStartDate || row.task.actualStart)\"\r\n (change)=\"onTaskDateChanged(row.key, 'actualStartDate', $any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n <div>\r\n <input\r\n class=\"w-full rounded-md border border-slate-300 px-2 py-1 text-sm text-slate-700 outline-none focus:border-slate-400\"\r\n type=\"date\"\r\n [value]=\"toDateInputValue(row.task.actualFinishDate || row.task.actualFinish)\"\r\n (change)=\"onTaskDateChanged(row.key, 'actualFinishDate', $any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n <div class=\"min-w-0\">\r\n @if (resourceOptions().length) {\r\n <div class=\"space-y-1\">\r\n <select\r\n class=\"w-full rounded-md border border-slate-300 px-2 py-1 text-sm text-slate-700 outline-none focus:border-slate-400\"\r\n [value]=\"resolveAssignedValue(row.task)\"\r\n (change)=\"onTaskAssignedToChanged(row.key, $any($event.target).value)\"\r\n >\r\n <option value=\"\">-</option>\r\n @for (option of resourceOptions(); track option.id) {\r\n <option [value]=\"option.id\">{{ option.label }}</option>\r\n }\r\n </select>\r\n @if (row.task.assignedTo) {\r\n <mt-entity-preview [data]=\"toAssignedEntity(row.task)\" />\r\n }\r\n </div>\r\n } @else if (row.task.assignedTo) {\r\n <mt-entity-preview [data]=\"toAssignedEntity(row.task)\" />\r\n } @else {\r\n <span class=\"text-slate-400\">-</span>\r\n }\r\n </div>\r\n\r\n <div>\r\n <div class=\"space-y-1\">\r\n <input\r\n class=\"w-full rounded-md border border-slate-300 px-2 py-1 text-sm text-slate-700 outline-none focus:border-slate-400\"\r\n type=\"number\"\r\n min=\"0\"\r\n max=\"100\"\r\n [value]=\"normalizeProgress(row.task.progress)\"\r\n (input)=\"onTaskProgressChanged(row.key, $any($event.target).value)\"\r\n />\r\n <mt-entity-preview [data]=\"toProgressEntity(row.task)\" />\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n\r\n @if (isTruncated()) {\r\n <p class=\"text-xs text-slate-500\">{{ labels().rowsLimited }}</p>\r\n }\r\n }\r\n }\r\n </div>\r\n\r\n <footer class=\"flex flex-wrap items-center justify-end gap-2 border-t border-slate-200 px-5 py-4\">\r\n <mt-button\r\n [label]=\"labels().cancel\"\r\n severity=\"secondary\"\r\n [outlined]=\"true\"\r\n (onClick)=\"close()\"\r\n />\r\n\r\n <mt-button\r\n [label]=\"labels().replace\"\r\n [disabled]=\"!canApply()\"\r\n [loading]=\"loadingApply()\"\r\n (onClick)=\"applyImport(true)\"\r\n />\r\n\r\n <mt-button\r\n [label]=\"labels().append\"\r\n severity=\"secondary\"\r\n [disabled]=\"!canApply()\"\r\n [loading]=\"loadingApply()\"\r\n (onClick)=\"applyImport(false)\"\r\n />\r\n </footer>\r\n </section>\r\n </div>\r\n}\r\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: EntityPreview, selector: "mt-entity-preview", inputs: ["data"] }] });
|
|
3505
3978
|
}
|
|
3506
3979
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: TaskScheduleImportModal, decorators: [{
|
|
3507
3980
|
type: Component,
|
|
3508
|
-
args: [{ selector: 'mt-task-schedule-import-modal', standalone: true, imports: [CommonModule, Button, EntityPreview], template: "@if (visible()) {\n <div class=\"fixed inset-0 z-[1000] grid place-items-center bg-slate-900/40 p-4\">\n <section\n class=\"w-full max-w-6xl overflow-hidden rounded-2xl bg-white shadow-2xl ring-1 ring-slate-200\"\n [attr.dir]=\"isRtl() ? 'rtl' : 'ltr'\"\n >\n <header class=\"flex items-center justify-between border-b border-slate-200 px-5 py-4\">\n <h2 class=\"text-base font-semibold text-slate-900\">\n {{ title() || labels().title }}\n </h2>\n\n <mt-button\n [label]=\"labels().cancel\"\n severity=\"secondary\"\n [text]=\"true\"\n (onClick)=\"close()\"\n />\n </header>\n\n <div class=\"space-y-4 p-5\">\n <div class=\"rounded-xl border border-slate-200 bg-slate-50 p-4\">\n <div class=\"flex flex-wrap items-center gap-3\">\n <label\n class=\"inline-flex cursor-pointer items-center rounded-lg border border-dashed border-slate-300 bg-white px-4 py-2 text-sm text-slate-700 hover:border-slate-400\"\n >\n <span>{{ labels().selectFile }}</span>\n <input\n class=\"hidden\"\n type=\"file\"\n accept=\".mpp,.xer\"\n (change)=\"onFileChanged($event)\"\n />\n </label>\n\n <span class=\"max-w-[22rem] truncate text-sm text-slate-500\">\n {{ selectedFile()?.name || '-' }}\n </span>\n\n <mt-button\n [label]=\"labels().startImport\"\n [disabled]=\"!canImport()\"\n [loading]=\"loadingImport()\"\n (onClick)=\"importFile()\"\n />\n </div>\n </div>\n\n @if (importResult(); as result) {\n @if (!previewRows().length) {\n <div class=\"rounded-lg border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-800\">\n {{ labels().noTasks }}\n </div>\n } @else {\n <div class=\"overflow-hidden rounded-xl border border-slate-200\">\n <div class=\"grid min-w-[1180px] grid-cols-[40px_minmax(220px,2fr)_minmax(130px,1fr)_minmax(130px,1fr)_minmax(130px,1fr)_minmax(130px,1fr)_minmax(190px,1.1fr)_minmax(120px,0.8fr)] border-b border-slate-200 bg-slate-100 px-3 py-2 text-xs font-semibold uppercase tracking-wide text-slate-600\">\n <label class=\"inline-flex items-center justify-center\">\n <input\n type=\"checkbox\"\n [checked]=\"allSelected()\"\n (change)=\"selectAllRows($any($event.target).checked)\"\n />\n </label>\n <div>{{ labels().task }}</div>\n <div>{{ labels().startDate }}</div>\n <div>{{ labels().finishDate }}</div>\n <div>{{ labels().actualStartDate }}</div>\n <div>{{ labels().actualFinishDate }}</div>\n <div>{{ labels().assignedTo }}</div>\n <div>{{ labels().progress }}</div>\n </div>\n\n <div class=\"max-h-[28rem] overflow-auto\">\n @for (row of previewRows(); track trackByRow($index, row)) {\n <div class=\"grid min-w-[1180px] grid-cols-[40px_minmax(220px,2fr)_minmax(130px,1fr)_minmax(130px,1fr)_minmax(130px,1fr)_minmax(130px,1fr)_minmax(190px,1.1fr)_minmax(120px,0.8fr)] items-center gap-x-2 border-b border-slate-100 px-3 py-2 text-sm\">\n <label class=\"inline-flex items-center justify-center\">\n <input\n type=\"checkbox\"\n [checked]=\"selectedTaskKeys().has(row.key)\"\n (change)=\"toggleRowSelection(row.key, $any($event.target).checked)\"\n />\n </label>\n\n <div class=\"min-w-0\" [style.paddingInlineStart.px]=\"row.depth * 18\">\n <input\n class=\"w-full rounded-md border border-slate-300 px-2 py-1 text-sm text-slate-700 outline-none focus:border-slate-400\"\n type=\"text\"\n [value]=\"row.task.title || row.task.name || ''\"\n (input)=\"onTaskTitleChanged(row.key, $any($event.target).value)\"\n />\n </div>\n\n <div>\n <input\n class=\"w-full rounded-md border border-slate-300 px-2 py-1 text-sm text-slate-700 outline-none focus:border-slate-400\"\n type=\"date\"\n [value]=\"toDateInputValue(row.task.startDate)\"\n (change)=\"onTaskDateChanged(row.key, 'startDate', $any($event.target).value)\"\n />\n </div>\n\n <div>\n <input\n class=\"w-full rounded-md border border-slate-300 px-2 py-1 text-sm text-slate-700 outline-none focus:border-slate-400\"\n type=\"date\"\n [value]=\"toDateInputValue(row.task.finishDate)\"\n (change)=\"onTaskDateChanged(row.key, 'finishDate', $any($event.target).value)\"\n />\n </div>\n\n <div>\n <input\n class=\"w-full rounded-md border border-slate-300 px-2 py-1 text-sm text-slate-700 outline-none focus:border-slate-400\"\n type=\"date\"\n [value]=\"toDateInputValue(row.task.actualStartDate || row.task.actualStart)\"\n (change)=\"onTaskDateChanged(row.key, 'actualStartDate', $any($event.target).value)\"\n />\n </div>\n\n <div>\n <input\n class=\"w-full rounded-md border border-slate-300 px-2 py-1 text-sm text-slate-700 outline-none focus:border-slate-400\"\n type=\"date\"\n [value]=\"toDateInputValue(row.task.actualFinishDate || row.task.actualFinish)\"\n (change)=\"onTaskDateChanged(row.key, 'actualFinishDate', $any($event.target).value)\"\n />\n </div>\n\n <div class=\"min-w-0\">\n @if (resourceOptions().length) {\n <div class=\"space-y-1\">\n <select\n class=\"w-full rounded-md border border-slate-300 px-2 py-1 text-sm text-slate-700 outline-none focus:border-slate-400\"\n [value]=\"resolveAssignedValue(row.task)\"\n (change)=\"onTaskAssignedToChanged(row.key, $any($event.target).value)\"\n >\n <option value=\"\">-</option>\n @for (option of resourceOptions(); track option.id) {\n <option [value]=\"option.id\">{{ option.label }}</option>\n }\n </select>\n @if (row.task.assignedTo) {\n <mt-entity-preview [data]=\"toAssignedEntity(row.task)\" />\n }\n </div>\n } @else if (row.task.assignedTo) {\n <mt-entity-preview [data]=\"toAssignedEntity(row.task)\" />\n } @else {\n <span class=\"text-slate-400\">-</span>\n }\n </div>\n\n <div>\n <div class=\"space-y-1\">\n <input\n class=\"w-full rounded-md border border-slate-300 px-2 py-1 text-sm text-slate-700 outline-none focus:border-slate-400\"\n type=\"number\"\n min=\"0\"\n max=\"100\"\n [value]=\"normalizeProgress(row.task.progress)\"\n (input)=\"onTaskProgressChanged(row.key, $any($event.target).value)\"\n />\n <mt-entity-preview [data]=\"toProgressEntity(row.task)\" />\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n\n @if (isTruncated()) {\n <p class=\"text-xs text-slate-500\">{{ labels().rowsLimited }}</p>\n }\n }\n }\n </div>\n\n <footer class=\"flex flex-wrap items-center justify-end gap-2 border-t border-slate-200 px-5 py-4\">\n <mt-button\n [label]=\"labels().cancel\"\n severity=\"secondary\"\n [outlined]=\"true\"\n (onClick)=\"close()\"\n />\n\n <mt-button\n [label]=\"labels().replace\"\n [disabled]=\"!canApply()\"\n [loading]=\"loadingApply()\"\n (onClick)=\"applyImport(true)\"\n />\n\n <mt-button\n [label]=\"labels().append\"\n severity=\"secondary\"\n [disabled]=\"!canApply()\"\n [loading]=\"loadingApply()\"\n (onClick)=\"applyImport(false)\"\n />\n </footer>\n </section>\n </div>\n}\r\n", styles: [":host{display:block}\n"] }]
|
|
3509
|
-
}], propDecorators: { visible: [{ type: i0.Input, args: [{ isSignal: true, alias: "visible", required: false }] }], context: [{ type: i0.Input, args: [{ isSignal: true, alias: "context", required: false }] }],
|
|
3981
|
+
args: [{ selector: 'mt-task-schedule-import-modal', standalone: true, imports: [CommonModule, Button, EntityPreview], template: "@if (visible()) {\r\n <div class=\"fixed inset-0 z-[1000] grid place-items-center bg-slate-900/40 p-4\">\r\n <section\r\n class=\"w-full max-w-6xl overflow-hidden rounded-2xl bg-white shadow-2xl ring-1 ring-slate-200\"\r\n [attr.dir]=\"isRtl() ? 'rtl' : 'ltr'\"\r\n >\r\n <header class=\"flex items-center justify-between border-b border-slate-200 px-5 py-4\">\r\n <h2 class=\"text-base font-semibold text-slate-900\">\r\n {{ title() || labels().title }}\r\n </h2>\r\n\r\n <mt-button\r\n [label]=\"labels().cancel\"\r\n severity=\"secondary\"\r\n [text]=\"true\"\r\n (onClick)=\"close()\"\r\n />\r\n </header>\r\n\r\n <div class=\"space-y-4 p-5\">\r\n <div class=\"rounded-xl border border-slate-200 bg-slate-50 p-4\">\r\n <div class=\"flex flex-wrap items-center gap-3\">\r\n <label\r\n class=\"inline-flex cursor-pointer items-center rounded-lg border border-dashed border-slate-300 bg-white px-4 py-2 text-sm text-slate-700 hover:border-slate-400\"\r\n >\r\n <span>{{ labels().selectFile }}</span>\r\n <input\r\n class=\"hidden\"\r\n type=\"file\"\r\n accept=\".mpp,.xer\"\r\n (change)=\"onFileChanged($event)\"\r\n />\r\n </label>\r\n\r\n <span class=\"max-w-[22rem] truncate text-sm text-slate-500\">\r\n {{ selectedFile()?.name || '-' }}\r\n </span>\r\n\r\n <mt-button\r\n [label]=\"labels().startImport\"\r\n [disabled]=\"!canImport()\"\r\n [loading]=\"loadingImport()\"\r\n (onClick)=\"importFile()\"\r\n />\r\n </div>\r\n </div>\r\n\r\n @if (importResult(); as result) {\r\n @if (!previewRows().length) {\r\n <div class=\"rounded-lg border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-800\">\r\n {{ labels().noTasks }}\r\n </div>\r\n } @else {\r\n <div class=\"overflow-hidden rounded-xl border border-slate-200\">\r\n <div class=\"grid min-w-[1180px] grid-cols-[40px_minmax(220px,2fr)_minmax(130px,1fr)_minmax(130px,1fr)_minmax(130px,1fr)_minmax(130px,1fr)_minmax(190px,1.1fr)_minmax(120px,0.8fr)] border-b border-slate-200 bg-slate-100 px-3 py-2 text-xs font-semibold uppercase tracking-wide text-slate-600\">\r\n <label class=\"inline-flex items-center justify-center\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"allSelected()\"\r\n (change)=\"selectAllRows($any($event.target).checked)\"\r\n />\r\n </label>\r\n <div>{{ labels().task }}</div>\r\n <div>{{ labels().startDate }}</div>\r\n <div>{{ labels().finishDate }}</div>\r\n <div>{{ labels().actualStartDate }}</div>\r\n <div>{{ labels().actualFinishDate }}</div>\r\n <div>{{ labels().assignedTo }}</div>\r\n <div>{{ labels().progress }}</div>\r\n </div>\r\n\r\n <div class=\"max-h-[28rem] overflow-auto\">\r\n @for (row of previewRows(); track trackByRow($index, row)) {\r\n <div class=\"grid min-w-[1180px] grid-cols-[40px_minmax(220px,2fr)_minmax(130px,1fr)_minmax(130px,1fr)_minmax(130px,1fr)_minmax(130px,1fr)_minmax(190px,1.1fr)_minmax(120px,0.8fr)] items-center gap-x-2 border-b border-slate-100 px-3 py-2 text-sm\">\r\n <label class=\"inline-flex items-center justify-center\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"selectedTaskKeys().has(row.key)\"\r\n (change)=\"toggleRowSelection(row.key, $any($event.target).checked)\"\r\n />\r\n </label>\r\n\r\n <div class=\"min-w-0\" [style.paddingInlineStart.px]=\"row.depth * 18\">\r\n <input\r\n class=\"w-full rounded-md border border-slate-300 px-2 py-1 text-sm text-slate-700 outline-none focus:border-slate-400\"\r\n type=\"text\"\r\n [value]=\"row.task.title || row.task.name || ''\"\r\n (input)=\"onTaskTitleChanged(row.key, $any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n <div>\r\n <input\r\n class=\"w-full rounded-md border border-slate-300 px-2 py-1 text-sm text-slate-700 outline-none focus:border-slate-400\"\r\n type=\"date\"\r\n [value]=\"toDateInputValue(row.task.startDate)\"\r\n (change)=\"onTaskDateChanged(row.key, 'startDate', $any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n <div>\r\n <input\r\n class=\"w-full rounded-md border border-slate-300 px-2 py-1 text-sm text-slate-700 outline-none focus:border-slate-400\"\r\n type=\"date\"\r\n [value]=\"toDateInputValue(row.task.finishDate)\"\r\n (change)=\"onTaskDateChanged(row.key, 'finishDate', $any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n <div>\r\n <input\r\n class=\"w-full rounded-md border border-slate-300 px-2 py-1 text-sm text-slate-700 outline-none focus:border-slate-400\"\r\n type=\"date\"\r\n [value]=\"toDateInputValue(row.task.actualStartDate || row.task.actualStart)\"\r\n (change)=\"onTaskDateChanged(row.key, 'actualStartDate', $any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n <div>\r\n <input\r\n class=\"w-full rounded-md border border-slate-300 px-2 py-1 text-sm text-slate-700 outline-none focus:border-slate-400\"\r\n type=\"date\"\r\n [value]=\"toDateInputValue(row.task.actualFinishDate || row.task.actualFinish)\"\r\n (change)=\"onTaskDateChanged(row.key, 'actualFinishDate', $any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n <div class=\"min-w-0\">\r\n @if (resourceOptions().length) {\r\n <div class=\"space-y-1\">\r\n <select\r\n class=\"w-full rounded-md border border-slate-300 px-2 py-1 text-sm text-slate-700 outline-none focus:border-slate-400\"\r\n [value]=\"resolveAssignedValue(row.task)\"\r\n (change)=\"onTaskAssignedToChanged(row.key, $any($event.target).value)\"\r\n >\r\n <option value=\"\">-</option>\r\n @for (option of resourceOptions(); track option.id) {\r\n <option [value]=\"option.id\">{{ option.label }}</option>\r\n }\r\n </select>\r\n @if (row.task.assignedTo) {\r\n <mt-entity-preview [data]=\"toAssignedEntity(row.task)\" />\r\n }\r\n </div>\r\n } @else if (row.task.assignedTo) {\r\n <mt-entity-preview [data]=\"toAssignedEntity(row.task)\" />\r\n } @else {\r\n <span class=\"text-slate-400\">-</span>\r\n }\r\n </div>\r\n\r\n <div>\r\n <div class=\"space-y-1\">\r\n <input\r\n class=\"w-full rounded-md border border-slate-300 px-2 py-1 text-sm text-slate-700 outline-none focus:border-slate-400\"\r\n type=\"number\"\r\n min=\"0\"\r\n max=\"100\"\r\n [value]=\"normalizeProgress(row.task.progress)\"\r\n (input)=\"onTaskProgressChanged(row.key, $any($event.target).value)\"\r\n />\r\n <mt-entity-preview [data]=\"toProgressEntity(row.task)\" />\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n\r\n @if (isTruncated()) {\r\n <p class=\"text-xs text-slate-500\">{{ labels().rowsLimited }}</p>\r\n }\r\n }\r\n }\r\n </div>\r\n\r\n <footer class=\"flex flex-wrap items-center justify-end gap-2 border-t border-slate-200 px-5 py-4\">\r\n <mt-button\r\n [label]=\"labels().cancel\"\r\n severity=\"secondary\"\r\n [outlined]=\"true\"\r\n (onClick)=\"close()\"\r\n />\r\n\r\n <mt-button\r\n [label]=\"labels().replace\"\r\n [disabled]=\"!canApply()\"\r\n [loading]=\"loadingApply()\"\r\n (onClick)=\"applyImport(true)\"\r\n />\r\n\r\n <mt-button\r\n [label]=\"labels().append\"\r\n severity=\"secondary\"\r\n [disabled]=\"!canApply()\"\r\n [loading]=\"loadingApply()\"\r\n (onClick)=\"applyImport(false)\"\r\n />\r\n </footer>\r\n </section>\r\n </div>\r\n}\r\n", styles: [":host{display:block}\n"] }]
|
|
3982
|
+
}], propDecorators: { visible: [{ type: i0.Input, args: [{ isSignal: true, alias: "visible", required: false }] }], context: [{ type: i0.Input, args: [{ isSignal: true, alias: "context", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], maxRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxRows", required: false }] }], closed: [{ type: i0.Output, args: ["closed"] }], imported: [{ type: i0.Output, args: ["imported"] }], applied: [{ type: i0.Output, args: ["applied"] }], failed: [{ type: i0.Output, args: ["failed"] }] } });
|
|
3510
3983
|
|
|
3511
3984
|
const DEFAULT_MODES = [
|
|
3512
3985
|
{ value: 'default' },
|
|
@@ -3522,16 +3995,6 @@ class TaskScheduleShell {
|
|
|
3522
3995
|
inject(TaskScheduleBackendAdapter);
|
|
3523
3996
|
queueService = inject(TaskScheduleQueueService);
|
|
3524
3997
|
context = input(null, ...(ngDevMode ? [{ debugName: "context" }] : []));
|
|
3525
|
-
langCode = input(null, ...(ngDevMode ? [{ debugName: "langCode" }] : []));
|
|
3526
|
-
dateFormat = input('dd/MM/yyyy', ...(ngDevMode ? [{ debugName: "dateFormat" }] : []));
|
|
3527
|
-
height = input('760px', ...(ngDevMode ? [{ debugName: "height" }] : []));
|
|
3528
|
-
modelType = input('default', ...(ngDevMode ? [{ debugName: "modelType" }] : []));
|
|
3529
|
-
modeOptions = input(null, ...(ngDevMode ? [{ debugName: "modeOptions" }] : []));
|
|
3530
|
-
allowEditMode = input(true, ...(ngDevMode ? [{ debugName: "allowEditMode" }] : []));
|
|
3531
|
-
allowImport = input(true, ...(ngDevMode ? [{ debugName: "allowImport" }] : []));
|
|
3532
|
-
allowSetBaseline = input(true, ...(ngDevMode ? [{ debugName: "allowSetBaseline" }] : []));
|
|
3533
|
-
hasTasks = input(true, ...(ngDevMode ? [{ debugName: "hasTasks" }] : []));
|
|
3534
|
-
baselinePending = input(false, ...(ngDevMode ? [{ debugName: "baselinePending" }] : []));
|
|
3535
3998
|
modeChanged = output();
|
|
3536
3999
|
baselineSet = output();
|
|
3537
4000
|
tasksExported = output();
|
|
@@ -3540,7 +4003,17 @@ class TaskScheduleShell {
|
|
|
3540
4003
|
showImportModal = signal(false, ...(ngDevMode ? [{ debugName: "showImportModal" }] : []));
|
|
3541
4004
|
settingBaseline = signal(false, ...(ngDevMode ? [{ debugName: "settingBaseline" }] : []));
|
|
3542
4005
|
exportingTasks = signal(false, ...(ngDevMode ? [{ debugName: "exportingTasks" }] : []));
|
|
3543
|
-
resolvedLangCode = computed(() => resolveTaskScheduleLanguage(this.
|
|
4006
|
+
resolvedLangCode = computed(() => resolveTaskScheduleLanguage(this.context()?.langCode), ...(ngDevMode ? [{ debugName: "resolvedLangCode" }] : []));
|
|
4007
|
+
resolvedContext = computed(() => {
|
|
4008
|
+
const context = this.context();
|
|
4009
|
+
if (!context) {
|
|
4010
|
+
return null;
|
|
4011
|
+
}
|
|
4012
|
+
return {
|
|
4013
|
+
...context,
|
|
4014
|
+
modelType: this.currentModelType(),
|
|
4015
|
+
};
|
|
4016
|
+
}, ...(ngDevMode ? [{ debugName: "resolvedContext" }] : []));
|
|
3544
4017
|
labels = computed(() => this.resolvedLangCode() === 'ar'
|
|
3545
4018
|
? {
|
|
3546
4019
|
mode: 'الوضع',
|
|
@@ -3568,29 +4041,30 @@ class TaskScheduleShell {
|
|
|
3568
4041
|
}, ...(ngDevMode ? [{ debugName: "labels" }] : []));
|
|
3569
4042
|
currentModelKey = computed(() => normalizeTaskScheduleModelType(this.currentModelType()), ...(ngDevMode ? [{ debugName: "currentModelKey" }] : []));
|
|
3570
4043
|
resolvedModes = computed(() => {
|
|
3571
|
-
const modes = this.
|
|
4044
|
+
const modes = this.context()?.modeOptions;
|
|
3572
4045
|
const source = modes?.length ? modes : DEFAULT_MODES;
|
|
3573
4046
|
return source
|
|
3574
|
-
.filter((item) => this.
|
|
4047
|
+
.filter((item) => (this.context()?.allowEditMode ?? true) ||
|
|
4048
|
+
normalizeTaskScheduleModelType(item.value) !== 'edit')
|
|
3575
4049
|
.map((item) => ({
|
|
3576
4050
|
value: item.value,
|
|
3577
4051
|
label: item.label || this.resolveModeLabel(item.value),
|
|
3578
4052
|
}));
|
|
3579
4053
|
}, ...(ngDevMode ? [{ debugName: "resolvedModes" }] : []));
|
|
3580
|
-
showSetBaselineAction = computed(() => this.
|
|
4054
|
+
showSetBaselineAction = computed(() => (this.context()?.allowSetBaseline ?? true) &&
|
|
3581
4055
|
(this.currentModelKey() === 'default' || this.currentModelKey() === 'edit'), ...(ngDevMode ? [{ debugName: "showSetBaselineAction" }] : []));
|
|
3582
4056
|
canSetBaselineAction = computed(() => this.showSetBaselineAction() &&
|
|
3583
4057
|
!!this.context() &&
|
|
3584
4058
|
!!this.adapter.setBaseline &&
|
|
3585
4059
|
!this.settingBaseline() &&
|
|
3586
|
-
!this.
|
|
3587
|
-
this.
|
|
3588
|
-
showImportAction = computed(() => this.
|
|
4060
|
+
!(this.context()?.baselinePending ?? false) &&
|
|
4061
|
+
(this.context()?.hasTasks ?? true), ...(ngDevMode ? [{ debugName: "canSetBaselineAction" }] : []));
|
|
4062
|
+
showImportAction = computed(() => (this.context()?.allowImport ?? true) && this.currentModelKey() === 'edit', ...(ngDevMode ? [{ debugName: "showImportAction" }] : []));
|
|
3589
4063
|
canOpenImport = computed(() => this.showImportAction() && !!this.context(), ...(ngDevMode ? [{ debugName: "canOpenImport" }] : []));
|
|
3590
4064
|
canExportTasks = computed(() => !!this.context() && !!this.adapter.exportTasks && !this.exportingTasks(), ...(ngDevMode ? [{ debugName: "canExportTasks" }] : []));
|
|
3591
4065
|
constructor() {
|
|
3592
4066
|
effect(() => {
|
|
3593
|
-
this.currentModelType.set(this.
|
|
4067
|
+
this.currentModelType.set(this.context()?.modelType ?? 'default');
|
|
3594
4068
|
});
|
|
3595
4069
|
}
|
|
3596
4070
|
onModeChange(nextValue) {
|
|
@@ -3717,12 +4191,12 @@ class TaskScheduleShell {
|
|
|
3717
4191
|
this.actionError.emit(message);
|
|
3718
4192
|
}
|
|
3719
4193
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: TaskScheduleShell, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3720
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: TaskScheduleShell, isStandalone: true, selector: "mt-task-schedule-shell", inputs: { context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: false, transformFunction: null }
|
|
4194
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: TaskScheduleShell, isStandalone: true, selector: "mt-task-schedule-shell", inputs: { context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { modeChanged: "modeChanged", baselineSet: "baselineSet", tasksExported: "tasksExported", actionError: "actionError" }, ngImport: i0, template: "<div class=\"task-schedule-shell\" [attr.dir]=\"resolvedLangCode() === 'ar' ? 'rtl' : 'ltr'\">\r\n <header class=\"task-schedule-shell__header\">\r\n <div class=\"task-schedule-shell__mode\">\r\n <label class=\"task-schedule-shell__label\">{{ labels().mode }}</label>\r\n <select\r\n class=\"task-schedule-shell__select\"\r\n [value]=\"currentModelType()\"\r\n (change)=\"onModeChange($any($event.target).value)\"\r\n >\r\n @for (mode of resolvedModes(); track mode.value) {\r\n <option [value]=\"mode.value\">{{ mode.label }}</option>\r\n }\r\n </select>\r\n </div>\r\n\r\n <div class=\"task-schedule-shell__actions\">\r\n @if (showSetBaselineAction()) {\r\n <button\r\n type=\"button\"\r\n class=\"task-schedule-shell__btn\"\r\n [disabled]=\"!canSetBaselineAction()\"\r\n (click)=\"setBaseline()\"\r\n >\r\n {{ baselinePending() ? labels().pending : labels().setBaseline }}\r\n </button>\r\n }\r\n\r\n @if (showImportAction()) {\r\n <button\r\n type=\"button\"\r\n class=\"task-schedule-shell__btn\"\r\n [disabled]=\"!canOpenImport()\"\r\n (click)=\"openImportModal()\"\r\n >\r\n {{ labels().import }}\r\n </button>\r\n }\r\n\r\n <button\r\n type=\"button\"\r\n class=\"task-schedule-shell__btn\"\r\n [disabled]=\"!canExportTasks()\"\r\n (click)=\"exportTasks()\"\r\n >\r\n {{ labels().export }}\r\n </button>\r\n </div>\r\n </header>\r\n\r\n <mt-task-schedule\n [context]=\"resolvedContext()\"\n (loadError)=\"onActionError($event)\"\n />\n\n @if (showImportModal()) {\n <mt-task-schedule-import-modal\n [visible]=\"showImportModal()\"\n [context]=\"resolvedContext()\"\n (closed)=\"closeImportModal()\"\n (failed)=\"onActionError($event)\"\n (applied)=\"onImportedTasksApplied()\"\n />\r\n }\r\n</div>\r\n", styles: [":host{display:block}.task-schedule-shell{display:flex;flex-direction:column;gap:12px}.task-schedule-shell__header{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:10px}.task-schedule-shell__mode{display:flex;align-items:center;gap:8px}.task-schedule-shell__label{color:#334155;font-size:13px;font-weight:600}.task-schedule-shell__select{border:1px solid #cbd5e1;border-radius:8px;height:36px;padding:0 10px;min-width:180px;background-color:#fff}.task-schedule-shell__actions{display:flex;flex-wrap:wrap;gap:8px}.task-schedule-shell__btn{border:1px solid #14b8a6;background:#14b8a6;color:#fff;border-radius:999px;padding:7px 14px;font-size:13px;font-weight:600;cursor:pointer}.task-schedule-shell__btn:disabled{opacity:.55;cursor:not-allowed}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: TaskSchedule, selector: "mt-task-schedule", inputs: ["context"], outputs: ["toolbarAction", "actionBegin", "actionCompleted", "loaded", "loadError"] }, { kind: "component", type: TaskScheduleImportModal, selector: "mt-task-schedule-import-modal", inputs: ["visible", "context", "title", "maxRows"], outputs: ["closed", "imported", "applied", "failed"] }] });
|
|
3721
4195
|
}
|
|
3722
4196
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: TaskScheduleShell, decorators: [{
|
|
3723
4197
|
type: Component,
|
|
3724
|
-
args: [{ selector: 'mt-task-schedule-shell', standalone: true, imports: [CommonModule, TaskSchedule, TaskScheduleImportModal], template: "<div class=\"task-schedule-shell\" [attr.dir]=\"resolvedLangCode() === 'ar' ? 'rtl' : 'ltr'\">\n <header class=\"task-schedule-shell__header\">\n <div class=\"task-schedule-shell__mode\">\n <label class=\"task-schedule-shell__label\">{{ labels().mode }}</label>\n <select\n class=\"task-schedule-shell__select\"\n [value]=\"currentModelType()\"\n (change)=\"onModeChange($any($event.target).value)\"\n >\n @for (mode of resolvedModes(); track mode.value) {\n <option [value]=\"mode.value\">{{ mode.label }}</option>\n }\n </select>\n </div>\n\n <div class=\"task-schedule-shell__actions\">\n @if (showSetBaselineAction()) {\n <button\n type=\"button\"\n class=\"task-schedule-shell__btn\"\n [disabled]=\"!canSetBaselineAction()\"\n (click)=\"setBaseline()\"\n >\n {{ baselinePending() ? labels().pending : labels().setBaseline }}\n </button>\n }\n\n @if (showImportAction()) {\n <button\n type=\"button\"\n class=\"task-schedule-shell__btn\"\n [disabled]=\"!canOpenImport()\"\n (click)=\"openImportModal()\"\n >\n {{ labels().import }}\n </button>\n }\n\n <button\n type=\"button\"\n class=\"task-schedule-shell__btn\"\n [disabled]=\"!canExportTasks()\"\n (click)=\"exportTasks()\"\n >\n {{ labels().export }}\n </button>\n </div>\n </header>\n\n <mt-task-schedule\n [
|
|
3725
|
-
}], ctorParameters: () => [], propDecorators: { context: [{ type: i0.Input, args: [{ isSignal: true, alias: "context", required: false }] }],
|
|
4198
|
+
args: [{ selector: 'mt-task-schedule-shell', standalone: true, imports: [CommonModule, TaskSchedule, TaskScheduleImportModal], template: "<div class=\"task-schedule-shell\" [attr.dir]=\"resolvedLangCode() === 'ar' ? 'rtl' : 'ltr'\">\r\n <header class=\"task-schedule-shell__header\">\r\n <div class=\"task-schedule-shell__mode\">\r\n <label class=\"task-schedule-shell__label\">{{ labels().mode }}</label>\r\n <select\r\n class=\"task-schedule-shell__select\"\r\n [value]=\"currentModelType()\"\r\n (change)=\"onModeChange($any($event.target).value)\"\r\n >\r\n @for (mode of resolvedModes(); track mode.value) {\r\n <option [value]=\"mode.value\">{{ mode.label }}</option>\r\n }\r\n </select>\r\n </div>\r\n\r\n <div class=\"task-schedule-shell__actions\">\r\n @if (showSetBaselineAction()) {\r\n <button\r\n type=\"button\"\r\n class=\"task-schedule-shell__btn\"\r\n [disabled]=\"!canSetBaselineAction()\"\r\n (click)=\"setBaseline()\"\r\n >\r\n {{ baselinePending() ? labels().pending : labels().setBaseline }}\r\n </button>\r\n }\r\n\r\n @if (showImportAction()) {\r\n <button\r\n type=\"button\"\r\n class=\"task-schedule-shell__btn\"\r\n [disabled]=\"!canOpenImport()\"\r\n (click)=\"openImportModal()\"\r\n >\r\n {{ labels().import }}\r\n </button>\r\n }\r\n\r\n <button\r\n type=\"button\"\r\n class=\"task-schedule-shell__btn\"\r\n [disabled]=\"!canExportTasks()\"\r\n (click)=\"exportTasks()\"\r\n >\r\n {{ labels().export }}\r\n </button>\r\n </div>\r\n </header>\r\n\r\n <mt-task-schedule\n [context]=\"resolvedContext()\"\n (loadError)=\"onActionError($event)\"\n />\n\n @if (showImportModal()) {\n <mt-task-schedule-import-modal\n [visible]=\"showImportModal()\"\n [context]=\"resolvedContext()\"\n (closed)=\"closeImportModal()\"\n (failed)=\"onActionError($event)\"\n (applied)=\"onImportedTasksApplied()\"\n />\r\n }\r\n</div>\r\n", styles: [":host{display:block}.task-schedule-shell{display:flex;flex-direction:column;gap:12px}.task-schedule-shell__header{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:10px}.task-schedule-shell__mode{display:flex;align-items:center;gap:8px}.task-schedule-shell__label{color:#334155;font-size:13px;font-weight:600}.task-schedule-shell__select{border:1px solid #cbd5e1;border-radius:8px;height:36px;padding:0 10px;min-width:180px;background-color:#fff}.task-schedule-shell__actions{display:flex;flex-wrap:wrap;gap:8px}.task-schedule-shell__btn{border:1px solid #14b8a6;background:#14b8a6;color:#fff;border-radius:999px;padding:7px 14px;font-size:13px;font-weight:600;cursor:pointer}.task-schedule-shell__btn:disabled{opacity:.55;cursor:not-allowed}\n"] }]
|
|
4199
|
+
}], ctorParameters: () => [], propDecorators: { context: [{ type: i0.Input, args: [{ isSignal: true, alias: "context", required: false }] }], modeChanged: [{ type: i0.Output, args: ["modeChanged"] }], baselineSet: [{ type: i0.Output, args: ["baselineSet"] }], tasksExported: [{ type: i0.Output, args: ["tasksExported"] }], actionError: [{ type: i0.Output, args: ["actionError"] }] } });
|
|
3726
4200
|
|
|
3727
4201
|
/**
|
|
3728
4202
|
* Generated bundle index. Do not edit.
|