@masterteam/task-schedule 0.0.15 → 0.0.17

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.
@@ -3,7 +3,8 @@ import * as i0 from '@angular/core';
3
3
  import { inject, Injectable, viewChild, input, signal, computed, effect, Component, linkedSignal, Injector, output, ViewChild } from '@angular/core';
4
4
  import * as i1$1 from '@syncfusion/ej2-angular-gantt';
5
5
  import { GanttModule, DayMarkersService, EditService, ExcelExportService, FilterService, CriticalPathService, PdfExportService, RowDDService, SelectionService, SortService, ToolbarService, ContextMenuService, ResizeService } from '@syncfusion/ej2-angular-gantt';
6
- import { switchMap, of, map, catchError, throwError, finalize, Subject, Subscription } from 'rxjs';
6
+ import { switchMap, of, map, timeout, catchError, throwError, finalize, Subject, Subscription } from 'rxjs';
7
+ import { MT_DATE_FORMATS, toAngularDateFormat, MTDateFormatPipe } from '@masterteam/components';
7
8
  import { ModalService } from '@masterteam/components/modal';
8
9
  import { HttpClient } from '@angular/common/http';
9
10
  import { L10n, setCulture } from '@syncfusion/ej2-base';
@@ -20,7 +21,6 @@ import { CheckboxField } from '@masterteam/components/checkbox-field';
20
21
  import { DateField } from '@masterteam/components/date-field';
21
22
  import { EntityPreview } from '@masterteam/components/entities';
22
23
  import { NumberField } from '@masterteam/components/number-field';
23
- import { Table } from '@masterteam/components/table';
24
24
  import { TextField } from '@masterteam/components/text-field';
25
25
 
26
26
  function normalizeTaskScheduleModelType(modelType) {
@@ -109,6 +109,7 @@ const NATIVE_PROPERTY_KEYS = new Set([
109
109
  'predecessor',
110
110
  'order',
111
111
  'externalId',
112
+ 'externalParentId',
112
113
  'parentId',
113
114
  'phaseGate',
114
115
  'phaseGateId',
@@ -117,6 +118,21 @@ const NATIVE_PROPERTY_KEYS = new Set([
117
118
  'isSummary',
118
119
  ]);
119
120
  const NATIVE_PROPERTY_LOOKUP_KEYS = new Set(Array.from(NATIVE_PROPERTY_KEYS).map((key) => normalizeLookupKey(key)));
121
+ const NATIVE_PROPERTY_ALIAS_TARGETS = {
122
+ startdate: 'plannedStart',
123
+ plannedstartdate: 'plannedStart',
124
+ enddate: 'plannedFinish',
125
+ finishdate: 'plannedFinish',
126
+ plannedfinishdate: 'plannedFinish',
127
+ actualstartdate: 'actualStart',
128
+ actualfinishdate: 'actualFinish',
129
+ baselinestartdate: 'baselineStart',
130
+ baselinefinishdate: 'baselineFinish',
131
+ baselineenddate: 'baselineFinish',
132
+ taskname: 'name',
133
+ };
134
+ const DEFAULT_MPP_REQUEST_TIMEOUT_MS$1 = 300_000;
135
+ const DEFAULT_MPP_PREVIEW_MAX_ROWS = 400;
120
136
  class TaskScheduleFetchService {
121
137
  http = inject(HttpClient);
122
138
  load(modelType, context) {
@@ -140,12 +156,21 @@ class TaskScheduleFetchService {
140
156
  'levels/{levelId}/{levelDataId}/schedule/mpp', { levelId, levelDataId });
141
157
  const formData = new FormData();
142
158
  formData.append('file', file, file.name);
143
- return this.readData(this.http.post(endpoint, formData)).pipe(map((payload) => ({
159
+ return this.readData(this.http
160
+ .post(endpoint, formData)
161
+ .pipe(timeout(this.resolveMppRequestTimeoutMs(context)))).pipe(map((payload) => ({
144
162
  fileName: this.toNullableString(this.readObjectValue(payload, ['fileName', 'name'])) ?? file.name,
145
- tasks: this.mapLooseTasks(this.extractTaskRows(payload), [], context.langCode === 'ar' ? 'ar' : 'en'),
146
- raw: payload,
163
+ tasks: this.mapLooseTasks(this.extractTaskRows(payload), [], context.langCode === 'ar' ? 'ar' : 'en', new Map(), this.resolveMppPreviewMaxRows(context)),
164
+ raw: context.mppKeepRawPayload ? payload : undefined,
147
165
  })));
148
166
  }
167
+ exportTasks(context) {
168
+ const endpoint = this.levelEndpoint(context, this.readEndpoint(context, 'exportTasks') ??
169
+ 'levels/{levelId}/{levelDataId}/schedule/mpp', 'Export tasks requires levelId and levelDataId.');
170
+ return this.http
171
+ .get(endpoint, { responseType: 'blob' })
172
+ .pipe(timeout(this.resolveMppRequestTimeoutMs(context)));
173
+ }
149
174
  loadBaselineSnapshot(context, version = 'latest') {
150
175
  const endpoint = this.levelEndpoint(context, version === 'latest'
151
176
  ? 'levels/{levelId}/{levelDataId}/schedule/baselines/latest'
@@ -167,11 +192,12 @@ class TaskScheduleFetchService {
167
192
  modelType === 'custom'
168
193
  ? this.mapCustomProperties(payload.catalog?.properties ?? [])
169
194
  : [];
195
+ const propertyAliases = this.mapPropertyAliases(payload.catalog?.properties ?? []);
170
196
  const tasks = modelType === 'resources'
171
- ? this.mapGroupedTasks(payload.data?.groups ?? [], customProperties, langCode)
197
+ ? this.mapGroupedTasks(payload.data?.groups ?? [], customProperties, propertyAliases, langCode)
172
198
  : modelType === 'unscheduled'
173
- ? this.mapLooseTasks(payload.data?.items ?? [], customProperties, langCode)
174
- : this.mapQueryTasks(payload.data?.records ?? [], payload.schemas ?? [], customProperties, langCode);
199
+ ? this.mapLooseTasks(payload.data?.items ?? [], customProperties, langCode, propertyAliases)
200
+ : this.mapQueryTasks(payload.data?.records ?? [], payload.schemas ?? [], customProperties, propertyAliases, langCode);
175
201
  return this.resolveResources(context, modelType, tasks).pipe(map((resources) => ({
176
202
  tasks,
177
203
  resources,
@@ -229,20 +255,20 @@ class TaskScheduleFetchService {
229
255
  'levels/{levelId}/{levelDataId}/schedule/read', fallbackMessage);
230
256
  return this.readData(this.http.post(endpoint, body));
231
257
  }
232
- mapQueryTasks(records, schemas, customProperties, langCode) {
258
+ mapQueryTasks(records, schemas, customProperties, propertyAliases, langCode) {
233
259
  const schemaMap = new Map((schemas ?? [])
234
260
  .filter((schema) => schema.id !== null && schema.id !== undefined)
235
261
  .map((schema) => [String(schema.id), schema]));
236
262
  return sortTasksByOrder((records ?? [])
237
- .map((record, index) => this.mapTaskSource(record, index + 1, customProperties, langCode, schemaMap.get(String(record.schemaId ?? '')) ?? null, record.children ?? []))
263
+ .map((record, index) => this.mapTaskSource(record, index + 1, customProperties, langCode, propertyAliases, schemaMap.get(String(record.schemaId ?? '')) ?? null, record.children ?? []))
238
264
  .filter((task) => task !== null));
239
265
  }
240
- mapGroupedTasks(groups, customProperties, langCode) {
266
+ mapGroupedTasks(groups, customProperties, propertyAliases, langCode) {
241
267
  const byId = new Map();
242
268
  for (const group of groups ?? []) {
243
269
  const items = Array.isArray(group?.items) ? group.items : [];
244
270
  for (let index = 0; index < items.length; index += 1) {
245
- const task = this.mapTaskSource(items[index], index + 1, customProperties, langCode, null, []);
271
+ const task = this.mapTaskSource(items[index], index + 1, customProperties, langCode, propertyAliases, null, []);
246
272
  if (!task) {
247
273
  continue;
248
274
  }
@@ -258,26 +284,46 @@ class TaskScheduleFetchService {
258
284
  }
259
285
  return sortTasksByOrder(Array.from(byId.values()));
260
286
  }
261
- mapLooseTasks(rows, customProperties, langCode) {
262
- return sortTasksByOrder((rows ?? [])
263
- .filter((row) => this.isObject(row))
264
- .map((row, index) => this.mapTaskSource(row, index + 1, customProperties, langCode))
265
- .filter((task) => task !== null));
287
+ mapLooseTasks(rows, customProperties, langCode, propertyAliases = new Map(), maxTasks = Number.POSITIVE_INFINITY) {
288
+ const budget = Number.isFinite(maxTasks)
289
+ ? { remaining: Math.max(0, Math.floor(maxTasks)) }
290
+ : undefined;
291
+ const tasks = [];
292
+ for (let index = 0; index < (rows ?? []).length; index += 1) {
293
+ if (budget && budget.remaining <= 0) {
294
+ break;
295
+ }
296
+ const row = rows[index];
297
+ if (!this.isObject(row)) {
298
+ continue;
299
+ }
300
+ const task = this.mapTaskSource(row, index + 1, customProperties, langCode, propertyAliases, null, undefined, budget);
301
+ if (task) {
302
+ tasks.push(task);
303
+ }
304
+ }
305
+ return sortTasksByOrder(tasks);
266
306
  }
267
- mapTaskSource(source, fallbackOrder, customProperties, langCode, schema = null, explicitChildren) {
307
+ mapTaskSource(source, fallbackOrder, customProperties, langCode, propertyAliases = new Map(), schema = null, explicitChildren, budget) {
308
+ if (budget && budget.remaining <= 0) {
309
+ return null;
310
+ }
268
311
  const id = this.toTaskId(source['id'] ?? source['taskId'] ?? source['Id']);
269
312
  if (id === null) {
270
313
  return null;
271
314
  }
272
- const rawType = this.toNullableString(this.readSourceValue(source, 'type')) ??
315
+ if (budget) {
316
+ budget.remaining -= 1;
317
+ }
318
+ const rawType = this.toNullableString(this.readNativeValue(source, 'type', propertyAliases)) ??
273
319
  this.toNullableString(schema?.key) ??
274
320
  'Task';
275
321
  const type = this.normalizeTaskType(rawType);
276
322
  const title = this.toNullableString(source['title'] ??
277
323
  source['name'] ??
278
324
  source['Name'] ??
279
- this.readNestedValue(source, 'name')) ?? `Task ${String(id)}`;
280
- const resources = this.normalizeResources(this.readSourceValue(source, 'resources'), this.readSourceValue(source, 'assignedTo'));
325
+ this.readNativeValue(source, 'name', propertyAliases)) ?? `Task ${String(id)}`;
326
+ const resources = this.normalizeResources(this.readNativeValue(source, 'resources', propertyAliases), this.readNativeValue(source, 'assignedTo', propertyAliases));
281
327
  const customValues = this.mapCustomValues(source, customProperties);
282
328
  const childRows = explicitChildren ??
283
329
  (Array.isArray(source['children'])
@@ -285,6 +331,7 @@ class TaskScheduleFetchService {
285
331
  : Array.isArray(source['subtasks'])
286
332
  ? source['subtasks']
287
333
  : []);
334
+ const subtasks = this.mapTaskChildren(childRows, customProperties, langCode, propertyAliases, budget);
288
335
  const task = {
289
336
  ...source,
290
337
  id,
@@ -294,52 +341,56 @@ class TaskScheduleFetchService {
294
341
  title,
295
342
  name: title,
296
343
  guid: this.toNullableString(this.readNestedValue(source, 'externalId') ??
344
+ this.readNativeValue(source, 'externalId', propertyAliases) ??
297
345
  this.readNestedValue(source, 'guid') ??
298
346
  source['externalId'] ??
299
347
  source['guid'] ??
300
348
  source['Guid']) ?? `task-${String(id)}`,
301
349
  parentGuid: this.toNullableString(this.readNestedValue(source, 'parentId') ??
302
350
  this.readNestedValue(source, 'externalParentId') ??
351
+ this.readNativeValue(source, 'parentId', propertyAliases) ??
352
+ this.readNativeValue(source, 'externalParentId', propertyAliases) ??
303
353
  source['parentGuid'] ??
304
354
  source['ParentGuid'] ??
305
355
  source['externalParentId']),
306
- parentId: this.toTaskId(source['parentId'] ?? source['ParentId']),
307
- startDate: this.toDate(this.readSourceValue(source, 'plannedStart') ??
308
- this.readSourceValue(source, 'Planned_Start') ??
309
- this.readSourceValue(source, 'startDate')),
310
- finishDate: this.toDate(this.readSourceValue(source, 'plannedFinish') ??
311
- this.readSourceValue(source, 'Planned_Finish') ??
312
- this.readSourceValue(source, 'finishDate') ??
313
- this.readSourceValue(source, 'endDate')),
314
- baselineStartDate: this.toDate(this.readSourceValue(source, 'baselineStart')),
315
- baselineEndDate: this.toDate(this.readSourceValue(source, 'baselineFinish')),
316
- actualStartDate: this.toDate(this.readSourceValue(source, 'actualStart')),
317
- actualFinishDate: this.toDate(this.readSourceValue(source, 'actualFinish')),
318
- predecessor: this.toNullableString(this.readSourceValue(source, 'predecessor')),
319
- duration: this.normalizeDuration(this.readSourceValue(source, 'duration'), type),
320
- progress: this.normalizeProgress(this.readSourceValue(source, 'progress')),
321
- details: this.toNullableString(this.readSourceValue(source, 'details') ??
322
- this.readSourceValue(source, 'description')),
323
- status: this.readNamedString(this.readSourceValue(source, 'status')),
356
+ parentId: this.toTaskId(source['parentId'] ??
357
+ source['ParentId'] ??
358
+ this.readNativeValue(source, 'parentId', propertyAliases)),
359
+ startDate: this.toDate(this.readNativeRawValue(source, 'plannedStart', propertyAliases) ??
360
+ this.readNativeRawValue(source, 'startDate', propertyAliases)),
361
+ finishDate: this.toDate(this.readNativeRawValue(source, 'plannedFinish', propertyAliases) ??
362
+ this.readNativeRawValue(source, 'finishDate', propertyAliases) ??
363
+ this.readNativeRawValue(source, 'endDate', propertyAliases)),
364
+ baselineStartDate: this.toDate(this.readNativeRawValue(source, 'baselineStart', propertyAliases)),
365
+ baselineEndDate: this.toDate(this.readNativeRawValue(source, 'baselineFinish', propertyAliases)),
366
+ actualStart: this.toDate(this.readNativeRawValue(source, 'actualStart', propertyAliases)),
367
+ actualFinish: this.toDate(this.readNativeRawValue(source, 'actualFinish', propertyAliases)),
368
+ baselineStart: this.toDate(this.readNativeRawValue(source, 'baselineStart', propertyAliases)),
369
+ baselineFinish: this.toDate(this.readNativeRawValue(source, 'baselineFinish', propertyAliases)),
370
+ actualStartDate: this.toDate(this.readNativeRawValue(source, 'actualStart', propertyAliases)),
371
+ actualFinishDate: this.toDate(this.readNativeRawValue(source, 'actualFinish', propertyAliases)),
372
+ predecessor: this.toNullableString(this.readNativeValue(source, 'predecessor', propertyAliases)),
373
+ duration: this.normalizeDuration(this.readNativeValue(source, 'duration', propertyAliases), type),
374
+ progress: this.normalizeProgress(this.readNativeValue(source, 'progress', propertyAliases)),
375
+ details: this.toNullableString(this.readNativeValue(source, 'details', propertyAliases) ??
376
+ this.readNativeValue(source, 'description', propertyAliases)),
377
+ status: this.readNamedString(this.readNativeValue(source, 'status', propertyAliases)),
324
378
  type,
325
- typeLabel: this.toNullableString(this.readSourceValue(source, 'typeLabel') ??
326
- this.readSourceValue(source, 'typeLable') ??
379
+ typeLabel: this.toNullableString(this.readNativeValue(source, 'typeLabel', propertyAliases) ??
380
+ this.readNativeValue(source, 'typeLable', propertyAliases) ??
327
381
  schema?.name) ?? this.localizeTaskType(type, langCode),
328
- typeLable: this.toNullableString(this.readSourceValue(source, 'typeLable') ??
329
- this.readSourceValue(source, 'typeLabel') ??
382
+ typeLable: this.toNullableString(this.readNativeValue(source, 'typeLable', propertyAliases) ??
383
+ this.readNativeValue(source, 'typeLabel', propertyAliases) ??
330
384
  schema?.name) ?? this.localizeTaskType(type, langCode),
331
- assignedTo: this.resolveAssignedTo(resources, this.readSourceValue(source, 'assignedTo')),
385
+ assignedTo: this.resolveAssignedTo(resources, this.readNativeValue(source, 'assignedTo', propertyAliases)),
332
386
  resources,
333
- phaseGate: this.toNullableString(this.readSourceValue(source, 'phaseGate')),
334
- phaseGateId: this.toTaskId(this.readSourceValue(source, 'phaseGateId')),
335
- criticalPath: Boolean(this.readSourceValue(source, 'criticalPath')),
387
+ phaseGate: this.toNullableString(this.readNativeValue(source, 'phaseGate', propertyAliases)),
388
+ phaseGateId: this.toTaskId(this.readNativeValue(source, 'phaseGateId', propertyAliases)),
389
+ criticalPath: Boolean(this.readNativeValue(source, 'criticalPath', propertyAliases)),
336
390
  isMilestone: type === 'Milestone',
337
- order: this.toNullableNumber(this.readSourceValue(source, 'order')) ??
338
- fallbackOrder,
339
- subtasks: childRows
340
- .filter((row) => this.isObject(row))
341
- .map((row, index) => this.mapTaskSource(row, index + 1, customProperties, langCode))
342
- .filter((row) => row !== null),
391
+ order: this.toNullableNumber(this.readNativeValue(source, 'order', propertyAliases)) ?? fallbackOrder,
392
+ subtasks,
393
+ children: subtasks,
343
394
  props: customValues.props,
344
395
  };
345
396
  for (const [key, value] of Object.entries(customValues.values)) {
@@ -347,6 +398,23 @@ class TaskScheduleFetchService {
347
398
  }
348
399
  return task;
349
400
  }
401
+ mapTaskChildren(rows, customProperties, langCode, propertyAliases, budget) {
402
+ const tasks = [];
403
+ for (let index = 0; index < (rows ?? []).length; index += 1) {
404
+ if (budget && budget.remaining <= 0) {
405
+ break;
406
+ }
407
+ const row = rows[index];
408
+ if (!this.isObject(row)) {
409
+ continue;
410
+ }
411
+ const task = this.mapTaskSource(row, index + 1, customProperties, langCode, propertyAliases, null, undefined, budget);
412
+ if (task) {
413
+ tasks.push(task);
414
+ }
415
+ }
416
+ return sortTasksByOrder(tasks);
417
+ }
350
418
  mapCustomProperties(properties) {
351
419
  return [...(properties ?? [])]
352
420
  .filter((property) => {
@@ -363,6 +431,7 @@ class TaskScheduleFetchService {
363
431
  id: property.id,
364
432
  key: property.normalizedKey ?? property.key,
365
433
  normalizedKey: property.normalizedKey ?? property.key,
434
+ sourceKey: property.key,
366
435
  name: property.label ?? property.key,
367
436
  viewType: property.viewType ?? 'Text',
368
437
  configuration: property.configuration,
@@ -370,17 +439,59 @@ class TaskScheduleFetchService {
370
439
  isCalculated: !!property.isCalculated,
371
440
  }));
372
441
  }
442
+ mapPropertyAliases(properties) {
443
+ const aliases = new Map();
444
+ for (const property of properties ?? []) {
445
+ const canonicalKey = this.resolveNativePropertyKey(property.normalizedKey ?? property.key);
446
+ if (!canonicalKey) {
447
+ continue;
448
+ }
449
+ this.addPropertyAlias(aliases, canonicalKey, property.key);
450
+ this.addPropertyAlias(aliases, canonicalKey, property.normalizedKey);
451
+ }
452
+ return aliases;
453
+ }
454
+ resolveNativePropertyKey(value) {
455
+ const lookupKey = normalizeLookupKey(String(value ?? ''));
456
+ if (!lookupKey) {
457
+ return null;
458
+ }
459
+ const aliasTarget = NATIVE_PROPERTY_ALIAS_TARGETS[lookupKey];
460
+ if (aliasTarget) {
461
+ return aliasTarget;
462
+ }
463
+ for (const nativeKey of NATIVE_PROPERTY_KEYS) {
464
+ const nativeLookupKey = normalizeLookupKey(nativeKey);
465
+ if (lookupKey === nativeLookupKey ||
466
+ (nativeLookupKey.length >= 5 && lookupKey.endsWith(nativeLookupKey))) {
467
+ return nativeKey;
468
+ }
469
+ }
470
+ return null;
471
+ }
472
+ addPropertyAlias(aliases, canonicalKey, alias) {
473
+ const resolvedAlias = String(alias ?? '').trim();
474
+ if (!resolvedAlias || resolvedAlias === canonicalKey) {
475
+ return;
476
+ }
477
+ const currentAliases = aliases.get(canonicalKey) ?? [];
478
+ if (!currentAliases.includes(resolvedAlias)) {
479
+ aliases.set(canonicalKey, [...currentAliases, resolvedAlias]);
480
+ }
481
+ }
373
482
  mapCustomValues(source, customProperties) {
374
483
  const values = {};
375
484
  const props = [];
376
485
  for (const property of customProperties) {
377
- const raw = this.readSourceRawValue(source, property.key);
486
+ const raw = this.readSourceRawValue(source, property.key) ??
487
+ this.readSourceRawValue(source, property.sourceKey ?? '');
378
488
  if (raw === undefined) {
379
489
  continue;
380
490
  }
381
491
  const value = String(property.viewType ?? '').toLowerCase() === 'date'
382
492
  ? this.toDate(raw)
383
- : this.readSourceValue(source, property.key);
493
+ : (this.readSourceValue(source, property.key) ??
494
+ this.readSourceValue(source, property.sourceKey ?? ''));
384
495
  values[property.key] = value;
385
496
  props.push({
386
497
  id: 0,
@@ -617,6 +728,18 @@ class TaskScheduleFetchService {
617
728
  }
618
729
  return resolved;
619
730
  }
731
+ resolveMppRequestTimeoutMs(context) {
732
+ const value = Number(context.mppRequestTimeoutMs);
733
+ return Number.isFinite(value) && value > 0
734
+ ? value
735
+ : DEFAULT_MPP_REQUEST_TIMEOUT_MS$1;
736
+ }
737
+ resolveMppPreviewMaxRows(context) {
738
+ const value = Number(context.mppPreviewMaxRows);
739
+ return Number.isFinite(value) && value > 0
740
+ ? Math.floor(value) + 1
741
+ : DEFAULT_MPP_PREVIEW_MAX_ROWS + 1;
742
+ }
620
743
  readEndpoint(context, key) {
621
744
  const value = context.endpoints?.[key];
622
745
  return typeof value === 'string' && value.trim() ? value.trim() : null;
@@ -698,6 +821,32 @@ class TaskScheduleFetchService {
698
821
  }
699
822
  return undefined;
700
823
  }
824
+ readNativeValue(source, key, aliases) {
825
+ const direct = this.readSourceValue(source, key);
826
+ if (direct !== undefined) {
827
+ return direct;
828
+ }
829
+ for (const alias of aliases.get(key) ?? []) {
830
+ const value = this.readSourceValue(source, alias);
831
+ if (value !== undefined) {
832
+ return value;
833
+ }
834
+ }
835
+ return undefined;
836
+ }
837
+ readNativeRawValue(source, key, aliases) {
838
+ const direct = this.readSourceRawValue(source, key);
839
+ if (direct !== undefined) {
840
+ return direct;
841
+ }
842
+ for (const alias of aliases.get(key) ?? []) {
843
+ const value = this.readSourceRawValue(source, alias);
844
+ if (value !== undefined) {
845
+ return value;
846
+ }
847
+ }
848
+ return undefined;
849
+ }
701
850
  readSourceValue(source, key) {
702
851
  const direct = this.readObjectValueByKey(source, key);
703
852
  if (direct !== undefined) {
@@ -953,22 +1102,53 @@ class TaskScheduleFetchService {
953
1102
  if (value === null || value === undefined || value === '') {
954
1103
  return null;
955
1104
  }
956
- if (value instanceof Date || typeof value === 'string') {
957
- return value;
1105
+ if (value instanceof Date) {
1106
+ return Number.isNaN(value.getTime()) ? null : this.toLocalDate(value);
1107
+ }
1108
+ if (typeof value === 'string') {
1109
+ const raw = value.trim();
1110
+ if (!raw) {
1111
+ return null;
1112
+ }
1113
+ const dateOnly = this.parseDateOnly(raw);
1114
+ if (dateOnly) {
1115
+ return dateOnly;
1116
+ }
1117
+ const date = new Date(raw);
1118
+ return Number.isNaN(date.getTime()) ? value : this.toLocalDate(date);
958
1119
  }
959
1120
  if (typeof value === 'number') {
960
1121
  const date = new Date(value);
961
- return Number.isNaN(date.getTime()) ? null : date;
1122
+ return Number.isNaN(date.getTime()) ? null : this.toLocalDate(date);
962
1123
  }
963
1124
  if (!this.isObject(value)) {
964
1125
  return String(value);
965
1126
  }
966
1127
  const row = value;
967
- return (row['value'] ??
968
- row['raw'] ??
969
- row['actualValue'] ??
970
- row['displayValue'] ??
971
- null);
1128
+ for (const key of ['raw', 'actualValue', 'value', 'displayValue']) {
1129
+ if (!(key in row)) {
1130
+ continue;
1131
+ }
1132
+ const date = this.toDate(row[key]);
1133
+ if (date !== null) {
1134
+ return date;
1135
+ }
1136
+ }
1137
+ return null;
1138
+ }
1139
+ parseDateOnly(value) {
1140
+ const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value);
1141
+ if (!match) {
1142
+ return null;
1143
+ }
1144
+ const year = Number(match[1]);
1145
+ const month = Number(match[2]);
1146
+ const day = Number(match[3]);
1147
+ const date = new Date(year, month - 1, day);
1148
+ return Number.isNaN(date.getTime()) ? null : date;
1149
+ }
1150
+ toLocalDate(value) {
1151
+ return new Date(value.getFullYear(), value.getMonth(), value.getDate());
972
1152
  }
973
1153
  readLegacyHolidays() {
974
1154
  if (typeof localStorage === 'undefined') {
@@ -1060,6 +1240,7 @@ function normalizeLookupKey(value) {
1060
1240
  }
1061
1241
 
1062
1242
  const DEFAULT_TASK_MODULE_ID = 3;
1243
+ const DEFAULT_MPP_REQUEST_TIMEOUT_MS = 300_000;
1063
1244
  class TaskScheduleActionService {
1064
1245
  http = inject(HttpClient);
1065
1246
  buildTaskMutation(task, options = {}) {
@@ -1289,7 +1470,9 @@ class TaskScheduleActionService {
1289
1470
  'tasks/{levelId}/import', {
1290
1471
  levelId: this.requireId(context.levelId, 'Apply import requires levelId.'),
1291
1472
  });
1292
- return this.readData(this.http.patch(endpoint, payload));
1473
+ return this.readData(this.http
1474
+ .patch(endpoint, payload)
1475
+ .pipe(timeout(this.resolveMppRequestTimeoutMs(context))));
1293
1476
  }
1294
1477
  setBaseline(context, _payload = {}) {
1295
1478
  const request = {
@@ -1617,6 +1800,12 @@ class TaskScheduleActionService {
1617
1800
  }
1618
1801
  return resolved;
1619
1802
  }
1803
+ resolveMppRequestTimeoutMs(context) {
1804
+ const value = Number(context.mppRequestTimeoutMs);
1805
+ return Number.isFinite(value) && value > 0
1806
+ ? value
1807
+ : DEFAULT_MPP_REQUEST_TIMEOUT_MS;
1808
+ }
1620
1809
  requireProcessId(value) {
1621
1810
  const resolved = this.toTaskId(value);
1622
1811
  if (resolved === null) {
@@ -2421,7 +2610,7 @@ class TaskScheduleDialog {
2421
2610
  };
2422
2611
  }
2423
2612
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: TaskScheduleDialog, deps: [], target: i0.ɵɵFactoryTarget.Component });
2424
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: TaskScheduleDialog, isStandalone: true, selector: "mt-task-schedule-dialog", inputs: { mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: false, transformFunction: null }, task: { classPropertyName: "task", publicName: "task", isSignal: true, isRequired: false, transformFunction: null }, typeOptions: { classPropertyName: "typeOptions", publicName: "typeOptions", isSignal: true, isRequired: false, transformFunction: null }, langCode: { classPropertyName: "langCode", publicName: "langCode", isSignal: true, isRequired: false, transformFunction: null }, parentGuid: { classPropertyName: "parentGuid", publicName: "parentGuid", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "clientForm", first: true, predicate: ClientForm, descendants: true, isSignal: true }], ngImport: i0, template: "<div [class]=\"'p-4 overflow-y-auto ' + (modal.contentClass || '')\">\r\n <div class=\"flex flex-col gap-4\">\r\n <mt-select-field\r\n [options]=\"typeSelectOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [label]=\"'task-schedule.dialog.type' | transloco\"\r\n [placeholder]=\"'task-schedule.dialog.typePlaceholder' | transloco\"\r\n [ngModel]=\"selectedType() ?? undefined\"\r\n (onChange)=\"onTypeChange($event)\"\r\n />\r\n\r\n @if (selectedType()) {\r\n <mt-client-form\r\n #clientForm\r\n [moduleKey]=\"'ModuleData'\"\r\n [moduleId]=\"selectedModuleId() ?? undefined\"\r\n [operationKey]=\"mode() === 'edit' ? 'Update' : 'Create'\"\r\n [formMode]=\"mode()\"\r\n [levelId]=\"context()?.levelId ?? undefined\"\r\n [levelDataId]=\"context()?.levelDataId ?? undefined\"\r\n [moduleDataId]=\"selectedModuleDataId() ?? undefined\"\r\n [lang]=\"langCode()\"\r\n [autoLoad]=\"true\"\r\n [ignoredFieldKeys]=\"ignoredFieldKeys()\"\r\n [submitRequestMapper]=\"submitRequestMapper\"\r\n (submitted)=\"onClientFormSubmitted($event)\"\r\n />\r\n } @else {\r\n <div\r\n class=\"rounded-xl border border-surface bg-content px-4 py-4 text-sm text-muted-color\"\r\n >\r\n {{ \"task-schedule.dialog.typeFirst\" | transloco }}\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n\r\n<div [class]=\"modal.footerClass\">\r\n <div class=\"flex items-center justify-end gap-3\">\r\n <mt-button\r\n [label]=\"'task-schedule.dialog.cancel' | transloco\"\r\n variant=\"outlined\"\r\n [disabled]=\"submitting()\"\r\n (onClick)=\"cancel()\"\r\n />\r\n <mt-button\r\n [label]=\"'task-schedule.dialog.save' | transloco\"\r\n severity=\"primary\"\r\n [loading]=\"submitting()\"\r\n [disabled]=\"submitting()\"\r\n (onClick)=\"save()\"\r\n />\r\n </div>\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { 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: SelectField, selector: "mt-select-field", inputs: ["field", "hint", "label", "placeholder", "hasPlaceholderPrefix", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "clearAfterSelect", "required", "group", "size", "optionGroupLabel", "optionGroupChildren", "loading", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape", "markCurrentUser"], outputs: ["onChange"] }, { kind: "component", type: ClientForm, selector: "mt-client-form", inputs: ["moduleKey", "operationKey", "moduleId", "levelId", "levelDataId", "moduleDataId", "requestSchemaId", "draftProcessId", "preview", "returnUrl", "defaultValues", "submitRequestMapper", "readonly", "autoLoad", "formMode", "renderMode", "showInternalStepActions", "confirmWarningsOnSubmit", "confirmWarningsOnStepChange", "lookups", "statuses", "ignoredFieldKeys", "allowedFieldKeys"], outputs: ["loaded", "submitted", "errored", "modeDetected", "formSourceDetected", "footerStateChanged"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "pipe", type: i2.TranslocoPipe, name: "transloco" }] });
2613
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: TaskScheduleDialog, isStandalone: true, selector: "mt-task-schedule-dialog", inputs: { mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: false, transformFunction: null }, task: { classPropertyName: "task", publicName: "task", isSignal: true, isRequired: false, transformFunction: null }, typeOptions: { classPropertyName: "typeOptions", publicName: "typeOptions", isSignal: true, isRequired: false, transformFunction: null }, langCode: { classPropertyName: "langCode", publicName: "langCode", isSignal: true, isRequired: false, transformFunction: null }, parentGuid: { classPropertyName: "parentGuid", publicName: "parentGuid", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "clientForm", first: true, predicate: ClientForm, descendants: true, isSignal: true }], ngImport: i0, template: "<div [class]=\"'p-4 overflow-y-auto ' + (modal.contentClass || '')\">\r\n <div class=\"flex flex-col gap-4\">\r\n <mt-select-field\r\n [options]=\"typeSelectOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [label]=\"'task-schedule.dialog.type' | transloco\"\r\n [placeholder]=\"'task-schedule.dialog.typePlaceholder' | transloco\"\r\n [ngModel]=\"selectedType() ?? undefined\"\r\n (onChange)=\"onTypeChange($event)\"\r\n />\r\n\r\n @if (selectedType()) {\r\n <mt-client-form\r\n #clientForm\r\n [moduleKey]=\"'ModuleData'\"\r\n [moduleId]=\"selectedModuleId() ?? undefined\"\r\n [operationKey]=\"mode() === 'edit' ? 'Update' : 'Create'\"\r\n [formMode]=\"mode()\"\r\n [levelId]=\"context()?.levelId ?? undefined\"\r\n [levelDataId]=\"context()?.levelDataId ?? undefined\"\r\n [moduleDataId]=\"selectedModuleDataId() ?? undefined\"\r\n [lang]=\"langCode()\"\r\n [autoLoad]=\"true\"\r\n [ignoredFieldKeys]=\"ignoredFieldKeys()\"\r\n [submitRequestMapper]=\"submitRequestMapper\"\r\n (submitted)=\"onClientFormSubmitted($event)\"\r\n />\r\n } @else {\r\n <div\r\n class=\"rounded-xl border border-surface bg-content px-4 py-4 text-sm text-muted-color\"\r\n >\r\n {{ \"task-schedule.dialog.typeFirst\" | transloco }}\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n\r\n<div [class]=\"modal.footerClass\">\r\n <div class=\"flex items-center justify-end gap-3\">\r\n <mt-button\r\n [label]=\"'task-schedule.dialog.cancel' | transloco\"\r\n variant=\"outlined\"\r\n [disabled]=\"submitting()\"\r\n (onClick)=\"cancel()\"\r\n />\r\n <mt-button\r\n [label]=\"'task-schedule.dialog.save' | transloco\"\r\n severity=\"primary\"\r\n [loading]=\"submitting()\"\r\n [disabled]=\"submitting()\"\r\n (onClick)=\"save()\"\r\n />\r\n </div>\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { 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: SelectField, selector: "mt-select-field", inputs: ["field", "hint", "label", "placeholder", "hasPlaceholderPrefix", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "clearAfterSelect", "required", "group", "size", "optionGroupLabel", "optionGroupChildren", "loading", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape", "markCurrentUser"], outputs: ["onChange"] }, { kind: "component", type: ClientForm, selector: "mt-client-form", inputs: ["moduleKey", "operationKey", "moduleId", "levelId", "levelDataId", "moduleDataId", "requestSchemaId", "draftProcessId", "preview", "returnUrl", "defaultValues", "submitRequestMapper", "readonly", "autoLoad", "formMode", "renderMode", "showInternalStepActions", "confirmWarningsOnSubmit", "confirmWarningsOnStepChange", "readonlyFieldDisplayMode", "lookups", "statuses", "ignoredFieldKeys", "allowedFieldKeys"], outputs: ["loaded", "submitted", "errored", "modeDetected", "formSourceDetected", "footerStateChanged"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "pipe", type: i2.TranslocoPipe, name: "transloco" }] });
2425
2614
  }
2426
2615
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: TaskScheduleDialog, decorators: [{
2427
2616
  type: Component,
@@ -2539,7 +2728,8 @@ class TaskScheduleImportDialog {
2539
2728
  return output;
2540
2729
  }, ...(ngDevMode ? [{ debugName: "resourceOptions" }] : /* istanbul ignore next */ []));
2541
2730
  isTruncated = computed(() => {
2542
- const loadedCount = this.countTasks(this.importResult()?.tasks ?? []);
2731
+ const maxRows = Math.max(1, this.maxRows());
2732
+ const loadedCount = this.countTasks(this.importResult()?.tasks ?? [], maxRows + 1);
2543
2733
  return loadedCount > this.previewRows().length;
2544
2734
  }, ...(ngDevMode ? [{ debugName: "isTruncated" }] : /* istanbul ignore next */ []));
2545
2735
  allSelected = computed(() => {
@@ -2551,8 +2741,11 @@ class TaskScheduleImportDialog {
2551
2741
  return rows.every((row) => selected.has(row.key));
2552
2742
  }, ...(ngDevMode ? [{ debugName: "allSelected" }] : /* istanbul ignore next */ []));
2553
2743
  hasSelection = computed(() => this.selectedTaskKeys().size > 0, ...(ngDevMode ? [{ debugName: "hasSelection" }] : /* istanbul ignore next */ []));
2554
- canImport = computed(() => !!this.selectedFile() && !this.loadingImport(), ...(ngDevMode ? [{ debugName: "canImport" }] : /* istanbul ignore next */ []));
2555
- canApply = computed(() => !!this.importResult() && this.hasSelection() && !this.loadingApply(), ...(ngDevMode ? [{ debugName: "canApply" }] : /* istanbul ignore next */ []));
2744
+ canImport = computed(() => !!this.selectedFile() && !this.loadingImport() && !this.loadingApply(), ...(ngDevMode ? [{ debugName: "canImport" }] : /* istanbul ignore next */ []));
2745
+ canApply = computed(() => !!this.importResult() &&
2746
+ this.hasSelection() &&
2747
+ !this.loadingApply() &&
2748
+ !this.loadingImport(), ...(ngDevMode ? [{ debugName: "canApply" }] : /* istanbul ignore next */ []));
2556
2749
  previewPageSize = computed(() => Math.min(Math.max(this.previewRows().length, 1), 50), ...(ngDevMode ? [{ debugName: "previewPageSize" }] : /* istanbul ignore next */ []));
2557
2750
  previewColumns = linkedSignal(() => [
2558
2751
  {
@@ -2613,6 +2806,9 @@ class TaskScheduleImportDialog {
2613
2806
  this.errorMessage.set(null);
2614
2807
  }
2615
2808
  importFile() {
2809
+ if (this.loadingImport() || this.loadingApply()) {
2810
+ return;
2811
+ }
2616
2812
  const context = this.context();
2617
2813
  const file = this.selectedFile();
2618
2814
  if (!context) {
@@ -2629,8 +2825,12 @@ class TaskScheduleImportDialog {
2629
2825
  }
2630
2826
  this.errorMessage.set(null);
2631
2827
  this.loadingImport.set(true);
2828
+ const importContext = {
2829
+ ...context,
2830
+ mppPreviewMaxRows: Math.max(1, this.maxRows()),
2831
+ };
2632
2832
  this.fetchService
2633
- .importTasks(context, file)
2833
+ .importTasks(importContext, file)
2634
2834
  .pipe(finalize(() => this.loadingImport.set(false)))
2635
2835
  .subscribe({
2636
2836
  next: (result) => {
@@ -2655,13 +2855,16 @@ class TaskScheduleImportDialog {
2655
2855
  selectAllRows(checked) {
2656
2856
  const next = new Set();
2657
2857
  if (checked) {
2658
- this.collectTaskKeys(this.importResult()?.tasks ?? []).forEach((key) => {
2858
+ this.previewRows().forEach(({ key }) => {
2659
2859
  next.add(key);
2660
2860
  });
2661
2861
  }
2662
2862
  this.selectedTaskKeys.set(next);
2663
2863
  }
2664
2864
  applyImport(overrideCurrent) {
2865
+ if (this.loadingImport() || this.loadingApply()) {
2866
+ return;
2867
+ }
2665
2868
  const context = this.context();
2666
2869
  const importResult = this.importResult();
2667
2870
  if (!context || !importResult) {
@@ -2674,7 +2877,7 @@ class TaskScheduleImportDialog {
2674
2877
  }
2675
2878
  const payload = {
2676
2879
  overrideCurrent,
2677
- data: this.buildApplyPayloadData(importResult.tasks),
2880
+ data: this.buildApplyPayloadData(),
2678
2881
  };
2679
2882
  this.errorMessage.set(null);
2680
2883
  this.loadingApply.set(true);
@@ -2806,6 +3009,9 @@ class TaskScheduleImportDialog {
2806
3009
  if (!path) {
2807
3010
  return null;
2808
3011
  }
3012
+ return this.findTaskByPath(path);
3013
+ }
3014
+ findTaskByPath(path) {
2809
3015
  const steps = path.split('.').filter((segment) => segment !== '');
2810
3016
  if (!steps.length || steps[0] !== 'root') {
2811
3017
  return null;
@@ -2840,42 +3046,53 @@ class TaskScheduleImportDialog {
2840
3046
  tasks: [...result.tasks],
2841
3047
  });
2842
3048
  }
2843
- buildApplyPayloadData(tasks) {
3049
+ buildApplyPayloadData() {
2844
3050
  const selected = this.selectedTaskKeys();
2845
- const output = [];
2846
- const walk = (rows, parentGuid, pathPrefix) => {
2847
- rows.forEach((task, index) => {
2848
- const path = `${pathPrefix}.${index}`;
2849
- const key = this.resolveTaskKey(task, path);
2850
- const payloadTask = {
2851
- ...task,
2852
- name: String(task.title ?? task.name ?? ''),
2853
- predecessors: task.predecessor ?? task.predecessors ?? '',
2854
- parentGuid: task.parentGuid ?? parentGuid,
2855
- assignedTo: this.resolveAssignedTo(task),
2856
- isSelected: selected.has(key),
2857
- subtasks: [],
2858
- children: [],
2859
- };
2860
- payloadTask['startDate'] = this.toApiDate(task.startDate);
2861
- payloadTask['finishDate'] = this.toApiDate(task.finishDate);
2862
- payloadTask['baselineStart'] = this.toApiDate(task.baselineStartDate ?? task.baselineStart);
2863
- payloadTask['baselineFinish'] = this.toApiDate(task.baselineEndDate ?? task.baselineFinish);
2864
- payloadTask['actualStart'] = this.toApiDate(task.actualStartDate ?? task.actualStart);
2865
- payloadTask['actualFinish'] = this.toApiDate(task.actualFinishDate ?? task.actualFinish);
2866
- payloadTask['customProperties'] =
2867
- task.customProperties ?? task.props ?? [];
2868
- payloadTask['isMilestone'] =
2869
- String(task.type ?? task.typeLabel ?? task.typeLable ?? '').toLowerCase() === 'milestone';
2870
- output.push(payloadTask);
2871
- const children = this.resolveChildTasks(task);
2872
- if (children.length) {
2873
- walk(children, task.guid ?? String(task.id ?? ''), path);
2874
- }
2875
- });
3051
+ return this.previewRows()
3052
+ .filter((row) => selected.has(row.key))
3053
+ .map((row) => this.buildApplyPayloadTask(row));
3054
+ }
3055
+ buildApplyPayloadTask(row) {
3056
+ const task = row.task;
3057
+ const payloadTask = {
3058
+ ...task,
3059
+ name: String(task.title ?? task.name ?? ''),
3060
+ predecessors: task.predecessor ?? task.predecessors ?? '',
3061
+ parentGuid: task.parentGuid ?? this.resolveParentGuidForPreviewRow(row.key),
3062
+ assignedTo: this.resolveAssignedTo(task),
3063
+ isSelected: true,
3064
+ subtasks: [],
3065
+ children: [],
2876
3066
  };
2877
- walk(tasks, null, 'root');
2878
- return output;
3067
+ payloadTask['startDate'] = this.toApiDate(task.startDate);
3068
+ payloadTask['finishDate'] = this.toApiDate(task.finishDate);
3069
+ payloadTask['baselineStart'] = this.toApiDate(task.baselineStartDate ?? task.baselineStart);
3070
+ payloadTask['baselineFinish'] = this.toApiDate(task.baselineEndDate ?? task.baselineFinish);
3071
+ payloadTask['actualStart'] = this.toApiDate(task.actualStartDate ?? task.actualStart);
3072
+ payloadTask['actualFinish'] = this.toApiDate(task.actualFinishDate ?? task.actualFinish);
3073
+ payloadTask['customProperties'] =
3074
+ task.customProperties ?? task.props ?? [];
3075
+ payloadTask['isMilestone'] =
3076
+ String(task.type ?? task.typeLabel ?? task.typeLable ?? '').toLowerCase() === 'milestone';
3077
+ return payloadTask;
3078
+ }
3079
+ resolveParentGuidForPreviewRow(rowKey) {
3080
+ const path = this.readPathFromRowKey(rowKey);
3081
+ if (!path) {
3082
+ return null;
3083
+ }
3084
+ const steps = path.split('.').filter((segment) => segment !== '');
3085
+ if (steps.length <= 2) {
3086
+ return null;
3087
+ }
3088
+ const parent = this.findTaskByPath(steps.slice(0, -1).join('.'));
3089
+ if (!parent) {
3090
+ return null;
3091
+ }
3092
+ const parentGuid = parent.guid ?? parent.id ?? null;
3093
+ return parentGuid === null || parentGuid === undefined
3094
+ ? null
3095
+ : String(parentGuid);
2879
3096
  }
2880
3097
  resolveChildTasks(task) {
2881
3098
  const subtasks = Array.isArray(task.subtasks) ? task.subtasks : [];
@@ -2889,21 +3106,6 @@ class TaskScheduleImportDialog {
2889
3106
  const base = task.guid ?? task.id ?? path;
2890
3107
  return `${String(base)}::${path}`;
2891
3108
  }
2892
- collectTaskKeys(tasks) {
2893
- const keys = new Set();
2894
- const walk = (rows, pathPrefix) => {
2895
- rows.forEach((task, index) => {
2896
- const path = `${pathPrefix}.${index}`;
2897
- keys.add(this.resolveTaskKey(task, path));
2898
- const children = this.resolveChildTasks(task);
2899
- if (children.length) {
2900
- walk(children, path);
2901
- }
2902
- });
2903
- };
2904
- walk(tasks, 'root');
2905
- return keys;
2906
- }
2907
3109
  resolveAssignedTo(task) {
2908
3110
  const assignedTo = task.assignedTo;
2909
3111
  if ((typeof assignedTo === 'string' || typeof assignedTo === 'number') &&
@@ -3014,6 +3216,7 @@ class TaskScheduleImportDialog {
3014
3216
  if (typeof value === 'object') {
3015
3217
  const row = value;
3016
3218
  return (this.toApiDate(row['actualValue']) ??
3219
+ this.toApiDate(row['raw']) ??
3017
3220
  this.toApiDate(row['displayValue']) ??
3018
3221
  this.toApiDate(row['value']) ??
3019
3222
  null);
@@ -3026,16 +3229,19 @@ class TaskScheduleImportDialog {
3026
3229
  const day = String(date.getDate()).padStart(2, '0');
3027
3230
  return `${year}-${month}-${day}`;
3028
3231
  }
3029
- countTasks(tasks) {
3232
+ countTasks(tasks, maxCount) {
3030
3233
  let count = 0;
3031
3234
  const walk = (rows) => {
3032
- rows.forEach((task) => {
3235
+ for (const task of rows) {
3236
+ if (count >= maxCount) {
3237
+ return;
3238
+ }
3033
3239
  count += 1;
3034
3240
  const children = this.resolveChildTasks(task);
3035
3241
  if (children.length) {
3036
3242
  walk(children);
3037
3243
  }
3038
- });
3244
+ }
3039
3245
  };
3040
3246
  walk(tasks);
3041
3247
  return count;
@@ -3044,24 +3250,24 @@ class TaskScheduleImportDialog {
3044
3250
  this.errorMessage.set(message);
3045
3251
  }
3046
3252
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: TaskScheduleImportDialog, deps: [], target: i0.ɵɵFactoryTarget.Component });
3047
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: TaskScheduleImportDialog, isStandalone: true, selector: "mt-task-schedule-import-dialog", inputs: { context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: false, transformFunction: null }, maxRows: { classPropertyName: "maxRows", publicName: "maxRows", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "selectionCellTpl", first: true, predicate: ["selectionCellTpl"], descendants: true, isSignal: true }, { propertyName: "taskCellTpl", first: true, predicate: ["taskCellTpl"], descendants: true, isSignal: true }, { propertyName: "startDateCellTpl", first: true, predicate: ["startDateCellTpl"], descendants: true, isSignal: true }, { propertyName: "finishDateCellTpl", first: true, predicate: ["finishDateCellTpl"], descendants: true, isSignal: true }, { propertyName: "actualStartDateCellTpl", first: true, predicate: ["actualStartDateCellTpl"], descendants: true, isSignal: true }, { propertyName: "actualFinishDateCellTpl", first: true, predicate: ["actualFinishDateCellTpl"], descendants: true, isSignal: true }, { propertyName: "assignedToCellTpl", first: true, predicate: ["assignedToCellTpl"], descendants: true, isSignal: true }, { propertyName: "progressCellTpl", first: true, predicate: ["progressCellTpl"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\r\n [class]=\"modal.contentClass\"\r\n [attr.dir]=\"isRtl() ? 'rtl' : 'ltr'\"\r\n class=\"flex h-full min-h-0 flex-col gap-4 !overflow-y-hidden p-5\"\r\n>\r\n <div class=\"rounded-lg border border-surface-200 bg-surface-50 p-4\">\r\n <div class=\"grid gap-3 lg:grid-cols-[minmax(0,1fr)_auto_auto] lg:items-end\">\r\n <input\r\n #fileInput\r\n class=\"hidden\"\r\n type=\"file\"\r\n accept=\".mpp,.xer\"\r\n (change)=\"onFileChanged($event)\"\r\n />\r\n\r\n <mt-text-field\r\n [ngModel]=\"selectedFile()?.name ?? ''\"\r\n [readonly]=\"true\"\r\n [placeholder]=\"labels().selectFile\"\r\n />\r\n\r\n <mt-button\r\n [label]=\"labels().selectFile\"\r\n severity=\"secondary\"\r\n variant=\"outlined\"\r\n [disabled]=\"loadingImport() || loadingApply()\"\r\n (onClick)=\"fileInput.click()\"\r\n />\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 (errorMessage()) {\r\n <div\r\n class=\"rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700\"\r\n >\r\n {{ errorMessage() }}\r\n </div>\r\n }\r\n\r\n <div class=\"min-h-0 flex-1 overflow-y-auto\">\r\n @if (importResult()) {\r\n @if (!previewRows().length) {\r\n <div\r\n class=\"rounded-lg border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-800\"\r\n >\r\n {{ labels().noTasks }}\r\n </div>\r\n } @else {\r\n <div class=\"rounded-lg border border-surface-200 bg-surface-0\">\r\n <div\r\n class=\"flex flex-wrap items-center justify-between gap-3 border-b border-surface-200 bg-surface-50 px-4 py-3\"\r\n >\r\n <div class=\"flex items-center gap-3\">\r\n <mt-checkbox-field\r\n [ngModel]=\"allSelected()\"\r\n (ngModelChange)=\"selectAllRows(!!$event)\"\r\n />\r\n <span class=\"text-sm text-surface-600\">\r\n {{ selectedTaskKeys().size }} / {{ previewRows().length }}\r\n </span>\r\n </div>\r\n\r\n @if (isTruncated()) {\r\n <p class=\"text-xs text-surface-500\">\r\n {{ labels().rowsLimited }}\r\n </p>\r\n }\r\n </div>\r\n\r\n <div class=\"px-2 py-2\">\r\n <mt-table\r\n [data]=\"previewRows()\"\r\n [columns]=\"previewColumns()\"\r\n dataKey=\"key\"\r\n storageKey=\"task-schedule-import-preview-table\"\r\n size=\"small\"\r\n [stripedRows]=\"true\"\r\n [showGridlines]=\"true\"\r\n [pageSize]=\"previewPageSize()\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n }\r\n </div>\r\n</div>\r\n\r\n<div [class]=\"modal.footerClass\">\r\n <mt-button\r\n [label]=\"labels().cancel\"\r\n variant=\"outlined\"\r\n [disabled]=\"loadingImport() || loadingApply()\"\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</div>\r\n\r\n<ng-template #selectionCellTpl let-row>\r\n <div class=\"flex items-center justify-center\">\r\n <mt-checkbox-field\r\n [ngModel]=\"selectedTaskKeys().has(row.key)\"\r\n (ngModelChange)=\"toggleRowSelection(row.key, !!$event)\"\r\n />\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #taskCellTpl let-row>\r\n <div class=\"min-w-0\" [style.paddingInlineStart.px]=\"row.depth * 18\">\r\n <mt-text-field\r\n [ngModel]=\"row.task.title || row.task.name || ''\"\r\n (ngModelChange)=\"onTaskTitleChanged(row.key, $event)\"\r\n />\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #startDateCellTpl let-row>\r\n <mt-date-field\r\n [ngModel]=\"toDateFieldValue(row.task.startDate)\"\r\n [showClear]=\"true\"\r\n (ngModelChange)=\"onTaskDateChanged(row.key, 'startDate', $event)\"\r\n />\r\n</ng-template>\r\n\r\n<ng-template #finishDateCellTpl let-row>\r\n <mt-date-field\r\n [ngModel]=\"toDateFieldValue(row.task.finishDate)\"\r\n [showClear]=\"true\"\r\n (ngModelChange)=\"onTaskDateChanged(row.key, 'finishDate', $event)\"\r\n />\r\n</ng-template>\r\n\r\n<ng-template #actualStartDateCellTpl let-row>\r\n <mt-date-field\r\n [ngModel]=\"\r\n toDateFieldValue(row.task.actualStartDate || row.task.actualStart)\r\n \"\r\n [showClear]=\"true\"\r\n (ngModelChange)=\"onTaskDateChanged(row.key, 'actualStartDate', $event)\"\r\n />\r\n</ng-template>\r\n\r\n<ng-template #actualFinishDateCellTpl let-row>\r\n <mt-date-field\r\n [ngModel]=\"\r\n toDateFieldValue(row.task.actualFinishDate || row.task.actualFinish)\r\n \"\r\n [showClear]=\"true\"\r\n (ngModelChange)=\"onTaskDateChanged(row.key, 'actualFinishDate', $event)\"\r\n />\r\n</ng-template>\r\n\r\n<ng-template #assignedToCellTpl let-row>\r\n <div class=\"min-w-0\">\r\n @if (resourceOptions().length) {\r\n <div class=\"space-y-2\">\r\n <mt-select-field\r\n [ngModel]=\"resolveAssignedValue(row.task)\"\r\n [options]=\"resourceOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"id\"\r\n [showClear]=\"true\"\r\n [hasPlaceholderPrefix]=\"false\"\r\n [placeholder]=\"labels().assignedTo\"\r\n (ngModelChange)=\"onTaskAssignedToChanged(row.key, $event)\"\r\n />\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</ng-template>\r\n\r\n<ng-template #progressCellTpl let-row>\r\n <div class=\"space-y-2\">\r\n <mt-number-field\r\n [ngModel]=\"normalizeProgress(row.task.progress)\"\r\n [min]=\"0\"\r\n [max]=\"100\"\r\n [useGrouping]=\"false\"\r\n [maxFractionDigits]=\"0\"\r\n (ngModelChange)=\"onTaskProgressChanged(row.key, $event)\"\r\n />\r\n <mt-entity-preview [data]=\"toProgressEntity(row.task)\" />\r\n </div>\r\n</ng-template>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { 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: CheckboxField, selector: "mt-checkbox-field", inputs: ["label", "labelPosition", "placeholder", "readonly", "pInputs", "required"], outputs: ["onChange"] }, { kind: "component", type: DateField, selector: "mt-date-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "showIcon", "showClear", "showTime", "pInputs", "required"] }, { kind: "component", type: EntityPreview, selector: "mt-entity-preview", inputs: ["data", "attachmentShape"] }, { kind: "component", type: NumberField, selector: "mt-number-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "pInputs", "format", "useGrouping", "maxFractionDigits", "min", "max", "required"] }, { kind: "component", type: SelectField, selector: "mt-select-field", inputs: ["field", "hint", "label", "placeholder", "hasPlaceholderPrefix", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "clearAfterSelect", "required", "group", "size", "optionGroupLabel", "optionGroupChildren", "loading", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape", "markCurrentUser"], outputs: ["onChange"] }, { kind: "component", type: Table, selector: "mt-table", inputs: ["filters", "data", "columns", "rowActions", "size", "showGridlines", "stripedRows", "selectableRows", "clickableRows", "generalSearch", "lazyLocalSearch", "showFilters", "filterMode", "loading", "updating", "lazy", "lazyLocalSort", "lazyTotalRecords", "reorderableColumns", "reorderableRows", "dataKey", "storageKey", "storageMode", "exportable", "printable", "groupable", "cellClickFilter", "freezeActions", "printTitle", "exportFilename", "actionShape", "rowActionsLoadingFn", "tableLayout", "noCard", "tabs", "tabsOptionLabel", "tabsOptionValue", "activeTab", "actions", "paginatorPosition", "alwaysShowPaginator", "rowsPerPageOptions", "pageSize", "currentPage", "first", "filterTerm", "groupBy"], outputs: ["selectionChange", "cellChange", "lazyLoad", "columnReorder", "rowReorder", "rowClick", "rowActionsRequested", "filtersChange", "activeTabChange", "onTabChange", "pageSizeChange", "currentPageChange", "firstChange", "filterTermChange", "groupByChange"] }, { kind: "component", type: TextField, selector: "mt-text-field", inputs: ["field", "hint", "label", "placeholder", "class", "type", "readonly", "pInputs", "required", "maxLength", "icon", "iconPosition"] }, { kind: "ngmodule", type: TranslocoModule }] });
3253
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: TaskScheduleImportDialog, isStandalone: true, selector: "mt-task-schedule-import-dialog", inputs: { context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: false, transformFunction: null }, maxRows: { classPropertyName: "maxRows", publicName: "maxRows", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "selectionCellTpl", first: true, predicate: ["selectionCellTpl"], descendants: true, isSignal: true }, { propertyName: "taskCellTpl", first: true, predicate: ["taskCellTpl"], descendants: true, isSignal: true }, { propertyName: "startDateCellTpl", first: true, predicate: ["startDateCellTpl"], descendants: true, isSignal: true }, { propertyName: "finishDateCellTpl", first: true, predicate: ["finishDateCellTpl"], descendants: true, isSignal: true }, { propertyName: "actualStartDateCellTpl", first: true, predicate: ["actualStartDateCellTpl"], descendants: true, isSignal: true }, { propertyName: "actualFinishDateCellTpl", first: true, predicate: ["actualFinishDateCellTpl"], descendants: true, isSignal: true }, { propertyName: "assignedToCellTpl", first: true, predicate: ["assignedToCellTpl"], descendants: true, isSignal: true }, { propertyName: "progressCellTpl", first: true, predicate: ["progressCellTpl"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n [class]=\"modal.contentClass\"\n [attr.dir]=\"isRtl() ? 'rtl' : 'ltr'\"\n class=\"flex h-full min-h-0 flex-col gap-4 !overflow-y-hidden p-5\"\n>\n <div class=\"rounded-lg border border-surface-200 bg-surface-50 p-4\">\n <div class=\"grid gap-3 lg:grid-cols-[minmax(0,1fr)_auto_auto] lg:items-end\">\n <input\n #fileInput\n class=\"hidden\"\n type=\"file\"\n accept=\".mpp,.xer\"\n (change)=\"onFileChanged($event)\"\n />\n\n <mt-text-field\n [ngModel]=\"selectedFile()?.name ?? ''\"\n [readonly]=\"true\"\n [placeholder]=\"labels().selectFile\"\n />\n\n <mt-button\n [label]=\"labels().selectFile\"\n severity=\"secondary\"\n variant=\"outlined\"\n [disabled]=\"loadingImport() || loadingApply()\"\n (onClick)=\"fileInput.click()\"\n />\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 (errorMessage()) {\n <div\n class=\"rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700\"\n >\n {{ errorMessage() }}\n </div>\n }\n\n <div class=\"min-h-0 flex-1 overflow-y-auto\">\n @if (importResult()) {\n @if (!previewRows().length) {\n <div\n class=\"rounded-lg border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-800\"\n >\n {{ labels().noTasks }}\n </div>\n } @else {\n <div class=\"rounded-lg border border-surface-200 bg-surface-0\">\n <div\n class=\"flex flex-wrap items-center justify-between gap-3 border-b border-surface-200 bg-surface-50 px-4 py-3\"\n >\n <div class=\"flex items-center gap-3\">\n <mt-checkbox-field\n [ngModel]=\"allSelected()\"\n (ngModelChange)=\"selectAllRows(!!$event)\"\n />\n <span class=\"text-sm text-surface-600\">\n {{ selectedTaskKeys().size }} / {{ previewRows().length }}\n </span>\n </div>\n\n @if (isTruncated()) {\n <p class=\"text-xs text-surface-500\">\n {{ labels().rowsLimited }}\n </p>\n }\n </div>\n\n <div class=\"px-2 py-2\">\n @defer (on idle) {\n <mt-table\n [data]=\"previewRows()\"\n [columns]=\"previewColumns()\"\n dataKey=\"key\"\n storageKey=\"task-schedule-import-preview-table\"\n size=\"small\"\n [stripedRows]=\"true\"\n [showGridlines]=\"true\"\n [pageSize]=\"previewPageSize()\"\n />\n } @placeholder {\n <div class=\"space-y-2 p-2\">\n <div class=\"h-9 rounded bg-surface-100\"></div>\n <div class=\"h-9 rounded bg-surface-100\"></div>\n <div class=\"h-9 rounded bg-surface-100\"></div>\n </div>\n }\n </div>\n </div>\n }\n }\n </div>\n</div>\n\n<div [class]=\"modal.footerClass\">\n <mt-button\n [label]=\"labels().cancel\"\n variant=\"outlined\"\n [disabled]=\"loadingImport() || loadingApply()\"\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</div>\n\n<ng-template #selectionCellTpl let-row>\n <div class=\"flex items-center justify-center\">\n <mt-checkbox-field\n [ngModel]=\"selectedTaskKeys().has(row.key)\"\n (ngModelChange)=\"toggleRowSelection(row.key, !!$event)\"\n />\n </div>\n</ng-template>\n\n<ng-template #taskCellTpl let-row>\n <div class=\"min-w-0\" [style.paddingInlineStart.px]=\"row.depth * 18\">\n <mt-text-field\n [ngModel]=\"row.task.title || row.task.name || ''\"\n (ngModelChange)=\"onTaskTitleChanged(row.key, $event)\"\n />\n </div>\n</ng-template>\n\n<ng-template #startDateCellTpl let-row>\n <mt-date-field\n [ngModel]=\"toDateFieldValue(row.task.startDate)\"\n [showClear]=\"true\"\n (ngModelChange)=\"onTaskDateChanged(row.key, 'startDate', $event)\"\n />\n</ng-template>\n\n<ng-template #finishDateCellTpl let-row>\n <mt-date-field\n [ngModel]=\"toDateFieldValue(row.task.finishDate)\"\n [showClear]=\"true\"\n (ngModelChange)=\"onTaskDateChanged(row.key, 'finishDate', $event)\"\n />\n</ng-template>\n\n<ng-template #actualStartDateCellTpl let-row>\n <mt-date-field\n [ngModel]=\"\n toDateFieldValue(row.task.actualStartDate || row.task.actualStart)\n \"\n [showClear]=\"true\"\n (ngModelChange)=\"onTaskDateChanged(row.key, 'actualStartDate', $event)\"\n />\n</ng-template>\n\n<ng-template #actualFinishDateCellTpl let-row>\n <mt-date-field\n [ngModel]=\"\n toDateFieldValue(row.task.actualFinishDate || row.task.actualFinish)\n \"\n [showClear]=\"true\"\n (ngModelChange)=\"onTaskDateChanged(row.key, 'actualFinishDate', $event)\"\n />\n</ng-template>\n\n<ng-template #assignedToCellTpl let-row>\n <div class=\"min-w-0\">\n @if (resourceOptions().length) {\n <div class=\"space-y-2\">\n <mt-select-field\n [ngModel]=\"resolveAssignedValue(row.task)\"\n [options]=\"resourceOptions()\"\n optionLabel=\"label\"\n optionValue=\"id\"\n [showClear]=\"true\"\n [hasPlaceholderPrefix]=\"false\"\n [placeholder]=\"labels().assignedTo\"\n (ngModelChange)=\"onTaskAssignedToChanged(row.key, $event)\"\n />\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</ng-template>\n\n<ng-template #progressCellTpl let-row>\n <div class=\"space-y-2\">\n <mt-number-field\n [ngModel]=\"normalizeProgress(row.task.progress)\"\n [min]=\"0\"\n [max]=\"100\"\n [useGrouping]=\"false\"\n [maxFractionDigits]=\"0\"\n (ngModelChange)=\"onTaskProgressChanged(row.key, $event)\"\n />\n <mt-entity-preview [data]=\"toProgressEntity(row.task)\" />\n </div>\n</ng-template>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { 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: CheckboxField, selector: "mt-checkbox-field", inputs: ["label", "labelPosition", "placeholder", "readonly", "pInputs", "required"], outputs: ["onChange"] }, { kind: "component", type: DateField, selector: "mt-date-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "showIcon", "showClear", "showTime", "pInputs", "required"] }, { kind: "component", type: EntityPreview, selector: "mt-entity-preview", inputs: ["data", "attachmentShape"] }, { kind: "component", type: NumberField, selector: "mt-number-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "pInputs", "format", "useGrouping", "maxFractionDigits", "min", "max", "required"] }, { kind: "component", type: SelectField, selector: "mt-select-field", inputs: ["field", "hint", "label", "placeholder", "hasPlaceholderPrefix", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "clearAfterSelect", "required", "group", "size", "optionGroupLabel", "optionGroupChildren", "loading", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape", "markCurrentUser"], outputs: ["onChange"] }, { kind: "component", type: TextField, selector: "mt-text-field", inputs: ["field", "hint", "label", "placeholder", "class", "type", "readonly", "pInputs", "required", "maxLength", "icon", "iconPosition"] }, { kind: "ngmodule", type: TranslocoModule }], deferBlockDependencies: [() => [import('@masterteam/components/table').then(m => m.Table)]] });
3048
3254
  }
3049
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: TaskScheduleImportDialog, decorators: [{
3050
- type: Component,
3051
- args: [{ selector: 'mt-task-schedule-import-dialog', standalone: true, imports: [
3052
- CommonModule,
3053
- FormsModule,
3054
- Button,
3055
- CheckboxField,
3056
- DateField,
3057
- EntityPreview,
3058
- NumberField,
3059
- SelectField,
3060
- Table,
3061
- TextField,
3062
- TranslocoModule,
3063
- ], template: "<div\r\n [class]=\"modal.contentClass\"\r\n [attr.dir]=\"isRtl() ? 'rtl' : 'ltr'\"\r\n class=\"flex h-full min-h-0 flex-col gap-4 !overflow-y-hidden p-5\"\r\n>\r\n <div class=\"rounded-lg border border-surface-200 bg-surface-50 p-4\">\r\n <div class=\"grid gap-3 lg:grid-cols-[minmax(0,1fr)_auto_auto] lg:items-end\">\r\n <input\r\n #fileInput\r\n class=\"hidden\"\r\n type=\"file\"\r\n accept=\".mpp,.xer\"\r\n (change)=\"onFileChanged($event)\"\r\n />\r\n\r\n <mt-text-field\r\n [ngModel]=\"selectedFile()?.name ?? ''\"\r\n [readonly]=\"true\"\r\n [placeholder]=\"labels().selectFile\"\r\n />\r\n\r\n <mt-button\r\n [label]=\"labels().selectFile\"\r\n severity=\"secondary\"\r\n variant=\"outlined\"\r\n [disabled]=\"loadingImport() || loadingApply()\"\r\n (onClick)=\"fileInput.click()\"\r\n />\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 (errorMessage()) {\r\n <div\r\n class=\"rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700\"\r\n >\r\n {{ errorMessage() }}\r\n </div>\r\n }\r\n\r\n <div class=\"min-h-0 flex-1 overflow-y-auto\">\r\n @if (importResult()) {\r\n @if (!previewRows().length) {\r\n <div\r\n class=\"rounded-lg border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-800\"\r\n >\r\n {{ labels().noTasks }}\r\n </div>\r\n } @else {\r\n <div class=\"rounded-lg border border-surface-200 bg-surface-0\">\r\n <div\r\n class=\"flex flex-wrap items-center justify-between gap-3 border-b border-surface-200 bg-surface-50 px-4 py-3\"\r\n >\r\n <div class=\"flex items-center gap-3\">\r\n <mt-checkbox-field\r\n [ngModel]=\"allSelected()\"\r\n (ngModelChange)=\"selectAllRows(!!$event)\"\r\n />\r\n <span class=\"text-sm text-surface-600\">\r\n {{ selectedTaskKeys().size }} / {{ previewRows().length }}\r\n </span>\r\n </div>\r\n\r\n @if (isTruncated()) {\r\n <p class=\"text-xs text-surface-500\">\r\n {{ labels().rowsLimited }}\r\n </p>\r\n }\r\n </div>\r\n\r\n <div class=\"px-2 py-2\">\r\n <mt-table\r\n [data]=\"previewRows()\"\r\n [columns]=\"previewColumns()\"\r\n dataKey=\"key\"\r\n storageKey=\"task-schedule-import-preview-table\"\r\n size=\"small\"\r\n [stripedRows]=\"true\"\r\n [showGridlines]=\"true\"\r\n [pageSize]=\"previewPageSize()\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n }\r\n </div>\r\n</div>\r\n\r\n<div [class]=\"modal.footerClass\">\r\n <mt-button\r\n [label]=\"labels().cancel\"\r\n variant=\"outlined\"\r\n [disabled]=\"loadingImport() || loadingApply()\"\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</div>\r\n\r\n<ng-template #selectionCellTpl let-row>\r\n <div class=\"flex items-center justify-center\">\r\n <mt-checkbox-field\r\n [ngModel]=\"selectedTaskKeys().has(row.key)\"\r\n (ngModelChange)=\"toggleRowSelection(row.key, !!$event)\"\r\n />\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #taskCellTpl let-row>\r\n <div class=\"min-w-0\" [style.paddingInlineStart.px]=\"row.depth * 18\">\r\n <mt-text-field\r\n [ngModel]=\"row.task.title || row.task.name || ''\"\r\n (ngModelChange)=\"onTaskTitleChanged(row.key, $event)\"\r\n />\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #startDateCellTpl let-row>\r\n <mt-date-field\r\n [ngModel]=\"toDateFieldValue(row.task.startDate)\"\r\n [showClear]=\"true\"\r\n (ngModelChange)=\"onTaskDateChanged(row.key, 'startDate', $event)\"\r\n />\r\n</ng-template>\r\n\r\n<ng-template #finishDateCellTpl let-row>\r\n <mt-date-field\r\n [ngModel]=\"toDateFieldValue(row.task.finishDate)\"\r\n [showClear]=\"true\"\r\n (ngModelChange)=\"onTaskDateChanged(row.key, 'finishDate', $event)\"\r\n />\r\n</ng-template>\r\n\r\n<ng-template #actualStartDateCellTpl let-row>\r\n <mt-date-field\r\n [ngModel]=\"\r\n toDateFieldValue(row.task.actualStartDate || row.task.actualStart)\r\n \"\r\n [showClear]=\"true\"\r\n (ngModelChange)=\"onTaskDateChanged(row.key, 'actualStartDate', $event)\"\r\n />\r\n</ng-template>\r\n\r\n<ng-template #actualFinishDateCellTpl let-row>\r\n <mt-date-field\r\n [ngModel]=\"\r\n toDateFieldValue(row.task.actualFinishDate || row.task.actualFinish)\r\n \"\r\n [showClear]=\"true\"\r\n (ngModelChange)=\"onTaskDateChanged(row.key, 'actualFinishDate', $event)\"\r\n />\r\n</ng-template>\r\n\r\n<ng-template #assignedToCellTpl let-row>\r\n <div class=\"min-w-0\">\r\n @if (resourceOptions().length) {\r\n <div class=\"space-y-2\">\r\n <mt-select-field\r\n [ngModel]=\"resolveAssignedValue(row.task)\"\r\n [options]=\"resourceOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"id\"\r\n [showClear]=\"true\"\r\n [hasPlaceholderPrefix]=\"false\"\r\n [placeholder]=\"labels().assignedTo\"\r\n (ngModelChange)=\"onTaskAssignedToChanged(row.key, $event)\"\r\n />\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</ng-template>\r\n\r\n<ng-template #progressCellTpl let-row>\r\n <div class=\"space-y-2\">\r\n <mt-number-field\r\n [ngModel]=\"normalizeProgress(row.task.progress)\"\r\n [min]=\"0\"\r\n [max]=\"100\"\r\n [useGrouping]=\"false\"\r\n [maxFractionDigits]=\"0\"\r\n (ngModelChange)=\"onTaskProgressChanged(row.key, $event)\"\r\n />\r\n <mt-entity-preview [data]=\"toProgressEntity(row.task)\" />\r\n </div>\r\n</ng-template>\r\n" }]
3064
- }], propDecorators: { selectionCellTpl: [{ type: i0.ViewChild, args: ['selectionCellTpl', { isSignal: true }] }], taskCellTpl: [{ type: i0.ViewChild, args: ['taskCellTpl', { isSignal: true }] }], startDateCellTpl: [{ type: i0.ViewChild, args: ['startDateCellTpl', { isSignal: true }] }], finishDateCellTpl: [{ type: i0.ViewChild, args: ['finishDateCellTpl', { isSignal: true }] }], actualStartDateCellTpl: [{ type: i0.ViewChild, args: ['actualStartDateCellTpl', { isSignal: true }] }], actualFinishDateCellTpl: [{ type: i0.ViewChild, args: ['actualFinishDateCellTpl', { isSignal: true }] }], assignedToCellTpl: [{ type: i0.ViewChild, args: ['assignedToCellTpl', { isSignal: true }] }], progressCellTpl: [{ type: i0.ViewChild, args: ['progressCellTpl', { isSignal: true }] }], context: [{ type: i0.Input, args: [{ isSignal: true, alias: "context", required: false }] }], maxRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxRows", required: false }] }] } });
3255
+ i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "21.2.8", ngImport: i0, type: TaskScheduleImportDialog, resolveDeferredDeps: () => [import('@masterteam/components/table').then(m => m.Table)], resolveMetadata: Table => ({ decorators: [{
3256
+ type: Component,
3257
+ args: [{ selector: 'mt-task-schedule-import-dialog', standalone: true, imports: [
3258
+ CommonModule,
3259
+ FormsModule,
3260
+ Button,
3261
+ CheckboxField,
3262
+ DateField,
3263
+ EntityPreview,
3264
+ NumberField,
3265
+ SelectField,
3266
+ Table,
3267
+ TextField,
3268
+ TranslocoModule,
3269
+ ], template: "<div\n [class]=\"modal.contentClass\"\n [attr.dir]=\"isRtl() ? 'rtl' : 'ltr'\"\n class=\"flex h-full min-h-0 flex-col gap-4 !overflow-y-hidden p-5\"\n>\n <div class=\"rounded-lg border border-surface-200 bg-surface-50 p-4\">\n <div class=\"grid gap-3 lg:grid-cols-[minmax(0,1fr)_auto_auto] lg:items-end\">\n <input\n #fileInput\n class=\"hidden\"\n type=\"file\"\n accept=\".mpp,.xer\"\n (change)=\"onFileChanged($event)\"\n />\n\n <mt-text-field\n [ngModel]=\"selectedFile()?.name ?? ''\"\n [readonly]=\"true\"\n [placeholder]=\"labels().selectFile\"\n />\n\n <mt-button\n [label]=\"labels().selectFile\"\n severity=\"secondary\"\n variant=\"outlined\"\n [disabled]=\"loadingImport() || loadingApply()\"\n (onClick)=\"fileInput.click()\"\n />\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 (errorMessage()) {\n <div\n class=\"rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700\"\n >\n {{ errorMessage() }}\n </div>\n }\n\n <div class=\"min-h-0 flex-1 overflow-y-auto\">\n @if (importResult()) {\n @if (!previewRows().length) {\n <div\n class=\"rounded-lg border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-800\"\n >\n {{ labels().noTasks }}\n </div>\n } @else {\n <div class=\"rounded-lg border border-surface-200 bg-surface-0\">\n <div\n class=\"flex flex-wrap items-center justify-between gap-3 border-b border-surface-200 bg-surface-50 px-4 py-3\"\n >\n <div class=\"flex items-center gap-3\">\n <mt-checkbox-field\n [ngModel]=\"allSelected()\"\n (ngModelChange)=\"selectAllRows(!!$event)\"\n />\n <span class=\"text-sm text-surface-600\">\n {{ selectedTaskKeys().size }} / {{ previewRows().length }}\n </span>\n </div>\n\n @if (isTruncated()) {\n <p class=\"text-xs text-surface-500\">\n {{ labels().rowsLimited }}\n </p>\n }\n </div>\n\n <div class=\"px-2 py-2\">\n @defer (on idle) {\n <mt-table\n [data]=\"previewRows()\"\n [columns]=\"previewColumns()\"\n dataKey=\"key\"\n storageKey=\"task-schedule-import-preview-table\"\n size=\"small\"\n [stripedRows]=\"true\"\n [showGridlines]=\"true\"\n [pageSize]=\"previewPageSize()\"\n />\n } @placeholder {\n <div class=\"space-y-2 p-2\">\n <div class=\"h-9 rounded bg-surface-100\"></div>\n <div class=\"h-9 rounded bg-surface-100\"></div>\n <div class=\"h-9 rounded bg-surface-100\"></div>\n </div>\n }\n </div>\n </div>\n }\n }\n </div>\n</div>\n\n<div [class]=\"modal.footerClass\">\n <mt-button\n [label]=\"labels().cancel\"\n variant=\"outlined\"\n [disabled]=\"loadingImport() || loadingApply()\"\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</div>\n\n<ng-template #selectionCellTpl let-row>\n <div class=\"flex items-center justify-center\">\n <mt-checkbox-field\n [ngModel]=\"selectedTaskKeys().has(row.key)\"\n (ngModelChange)=\"toggleRowSelection(row.key, !!$event)\"\n />\n </div>\n</ng-template>\n\n<ng-template #taskCellTpl let-row>\n <div class=\"min-w-0\" [style.paddingInlineStart.px]=\"row.depth * 18\">\n <mt-text-field\n [ngModel]=\"row.task.title || row.task.name || ''\"\n (ngModelChange)=\"onTaskTitleChanged(row.key, $event)\"\n />\n </div>\n</ng-template>\n\n<ng-template #startDateCellTpl let-row>\n <mt-date-field\n [ngModel]=\"toDateFieldValue(row.task.startDate)\"\n [showClear]=\"true\"\n (ngModelChange)=\"onTaskDateChanged(row.key, 'startDate', $event)\"\n />\n</ng-template>\n\n<ng-template #finishDateCellTpl let-row>\n <mt-date-field\n [ngModel]=\"toDateFieldValue(row.task.finishDate)\"\n [showClear]=\"true\"\n (ngModelChange)=\"onTaskDateChanged(row.key, 'finishDate', $event)\"\n />\n</ng-template>\n\n<ng-template #actualStartDateCellTpl let-row>\n <mt-date-field\n [ngModel]=\"\n toDateFieldValue(row.task.actualStartDate || row.task.actualStart)\n \"\n [showClear]=\"true\"\n (ngModelChange)=\"onTaskDateChanged(row.key, 'actualStartDate', $event)\"\n />\n</ng-template>\n\n<ng-template #actualFinishDateCellTpl let-row>\n <mt-date-field\n [ngModel]=\"\n toDateFieldValue(row.task.actualFinishDate || row.task.actualFinish)\n \"\n [showClear]=\"true\"\n (ngModelChange)=\"onTaskDateChanged(row.key, 'actualFinishDate', $event)\"\n />\n</ng-template>\n\n<ng-template #assignedToCellTpl let-row>\n <div class=\"min-w-0\">\n @if (resourceOptions().length) {\n <div class=\"space-y-2\">\n <mt-select-field\n [ngModel]=\"resolveAssignedValue(row.task)\"\n [options]=\"resourceOptions()\"\n optionLabel=\"label\"\n optionValue=\"id\"\n [showClear]=\"true\"\n [hasPlaceholderPrefix]=\"false\"\n [placeholder]=\"labels().assignedTo\"\n (ngModelChange)=\"onTaskAssignedToChanged(row.key, $event)\"\n />\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</ng-template>\n\n<ng-template #progressCellTpl let-row>\n <div class=\"space-y-2\">\n <mt-number-field\n [ngModel]=\"normalizeProgress(row.task.progress)\"\n [min]=\"0\"\n [max]=\"100\"\n [useGrouping]=\"false\"\n [maxFractionDigits]=\"0\"\n (ngModelChange)=\"onTaskProgressChanged(row.key, $event)\"\n />\n <mt-entity-preview [data]=\"toProgressEntity(row.task)\" />\n </div>\n</ng-template>\n" }]
3270
+ }], ctorParameters: null, propDecorators: { selectionCellTpl: [{ type: i0.ViewChild, args: ['selectionCellTpl', { isSignal: true }] }], taskCellTpl: [{ type: i0.ViewChild, args: ['taskCellTpl', { isSignal: true }] }], startDateCellTpl: [{ type: i0.ViewChild, args: ['startDateCellTpl', { isSignal: true }] }], finishDateCellTpl: [{ type: i0.ViewChild, args: ['finishDateCellTpl', { isSignal: true }] }], actualStartDateCellTpl: [{ type: i0.ViewChild, args: ['actualStartDateCellTpl', { isSignal: true }] }], actualFinishDateCellTpl: [{ type: i0.ViewChild, args: ['actualFinishDateCellTpl', { isSignal: true }] }], assignedToCellTpl: [{ type: i0.ViewChild, args: ['assignedToCellTpl', { isSignal: true }] }], progressCellTpl: [{ type: i0.ViewChild, args: ['progressCellTpl', { isSignal: true }] }], context: [{ type: i0.Input, args: [{ isSignal: true, alias: "context", required: false }] }], maxRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxRows", required: false }] }] } }) });
3065
3271
 
3066
3272
  class TaskScheduleQueueService {
3067
3273
  basicOrderColumns = new Map();
@@ -3270,6 +3476,7 @@ class TaskSchedule {
3270
3476
  fetchService = inject(TaskScheduleFetchService);
3271
3477
  actionService = inject(TaskScheduleActionService);
3272
3478
  modal = inject(ModalService);
3479
+ dateFormats = inject(MT_DATE_FORMATS);
3273
3480
  queueService = inject(TaskScheduleQueueService);
3274
3481
  injector = inject(Injector);
3275
3482
  loadEffect;
@@ -3299,7 +3506,7 @@ class TaskSchedule {
3299
3506
  }, ...(ngDevMode ? [{ debugName: "treeColumnIndex" }] : /* istanbul ignore next */ []));
3300
3507
  ganttId = `mtTaskScheduleGantt-${Math.random().toString(36).slice(2, 10)}`;
3301
3508
  resolvedModelTypeInput = computed(() => this.context()?.modelType ?? 'default', ...(ngDevMode ? [{ debugName: "resolvedModelTypeInput" }] : /* istanbul ignore next */ []));
3302
- resolvedDateFormat = computed(() => this.context()?.dateFormat ?? 'dd/MM/yyyy', ...(ngDevMode ? [{ debugName: "resolvedDateFormat" }] : /* istanbul ignore next */ []));
3509
+ resolvedDateFormat = computed(() => toAngularDateFormat(this.context()?.dateFormat ?? this.dateFormats.date), ...(ngDevMode ? [{ debugName: "resolvedDateFormat" }] : /* istanbul ignore next */ []));
3303
3510
  resolvedHeight = computed(() => this.context()?.height ?? '760px', ...(ngDevMode ? [{ debugName: "resolvedHeight" }] : /* istanbul ignore next */ []));
3304
3511
  resolvedModelType = computed(() => normalizeTaskScheduleModelType(this.resolvedModelTypeInput()), ...(ngDevMode ? [{ debugName: "resolvedModelType" }] : /* istanbul ignore next */ []));
3305
3512
  resolvedLangCode = computed(() => this.context()?.langCode === 'ar' ? 'ar' : 'en', ...(ngDevMode ? [{ debugName: "resolvedLangCode" }] : /* istanbul ignore next */ []));
@@ -3891,11 +4098,16 @@ class TaskSchedule {
3891
4098
  ToolbarService,
3892
4099
  ContextMenuService,
3893
4100
  ResizeService,
3894
- ], 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\"\r\n [allowResizing]=\"true\"\r\n [enableRtl]=\"enableRtl()\"\r\n [locale]=\"locale()\"\r\n [height]=\"resolvedHeight()\"\r\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]=\"treeColumnIndex()\"\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 [allowRowDragAndDrop]=\"ganttConfig().allowRowDragAndDrop\"\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()\"\r\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 {{ data?.startDate ?? \"-\" }}\r\n </div>\r\n <div>\r\n {{ tooltipTranslations().endsOn }}:\r\n {{ data?.finishDate ?? \"-\" }}\r\n </div>\r\n @if (data?.baselineStartDate) {\r\n <div>\r\n {{ tooltipTranslations().plannedStart }}:\r\n {{ data?.baselineStartDate ?? \"-\" }}\r\n </div>\r\n }\r\n @if (data?.baselineEndDate) {\r\n <div>\r\n {{ tooltipTranslations().plannedEnd }}:\r\n {{ data?.baselineEndDate ?? \"-\" }}\r\n </div>\r\n }\r\n <div>\r\n {{ tooltipTranslations().progress }}: {{ data?.progress ?? 0 }}\r\n </div>\r\n </div>\r\n </ng-template>\r\n\r\n <ng-template #taskbarTemplate let-data>\r\n <mt-task-schedule-taskbar-template\r\n [data]=\"data\"\r\n [langCode]=\"resolvedLangCode()\"\r\n />\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$1.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"] }] });
4101
+ ], 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\"\r\n [allowResizing]=\"true\"\r\n [enableRtl]=\"enableRtl()\"\r\n [locale]=\"locale()\"\r\n [height]=\"resolvedHeight()\"\r\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]=\"treeColumnIndex()\"\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 [allowRowDragAndDrop]=\"ganttConfig().allowRowDragAndDrop\"\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()\"\r\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 {{ data?.startDate ? (data.startDate | mtDateFormat: \"date\") : \"-\" }}\r\n </div>\r\n <div>\r\n {{ tooltipTranslations().endsOn }}:\r\n {{\r\n data?.finishDate ? (data.finishDate | mtDateFormat: \"date\") : \"-\"\r\n }}\r\n </div>\r\n @if (data?.baselineStartDate) {\r\n <div>\r\n {{ tooltipTranslations().plannedStart }}:\r\n {{\r\n data?.baselineStartDate\r\n ? (data.baselineStartDate | mtDateFormat: \"date\")\r\n : \"-\"\r\n }}\r\n </div>\r\n }\r\n @if (data?.baselineEndDate) {\r\n <div>\r\n {{ tooltipTranslations().plannedEnd }}:\r\n {{\r\n data?.baselineEndDate\r\n ? (data.baselineEndDate | mtDateFormat: \"date\")\r\n : \"-\"\r\n }}\r\n </div>\r\n }\r\n <div>\r\n {{ tooltipTranslations().progress }}: {{ data?.progress ?? 0 }}\r\n </div>\r\n </div>\r\n </ng-template>\r\n\r\n <ng-template #taskbarTemplate let-data>\r\n <mt-task-schedule-taskbar-template\r\n [data]=\"data\"\r\n [langCode]=\"resolvedLangCode()\"\r\n />\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$1.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"] }, { kind: "pipe", type: MTDateFormatPipe, name: "mtDateFormat" }] });
3895
4102
  }
3896
4103
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: TaskSchedule, decorators: [{
3897
4104
  type: Component,
3898
- args: [{ selector: 'mt-task-schedule', standalone: true, imports: [CommonModule, GanttModule, TaskScheduleTaskbarTemplate], host: { class: 'block' }, providers: [
4105
+ args: [{ selector: 'mt-task-schedule', standalone: true, imports: [
4106
+ CommonModule,
4107
+ GanttModule,
4108
+ MTDateFormatPipe,
4109
+ TaskScheduleTaskbarTemplate,
4110
+ ], host: { class: 'block' }, providers: [
3899
4111
  DayMarkersService,
3900
4112
  EditService,
3901
4113
  ExcelExportService,
@@ -3908,7 +4120,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
3908
4120
  ToolbarService,
3909
4121
  ContextMenuService,
3910
4122
  ResizeService,
3911
- ], 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\"\r\n [allowResizing]=\"true\"\r\n [enableRtl]=\"enableRtl()\"\r\n [locale]=\"locale()\"\r\n [height]=\"resolvedHeight()\"\r\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]=\"treeColumnIndex()\"\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 [allowRowDragAndDrop]=\"ganttConfig().allowRowDragAndDrop\"\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()\"\r\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 {{ data?.startDate ?? \"-\" }}\r\n </div>\r\n <div>\r\n {{ tooltipTranslations().endsOn }}:\r\n {{ data?.finishDate ?? \"-\" }}\r\n </div>\r\n @if (data?.baselineStartDate) {\r\n <div>\r\n {{ tooltipTranslations().plannedStart }}:\r\n {{ data?.baselineStartDate ?? \"-\" }}\r\n </div>\r\n }\r\n @if (data?.baselineEndDate) {\r\n <div>\r\n {{ tooltipTranslations().plannedEnd }}:\r\n {{ data?.baselineEndDate ?? \"-\" }}\r\n </div>\r\n }\r\n <div>\r\n {{ tooltipTranslations().progress }}: {{ data?.progress ?? 0 }}\r\n </div>\r\n </div>\r\n </ng-template>\r\n\r\n <ng-template #taskbarTemplate let-data>\r\n <mt-task-schedule-taskbar-template\r\n [data]=\"data\"\r\n [langCode]=\"resolvedLangCode()\"\r\n />\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"] }]
4123
+ ], 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\"\r\n [allowResizing]=\"true\"\r\n [enableRtl]=\"enableRtl()\"\r\n [locale]=\"locale()\"\r\n [height]=\"resolvedHeight()\"\r\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]=\"treeColumnIndex()\"\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 [allowRowDragAndDrop]=\"ganttConfig().allowRowDragAndDrop\"\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()\"\r\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 {{ data?.startDate ? (data.startDate | mtDateFormat: \"date\") : \"-\" }}\r\n </div>\r\n <div>\r\n {{ tooltipTranslations().endsOn }}:\r\n {{\r\n data?.finishDate ? (data.finishDate | mtDateFormat: \"date\") : \"-\"\r\n }}\r\n </div>\r\n @if (data?.baselineStartDate) {\r\n <div>\r\n {{ tooltipTranslations().plannedStart }}:\r\n {{\r\n data?.baselineStartDate\r\n ? (data.baselineStartDate | mtDateFormat: \"date\")\r\n : \"-\"\r\n }}\r\n </div>\r\n }\r\n @if (data?.baselineEndDate) {\r\n <div>\r\n {{ tooltipTranslations().plannedEnd }}:\r\n {{\r\n data?.baselineEndDate\r\n ? (data.baselineEndDate | mtDateFormat: \"date\")\r\n : \"-\"\r\n }}\r\n </div>\r\n }\r\n <div>\r\n {{ tooltipTranslations().progress }}: {{ data?.progress ?? 0 }}\r\n </div>\r\n </div>\r\n </ng-template>\r\n\r\n <ng-template #taskbarTemplate let-data>\r\n <mt-task-schedule-taskbar-template\r\n [data]=\"data\"\r\n [langCode]=\"resolvedLangCode()\"\r\n />\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"] }]
3912
4124
  }], propDecorators: { ganttObj: [{
3913
4125
  type: ViewChild,
3914
4126
  args: ['ganttObj']