@masterteam/workspace-builder 0.0.10 → 0.0.12

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.
@@ -1,8 +1,7 @@
1
1
  import * as i1$1 from '@angular/common';
2
2
  import { CommonModule } from '@angular/common';
3
3
  import * as i0 from '@angular/core';
4
- import { inject, Injectable, computed, input, signal, linkedSignal, Component, booleanAttribute, effect, ChangeDetectionStrategy } from '@angular/core';
5
- import { toSignal } from '@angular/core/rxjs-interop';
4
+ import { inject, Injectable, computed, signal, linkedSignal, Component, input, booleanAttribute, effect, ChangeDetectionStrategy } from '@angular/core';
6
5
  import { TranslocoService, TranslocoDirective } from '@jsverse/transloco';
7
6
  import { ConfirmationService } from '@masterteam/components/confirmation';
8
7
  import { DynamicDialogConfig, ModalRef, DialogService } from '@masterteam/components/dialog';
@@ -10,11 +9,9 @@ import { ModalService } from '@masterteam/components/modal';
10
9
  import { Page } from '@masterteam/components/page';
11
10
  import { Card } from '@masterteam/components/card';
12
11
  import { ToastService } from '@masterteam/components/toast';
13
- import * as i3 from 'primeng/contextmenu';
14
- import { ContextMenuModule } from 'primeng/contextmenu';
15
12
  import * as i2 from 'primeng/dragdrop';
16
13
  import { DragDropModule } from 'primeng/dragdrop';
17
- import * as i4 from 'primeng/skeleton';
14
+ import * as i3 from 'primeng/skeleton';
18
15
  import { SkeletonModule } from 'primeng/skeleton';
19
16
  import { finalize } from 'rxjs';
20
17
  import { Action, Selector, State, Store, select } from '@ngxs/store';
@@ -48,12 +45,10 @@ class SaveWorkspaceBuilderLayout {
48
45
  }
49
46
  class CreateWorkspaceBuilderGroup {
50
47
  title;
51
- area;
52
48
  order;
53
49
  static type = '[WorkspaceBuilder] Create Group';
54
- constructor(title, area = 'main', order) {
50
+ constructor(title, order) {
55
51
  this.title = title;
56
- this.area = area;
57
52
  this.order = order;
58
53
  }
59
54
  }
@@ -92,7 +87,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
92
87
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
93
88
  return c > 3 && r && Object.defineProperty(target, key, r), r;
94
89
  };
95
- const AREAS = ['main', 'more'];
90
+ // AREA is kept as a reference constant (single-area layout)
96
91
  function normalizeName(value) {
97
92
  if (typeof value === 'string') {
98
93
  return value;
@@ -128,15 +123,13 @@ function extractLocalizedTitle(value) {
128
123
  function createEmptyLayout(levelId = 0) {
129
124
  return {
130
125
  levelId,
131
- main: [],
132
- more: [],
126
+ tabs: [],
133
127
  };
134
128
  }
135
129
  function cloneLayout(layout) {
136
130
  return {
137
131
  levelId: layout.levelId,
138
- main: layout.main.map(cloneItem),
139
- more: layout.more.map(cloneItem),
132
+ tabs: layout.tabs.map(cloneItem),
140
133
  };
141
134
  }
142
135
  function cloneItem(item) {
@@ -199,32 +192,13 @@ function normalizeAreaItems(items) {
199
192
  function normalizeLayout(layout) {
200
193
  const normalized = {
201
194
  levelId: layout?.levelId ?? 0,
202
- main: normalizeAreaItems(layout?.main ?? []),
203
- more: normalizeAreaItems(layout?.more ?? []),
195
+ tabs: normalizeAreaItems(layout?.tabs ?? []),
204
196
  };
205
197
  return normalized;
206
198
  }
207
199
  function toSaveLayoutDto(layout) {
208
200
  return {
209
- main: layout.main.map((item, index) => {
210
- if (item.type === 'group') {
211
- return {
212
- type: 'group',
213
- id: item.id,
214
- order: index + 1,
215
- modules: item.modules.map((module, moduleIndex) => ({
216
- id: module.id,
217
- order: moduleIndex + 1,
218
- })),
219
- };
220
- }
221
- return {
222
- type: 'module',
223
- id: item.id,
224
- order: index + 1,
225
- };
226
- }),
227
- more: layout.more.map((item, index) => {
201
+ tabs: layout.tabs.map((item, index) => {
228
202
  if (item.type === 'group') {
229
203
  return {
230
204
  type: 'group',
@@ -251,38 +225,36 @@ function validateLayout(layout) {
251
225
  const errors = [];
252
226
  const moduleIds = [];
253
227
  const groupIds = [];
254
- for (const area of AREAS) {
255
- const items = layout[area];
256
- const orders = items.map((item) => item.order);
257
- if (hasDuplicate(orders.map(String))) {
258
- errors.push(`Duplicate order detected in ${area} list.`);
259
- }
260
- items.forEach((item) => {
261
- if (item.type === 'group') {
262
- groupIds.push(item.id);
263
- const groupOrders = item.modules.map((module) => module.order);
264
- if (hasDuplicate(groupOrders.map(String))) {
265
- errors.push(`Duplicate order detected in group ${item.id}.`);
266
- }
267
- item.modules.forEach((module) => {
268
- const typedModule = module;
269
- if (typedModule?.type === 'group' ||
270
- Array.isArray(typedModule?.modules)) {
271
- errors.push(`Nested groups are not supported (group ${item.id}).`);
272
- }
273
- moduleIds.push(module.id);
274
- });
275
- }
276
- else {
277
- moduleIds.push(item.id);
278
- }
279
- });
228
+ const items = layout.tabs;
229
+ const orders = items.map((item) => item.order);
230
+ if (hasDuplicate(orders.map(String))) {
231
+ errors.push('Duplicate order detected in tabs list.');
280
232
  }
233
+ items.forEach((item) => {
234
+ if (item.type === 'group') {
235
+ groupIds.push(item.id);
236
+ const groupOrders = item.modules.map((module) => module.order);
237
+ if (hasDuplicate(groupOrders.map(String))) {
238
+ errors.push(`Duplicate order detected in group ${item.id}.`);
239
+ }
240
+ item.modules.forEach((module) => {
241
+ const typedModule = module;
242
+ if (typedModule?.type === 'group' ||
243
+ Array.isArray(typedModule?.modules)) {
244
+ errors.push(`Nested groups are not supported (group ${item.id}).`);
245
+ }
246
+ moduleIds.push(module.id);
247
+ });
248
+ }
249
+ else {
250
+ moduleIds.push(item.id);
251
+ }
252
+ });
281
253
  if (hasDuplicate(moduleIds)) {
282
- errors.push('Duplicate module IDs detected across main, more, and groups.');
254
+ errors.push('Duplicate module IDs detected in tabs and groups.');
283
255
  }
284
256
  if (hasDuplicate(groupIds)) {
285
- errors.push('Duplicate group IDs detected in layout.');
257
+ errors.push('Duplicate group IDs detected in tabs.');
286
258
  }
287
259
  return Array.from(new Set(errors));
288
260
  }
@@ -292,9 +264,9 @@ function computeIsDirty(layout, originalLayout) {
292
264
  }
293
265
  return (JSON.stringify(toSaveLayoutDto(layout)) !== JSON.stringify(originalLayout));
294
266
  }
295
- function insertGroupIntoLayout(layout, groupId, title, area, order) {
267
+ function insertGroupIntoLayout(layout, groupId, title, order) {
296
268
  const next = cloneLayout(layout);
297
- const list = next[area];
269
+ const list = next.tabs;
298
270
  const insertIndex = Math.max(0, Math.min((order ?? list.length + 1) - 1, list.length));
299
271
  const group = {
300
272
  type: 'group',
@@ -309,32 +281,25 @@ function insertGroupIntoLayout(layout, groupId, title, area, order) {
309
281
  }
310
282
  function renameGroupInLayout(layout, groupId, title) {
311
283
  const next = cloneLayout(layout);
312
- for (const area of AREAS) {
313
- const group = next[area].find((item) => item.type === 'group' && item.id === groupId);
314
- if (group) {
315
- group.name = title.en || title.ar;
316
- group.localizedName = { ...title };
317
- break;
318
- }
284
+ const group = next.tabs.find((item) => item.type === 'group' && item.id === groupId);
285
+ if (group) {
286
+ group.name = title.en || title.ar;
287
+ group.localizedName = { ...title };
319
288
  }
320
289
  return normalizeLayout(next);
321
290
  }
322
291
  function removeGroupAndPromoteModules(layout, groupId) {
323
292
  const next = cloneLayout(layout);
324
- for (const area of AREAS) {
325
- const index = next[area].findIndex((item) => item.type === 'group' && item.id === groupId);
326
- if (index === -1) {
327
- continue;
328
- }
329
- const group = next[area][index];
293
+ const index = next.tabs.findIndex((item) => item.type === 'group' && item.id === groupId);
294
+ if (index !== -1) {
295
+ const group = next.tabs[index];
330
296
  const promotedModules = group.modules.map((module) => ({
331
297
  type: 'module',
332
298
  id: module.id,
333
299
  name: module.name,
334
300
  order: 0,
335
301
  }));
336
- next[area].splice(index, 1, ...promotedModules);
337
- break;
302
+ next.tabs.splice(index, 1, ...promotedModules);
338
303
  }
339
304
  return normalizeLayout(next);
340
305
  }
@@ -356,11 +321,8 @@ let WorkspaceBuilderState = class WorkspaceBuilderState extends CrudStateBase {
356
321
  static getLayout(state) {
357
322
  return state.layout;
358
323
  }
359
- static getMainItems(state) {
360
- return state.layout.main;
361
- }
362
- static getMoreItems(state) {
363
- return state.layout.more;
324
+ static getTabItems(state) {
325
+ return state.layout.tabs;
364
326
  }
365
327
  static getValidationErrors(state) {
366
328
  return state.validationErrors;
@@ -402,8 +364,9 @@ let WorkspaceBuilderState = class WorkspaceBuilderState extends CrudStateBase {
402
364
  key: WorkspaceBuilderActionKey.GetLayout,
403
365
  request$: req$,
404
366
  onSuccess: (response) => {
405
- const incoming = response.data
406
- ? { ...response.data, levelId }
367
+ const data = response.data;
368
+ const incoming = data
369
+ ? { levelId, tabs: data.tabs ?? [] }
407
370
  : createEmptyLayout(levelId);
408
371
  const normalized = normalizeLayout(incoming);
409
372
  const validationErrors = validateLayout(normalized);
@@ -464,14 +427,13 @@ let WorkspaceBuilderState = class WorkspaceBuilderState extends CrudStateBase {
464
427
  }),
465
428
  });
466
429
  }
467
- createGroup(ctx, { title, area, order }) {
430
+ createGroup(ctx, { title, order }) {
468
431
  const { levelId } = ctx.getState();
469
432
  if (!levelId) {
470
433
  return;
471
434
  }
472
435
  const req$ = this.http.post(`levels/${levelId}/workspaceBuilder/groups`, {
473
436
  title,
474
- area,
475
437
  order: order ?? 1,
476
438
  });
477
439
  return handleApiRequest({
@@ -483,7 +445,7 @@ let WorkspaceBuilderState = class WorkspaceBuilderState extends CrudStateBase {
483
445
  if (!groupId) {
484
446
  return {};
485
447
  }
486
- const nextLayout = insertGroupIntoLayout(state.layout, groupId, title, area, order);
448
+ const nextLayout = insertGroupIntoLayout(state.layout, groupId, title, order);
487
449
  const validationErrors = validateLayout(nextLayout);
488
450
  return {
489
451
  layout: nextLayout,
@@ -552,8 +514,8 @@ let WorkspaceBuilderState = class WorkspaceBuilderState extends CrudStateBase {
552
514
  resetState(ctx) {
553
515
  ctx.setState(DEFAULTS);
554
516
  }
555
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: WorkspaceBuilderState, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
556
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: WorkspaceBuilderState });
517
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkspaceBuilderState, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
518
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkspaceBuilderState });
557
519
  };
558
520
  __decorate([
559
521
  Action(SetWorkspaceBuilderLevelId)
@@ -587,10 +549,7 @@ __decorate([
587
549
  ], WorkspaceBuilderState, "getLayout", null);
588
550
  __decorate([
589
551
  Selector()
590
- ], WorkspaceBuilderState, "getMainItems", null);
591
- __decorate([
592
- Selector()
593
- ], WorkspaceBuilderState, "getMoreItems", null);
552
+ ], WorkspaceBuilderState, "getTabItems", null);
594
553
  __decorate([
595
554
  Selector()
596
555
  ], WorkspaceBuilderState, "getValidationErrors", null);
@@ -612,7 +571,7 @@ WorkspaceBuilderState = __decorate([
612
571
  defaults: DEFAULTS,
613
572
  })
614
573
  ], WorkspaceBuilderState);
615
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: WorkspaceBuilderState, decorators: [{
574
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkspaceBuilderState, decorators: [{
616
575
  type: Injectable
617
576
  }], propDecorators: { setLevelId: [], getLayout: [], patchLayoutLocally: [], saveLayout: [], createGroup: [], renameGroup: [], deleteGroup: [], resetState: [] } });
618
577
 
@@ -620,20 +579,19 @@ class WorkspaceBuilderFacade {
620
579
  store = inject(Store);
621
580
  levelId = select(WorkspaceBuilderState.getLevelId);
622
581
  layout = select(WorkspaceBuilderState.getLayout);
623
- mainItems = select(WorkspaceBuilderState.getMainItems);
624
- moreItems = select(WorkspaceBuilderState.getMoreItems);
582
+ tabItems = select(WorkspaceBuilderState.getTabItems);
625
583
  validationErrors = select(WorkspaceBuilderState.getValidationErrors);
626
584
  isDirty = select(WorkspaceBuilderState.getIsDirty);
627
585
  successMessages = select(WorkspaceBuilderState.getSuccessMessages);
628
586
  loadingActive = select(WorkspaceBuilderState.getLoadingActive);
629
587
  errors = select(WorkspaceBuilderState.getErrors);
630
- isLoadingLayout = computed(() => this.loadingActive().includes(WorkspaceBuilderActionKey.GetLayout), ...(ngDevMode ? [{ debugName: "isLoadingLayout" }] : []));
631
- isSavingLayout = computed(() => this.loadingActive().includes(WorkspaceBuilderActionKey.SaveLayout), ...(ngDevMode ? [{ debugName: "isSavingLayout" }] : []));
632
- isCreatingGroup = computed(() => this.loadingActive().includes(WorkspaceBuilderActionKey.CreateGroup), ...(ngDevMode ? [{ debugName: "isCreatingGroup" }] : []));
633
- isUpdatingGroup = computed(() => this.loadingActive().includes(WorkspaceBuilderActionKey.UpdateGroup), ...(ngDevMode ? [{ debugName: "isUpdatingGroup" }] : []));
634
- isDeletingGroup = computed(() => this.loadingActive().includes(WorkspaceBuilderActionKey.DeleteGroup), ...(ngDevMode ? [{ debugName: "isDeletingGroup" }] : []));
635
- layoutError = computed(() => this.errors()[WorkspaceBuilderActionKey.GetLayout] ?? null, ...(ngDevMode ? [{ debugName: "layoutError" }] : []));
636
- saveError = computed(() => this.errors()[WorkspaceBuilderActionKey.SaveLayout] ?? null, ...(ngDevMode ? [{ debugName: "saveError" }] : []));
588
+ isLoadingLayout = computed(() => this.loadingActive().includes(WorkspaceBuilderActionKey.GetLayout), ...(ngDevMode ? [{ debugName: "isLoadingLayout" }] : /* istanbul ignore next */ []));
589
+ isSavingLayout = computed(() => this.loadingActive().includes(WorkspaceBuilderActionKey.SaveLayout), ...(ngDevMode ? [{ debugName: "isSavingLayout" }] : /* istanbul ignore next */ []));
590
+ isCreatingGroup = computed(() => this.loadingActive().includes(WorkspaceBuilderActionKey.CreateGroup), ...(ngDevMode ? [{ debugName: "isCreatingGroup" }] : /* istanbul ignore next */ []));
591
+ isUpdatingGroup = computed(() => this.loadingActive().includes(WorkspaceBuilderActionKey.UpdateGroup), ...(ngDevMode ? [{ debugName: "isUpdatingGroup" }] : /* istanbul ignore next */ []));
592
+ isDeletingGroup = computed(() => this.loadingActive().includes(WorkspaceBuilderActionKey.DeleteGroup), ...(ngDevMode ? [{ debugName: "isDeletingGroup" }] : /* istanbul ignore next */ []));
593
+ layoutError = computed(() => this.errors()[WorkspaceBuilderActionKey.GetLayout] ?? null, ...(ngDevMode ? [{ debugName: "layoutError" }] : /* istanbul ignore next */ []));
594
+ saveError = computed(() => this.errors()[WorkspaceBuilderActionKey.SaveLayout] ?? null, ...(ngDevMode ? [{ debugName: "saveError" }] : /* istanbul ignore next */ []));
637
595
  getSuccessMessage(key) {
638
596
  return this.successMessages()[key] ?? null;
639
597
  }
@@ -652,8 +610,8 @@ class WorkspaceBuilderFacade {
652
610
  saveLayout() {
653
611
  return this.store.dispatch(new SaveWorkspaceBuilderLayout());
654
612
  }
655
- createGroup(title, area = 'main', order) {
656
- return this.store.dispatch(new CreateWorkspaceBuilderGroup(title, area, order));
613
+ createGroup(title, order) {
614
+ return this.store.dispatch(new CreateWorkspaceBuilderGroup(title, order));
657
615
  }
658
616
  renameGroup(groupId, title) {
659
617
  return this.store.dispatch(new RenameWorkspaceBuilderGroup(groupId, title));
@@ -664,23 +622,22 @@ class WorkspaceBuilderFacade {
664
622
  resetState() {
665
623
  return this.store.dispatch(new ResetWorkspaceBuilderState());
666
624
  }
667
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: WorkspaceBuilderFacade, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
668
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: WorkspaceBuilderFacade, providedIn: 'root' });
625
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkspaceBuilderFacade, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
626
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkspaceBuilderFacade, providedIn: 'root' });
669
627
  }
670
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: WorkspaceBuilderFacade, decorators: [{
628
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkspaceBuilderFacade, decorators: [{
671
629
  type: Injectable,
672
630
  args: [{ providedIn: 'root' }]
673
631
  }] });
674
632
 
675
633
  class WorkspaceBuilderCreateGroupDialog {
676
- area = input(null, ...(ngDevMode ? [{ debugName: "area" }] : []));
677
634
  modal = inject(ModalService);
678
635
  config = inject(DynamicDialogConfig, { optional: true });
679
636
  ref = inject(ModalRef);
680
637
  facade = inject(WorkspaceBuilderFacade);
681
638
  ts = inject(ToastService);
682
639
  translocoService = inject(TranslocoService);
683
- isSaving = signal(false, ...(ngDevMode ? [{ debugName: "isSaving" }] : []));
640
+ isSaving = signal(false, ...(ngDevMode ? [{ debugName: "isSaving" }] : /* istanbul ignore next */ []));
684
641
  formControl = new FormControl(null);
685
642
  dynamicFormConfig = linkedSignal(() => ({
686
643
  sections: [
@@ -707,7 +664,7 @@ class WorkspaceBuilderCreateGroupDialog {
707
664
  ],
708
665
  },
709
666
  ],
710
- }), ...(ngDevMode ? [{ debugName: "dynamicFormConfig" }] : []));
667
+ }), ...(ngDevMode ? [{ debugName: "dynamicFormConfig" }] : /* istanbul ignore next */ []));
711
668
  get isEditMode() {
712
669
  return !!this.dialogData.groupId;
713
670
  }
@@ -725,9 +682,6 @@ class WorkspaceBuilderCreateGroupDialog {
725
682
  });
726
683
  }
727
684
  }
728
- resolvedArea() {
729
- return this.area() ?? this.dialogData.area ?? 'main';
730
- }
731
685
  submit() {
732
686
  const value = this.formControl.value;
733
687
  const en = (value?.title?.en ?? '').trim();
@@ -751,9 +705,8 @@ class WorkspaceBuilderCreateGroupDialog {
751
705
  });
752
706
  }
753
707
  else {
754
- const area = this.resolvedArea();
755
708
  const order = this.dialogData.order;
756
- this.facade.createGroup(title, area, order).subscribe({
709
+ this.facade.createGroup(title, order).subscribe({
757
710
  next: () => {
758
711
  this.ts.success(this.translocoService.translate('workspace-builder.group-create-success'));
759
712
  this.facade.getLayout();
@@ -769,10 +722,10 @@ class WorkspaceBuilderCreateGroupDialog {
769
722
  cancel() {
770
723
  this.ref.close(null);
771
724
  }
772
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: WorkspaceBuilderCreateGroupDialog, deps: [], target: i0.ɵɵFactoryTarget.Component });
773
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.3", type: WorkspaceBuilderCreateGroupDialog, isStandalone: true, selector: "mt-workspace-builder-create-group-dialog", inputs: { area: { classPropertyName: "area", publicName: "area", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'workspace-builder'\">\r\n <div [class]=\"'flex flex-col gap-3 p-4 ' + modal.contentClass\">\r\n <form class=\"col-span-1\">\r\n <mt-dynamic-form\r\n [formConfig]=\"dynamicFormConfig()\"\r\n [formControl]=\"formControl\"\r\n />\r\n </form>\r\n </div>\r\n\r\n <div [class]=\"modal.footerClass\">\r\n <mt-button\r\n variant=\"outlined\"\r\n [label]=\"t('cancel')\"\r\n (onClick)=\"cancel()\"\r\n ></mt-button>\r\n\r\n <mt-button\r\n [label]=\"isEditMode ? t('save') : t('add-group')\"\r\n [disabled]=\"!formControl.valid\"\r\n [loading]=\"isSaving()\"\r\n (onClick)=\"submit()\"\r\n ></mt-button>\r\n </div>\r\n</ng-container>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { 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: DynamicForm, selector: "mt-dynamic-form", inputs: ["formConfig", "forcedHiddenFieldKeys", "preserveForcedHiddenValues", "visibleSectionKeys"], outputs: ["runtimeMessagesChange"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }] });
725
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkspaceBuilderCreateGroupDialog, deps: [], target: i0.ɵɵFactoryTarget.Component });
726
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.8", type: WorkspaceBuilderCreateGroupDialog, isStandalone: true, selector: "mt-workspace-builder-create-group-dialog", ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'workspace-builder'\">\r\n <div [class]=\"'flex flex-col gap-3 p-4 ' + modal.contentClass\">\r\n <form class=\"col-span-1\">\r\n <mt-dynamic-form\r\n [formConfig]=\"dynamicFormConfig()\"\r\n [formControl]=\"formControl\"\r\n />\r\n </form>\r\n </div>\r\n\r\n <div [class]=\"modal.footerClass\">\r\n <mt-button\r\n variant=\"outlined\"\r\n [label]=\"t('cancel')\"\r\n (onClick)=\"cancel()\"\r\n ></mt-button>\r\n\r\n <mt-button\r\n [label]=\"isEditMode ? t('save') : t('add-group')\"\r\n [disabled]=\"!formControl.valid\"\r\n [loading]=\"isSaving()\"\r\n (onClick)=\"submit()\"\r\n ></mt-button>\r\n </div>\r\n</ng-container>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { 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: DynamicForm, selector: "mt-dynamic-form", inputs: ["formConfig", "forcedHiddenFieldKeys", "preserveForcedHiddenValues", "visibleSectionKeys"], outputs: ["runtimeMessagesChange"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }] });
774
727
  }
775
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: WorkspaceBuilderCreateGroupDialog, decorators: [{
728
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkspaceBuilderCreateGroupDialog, decorators: [{
776
729
  type: Component,
777
730
  args: [{ selector: 'mt-workspace-builder-create-group-dialog', standalone: true, imports: [
778
731
  CommonModule,
@@ -781,22 +734,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
781
734
  DynamicForm,
782
735
  TranslocoDirective,
783
736
  ], template: "<ng-container *transloco=\"let t; prefix: 'workspace-builder'\">\r\n <div [class]=\"'flex flex-col gap-3 p-4 ' + modal.contentClass\">\r\n <form class=\"col-span-1\">\r\n <mt-dynamic-form\r\n [formConfig]=\"dynamicFormConfig()\"\r\n [formControl]=\"formControl\"\r\n />\r\n </form>\r\n </div>\r\n\r\n <div [class]=\"modal.footerClass\">\r\n <mt-button\r\n variant=\"outlined\"\r\n [label]=\"t('cancel')\"\r\n (onClick)=\"cancel()\"\r\n ></mt-button>\r\n\r\n <mt-button\r\n [label]=\"isEditMode ? t('save') : t('add-group')\"\r\n [disabled]=\"!formControl.valid\"\r\n [loading]=\"isSaving()\"\r\n (onClick)=\"submit()\"\r\n ></mt-button>\r\n </div>\r\n</ng-container>\r\n" }]
784
- }], ctorParameters: () => [], propDecorators: { area: [{ type: i0.Input, args: [{ isSignal: true, alias: "area", required: false }] }] } });
737
+ }], ctorParameters: () => [] });
785
738
 
786
739
  const DRAG_PAYLOAD_MIME = 'application/x-workspace-builder';
787
740
  class WorkspaceBuilder {
788
- levelId = input(null, ...(ngDevMode ? [{ debugName: "levelId" }] : []));
789
- showHeader = input(true, { ...(ngDevMode ? { debugName: "showHeader" } : {}), transform: booleanAttribute });
790
- autoSave = input(true, { ...(ngDevMode ? { debugName: "autoSave" } : {}), transform: booleanAttribute });
791
- areas = ['main', 'more'];
741
+ levelId = input(null, ...(ngDevMode ? [{ debugName: "levelId" }] : /* istanbul ignore next */ []));
742
+ showHeader = input(true, { ...(ngDevMode ? { debugName: "showHeader" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
743
+ autoSave = input(true, { ...(ngDevMode ? { debugName: "autoSave" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
744
+ areas = ['tabs'];
792
745
  dropScope = 'workspace-builder-item';
793
746
  loadingSkeletonRows = [0, 1, 2, 3];
794
- createGroupArea = signal('main', ...(ngDevMode ? [{ debugName: "createGroupArea" }] : []));
795
- isDragging = signal(false, ...(ngDevMode ? [{ debugName: "isDragging" }] : []));
796
- activeDropSlotKey = signal(null, ...(ngDevMode ? [{ debugName: "activeDropSlotKey" }] : []));
797
- expandedGroups = signal({}, ...(ngDevMode ? [{ debugName: "expandedGroups" }] : []));
798
- dragPayload = signal(null, ...(ngDevMode ? [{ debugName: "dragPayload" }] : []));
747
+ isDragging = signal(false, ...(ngDevMode ? [{ debugName: "isDragging" }] : /* istanbul ignore next */ []));
748
+ activeDropSlotKey = signal(null, ...(ngDevMode ? [{ debugName: "activeDropSlotKey" }] : /* istanbul ignore next */ []));
749
+ expandedGroups = signal({}, ...(ngDevMode ? [{ debugName: "expandedGroups" }] : /* istanbul ignore next */ []));
750
+ dragPayload = signal(null, ...(ngDevMode ? [{ debugName: "dragPayload" }] : /* istanbul ignore next */ []));
799
751
  dragCleanupTimer = null;
752
+ scrollAnimFrame = null;
753
+ scrollContainer = null;
754
+ scrollDirection = 0;
800
755
  autoSaveInFlight = false;
801
756
  autoSaveQueued = false;
802
757
  autoSaveQueuedNotifySuccess = false;
@@ -805,21 +760,11 @@ class WorkspaceBuilder {
805
760
  modal = inject(ModalService);
806
761
  transloco = inject(TranslocoService);
807
762
  ts = inject(ToastService);
808
- addGroupLabel = toSignal(this.transloco.selectTranslate('workspace-builder.add-group'), {
809
- initialValue: this.transloco.translate('workspace-builder.add-group'),
810
- });
811
763
  layout = this.facade.layout;
812
764
  validationErrors = this.facade.validationErrors;
813
765
  isLoadingLayout = this.facade.isLoadingLayout;
814
766
  layoutError = this.facade.layoutError;
815
767
  isSavingLayout = this.facade.isSavingLayout;
816
- areaContextItems = computed(() => [
817
- {
818
- label: this.addGroupLabel(),
819
- icon: 'pi pi-plus',
820
- command: () => this.openCreateGroupDialog(this.createGroupArea()),
821
- },
822
- ], ...(ngDevMode ? [{ debugName: "areaContextItems" }] : []));
823
768
  constructor() {
824
769
  effect(() => {
825
770
  const levelId = this.levelId();
@@ -856,8 +801,8 @@ class WorkspaceBuilder {
856
801
  this.clearDragCleanupTimer();
857
802
  this.facade.resetState();
858
803
  }
859
- areaItems(area) {
860
- return this.layout()[area];
804
+ areaItems(_area) {
805
+ return this.layout().tabs;
861
806
  }
862
807
  trackItem(item) {
863
808
  return `${item.type}:${item.id}`;
@@ -963,9 +908,7 @@ class WorkspaceBuilder {
963
908
  if (!payload)
964
909
  return false;
965
910
  if (payload.kind === 'group') {
966
- if (payload.source.area !== area)
967
- return false;
968
- const list = this.layout()[area];
911
+ const list = this.layout().tabs;
969
912
  const movingIds = new Set(payload.groups.map((group) => group.id));
970
913
  const movingIndexes = list
971
914
  .map((item, i) => item.type === 'group' && movingIds.has(item.id) ? i : -1)
@@ -975,10 +918,10 @@ class WorkspaceBuilder {
975
918
  const sourceIndex = movingIndexes[0];
976
919
  return index === sourceIndex || index === sourceIndex + 1;
977
920
  }
978
- if (payload.source.type !== 'area' || payload.source.area !== area) {
921
+ if (payload.source.type !== 'area') {
979
922
  return false;
980
923
  }
981
- const list = this.layout()[area];
924
+ const list = this.layout().tabs;
982
925
  const movingIds = new Set(payload.modules.map((module) => module.id));
983
926
  const movingIndexes = list
984
927
  .map((item, i) => item.type === 'module' && movingIds.has(item.id) ? i : -1)
@@ -1025,14 +968,9 @@ class WorkspaceBuilder {
1025
968
  const index = this.resolveSiblingDropIndex(event, moduleIndex);
1026
969
  this.handleDrop({ type: 'group', area, groupId }, index, event);
1027
970
  }
1028
- onAreaContextMenu(event, area, contextMenu) {
1029
- event.preventDefault();
1030
- this.createGroupArea.set(area);
1031
- contextMenu.show(event);
1032
- }
1033
- openCreateGroupDialog(area) {
1034
- const order = this.layout()[area].length + 1;
1035
- const data = { area, order };
971
+ openCreateGroupDialog(_area = 'tabs') {
972
+ const order = this.layout().tabs.length + 1;
973
+ const data = { order };
1036
974
  this.modal.openModal(WorkspaceBuilderCreateGroupDialog, 'dialog', {
1037
975
  header: this.transloco.translate('workspace-builder.create-group'),
1038
976
  styleClass: '!w-[28rem]',
@@ -1040,7 +978,6 @@ class WorkspaceBuilder {
1040
978
  appendTo: 'body',
1041
979
  dismissableMask: true,
1042
980
  data,
1043
- inputValues: { area },
1044
981
  });
1045
982
  }
1046
983
  startRenameGroup(group) {
@@ -1055,7 +992,6 @@ class WorkspaceBuilder {
1055
992
  appendTo: 'body',
1056
993
  dismissableMask: true,
1057
994
  data,
1058
- inputValues: { area: null },
1059
995
  });
1060
996
  }
1061
997
  onSaveClick() {
@@ -1096,12 +1032,12 @@ class WorkspaceBuilder {
1096
1032
  return;
1097
1033
  }
1098
1034
  const [module] = group.modules.splice(moduleIndex, 1);
1099
- const areaItems = nextLayout[area];
1100
- const groupIndex = areaItems.findIndex((item) => item.type === 'group' && item.id === groupId);
1035
+ const tabsItems = nextLayout.tabs;
1036
+ const groupIndex = tabsItems.findIndex((item) => item.type === 'group' && item.id === groupId);
1101
1037
  if (groupIndex === -1) {
1102
1038
  return;
1103
1039
  }
1104
- areaItems.splice(groupIndex + 1, 0, {
1040
+ tabsItems.splice(groupIndex + 1, 0, {
1105
1041
  type: 'module',
1106
1042
  id: module.id,
1107
1043
  name: module.name,
@@ -1162,14 +1098,8 @@ class WorkspaceBuilder {
1162
1098
  }
1163
1099
  }))
1164
1100
  .subscribe({
1165
- next: () => {
1166
- if (notifyOnSuccess) {
1167
- this.ts.success(this.getSuccessMessage(WorkspaceBuilderActionKey.SaveLayout, 'workspace-builder.layout-update-success'));
1168
- }
1169
- },
1170
- error: () => {
1171
- this.ts.error(this.getErrorMessage(WorkspaceBuilderActionKey.SaveLayout, 'workspace-builder.layout-update-error'));
1172
- },
1101
+ next: () => { },
1102
+ error: () => { },
1173
1103
  });
1174
1104
  }
1175
1105
  resolveDropPayload(event) {
@@ -1210,15 +1140,70 @@ class WorkspaceBuilder {
1210
1140
  this.activeDropSlotKey.set(null);
1211
1141
  this.clearDragCleanupTimer();
1212
1142
  }
1143
+ onAreaBodyDragOver(event) {
1144
+ this.allowNativeDrop(event);
1145
+ this.updateEdgeScroll(event);
1146
+ }
1147
+ onAreaBodyDragLeave(event) {
1148
+ const container = event.currentTarget;
1149
+ const related = event.relatedTarget;
1150
+ if (!related || !container?.contains(related)) {
1151
+ this.stopEdgeScroll();
1152
+ }
1153
+ }
1154
+ updateEdgeScroll(event) {
1155
+ const container = event.currentTarget;
1156
+ if (!container)
1157
+ return;
1158
+ const rect = container.getBoundingClientRect();
1159
+ const y = event.clientY;
1160
+ const zone = 80;
1161
+ let direction = 0;
1162
+ if (y - rect.top < zone && container.scrollTop > 0) {
1163
+ direction = -1;
1164
+ }
1165
+ else if (rect.bottom - y < zone &&
1166
+ container.scrollTop < container.scrollHeight - container.clientHeight) {
1167
+ direction = 1;
1168
+ }
1169
+ if (this.scrollContainer !== container ||
1170
+ this.scrollDirection !== direction) {
1171
+ this.scrollContainer = container;
1172
+ this.scrollDirection = direction;
1173
+ this.stopEdgeScroll();
1174
+ if (direction !== 0) {
1175
+ this.runEdgeScroll();
1176
+ }
1177
+ }
1178
+ }
1179
+ runEdgeScroll() {
1180
+ const tick = () => {
1181
+ if (!this.scrollContainer || this.scrollDirection === 0)
1182
+ return;
1183
+ this.scrollContainer.scrollTop += this.scrollDirection * 14;
1184
+ this.scrollAnimFrame = requestAnimationFrame(tick);
1185
+ };
1186
+ this.scrollAnimFrame = requestAnimationFrame(tick);
1187
+ }
1188
+ stopEdgeScroll() {
1189
+ if (this.scrollAnimFrame !== null) {
1190
+ cancelAnimationFrame(this.scrollAnimFrame);
1191
+ this.scrollAnimFrame = null;
1192
+ }
1193
+ this.scrollDirection = 0;
1194
+ this.scrollContainer = null;
1195
+ }
1213
1196
  endDragSession() {
1214
1197
  this.isDragging.set(false);
1215
1198
  this.activeDropSlotKey.set(null);
1216
1199
  this.dragPayload.set(null);
1200
+ this.stopEdgeScroll();
1217
1201
  this.clearDragCleanupTimer();
1218
1202
  }
1219
1203
  scheduleDragSessionCleanup() {
1220
1204
  this.isDragging.set(false);
1221
1205
  this.activeDropSlotKey.set(null);
1206
+ this.stopEdgeScroll();
1222
1207
  this.clearDragCleanupTimer();
1223
1208
  this.dragCleanupTimer = setTimeout(() => {
1224
1209
  this.dragPayload.set(null);
@@ -1286,53 +1271,34 @@ class WorkspaceBuilder {
1286
1271
  if (!root) {
1287
1272
  return null;
1288
1273
  }
1289
- const selector = area === 'main'
1290
- ? `[data-area="main"][data-item-index="${itemIndex}"]`
1291
- : `[data-area="more"][data-item-index="${itemIndex}"]`;
1274
+ const selector = `[data-area="tabs"][data-item-index="${itemIndex}"]`;
1292
1275
  return root.querySelector(selector);
1293
1276
  }
1294
1277
  moveGroups(layout, payload, target, targetIndex) {
1295
1278
  if (target.type !== 'area') {
1296
1279
  return;
1297
1280
  }
1298
- const sourceArea = payload.source.area;
1299
- const targetArea = target.area;
1300
1281
  const groupIds = new Set(payload.groups.map((group) => group.id));
1301
- if (sourceArea === targetArea) {
1302
- const original = layout[sourceArea];
1303
- const moving = original.filter((item) => item.type === 'group' && groupIds.has(item.id));
1304
- if (moving.length === 0) {
1305
- return;
1306
- }
1307
- const removedBefore = original
1308
- .slice(0, targetIndex)
1309
- .filter((item) => item.type === 'group' && groupIds.has(item.id)).length;
1310
- const remaining = original.filter((item) => !(item.type === 'group' && groupIds.has(item.id)));
1311
- const insertIndex = this.clampIndex(targetIndex - removedBefore, remaining.length);
1312
- layout[sourceArea] = [
1313
- ...remaining.slice(0, insertIndex),
1314
- ...moving,
1315
- ...remaining.slice(insertIndex),
1316
- ];
1317
- return;
1318
- }
1319
- const sourceList = layout[sourceArea];
1320
- const moving = sourceList.filter((item) => item.type === 'group' && groupIds.has(item.id));
1282
+ const original = layout.tabs;
1283
+ const moving = original.filter((item) => item.type === 'group' && groupIds.has(item.id));
1321
1284
  if (moving.length === 0) {
1322
1285
  return;
1323
1286
  }
1324
- layout[sourceArea] = sourceList.filter((item) => !(item.type === 'group' && groupIds.has(item.id)));
1325
- const targetList = layout[targetArea];
1326
- const insertIndex = this.clampIndex(targetIndex, targetList.length);
1327
- targetList.splice(insertIndex, 0, ...moving);
1287
+ const removedBefore = original
1288
+ .slice(0, targetIndex)
1289
+ .filter((item) => item.type === 'group' && groupIds.has(item.id)).length;
1290
+ const remaining = original.filter((item) => !(item.type === 'group' && groupIds.has(item.id)));
1291
+ const insertIndex = this.clampIndex(targetIndex - removedBefore, remaining.length);
1292
+ layout.tabs = [
1293
+ ...remaining.slice(0, insertIndex),
1294
+ ...moving,
1295
+ ...remaining.slice(insertIndex),
1296
+ ];
1328
1297
  }
1329
1298
  moveModules(layout, payload, target, targetIndex) {
1330
1299
  const moduleIds = new Set(payload.modules.map((module) => module.id));
1331
- if (payload.source.type === 'area' &&
1332
- target.type === 'area' &&
1333
- payload.source.area === target.area) {
1334
- const area = payload.source.area;
1335
- const original = layout[area];
1300
+ if (payload.source.type === 'area' && target.type === 'area') {
1301
+ const original = layout.tabs;
1336
1302
  const moving = original.filter((item) => item.type === 'module' && moduleIds.has(item.id));
1337
1303
  if (moving.length === 0) {
1338
1304
  return;
@@ -1342,7 +1308,7 @@ class WorkspaceBuilder {
1342
1308
  .filter((item) => item.type === 'module' && moduleIds.has(item.id)).length;
1343
1309
  const remaining = original.filter((item) => !(item.type === 'module' && moduleIds.has(item.id)));
1344
1310
  const insertIndex = this.clampIndex(targetIndex - removedBefore, remaining.length);
1345
- layout[area] = [
1311
+ layout.tabs = [
1346
1312
  ...remaining.slice(0, insertIndex),
1347
1313
  ...moving,
1348
1314
  ...remaining.slice(insertIndex),
@@ -1379,7 +1345,7 @@ class WorkspaceBuilder {
1379
1345
  return;
1380
1346
  }
1381
1347
  if (target.type === 'area') {
1382
- const areaList = layout[target.area];
1348
+ const areaList = layout.tabs;
1383
1349
  const insertIndex = this.clampIndex(targetIndex, areaList.length);
1384
1350
  const topLevelModules = extracted.map((module) => ({
1385
1351
  type: 'module',
@@ -1399,7 +1365,7 @@ class WorkspaceBuilder {
1399
1365
  }
1400
1366
  extractModulesFromSource(layout, source, moduleIds) {
1401
1367
  if (source.type === 'area') {
1402
- const areaList = layout[source.area];
1368
+ const areaList = layout.tabs;
1403
1369
  const moving = areaList
1404
1370
  .filter((item) => item.type === 'module' && moduleIds.has(item.id))
1405
1371
  .map((module) => ({
@@ -1407,7 +1373,7 @@ class WorkspaceBuilder {
1407
1373
  name: module.name,
1408
1374
  order: module.order,
1409
1375
  }));
1410
- layout[source.area] = areaList.filter((item) => !(item.type === 'module' && moduleIds.has(item.id)));
1376
+ layout.tabs = areaList.filter((item) => !(item.type === 'module' && moduleIds.has(item.id)));
1411
1377
  return moving;
1412
1378
  }
1413
1379
  const group = this.findGroup(layout, source.area, source.groupId);
@@ -1419,20 +1385,19 @@ class WorkspaceBuilder {
1419
1385
  return moving;
1420
1386
  }
1421
1387
  findGroup(layout, area, groupId) {
1422
- const found = layout[area].find((item) => item.type === 'group' && item.id === groupId);
1388
+ const found = layout.tabs.find((item) => item.type === 'group' && item.id === groupId);
1423
1389
  return found ?? null;
1424
1390
  }
1425
1391
  clampIndex(index, length) {
1426
1392
  return Math.max(0, Math.min(index, length));
1427
1393
  }
1428
1394
  getAllGroups(layout) {
1429
- return [...layout.main, ...layout.more].filter((item) => item.type === 'group');
1395
+ return [...layout.tabs].filter((item) => item.type === 'group');
1430
1396
  }
1431
1397
  cloneLayout(layout) {
1432
1398
  return {
1433
1399
  levelId: layout.levelId,
1434
- main: layout.main.map((item) => this.cloneItem(item)),
1435
- more: layout.more.map((item) => this.cloneItem(item)),
1400
+ tabs: layout.tabs.map((item) => this.cloneItem(item)),
1436
1401
  };
1437
1402
  }
1438
1403
  cloneItem(item) {
@@ -1471,10 +1436,10 @@ class WorkspaceBuilder {
1471
1436
  }
1472
1437
  return this.transloco.translate(fallbackTranslationKey);
1473
1438
  }
1474
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: WorkspaceBuilder, deps: [], target: i0.ɵɵFactoryTarget.Component });
1475
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: WorkspaceBuilder, isStandalone: true, selector: "mt-workspace-builder", inputs: { levelId: { classPropertyName: "levelId", publicName: "levelId", isSignal: true, isRequired: false, transformFunction: null }, showHeader: { classPropertyName: "showHeader", publicName: "showHeader", isSignal: true, isRequired: false, transformFunction: null }, autoSave: { classPropertyName: "autoSave", publicName: "autoSave", isSignal: true, isRequired: false, transformFunction: null } }, providers: [DialogService], ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'workspace-builder'\">\r\n <p-contextMenu\r\n #areaContextMenu\r\n [model]=\"areaContextItems()\"\r\n appendTo=\"body\"\r\n />\r\n\r\n <ng-template #builderContent>\r\n @if (isLoadingLayout()) {\r\n <div class=\"grid gap-5\">\r\n <div class=\"grid grid-cols-1 gap-5 xl:grid-cols-2\">\r\n @for (area of areas; track area) {\r\n <mt-card\r\n [title]=\"t(area)\"\r\n [paddingless]=\"true\"\r\n class=\"min-h-[26rem] overflow-hidden bg-surface-0\"\r\n >\r\n <div\r\n class=\"grid min-h-full content-start gap-4 bg-surface-50/60 p-5 pt-4\"\r\n >\r\n @for (row of loadingSkeletonRows; track row) {\r\n <div\r\n class=\"rounded-lg border border-surface-200 bg-surface-0 px-3 py-3 shadow-sm\"\r\n >\r\n <div class=\"flex items-center gap-3\">\r\n <p-skeleton size=\"2rem\" borderRadius=\"0.75rem\" />\r\n <div class=\"grid flex-1 gap-2\">\r\n <p-skeleton width=\"75%\" height=\"1rem\" />\r\n <p-skeleton width=\"45%\" height=\"0.8rem\" />\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n </div>\r\n </div>\r\n } @else if (layoutError(); as error) {\r\n <div\r\n class=\"grid gap-4 rounded-xl border border-red-200 bg-red-50 px-5 py-6 text-red-700 shadow-sm\"\r\n >\r\n <div class=\"grid gap-1\">\r\n <div class=\"text-sm font-semibold\">\r\n {{ t(\"load-error-title\") }}\r\n </div>\r\n <p class=\"m-0 text-sm text-red-600\">\r\n {{ error || t(\"load-error-description\") }}\r\n </p>\r\n </div>\r\n\r\n <div>\r\n <mt-button\r\n [label]=\"t('retry')\"\r\n icon=\"arrow.refresh-cw-01\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n (onClick)=\"reloadLayout()\"\r\n />\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"grid gap-5\">\r\n @if (validationErrors().length > 0) {\r\n <div\r\n class=\"rounded-lg border border-red-200 bg-red-50 px-4 py-3.5 text-red-700 shadow-sm\"\r\n >\r\n <div class=\"mb-2 text-sm font-semibold\">\r\n {{ t(\"validation-title\") }}\r\n </div>\r\n <ul class=\"m-0 list-disc ps-4\">\r\n @for (error of validationErrors(); track error) {\r\n <li>{{ error }}</li>\r\n }\r\n </ul>\r\n </div>\r\n }\r\n\r\n <div class=\"grid grid-cols-1 gap-5 xl:grid-cols-2\">\r\n @for (area of areas; track area) {\r\n <mt-card\r\n [title]=\"t(area)\"\r\n [paddingless]=\"true\"\r\n class=\"min-h-[26rem] overflow-hidden bg-surface-0\"\r\n (contextmenu)=\"onAreaContextMenu($event, area, areaContextMenu)\"\r\n (dragover)=\"allowNativeDrop($event)\"\r\n (drop)=\"onNativeAreaDrop($event, area)\"\r\n >\r\n <ng-template #cardEnd>\r\n <mt-button\r\n [label]=\"t('add-group')\"\r\n icon=\"general.plus\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n (onClick)=\"openCreateGroupDialog(area)\"\r\n />\r\n </ng-template>\r\n\r\n <div\r\n class=\"workspace-area-body grid min-h-full content-start gap-2 bg-surface-50/60 p-5 pt-2\"\r\n [class.drag-active]=\"isDragging()\"\r\n (dragover)=\"allowNativeDrop($event)\"\r\n (drop)=\"onNativeAreaDrop($event, area)\"\r\n [pDroppable]=\"dropScope\"\r\n (onDrop)=\"onDropToArea($event, area, areaItems(area).length)\"\r\n >\r\n <div\r\n class=\"drop-slot\"\r\n [class.drop-slot-active]=\"\r\n activeDropSlotKey() === areaDropSlotKey(area, 0)\r\n \"\r\n [class.drop-slot-disabled]=\"isAreaDropSlotDisabled(area, 0)\"\r\n [pDroppable]=\"dropScope\"\r\n (dragover)=\"\r\n onDropSlotDragOver(\r\n $event,\r\n areaDropSlotKey(area, 0),\r\n isAreaDropSlotDisabled(area, 0)\r\n )\r\n \"\r\n (dragleave)=\"\r\n onDropSlotDragLeave($event, areaDropSlotKey(area, 0))\r\n \"\r\n (onDrop)=\"\r\n onDropToArea(\r\n $event,\r\n area,\r\n 0,\r\n isAreaDropSlotDisabled(area, 0)\r\n )\r\n \"\r\n ></div>\r\n\r\n @for (\r\n item of areaItems(area);\r\n track trackItem(item);\r\n let i = $index\r\n ) {\r\n @if (item.type === \"module\") {\r\n <div\r\n class=\"workspace-draggable-item flex min-h-11 cursor-grab items-center gap-3 rounded-lg border border-surface-200 bg-surface-0 px-3 py-2.5 transition-all duration-150 hover:-translate-y-0.5 hover:border-surface-300 hover:shadow-sm active:cursor-grabbing\"\r\n [attr.data-area]=\"area\"\r\n [attr.data-item-index]=\"i\"\r\n [pDraggable]=\"dropScope\"\r\n (onDragStart)=\"\r\n onModuleDragStart($event, item, {\r\n type: 'area',\r\n area: area,\r\n })\r\n \"\r\n (onDragEnd)=\"onDragEnd()\"\r\n >\r\n <span\r\n class=\"drag-handle flex size-8 shrink-0 items-center justify-center text-surface-500\"\r\n draggable=\"false\"\r\n >\r\n <mt-icon\r\n class=\"pointer-events-none text-xl text-primary\"\r\n icon=\"general.menu-05\"\r\n />\r\n </span>\r\n <span class=\"min-w-0 flex-1 truncate py-1.5\">{{\r\n item.name\r\n }}</span>\r\n </div>\r\n } @else {\r\n <div\r\n class=\"workspace-group-card grid cursor-grab gap-3 rounded-md border border-surface-200 bg-surface-0 p-3 transition-all duration-150 hover:-translate-y-0.5 hover:border-surface-300 hover:shadow-sm active:cursor-grabbing\"\r\n [attr.data-area]=\"area\"\r\n [attr.data-item-index]=\"i\"\r\n [pDraggable]=\"dropScope\"\r\n (onDragStart)=\"onGroupDragStart($event, item, area)\"\r\n (onDragEnd)=\"onDragEnd()\"\r\n (dragover)=\"allowNativeDrop($event)\"\r\n (drop)=\"onNativeGroupDrop($event, area, item.id)\"\r\n >\r\n <div\r\n class=\"group-header flex flex-wrap items-center gap-2 rounded-lg border-2 border-surface-200 bg-surface-50/80 px-2 py-2\"\r\n [pDroppable]=\"dropScope\"\r\n (onDrop)=\"\r\n onDropToGroup(\r\n $event,\r\n area,\r\n item.id,\r\n item.modules.length\r\n )\r\n \"\r\n >\r\n <mt-button\r\n class=\"expand-btn\"\r\n [icon]=\"\r\n isGroupExpanded(item.id)\r\n ? 'arrow.chevron-up'\r\n : 'arrow.chevron-down'\r\n \"\r\n severity=\"secondary\"\r\n variant=\"text\"\r\n (onClick)=\"toggleGroup(item.id)\"\r\n />\r\n <span\r\n class=\"group-drag-handle flex size-8 shrink-0 items-center justify-center text-surface-500\"\r\n draggable=\"false\"\r\n >\r\n <mt-icon\r\n class=\"pointer-events-none text-xl text-primary\"\r\n icon=\"general.menu-05\"\r\n />\r\n </span>\r\n\r\n <span\r\n class=\"min-w-0 flex-1 truncate text-lg mx-1 font-semibold text-surface-600\"\r\n >{{ item.name }}</span\r\n >\r\n <mt-button\r\n icon=\"general.edit-05\"\r\n [tooltip]=\"t('rename-group')\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n (onClick)=\"startRenameGroup(item)\"\r\n />\r\n\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n [tooltip]=\"t('delete-group')\"\r\n severity=\"danger\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n (onClick)=\"deleteGroup(item.id, $event)\"\r\n />\r\n </div>\r\n\r\n @if (isGroupExpanded(item.id)) {\r\n <div\r\n class=\"group-modules grid gap-2 border-t-2 border-dashed border-surface-300 pt-3\"\r\n [pDroppable]=\"dropScope\"\r\n (onDrop)=\"\r\n onDropToGroup(\r\n $event,\r\n area,\r\n item.id,\r\n item.modules.length\r\n )\r\n \"\r\n >\r\n <div\r\n class=\"drop-slot\"\r\n [class.drop-slot-active]=\"\r\n activeDropSlotKey() ===\r\n groupDropSlotKey(area, item.id, 0)\r\n \"\r\n [class.drop-slot-disabled]=\"\r\n isGroupDropSlotDisabled(area, item.id, 0)\r\n \"\r\n [pDroppable]=\"dropScope\"\r\n (dragover)=\"\r\n onDropSlotDragOver(\r\n $event,\r\n groupDropSlotKey(area, item.id, 0),\r\n isGroupDropSlotDisabled(area, item.id, 0)\r\n )\r\n \"\r\n (dragleave)=\"\r\n onDropSlotDragLeave(\r\n $event,\r\n groupDropSlotKey(area, item.id, 0)\r\n )\r\n \"\r\n (onDrop)=\"\r\n onDropToGroup(\r\n $event,\r\n area,\r\n item.id,\r\n 0,\r\n isGroupDropSlotDisabled(area, item.id, 0)\r\n )\r\n \"\r\n ></div>\r\n\r\n @for (\r\n module of item.modules;\r\n track module.id;\r\n let j = $index\r\n ) {\r\n <div\r\n class=\"workspace-draggable-item workspace-group-module-item ms-3 flex min-h-11 cursor-grab items-center gap-3 rounded-lg border border-surface-200 bg-surface-0 px-3 py-2.5 transition-all duration-150 hover:-translate-y-0.5 hover:border-surface-300 hover:shadow-sm active:cursor-grabbing\"\r\n [pDraggable]=\"dropScope\"\r\n (dragover)=\"allowNativeDrop($event)\"\r\n (drop)=\"\r\n onNativeGroupModuleDrop(\r\n $event,\r\n area,\r\n item.id,\r\n j\r\n )\r\n \"\r\n (onDragStart)=\"\r\n onModuleDragStart($event, module, {\r\n type: 'group',\r\n area: area,\r\n groupId: item.id,\r\n })\r\n \"\r\n (onDragEnd)=\"onDragEnd()\"\r\n >\r\n <span\r\n class=\"drag-handle flex size-8 shrink-0 items-center justify-center text-surface-500\"\r\n draggable=\"false\"\r\n >\r\n <mt-icon\r\n class=\"pointer-events-none text-xl text-primary\"\r\n icon=\"general.menu-05\"\r\n />\r\n </span>\r\n <span class=\"min-w-0 flex-1 truncate py-1.5\">{{\r\n module.name\r\n }}</span>\r\n <mt-button\r\n icon=\"general.minus\"\r\n [tooltip]=\"t('remove')\"\r\n severity=\"secondary\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n (onClick)=\"\r\n removeModuleFromGroup(\r\n area,\r\n item.id,\r\n module.id\r\n )\r\n \"\r\n />\r\n </div>\r\n\r\n <div\r\n class=\"drop-slot\"\r\n [class.drop-slot-active]=\"\r\n activeDropSlotKey() ===\r\n groupDropSlotKey(area, item.id, j + 1)\r\n \"\r\n [class.drop-slot-disabled]=\"\r\n isGroupDropSlotDisabled(area, item.id, j + 1)\r\n \"\r\n [pDroppable]=\"dropScope\"\r\n (dragover)=\"\r\n onDropSlotDragOver(\r\n $event,\r\n groupDropSlotKey(area, item.id, j + 1),\r\n isGroupDropSlotDisabled(area, item.id, j + 1)\r\n )\r\n \"\r\n (dragleave)=\"\r\n onDropSlotDragLeave(\r\n $event,\r\n groupDropSlotKey(area, item.id, j + 1)\r\n )\r\n \"\r\n (onDrop)=\"\r\n onDropToGroup(\r\n $event,\r\n area,\r\n item.id,\r\n j + 1,\r\n isGroupDropSlotDisabled(area, item.id, j + 1)\r\n )\r\n \"\r\n ></div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n <div\r\n class=\"drop-slot\"\r\n [class.drop-slot-active]=\"\r\n activeDropSlotKey() === areaDropSlotKey(area, i + 1)\r\n \"\r\n [class.drop-slot-disabled]=\"\r\n isAreaDropSlotDisabled(area, i + 1)\r\n \"\r\n [pDroppable]=\"dropScope\"\r\n (dragover)=\"\r\n onDropSlotDragOver(\r\n $event,\r\n areaDropSlotKey(area, i + 1),\r\n isAreaDropSlotDisabled(area, i + 1)\r\n )\r\n \"\r\n (dragleave)=\"\r\n onDropSlotDragLeave($event, areaDropSlotKey(area, i + 1))\r\n \"\r\n (onDrop)=\"\r\n onDropToArea(\r\n $event,\r\n area,\r\n i + 1,\r\n isAreaDropSlotDisabled(area, i + 1)\r\n )\r\n \"\r\n ></div>\r\n }\r\n\r\n @if (areaItems(area).length === 0) {\r\n <div\r\n class=\"empty-area grid min-h-32 place-items-center rounded-lg border border-dashed border-surface-300 bg-surface-0/80 px-4 py-6 text-center text-sm text-surface-500\"\r\n [pDroppable]=\"dropScope\"\r\n (onDrop)=\"onDropToArea($event, area, 0)\"\r\n >\r\n {{ t(\"empty-area\") }}\r\n </div>\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </ng-template>\r\n\r\n @if (showHeader()) {\r\n <mt-page [title]=\"t('title')\" avatarIcon=\"layout.layout-grid-01\">\r\n <ng-template #headerEnd>\r\n @if (!autoSave()) {\r\n <div class=\"flex items-center\">\r\n <mt-button\r\n [label]=\"t('save')\"\r\n icon=\"general.save-02\"\r\n severity=\"primary\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n [loading]=\"isSavingLayout()\"\r\n [disabled]=\"\r\n isLoadingLayout() ||\r\n !!layoutError() ||\r\n isSavingLayout() ||\r\n validationErrors().length > 0\r\n \"\r\n (onClick)=\"onSaveClick()\"\r\n />\r\n </div>\r\n }\r\n </ng-template>\r\n\r\n <ng-container [ngTemplateOutlet]=\"builderContent\" />\r\n </mt-page>\r\n } @else {\r\n <div class=\"w-full overflow-y-auto p-5\">\r\n @if (!autoSave()) {\r\n <div class=\"mb-4 flex justify-end\">\r\n <mt-button\r\n [label]=\"t('save')\"\r\n icon=\"general.save-02\"\r\n severity=\"primary\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n [loading]=\"isSavingLayout()\"\r\n [disabled]=\"\r\n isLoadingLayout() ||\r\n !!layoutError() ||\r\n isSavingLayout() ||\r\n validationErrors().length > 0\r\n \"\r\n (onClick)=\"onSaveClick()\"\r\n />\r\n </div>\r\n }\r\n\r\n <ng-container [ngTemplateOutlet]=\"builderContent\" />\r\n </div>\r\n }\r\n</ng-container>\r\n", styles: [".workspace-area-body{transition:background-color .18s ease,box-shadow .18s ease}.workspace-area-body.drag-active{cursor:grabbing}.workspace-draggable-item.p-draggable-dragging,.workspace-group-card.p-draggable-dragging{transform:scale(.985);box-shadow:0 12px 30px color-mix(in srgb,var(--p-text-color) 14%,transparent)}.drag-handle,.group-drag-handle{user-select:none;-webkit-user-select:none;touch-action:none;transition:transform .15s ease,border-color .15s ease,background-color .15s ease,color .15s ease}.drag-handle:active,.group-drag-handle:active{transform:scale(.96)}.workspace-area-body.drag-active .drag-handle,.workspace-area-body.drag-active .group-drag-handle{cursor:grabbing}.drop-slot{width:100%;height:.4rem;border:1px solid transparent;border-radius:9999px;background:transparent;opacity:0;transition:height .15s ease,border-color .15s ease,background-color .15s ease,box-shadow .15s ease,transform .15s ease,opacity .15s ease}.workspace-area-body.drag-active .drop-slot{height:.65rem;border-color:var(--p-surface-300);background:color-mix(in srgb,var(--p-surface-100) 55%,transparent);opacity:.28;transform:scaleX(.98)}.workspace-area-body.drag-active .drop-slot.drop-slot-disabled{opacity:0;height:.4rem;pointer-events:none}.empty-area.p-droppable-enter{border-color:var(--p-primary-400);background:var(--p-primary-50)}.drop-slot.p-droppable-enter,.workspace-area-body.drag-active .drop-slot:hover,.workspace-area-body.drag-active .drop-slot.drop-slot-active{height:2.5rem;border-width:1px;border-color:color-mix(in srgb,var(--p-primary-500) 55%,var(--p-surface-300));background:color-mix(in srgb,var(--p-primary-50) 45%,transparent);box-shadow:0 0 0 2px color-mix(in srgb,var(--p-primary-300) 22%,transparent);opacity:1;transform:scaleX(1.01)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i2.Draggable, selector: "[pDraggable]", inputs: ["pDraggable", "dragEffect", "dragHandle", "pDraggableDisabled"], outputs: ["onDragStart", "onDragEnd", "onDrag"] }, { kind: "directive", type: i2.Droppable, selector: "[pDroppable]", inputs: ["pDroppable", "pDroppableDisabled", "dropEffect"], outputs: ["onDragEnter", "onDragLeave", "onDrop"] }, { 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: Icon, selector: "mt-icon", inputs: ["icon"] }, { kind: "component", type: Page, selector: "mt-page", inputs: ["backButton", "backButtonIcon", "avatarIcon", "avatarStyle", "avatarShape", "title", "tabs", "activeTab", "contentClass", "contentId"], outputs: ["backButtonClick", "tabChange"] }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { kind: "ngmodule", type: ContextMenuModule }, { kind: "component", type: i3.ContextMenu, selector: "p-contextMenu, p-contextmenu, p-context-menu", inputs: ["model", "triggerEvent", "target", "global", "style", "styleClass", "autoZIndex", "baseZIndex", "id", "breakpoint", "ariaLabel", "ariaLabelledBy", "pressDelay", "appendTo", "motionOptions"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type: i4.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1439
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkspaceBuilder, deps: [], target: i0.ɵɵFactoryTarget.Component });
1440
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: WorkspaceBuilder, isStandalone: true, selector: "mt-workspace-builder", inputs: { levelId: { classPropertyName: "levelId", publicName: "levelId", isSignal: true, isRequired: false, transformFunction: null }, showHeader: { classPropertyName: "showHeader", publicName: "showHeader", isSignal: true, isRequired: false, transformFunction: null }, autoSave: { classPropertyName: "autoSave", publicName: "autoSave", isSignal: true, isRequired: false, transformFunction: null } }, providers: [DialogService], ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'workspace-builder'\">\r\n <ng-template #builderContent>\r\n @if (isLoadingLayout()) {\r\n <div class=\"grid gap-5 w-1/2 mx-auto\">\r\n <div class=\"grid gap-5\">\r\n @for (area of areas; track area) {\r\n <mt-card\r\n [title]=\"t(area)\"\r\n [paddingless]=\"true\"\r\n class=\"h-[calc(100svh-10rem)] overflow-hidden bg-surface-0\"\r\n >\r\n <div\r\n class=\"grid min-h-full content-start gap-4 bg-surface-50/60 p-5 pt-4\"\r\n >\r\n @for (row of loadingSkeletonRows; track row) {\r\n <div\r\n class=\"rounded-lg border border-surface-200 bg-surface-0 px-3 py-3 shadow-sm\"\r\n >\r\n <div class=\"flex items-center gap-3\">\r\n <p-skeleton size=\"2rem\" borderRadius=\"0.75rem\" />\r\n <div class=\"grid flex-1 gap-2\">\r\n <p-skeleton width=\"75%\" height=\"1rem\" />\r\n <p-skeleton width=\"45%\" height=\"0.8rem\" />\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n </div>\r\n </div>\r\n } @else if (layoutError(); as error) {\r\n <div\r\n class=\"grid gap-4 rounded-xl border border-red-200 bg-red-50 px-5 py-6 text-red-700 shadow-sm\"\r\n >\r\n <div class=\"grid gap-1\">\r\n <div class=\"text-sm font-semibold\">\r\n {{ t(\"load-error-title\") }}\r\n </div>\r\n <p class=\"m-0 text-sm text-red-600\">\r\n {{ error || t(\"load-error-description\") }}\r\n </p>\r\n </div>\r\n\r\n <div>\r\n <mt-button\r\n [label]=\"t('retry')\"\r\n icon=\"arrow.refresh-cw-01\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n (onClick)=\"reloadLayout()\"\r\n />\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"grid gap-5\">\r\n @if (validationErrors().length > 0) {\r\n <div\r\n class=\"rounded-lg border border-red-200 bg-red-50 px-4 py-3.5 text-red-700 shadow-sm\"\r\n >\r\n <div class=\"mb-2 text-sm font-semibold\">\r\n {{ t(\"validation-title\") }}\r\n </div>\r\n <ul class=\"m-0 list-disc ps-4\">\r\n @for (error of validationErrors(); track error) {\r\n <li>{{ error }}</li>\r\n }\r\n </ul>\r\n </div>\r\n }\r\n\r\n <div class=\"grid gap-5 w-1/2 mx-auto\">\r\n @for (area of areas; track area) {\r\n <mt-card\r\n [title]=\"t(area)\"\r\n [paddingless]=\"true\"\r\n class=\"h-[calc(100svh-10rem)] overflow-hidden bg-surface-0\"\r\n (dragover)=\"allowNativeDrop($event)\"\r\n (drop)=\"onNativeAreaDrop($event, area)\"\r\n >\r\n <ng-template #cardEnd>\r\n <mt-button\r\n [label]=\"t('add-group')\"\r\n icon=\"general.plus\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n (onClick)=\"openCreateGroupDialog(area)\"\r\n />\r\n </ng-template>\r\n\r\n <div\r\n class=\"workspace-area-body grid h-full overflow-y-auto content-start gap-1 bg-surface-50/60 p-5 pt-2\"\r\n [class.drag-active]=\"isDragging()\"\r\n (dragover)=\"onAreaBodyDragOver($event)\"\r\n (dragleave)=\"onAreaBodyDragLeave($event)\"\r\n (drop)=\"onNativeAreaDrop($event, area)\"\r\n [pDroppable]=\"dropScope\"\r\n (onDrop)=\"onDropToArea($event, area, areaItems(area).length)\"\r\n >\r\n <div\r\n class=\"drop-slot\"\r\n [class.drop-slot-active]=\"\r\n activeDropSlotKey() === areaDropSlotKey(area, 0)\r\n \"\r\n [class.drop-slot-disabled]=\"isAreaDropSlotDisabled(area, 0)\"\r\n [pDroppable]=\"dropScope\"\r\n (dragover)=\"\r\n onDropSlotDragOver(\r\n $event,\r\n areaDropSlotKey(area, 0),\r\n isAreaDropSlotDisabled(area, 0)\r\n )\r\n \"\r\n (dragleave)=\"\r\n onDropSlotDragLeave($event, areaDropSlotKey(area, 0))\r\n \"\r\n (onDrop)=\"\r\n onDropToArea(\r\n $event,\r\n area,\r\n 0,\r\n isAreaDropSlotDisabled(area, 0)\r\n )\r\n \"\r\n ></div>\r\n\r\n @for (\r\n item of areaItems(area);\r\n track trackItem(item);\r\n let i = $index\r\n ) {\r\n @if (item.type === \"module\") {\r\n <div\r\n class=\"workspace-draggable-item flex cursor-grab items-center gap-3 rounded-lg border border-surface-200 bg-surface-0 px-3 py-2.5 transition-all duration-150 hover:-translate-y-0.5 hover:border-surface-300 hover:shadow-sm active:cursor-grabbing\"\r\n [attr.data-area]=\"area\"\r\n [attr.data-item-index]=\"i\"\r\n [pDraggable]=\"dropScope\"\r\n (onDragStart)=\"\r\n onModuleDragStart($event, item, {\r\n type: 'area',\r\n area: area,\r\n })\r\n \"\r\n (onDragEnd)=\"onDragEnd()\"\r\n >\r\n <span\r\n class=\"drag-handle flex size-8 shrink-0 items-center justify-center text-surface-500\"\r\n draggable=\"false\"\r\n >\r\n <mt-icon\r\n class=\"pointer-events-none text-xl text-primary\"\r\n icon=\"general.menu-05\"\r\n />\r\n </span>\r\n <span class=\"min-w-0 flex-1 truncate py-1.5\">{{\r\n item.name\r\n }}</span>\r\n </div>\r\n } @else {\r\n <div\r\n class=\"workspace-group-card grid cursor-grab gap-3 rounded-md border border-surface-200 bg-surface-0 p-3 transition-all duration-150 hover:-translate-y-0.5 hover:border-surface-300 hover:shadow-sm active:cursor-grabbing\"\r\n [attr.data-area]=\"area\"\r\n [attr.data-item-index]=\"i\"\r\n [pDraggable]=\"dropScope\"\r\n (onDragStart)=\"onGroupDragStart($event, item, area)\"\r\n (onDragEnd)=\"onDragEnd()\"\r\n (dragover)=\"allowNativeDrop($event)\"\r\n (drop)=\"onNativeGroupDrop($event, area, item.id)\"\r\n >\r\n <div\r\n class=\"group-header flex flex-wrap items-center gap-2 rounded-lg border-2 border-surface-200 bg-surface-50/80 px-2 py-2\"\r\n [pDroppable]=\"dropScope\"\r\n (onDrop)=\"\r\n onDropToGroup(\r\n $event,\r\n area,\r\n item.id,\r\n item.modules.length\r\n )\r\n \"\r\n >\r\n <mt-button\r\n class=\"expand-btn\"\r\n [icon]=\"\r\n isGroupExpanded(item.id)\r\n ? 'arrow.chevron-up'\r\n : 'arrow.chevron-down'\r\n \"\r\n severity=\"secondary\"\r\n variant=\"text\"\r\n (onClick)=\"toggleGroup(item.id)\"\r\n />\r\n <span\r\n class=\"group-drag-handle flex size-8 shrink-0 items-center justify-center text-surface-500\"\r\n draggable=\"false\"\r\n >\r\n <mt-icon\r\n class=\"pointer-events-none text-xl text-primary\"\r\n icon=\"general.menu-05\"\r\n />\r\n </span>\r\n\r\n <span\r\n class=\"min-w-0 flex-1 truncate text-lg mx-1 font-semibold text-surface-600\"\r\n >{{ item.name }}</span\r\n >\r\n <mt-button\r\n icon=\"general.edit-05\"\r\n [tooltip]=\"t('rename-group')\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n (onClick)=\"startRenameGroup(item)\"\r\n />\r\n\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n [tooltip]=\"t('delete-group')\"\r\n severity=\"danger\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n (onClick)=\"deleteGroup(item.id, $event)\"\r\n />\r\n </div>\r\n\r\n @if (isGroupExpanded(item.id)) {\r\n <div\r\n class=\"group-modules grid gap-2 border-t-2 border-dashed border-surface-300 pt-3\"\r\n [pDroppable]=\"dropScope\"\r\n (onDrop)=\"\r\n onDropToGroup(\r\n $event,\r\n area,\r\n item.id,\r\n item.modules.length\r\n )\r\n \"\r\n >\r\n <div\r\n class=\"drop-slot\"\r\n [class.drop-slot-active]=\"\r\n activeDropSlotKey() ===\r\n groupDropSlotKey(area, item.id, 0)\r\n \"\r\n [class.drop-slot-disabled]=\"\r\n isGroupDropSlotDisabled(area, item.id, 0)\r\n \"\r\n [pDroppable]=\"dropScope\"\r\n (dragover)=\"\r\n onDropSlotDragOver(\r\n $event,\r\n groupDropSlotKey(area, item.id, 0),\r\n isGroupDropSlotDisabled(area, item.id, 0)\r\n )\r\n \"\r\n (dragleave)=\"\r\n onDropSlotDragLeave(\r\n $event,\r\n groupDropSlotKey(area, item.id, 0)\r\n )\r\n \"\r\n (onDrop)=\"\r\n onDropToGroup(\r\n $event,\r\n area,\r\n item.id,\r\n 0,\r\n isGroupDropSlotDisabled(area, item.id, 0)\r\n )\r\n \"\r\n ></div>\r\n\r\n @for (\r\n module of item.modules;\r\n track module.id;\r\n let j = $index\r\n ) {\r\n <div\r\n class=\"workspace-draggable-item workspace-group-module-item ms-3 flex cursor-grab items-center gap-3 rounded-lg border border-surface-200 bg-surface-0 px-3 py-2.5 transition-all duration-150 hover:-translate-y-0.5 hover:border-surface-300 hover:shadow-sm active:cursor-grabbing\"\r\n [pDraggable]=\"dropScope\"\r\n (dragover)=\"allowNativeDrop($event)\"\r\n (drop)=\"\r\n onNativeGroupModuleDrop(\r\n $event,\r\n area,\r\n item.id,\r\n j\r\n )\r\n \"\r\n (onDragStart)=\"\r\n onModuleDragStart($event, module, {\r\n type: 'group',\r\n area: area,\r\n groupId: item.id,\r\n })\r\n \"\r\n (onDragEnd)=\"onDragEnd()\"\r\n >\r\n <span\r\n class=\"drag-handle flex size-8 shrink-0 items-center justify-center text-surface-500\"\r\n draggable=\"false\"\r\n >\r\n <mt-icon\r\n class=\"pointer-events-none text-xl text-primary\"\r\n icon=\"general.menu-05\"\r\n />\r\n </span>\r\n <span class=\"min-w-0 flex-1 truncate py-1.5\">{{\r\n module.name\r\n }}</span>\r\n <mt-button\r\n icon=\"general.minus\"\r\n [tooltip]=\"t('remove')\"\r\n severity=\"secondary\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n (onClick)=\"\r\n removeModuleFromGroup(\r\n area,\r\n item.id,\r\n module.id\r\n )\r\n \"\r\n />\r\n </div>\r\n\r\n <div\r\n class=\"drop-slot\"\r\n [class.drop-slot-active]=\"\r\n activeDropSlotKey() ===\r\n groupDropSlotKey(area, item.id, j + 1)\r\n \"\r\n [class.drop-slot-disabled]=\"\r\n isGroupDropSlotDisabled(area, item.id, j + 1)\r\n \"\r\n [pDroppable]=\"dropScope\"\r\n (dragover)=\"\r\n onDropSlotDragOver(\r\n $event,\r\n groupDropSlotKey(area, item.id, j + 1),\r\n isGroupDropSlotDisabled(area, item.id, j + 1)\r\n )\r\n \"\r\n (dragleave)=\"\r\n onDropSlotDragLeave(\r\n $event,\r\n groupDropSlotKey(area, item.id, j + 1)\r\n )\r\n \"\r\n (onDrop)=\"\r\n onDropToGroup(\r\n $event,\r\n area,\r\n item.id,\r\n j + 1,\r\n isGroupDropSlotDisabled(area, item.id, j + 1)\r\n )\r\n \"\r\n ></div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n <div\r\n class=\"drop-slot\"\r\n [class.drop-slot-active]=\"\r\n activeDropSlotKey() === areaDropSlotKey(area, i + 1)\r\n \"\r\n [class.drop-slot-disabled]=\"\r\n isAreaDropSlotDisabled(area, i + 1)\r\n \"\r\n [pDroppable]=\"dropScope\"\r\n (dragover)=\"\r\n onDropSlotDragOver(\r\n $event,\r\n areaDropSlotKey(area, i + 1),\r\n isAreaDropSlotDisabled(area, i + 1)\r\n )\r\n \"\r\n (dragleave)=\"\r\n onDropSlotDragLeave($event, areaDropSlotKey(area, i + 1))\r\n \"\r\n (onDrop)=\"\r\n onDropToArea(\r\n $event,\r\n area,\r\n i + 1,\r\n isAreaDropSlotDisabled(area, i + 1)\r\n )\r\n \"\r\n ></div>\r\n }\r\n\r\n @if (areaItems(area).length === 0) {\r\n <div\r\n class=\"empty-area grid min-h-32 place-items-center rounded-lg border border-dashed border-surface-300 bg-surface-0/80 px-4 py-6 text-center text-sm text-surface-500\"\r\n [pDroppable]=\"dropScope\"\r\n (onDrop)=\"onDropToArea($event, area, 0)\"\r\n >\r\n {{ t(\"empty-area\") }}\r\n </div>\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </ng-template>\r\n\r\n @if (showHeader()) {\r\n <mt-page [title]=\"t('title')\" avatarIcon=\"layout.layout-grid-01\">\r\n <ng-template #headerEnd>\r\n @if (!autoSave()) {\r\n <div class=\"flex items-center\">\r\n <mt-button\r\n [label]=\"t('save')\"\r\n icon=\"general.save-02\"\r\n severity=\"primary\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n [loading]=\"isSavingLayout()\"\r\n [disabled]=\"\r\n isLoadingLayout() ||\r\n !!layoutError() ||\r\n isSavingLayout() ||\r\n validationErrors().length > 0\r\n \"\r\n (onClick)=\"onSaveClick()\"\r\n />\r\n </div>\r\n }\r\n </ng-template>\r\n\r\n <ng-container [ngTemplateOutlet]=\"builderContent\" />\r\n </mt-page>\r\n } @else {\r\n <div class=\"w-full overflow-y-auto p-5\">\r\n @if (!autoSave()) {\r\n <div class=\"mb-4 flex justify-end\">\r\n <mt-button\r\n [label]=\"t('save')\"\r\n icon=\"general.save-02\"\r\n severity=\"primary\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n [loading]=\"isSavingLayout()\"\r\n [disabled]=\"\r\n isLoadingLayout() ||\r\n !!layoutError() ||\r\n isSavingLayout() ||\r\n validationErrors().length > 0\r\n \"\r\n (onClick)=\"onSaveClick()\"\r\n />\r\n </div>\r\n }\r\n\r\n <ng-container [ngTemplateOutlet]=\"builderContent\" />\r\n </div>\r\n }\r\n</ng-container>\r\n", styles: [".workspace-area-body{transition:background-color .18s ease,box-shadow .18s ease}.workspace-area-body.drag-active{cursor:grabbing}.workspace-draggable-item.p-draggable-dragging,.workspace-group-card.p-draggable-dragging{transform:scale(.985);box-shadow:0 12px 30px color-mix(in srgb,var(--p-text-color) 14%,transparent)}.drag-handle,.group-drag-handle{user-select:none;-webkit-user-select:none;touch-action:none;transition:transform .15s ease,border-color .15s ease,background-color .15s ease,color .15s ease}.drag-handle:active,.group-drag-handle:active{transform:scale(.96)}.workspace-area-body.drag-active .drag-handle,.workspace-area-body.drag-active .group-drag-handle{cursor:grabbing}.drop-slot{width:100%;height:.4rem;border:1px solid transparent;border-radius:9999px;background:transparent;opacity:0;transition:height .15s ease,border-color .15s ease,background-color .15s ease,box-shadow .15s ease,transform .15s ease,opacity .15s ease}.workspace-area-body.drag-active .drop-slot{height:.65rem;border-color:var(--p-surface-300);background:color-mix(in srgb,var(--p-surface-100) 55%,transparent);opacity:.28;transform:scaleX(.98)}.workspace-area-body.drag-active .drop-slot.drop-slot-disabled{opacity:0;height:.4rem;pointer-events:none}.empty-area.p-droppable-enter{border-color:var(--p-primary-400);background:var(--p-primary-50)}.drop-slot.p-droppable-enter,.workspace-area-body.drag-active .drop-slot:hover,.workspace-area-body.drag-active .drop-slot.drop-slot-active{height:2.5rem;border-width:1px;border-color:color-mix(in srgb,var(--p-primary-500) 55%,var(--p-surface-300));background:color-mix(in srgb,var(--p-primary-50) 45%,transparent);box-shadow:0 0 0 2px color-mix(in srgb,var(--p-primary-300) 22%,transparent);opacity:1;transform:scaleX(1.01)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i2.Draggable, selector: "[pDraggable]", inputs: ["pDraggable", "dragEffect", "dragHandle", "pDraggableDisabled"], outputs: ["onDragStart", "onDragEnd", "onDrag"] }, { kind: "directive", type: i2.Droppable, selector: "[pDroppable]", inputs: ["pDroppable", "pDroppableDisabled", "dropEffect"], outputs: ["onDragEnter", "onDragLeave", "onDrop"] }, { 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: Icon, selector: "mt-icon", inputs: ["icon"] }, { kind: "component", type: Page, selector: "mt-page", inputs: ["backButton", "backButtonIcon", "avatarIcon", "avatarStyle", "avatarShape", "title", "tabs", "activeTab", "contentClass", "contentId"], outputs: ["backButtonClick", "tabChange"] }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type: i3.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1476
1441
  }
1477
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: WorkspaceBuilder, decorators: [{
1442
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkspaceBuilder, decorators: [{
1478
1443
  type: Component,
1479
1444
  args: [{ selector: 'mt-workspace-builder', standalone: true, imports: [
1480
1445
  CommonModule,
@@ -1484,9 +1449,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
1484
1449
  Icon,
1485
1450
  Page,
1486
1451
  Card,
1487
- ContextMenuModule,
1488
1452
  SkeletonModule,
1489
- ], changeDetection: ChangeDetectionStrategy.OnPush, providers: [DialogService], template: "<ng-container *transloco=\"let t; prefix: 'workspace-builder'\">\r\n <p-contextMenu\r\n #areaContextMenu\r\n [model]=\"areaContextItems()\"\r\n appendTo=\"body\"\r\n />\r\n\r\n <ng-template #builderContent>\r\n @if (isLoadingLayout()) {\r\n <div class=\"grid gap-5\">\r\n <div class=\"grid grid-cols-1 gap-5 xl:grid-cols-2\">\r\n @for (area of areas; track area) {\r\n <mt-card\r\n [title]=\"t(area)\"\r\n [paddingless]=\"true\"\r\n class=\"min-h-[26rem] overflow-hidden bg-surface-0\"\r\n >\r\n <div\r\n class=\"grid min-h-full content-start gap-4 bg-surface-50/60 p-5 pt-4\"\r\n >\r\n @for (row of loadingSkeletonRows; track row) {\r\n <div\r\n class=\"rounded-lg border border-surface-200 bg-surface-0 px-3 py-3 shadow-sm\"\r\n >\r\n <div class=\"flex items-center gap-3\">\r\n <p-skeleton size=\"2rem\" borderRadius=\"0.75rem\" />\r\n <div class=\"grid flex-1 gap-2\">\r\n <p-skeleton width=\"75%\" height=\"1rem\" />\r\n <p-skeleton width=\"45%\" height=\"0.8rem\" />\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n </div>\r\n </div>\r\n } @else if (layoutError(); as error) {\r\n <div\r\n class=\"grid gap-4 rounded-xl border border-red-200 bg-red-50 px-5 py-6 text-red-700 shadow-sm\"\r\n >\r\n <div class=\"grid gap-1\">\r\n <div class=\"text-sm font-semibold\">\r\n {{ t(\"load-error-title\") }}\r\n </div>\r\n <p class=\"m-0 text-sm text-red-600\">\r\n {{ error || t(\"load-error-description\") }}\r\n </p>\r\n </div>\r\n\r\n <div>\r\n <mt-button\r\n [label]=\"t('retry')\"\r\n icon=\"arrow.refresh-cw-01\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n (onClick)=\"reloadLayout()\"\r\n />\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"grid gap-5\">\r\n @if (validationErrors().length > 0) {\r\n <div\r\n class=\"rounded-lg border border-red-200 bg-red-50 px-4 py-3.5 text-red-700 shadow-sm\"\r\n >\r\n <div class=\"mb-2 text-sm font-semibold\">\r\n {{ t(\"validation-title\") }}\r\n </div>\r\n <ul class=\"m-0 list-disc ps-4\">\r\n @for (error of validationErrors(); track error) {\r\n <li>{{ error }}</li>\r\n }\r\n </ul>\r\n </div>\r\n }\r\n\r\n <div class=\"grid grid-cols-1 gap-5 xl:grid-cols-2\">\r\n @for (area of areas; track area) {\r\n <mt-card\r\n [title]=\"t(area)\"\r\n [paddingless]=\"true\"\r\n class=\"min-h-[26rem] overflow-hidden bg-surface-0\"\r\n (contextmenu)=\"onAreaContextMenu($event, area, areaContextMenu)\"\r\n (dragover)=\"allowNativeDrop($event)\"\r\n (drop)=\"onNativeAreaDrop($event, area)\"\r\n >\r\n <ng-template #cardEnd>\r\n <mt-button\r\n [label]=\"t('add-group')\"\r\n icon=\"general.plus\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n (onClick)=\"openCreateGroupDialog(area)\"\r\n />\r\n </ng-template>\r\n\r\n <div\r\n class=\"workspace-area-body grid min-h-full content-start gap-2 bg-surface-50/60 p-5 pt-2\"\r\n [class.drag-active]=\"isDragging()\"\r\n (dragover)=\"allowNativeDrop($event)\"\r\n (drop)=\"onNativeAreaDrop($event, area)\"\r\n [pDroppable]=\"dropScope\"\r\n (onDrop)=\"onDropToArea($event, area, areaItems(area).length)\"\r\n >\r\n <div\r\n class=\"drop-slot\"\r\n [class.drop-slot-active]=\"\r\n activeDropSlotKey() === areaDropSlotKey(area, 0)\r\n \"\r\n [class.drop-slot-disabled]=\"isAreaDropSlotDisabled(area, 0)\"\r\n [pDroppable]=\"dropScope\"\r\n (dragover)=\"\r\n onDropSlotDragOver(\r\n $event,\r\n areaDropSlotKey(area, 0),\r\n isAreaDropSlotDisabled(area, 0)\r\n )\r\n \"\r\n (dragleave)=\"\r\n onDropSlotDragLeave($event, areaDropSlotKey(area, 0))\r\n \"\r\n (onDrop)=\"\r\n onDropToArea(\r\n $event,\r\n area,\r\n 0,\r\n isAreaDropSlotDisabled(area, 0)\r\n )\r\n \"\r\n ></div>\r\n\r\n @for (\r\n item of areaItems(area);\r\n track trackItem(item);\r\n let i = $index\r\n ) {\r\n @if (item.type === \"module\") {\r\n <div\r\n class=\"workspace-draggable-item flex min-h-11 cursor-grab items-center gap-3 rounded-lg border border-surface-200 bg-surface-0 px-3 py-2.5 transition-all duration-150 hover:-translate-y-0.5 hover:border-surface-300 hover:shadow-sm active:cursor-grabbing\"\r\n [attr.data-area]=\"area\"\r\n [attr.data-item-index]=\"i\"\r\n [pDraggable]=\"dropScope\"\r\n (onDragStart)=\"\r\n onModuleDragStart($event, item, {\r\n type: 'area',\r\n area: area,\r\n })\r\n \"\r\n (onDragEnd)=\"onDragEnd()\"\r\n >\r\n <span\r\n class=\"drag-handle flex size-8 shrink-0 items-center justify-center text-surface-500\"\r\n draggable=\"false\"\r\n >\r\n <mt-icon\r\n class=\"pointer-events-none text-xl text-primary\"\r\n icon=\"general.menu-05\"\r\n />\r\n </span>\r\n <span class=\"min-w-0 flex-1 truncate py-1.5\">{{\r\n item.name\r\n }}</span>\r\n </div>\r\n } @else {\r\n <div\r\n class=\"workspace-group-card grid cursor-grab gap-3 rounded-md border border-surface-200 bg-surface-0 p-3 transition-all duration-150 hover:-translate-y-0.5 hover:border-surface-300 hover:shadow-sm active:cursor-grabbing\"\r\n [attr.data-area]=\"area\"\r\n [attr.data-item-index]=\"i\"\r\n [pDraggable]=\"dropScope\"\r\n (onDragStart)=\"onGroupDragStart($event, item, area)\"\r\n (onDragEnd)=\"onDragEnd()\"\r\n (dragover)=\"allowNativeDrop($event)\"\r\n (drop)=\"onNativeGroupDrop($event, area, item.id)\"\r\n >\r\n <div\r\n class=\"group-header flex flex-wrap items-center gap-2 rounded-lg border-2 border-surface-200 bg-surface-50/80 px-2 py-2\"\r\n [pDroppable]=\"dropScope\"\r\n (onDrop)=\"\r\n onDropToGroup(\r\n $event,\r\n area,\r\n item.id,\r\n item.modules.length\r\n )\r\n \"\r\n >\r\n <mt-button\r\n class=\"expand-btn\"\r\n [icon]=\"\r\n isGroupExpanded(item.id)\r\n ? 'arrow.chevron-up'\r\n : 'arrow.chevron-down'\r\n \"\r\n severity=\"secondary\"\r\n variant=\"text\"\r\n (onClick)=\"toggleGroup(item.id)\"\r\n />\r\n <span\r\n class=\"group-drag-handle flex size-8 shrink-0 items-center justify-center text-surface-500\"\r\n draggable=\"false\"\r\n >\r\n <mt-icon\r\n class=\"pointer-events-none text-xl text-primary\"\r\n icon=\"general.menu-05\"\r\n />\r\n </span>\r\n\r\n <span\r\n class=\"min-w-0 flex-1 truncate text-lg mx-1 font-semibold text-surface-600\"\r\n >{{ item.name }}</span\r\n >\r\n <mt-button\r\n icon=\"general.edit-05\"\r\n [tooltip]=\"t('rename-group')\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n (onClick)=\"startRenameGroup(item)\"\r\n />\r\n\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n [tooltip]=\"t('delete-group')\"\r\n severity=\"danger\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n (onClick)=\"deleteGroup(item.id, $event)\"\r\n />\r\n </div>\r\n\r\n @if (isGroupExpanded(item.id)) {\r\n <div\r\n class=\"group-modules grid gap-2 border-t-2 border-dashed border-surface-300 pt-3\"\r\n [pDroppable]=\"dropScope\"\r\n (onDrop)=\"\r\n onDropToGroup(\r\n $event,\r\n area,\r\n item.id,\r\n item.modules.length\r\n )\r\n \"\r\n >\r\n <div\r\n class=\"drop-slot\"\r\n [class.drop-slot-active]=\"\r\n activeDropSlotKey() ===\r\n groupDropSlotKey(area, item.id, 0)\r\n \"\r\n [class.drop-slot-disabled]=\"\r\n isGroupDropSlotDisabled(area, item.id, 0)\r\n \"\r\n [pDroppable]=\"dropScope\"\r\n (dragover)=\"\r\n onDropSlotDragOver(\r\n $event,\r\n groupDropSlotKey(area, item.id, 0),\r\n isGroupDropSlotDisabled(area, item.id, 0)\r\n )\r\n \"\r\n (dragleave)=\"\r\n onDropSlotDragLeave(\r\n $event,\r\n groupDropSlotKey(area, item.id, 0)\r\n )\r\n \"\r\n (onDrop)=\"\r\n onDropToGroup(\r\n $event,\r\n area,\r\n item.id,\r\n 0,\r\n isGroupDropSlotDisabled(area, item.id, 0)\r\n )\r\n \"\r\n ></div>\r\n\r\n @for (\r\n module of item.modules;\r\n track module.id;\r\n let j = $index\r\n ) {\r\n <div\r\n class=\"workspace-draggable-item workspace-group-module-item ms-3 flex min-h-11 cursor-grab items-center gap-3 rounded-lg border border-surface-200 bg-surface-0 px-3 py-2.5 transition-all duration-150 hover:-translate-y-0.5 hover:border-surface-300 hover:shadow-sm active:cursor-grabbing\"\r\n [pDraggable]=\"dropScope\"\r\n (dragover)=\"allowNativeDrop($event)\"\r\n (drop)=\"\r\n onNativeGroupModuleDrop(\r\n $event,\r\n area,\r\n item.id,\r\n j\r\n )\r\n \"\r\n (onDragStart)=\"\r\n onModuleDragStart($event, module, {\r\n type: 'group',\r\n area: area,\r\n groupId: item.id,\r\n })\r\n \"\r\n (onDragEnd)=\"onDragEnd()\"\r\n >\r\n <span\r\n class=\"drag-handle flex size-8 shrink-0 items-center justify-center text-surface-500\"\r\n draggable=\"false\"\r\n >\r\n <mt-icon\r\n class=\"pointer-events-none text-xl text-primary\"\r\n icon=\"general.menu-05\"\r\n />\r\n </span>\r\n <span class=\"min-w-0 flex-1 truncate py-1.5\">{{\r\n module.name\r\n }}</span>\r\n <mt-button\r\n icon=\"general.minus\"\r\n [tooltip]=\"t('remove')\"\r\n severity=\"secondary\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n (onClick)=\"\r\n removeModuleFromGroup(\r\n area,\r\n item.id,\r\n module.id\r\n )\r\n \"\r\n />\r\n </div>\r\n\r\n <div\r\n class=\"drop-slot\"\r\n [class.drop-slot-active]=\"\r\n activeDropSlotKey() ===\r\n groupDropSlotKey(area, item.id, j + 1)\r\n \"\r\n [class.drop-slot-disabled]=\"\r\n isGroupDropSlotDisabled(area, item.id, j + 1)\r\n \"\r\n [pDroppable]=\"dropScope\"\r\n (dragover)=\"\r\n onDropSlotDragOver(\r\n $event,\r\n groupDropSlotKey(area, item.id, j + 1),\r\n isGroupDropSlotDisabled(area, item.id, j + 1)\r\n )\r\n \"\r\n (dragleave)=\"\r\n onDropSlotDragLeave(\r\n $event,\r\n groupDropSlotKey(area, item.id, j + 1)\r\n )\r\n \"\r\n (onDrop)=\"\r\n onDropToGroup(\r\n $event,\r\n area,\r\n item.id,\r\n j + 1,\r\n isGroupDropSlotDisabled(area, item.id, j + 1)\r\n )\r\n \"\r\n ></div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n <div\r\n class=\"drop-slot\"\r\n [class.drop-slot-active]=\"\r\n activeDropSlotKey() === areaDropSlotKey(area, i + 1)\r\n \"\r\n [class.drop-slot-disabled]=\"\r\n isAreaDropSlotDisabled(area, i + 1)\r\n \"\r\n [pDroppable]=\"dropScope\"\r\n (dragover)=\"\r\n onDropSlotDragOver(\r\n $event,\r\n areaDropSlotKey(area, i + 1),\r\n isAreaDropSlotDisabled(area, i + 1)\r\n )\r\n \"\r\n (dragleave)=\"\r\n onDropSlotDragLeave($event, areaDropSlotKey(area, i + 1))\r\n \"\r\n (onDrop)=\"\r\n onDropToArea(\r\n $event,\r\n area,\r\n i + 1,\r\n isAreaDropSlotDisabled(area, i + 1)\r\n )\r\n \"\r\n ></div>\r\n }\r\n\r\n @if (areaItems(area).length === 0) {\r\n <div\r\n class=\"empty-area grid min-h-32 place-items-center rounded-lg border border-dashed border-surface-300 bg-surface-0/80 px-4 py-6 text-center text-sm text-surface-500\"\r\n [pDroppable]=\"dropScope\"\r\n (onDrop)=\"onDropToArea($event, area, 0)\"\r\n >\r\n {{ t(\"empty-area\") }}\r\n </div>\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </ng-template>\r\n\r\n @if (showHeader()) {\r\n <mt-page [title]=\"t('title')\" avatarIcon=\"layout.layout-grid-01\">\r\n <ng-template #headerEnd>\r\n @if (!autoSave()) {\r\n <div class=\"flex items-center\">\r\n <mt-button\r\n [label]=\"t('save')\"\r\n icon=\"general.save-02\"\r\n severity=\"primary\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n [loading]=\"isSavingLayout()\"\r\n [disabled]=\"\r\n isLoadingLayout() ||\r\n !!layoutError() ||\r\n isSavingLayout() ||\r\n validationErrors().length > 0\r\n \"\r\n (onClick)=\"onSaveClick()\"\r\n />\r\n </div>\r\n }\r\n </ng-template>\r\n\r\n <ng-container [ngTemplateOutlet]=\"builderContent\" />\r\n </mt-page>\r\n } @else {\r\n <div class=\"w-full overflow-y-auto p-5\">\r\n @if (!autoSave()) {\r\n <div class=\"mb-4 flex justify-end\">\r\n <mt-button\r\n [label]=\"t('save')\"\r\n icon=\"general.save-02\"\r\n severity=\"primary\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n [loading]=\"isSavingLayout()\"\r\n [disabled]=\"\r\n isLoadingLayout() ||\r\n !!layoutError() ||\r\n isSavingLayout() ||\r\n validationErrors().length > 0\r\n \"\r\n (onClick)=\"onSaveClick()\"\r\n />\r\n </div>\r\n }\r\n\r\n <ng-container [ngTemplateOutlet]=\"builderContent\" />\r\n </div>\r\n }\r\n</ng-container>\r\n", styles: [".workspace-area-body{transition:background-color .18s ease,box-shadow .18s ease}.workspace-area-body.drag-active{cursor:grabbing}.workspace-draggable-item.p-draggable-dragging,.workspace-group-card.p-draggable-dragging{transform:scale(.985);box-shadow:0 12px 30px color-mix(in srgb,var(--p-text-color) 14%,transparent)}.drag-handle,.group-drag-handle{user-select:none;-webkit-user-select:none;touch-action:none;transition:transform .15s ease,border-color .15s ease,background-color .15s ease,color .15s ease}.drag-handle:active,.group-drag-handle:active{transform:scale(.96)}.workspace-area-body.drag-active .drag-handle,.workspace-area-body.drag-active .group-drag-handle{cursor:grabbing}.drop-slot{width:100%;height:.4rem;border:1px solid transparent;border-radius:9999px;background:transparent;opacity:0;transition:height .15s ease,border-color .15s ease,background-color .15s ease,box-shadow .15s ease,transform .15s ease,opacity .15s ease}.workspace-area-body.drag-active .drop-slot{height:.65rem;border-color:var(--p-surface-300);background:color-mix(in srgb,var(--p-surface-100) 55%,transparent);opacity:.28;transform:scaleX(.98)}.workspace-area-body.drag-active .drop-slot.drop-slot-disabled{opacity:0;height:.4rem;pointer-events:none}.empty-area.p-droppable-enter{border-color:var(--p-primary-400);background:var(--p-primary-50)}.drop-slot.p-droppable-enter,.workspace-area-body.drag-active .drop-slot:hover,.workspace-area-body.drag-active .drop-slot.drop-slot-active{height:2.5rem;border-width:1px;border-color:color-mix(in srgb,var(--p-primary-500) 55%,var(--p-surface-300));background:color-mix(in srgb,var(--p-primary-50) 45%,transparent);box-shadow:0 0 0 2px color-mix(in srgb,var(--p-primary-300) 22%,transparent);opacity:1;transform:scaleX(1.01)}\n"] }]
1453
+ ], changeDetection: ChangeDetectionStrategy.OnPush, providers: [DialogService], template: "<ng-container *transloco=\"let t; prefix: 'workspace-builder'\">\r\n <ng-template #builderContent>\r\n @if (isLoadingLayout()) {\r\n <div class=\"grid gap-5 w-1/2 mx-auto\">\r\n <div class=\"grid gap-5\">\r\n @for (area of areas; track area) {\r\n <mt-card\r\n [title]=\"t(area)\"\r\n [paddingless]=\"true\"\r\n class=\"h-[calc(100svh-10rem)] overflow-hidden bg-surface-0\"\r\n >\r\n <div\r\n class=\"grid min-h-full content-start gap-4 bg-surface-50/60 p-5 pt-4\"\r\n >\r\n @for (row of loadingSkeletonRows; track row) {\r\n <div\r\n class=\"rounded-lg border border-surface-200 bg-surface-0 px-3 py-3 shadow-sm\"\r\n >\r\n <div class=\"flex items-center gap-3\">\r\n <p-skeleton size=\"2rem\" borderRadius=\"0.75rem\" />\r\n <div class=\"grid flex-1 gap-2\">\r\n <p-skeleton width=\"75%\" height=\"1rem\" />\r\n <p-skeleton width=\"45%\" height=\"0.8rem\" />\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n </div>\r\n </div>\r\n } @else if (layoutError(); as error) {\r\n <div\r\n class=\"grid gap-4 rounded-xl border border-red-200 bg-red-50 px-5 py-6 text-red-700 shadow-sm\"\r\n >\r\n <div class=\"grid gap-1\">\r\n <div class=\"text-sm font-semibold\">\r\n {{ t(\"load-error-title\") }}\r\n </div>\r\n <p class=\"m-0 text-sm text-red-600\">\r\n {{ error || t(\"load-error-description\") }}\r\n </p>\r\n </div>\r\n\r\n <div>\r\n <mt-button\r\n [label]=\"t('retry')\"\r\n icon=\"arrow.refresh-cw-01\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n (onClick)=\"reloadLayout()\"\r\n />\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"grid gap-5\">\r\n @if (validationErrors().length > 0) {\r\n <div\r\n class=\"rounded-lg border border-red-200 bg-red-50 px-4 py-3.5 text-red-700 shadow-sm\"\r\n >\r\n <div class=\"mb-2 text-sm font-semibold\">\r\n {{ t(\"validation-title\") }}\r\n </div>\r\n <ul class=\"m-0 list-disc ps-4\">\r\n @for (error of validationErrors(); track error) {\r\n <li>{{ error }}</li>\r\n }\r\n </ul>\r\n </div>\r\n }\r\n\r\n <div class=\"grid gap-5 w-1/2 mx-auto\">\r\n @for (area of areas; track area) {\r\n <mt-card\r\n [title]=\"t(area)\"\r\n [paddingless]=\"true\"\r\n class=\"h-[calc(100svh-10rem)] overflow-hidden bg-surface-0\"\r\n (dragover)=\"allowNativeDrop($event)\"\r\n (drop)=\"onNativeAreaDrop($event, area)\"\r\n >\r\n <ng-template #cardEnd>\r\n <mt-button\r\n [label]=\"t('add-group')\"\r\n icon=\"general.plus\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n (onClick)=\"openCreateGroupDialog(area)\"\r\n />\r\n </ng-template>\r\n\r\n <div\r\n class=\"workspace-area-body grid h-full overflow-y-auto content-start gap-1 bg-surface-50/60 p-5 pt-2\"\r\n [class.drag-active]=\"isDragging()\"\r\n (dragover)=\"onAreaBodyDragOver($event)\"\r\n (dragleave)=\"onAreaBodyDragLeave($event)\"\r\n (drop)=\"onNativeAreaDrop($event, area)\"\r\n [pDroppable]=\"dropScope\"\r\n (onDrop)=\"onDropToArea($event, area, areaItems(area).length)\"\r\n >\r\n <div\r\n class=\"drop-slot\"\r\n [class.drop-slot-active]=\"\r\n activeDropSlotKey() === areaDropSlotKey(area, 0)\r\n \"\r\n [class.drop-slot-disabled]=\"isAreaDropSlotDisabled(area, 0)\"\r\n [pDroppable]=\"dropScope\"\r\n (dragover)=\"\r\n onDropSlotDragOver(\r\n $event,\r\n areaDropSlotKey(area, 0),\r\n isAreaDropSlotDisabled(area, 0)\r\n )\r\n \"\r\n (dragleave)=\"\r\n onDropSlotDragLeave($event, areaDropSlotKey(area, 0))\r\n \"\r\n (onDrop)=\"\r\n onDropToArea(\r\n $event,\r\n area,\r\n 0,\r\n isAreaDropSlotDisabled(area, 0)\r\n )\r\n \"\r\n ></div>\r\n\r\n @for (\r\n item of areaItems(area);\r\n track trackItem(item);\r\n let i = $index\r\n ) {\r\n @if (item.type === \"module\") {\r\n <div\r\n class=\"workspace-draggable-item flex cursor-grab items-center gap-3 rounded-lg border border-surface-200 bg-surface-0 px-3 py-2.5 transition-all duration-150 hover:-translate-y-0.5 hover:border-surface-300 hover:shadow-sm active:cursor-grabbing\"\r\n [attr.data-area]=\"area\"\r\n [attr.data-item-index]=\"i\"\r\n [pDraggable]=\"dropScope\"\r\n (onDragStart)=\"\r\n onModuleDragStart($event, item, {\r\n type: 'area',\r\n area: area,\r\n })\r\n \"\r\n (onDragEnd)=\"onDragEnd()\"\r\n >\r\n <span\r\n class=\"drag-handle flex size-8 shrink-0 items-center justify-center text-surface-500\"\r\n draggable=\"false\"\r\n >\r\n <mt-icon\r\n class=\"pointer-events-none text-xl text-primary\"\r\n icon=\"general.menu-05\"\r\n />\r\n </span>\r\n <span class=\"min-w-0 flex-1 truncate py-1.5\">{{\r\n item.name\r\n }}</span>\r\n </div>\r\n } @else {\r\n <div\r\n class=\"workspace-group-card grid cursor-grab gap-3 rounded-md border border-surface-200 bg-surface-0 p-3 transition-all duration-150 hover:-translate-y-0.5 hover:border-surface-300 hover:shadow-sm active:cursor-grabbing\"\r\n [attr.data-area]=\"area\"\r\n [attr.data-item-index]=\"i\"\r\n [pDraggable]=\"dropScope\"\r\n (onDragStart)=\"onGroupDragStart($event, item, area)\"\r\n (onDragEnd)=\"onDragEnd()\"\r\n (dragover)=\"allowNativeDrop($event)\"\r\n (drop)=\"onNativeGroupDrop($event, area, item.id)\"\r\n >\r\n <div\r\n class=\"group-header flex flex-wrap items-center gap-2 rounded-lg border-2 border-surface-200 bg-surface-50/80 px-2 py-2\"\r\n [pDroppable]=\"dropScope\"\r\n (onDrop)=\"\r\n onDropToGroup(\r\n $event,\r\n area,\r\n item.id,\r\n item.modules.length\r\n )\r\n \"\r\n >\r\n <mt-button\r\n class=\"expand-btn\"\r\n [icon]=\"\r\n isGroupExpanded(item.id)\r\n ? 'arrow.chevron-up'\r\n : 'arrow.chevron-down'\r\n \"\r\n severity=\"secondary\"\r\n variant=\"text\"\r\n (onClick)=\"toggleGroup(item.id)\"\r\n />\r\n <span\r\n class=\"group-drag-handle flex size-8 shrink-0 items-center justify-center text-surface-500\"\r\n draggable=\"false\"\r\n >\r\n <mt-icon\r\n class=\"pointer-events-none text-xl text-primary\"\r\n icon=\"general.menu-05\"\r\n />\r\n </span>\r\n\r\n <span\r\n class=\"min-w-0 flex-1 truncate text-lg mx-1 font-semibold text-surface-600\"\r\n >{{ item.name }}</span\r\n >\r\n <mt-button\r\n icon=\"general.edit-05\"\r\n [tooltip]=\"t('rename-group')\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n (onClick)=\"startRenameGroup(item)\"\r\n />\r\n\r\n <mt-button\r\n icon=\"general.trash-01\"\r\n [tooltip]=\"t('delete-group')\"\r\n severity=\"danger\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n (onClick)=\"deleteGroup(item.id, $event)\"\r\n />\r\n </div>\r\n\r\n @if (isGroupExpanded(item.id)) {\r\n <div\r\n class=\"group-modules grid gap-2 border-t-2 border-dashed border-surface-300 pt-3\"\r\n [pDroppable]=\"dropScope\"\r\n (onDrop)=\"\r\n onDropToGroup(\r\n $event,\r\n area,\r\n item.id,\r\n item.modules.length\r\n )\r\n \"\r\n >\r\n <div\r\n class=\"drop-slot\"\r\n [class.drop-slot-active]=\"\r\n activeDropSlotKey() ===\r\n groupDropSlotKey(area, item.id, 0)\r\n \"\r\n [class.drop-slot-disabled]=\"\r\n isGroupDropSlotDisabled(area, item.id, 0)\r\n \"\r\n [pDroppable]=\"dropScope\"\r\n (dragover)=\"\r\n onDropSlotDragOver(\r\n $event,\r\n groupDropSlotKey(area, item.id, 0),\r\n isGroupDropSlotDisabled(area, item.id, 0)\r\n )\r\n \"\r\n (dragleave)=\"\r\n onDropSlotDragLeave(\r\n $event,\r\n groupDropSlotKey(area, item.id, 0)\r\n )\r\n \"\r\n (onDrop)=\"\r\n onDropToGroup(\r\n $event,\r\n area,\r\n item.id,\r\n 0,\r\n isGroupDropSlotDisabled(area, item.id, 0)\r\n )\r\n \"\r\n ></div>\r\n\r\n @for (\r\n module of item.modules;\r\n track module.id;\r\n let j = $index\r\n ) {\r\n <div\r\n class=\"workspace-draggable-item workspace-group-module-item ms-3 flex cursor-grab items-center gap-3 rounded-lg border border-surface-200 bg-surface-0 px-3 py-2.5 transition-all duration-150 hover:-translate-y-0.5 hover:border-surface-300 hover:shadow-sm active:cursor-grabbing\"\r\n [pDraggable]=\"dropScope\"\r\n (dragover)=\"allowNativeDrop($event)\"\r\n (drop)=\"\r\n onNativeGroupModuleDrop(\r\n $event,\r\n area,\r\n item.id,\r\n j\r\n )\r\n \"\r\n (onDragStart)=\"\r\n onModuleDragStart($event, module, {\r\n type: 'group',\r\n area: area,\r\n groupId: item.id,\r\n })\r\n \"\r\n (onDragEnd)=\"onDragEnd()\"\r\n >\r\n <span\r\n class=\"drag-handle flex size-8 shrink-0 items-center justify-center text-surface-500\"\r\n draggable=\"false\"\r\n >\r\n <mt-icon\r\n class=\"pointer-events-none text-xl text-primary\"\r\n icon=\"general.menu-05\"\r\n />\r\n </span>\r\n <span class=\"min-w-0 flex-1 truncate py-1.5\">{{\r\n module.name\r\n }}</span>\r\n <mt-button\r\n icon=\"general.minus\"\r\n [tooltip]=\"t('remove')\"\r\n severity=\"secondary\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n (onClick)=\"\r\n removeModuleFromGroup(\r\n area,\r\n item.id,\r\n module.id\r\n )\r\n \"\r\n />\r\n </div>\r\n\r\n <div\r\n class=\"drop-slot\"\r\n [class.drop-slot-active]=\"\r\n activeDropSlotKey() ===\r\n groupDropSlotKey(area, item.id, j + 1)\r\n \"\r\n [class.drop-slot-disabled]=\"\r\n isGroupDropSlotDisabled(area, item.id, j + 1)\r\n \"\r\n [pDroppable]=\"dropScope\"\r\n (dragover)=\"\r\n onDropSlotDragOver(\r\n $event,\r\n groupDropSlotKey(area, item.id, j + 1),\r\n isGroupDropSlotDisabled(area, item.id, j + 1)\r\n )\r\n \"\r\n (dragleave)=\"\r\n onDropSlotDragLeave(\r\n $event,\r\n groupDropSlotKey(area, item.id, j + 1)\r\n )\r\n \"\r\n (onDrop)=\"\r\n onDropToGroup(\r\n $event,\r\n area,\r\n item.id,\r\n j + 1,\r\n isGroupDropSlotDisabled(area, item.id, j + 1)\r\n )\r\n \"\r\n ></div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n <div\r\n class=\"drop-slot\"\r\n [class.drop-slot-active]=\"\r\n activeDropSlotKey() === areaDropSlotKey(area, i + 1)\r\n \"\r\n [class.drop-slot-disabled]=\"\r\n isAreaDropSlotDisabled(area, i + 1)\r\n \"\r\n [pDroppable]=\"dropScope\"\r\n (dragover)=\"\r\n onDropSlotDragOver(\r\n $event,\r\n areaDropSlotKey(area, i + 1),\r\n isAreaDropSlotDisabled(area, i + 1)\r\n )\r\n \"\r\n (dragleave)=\"\r\n onDropSlotDragLeave($event, areaDropSlotKey(area, i + 1))\r\n \"\r\n (onDrop)=\"\r\n onDropToArea(\r\n $event,\r\n area,\r\n i + 1,\r\n isAreaDropSlotDisabled(area, i + 1)\r\n )\r\n \"\r\n ></div>\r\n }\r\n\r\n @if (areaItems(area).length === 0) {\r\n <div\r\n class=\"empty-area grid min-h-32 place-items-center rounded-lg border border-dashed border-surface-300 bg-surface-0/80 px-4 py-6 text-center text-sm text-surface-500\"\r\n [pDroppable]=\"dropScope\"\r\n (onDrop)=\"onDropToArea($event, area, 0)\"\r\n >\r\n {{ t(\"empty-area\") }}\r\n </div>\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </ng-template>\r\n\r\n @if (showHeader()) {\r\n <mt-page [title]=\"t('title')\" avatarIcon=\"layout.layout-grid-01\">\r\n <ng-template #headerEnd>\r\n @if (!autoSave()) {\r\n <div class=\"flex items-center\">\r\n <mt-button\r\n [label]=\"t('save')\"\r\n icon=\"general.save-02\"\r\n severity=\"primary\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n [loading]=\"isSavingLayout()\"\r\n [disabled]=\"\r\n isLoadingLayout() ||\r\n !!layoutError() ||\r\n isSavingLayout() ||\r\n validationErrors().length > 0\r\n \"\r\n (onClick)=\"onSaveClick()\"\r\n />\r\n </div>\r\n }\r\n </ng-template>\r\n\r\n <ng-container [ngTemplateOutlet]=\"builderContent\" />\r\n </mt-page>\r\n } @else {\r\n <div class=\"w-full overflow-y-auto p-5\">\r\n @if (!autoSave()) {\r\n <div class=\"mb-4 flex justify-end\">\r\n <mt-button\r\n [label]=\"t('save')\"\r\n icon=\"general.save-02\"\r\n severity=\"primary\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n [loading]=\"isSavingLayout()\"\r\n [disabled]=\"\r\n isLoadingLayout() ||\r\n !!layoutError() ||\r\n isSavingLayout() ||\r\n validationErrors().length > 0\r\n \"\r\n (onClick)=\"onSaveClick()\"\r\n />\r\n </div>\r\n }\r\n\r\n <ng-container [ngTemplateOutlet]=\"builderContent\" />\r\n </div>\r\n }\r\n</ng-container>\r\n", styles: [".workspace-area-body{transition:background-color .18s ease,box-shadow .18s ease}.workspace-area-body.drag-active{cursor:grabbing}.workspace-draggable-item.p-draggable-dragging,.workspace-group-card.p-draggable-dragging{transform:scale(.985);box-shadow:0 12px 30px color-mix(in srgb,var(--p-text-color) 14%,transparent)}.drag-handle,.group-drag-handle{user-select:none;-webkit-user-select:none;touch-action:none;transition:transform .15s ease,border-color .15s ease,background-color .15s ease,color .15s ease}.drag-handle:active,.group-drag-handle:active{transform:scale(.96)}.workspace-area-body.drag-active .drag-handle,.workspace-area-body.drag-active .group-drag-handle{cursor:grabbing}.drop-slot{width:100%;height:.4rem;border:1px solid transparent;border-radius:9999px;background:transparent;opacity:0;transition:height .15s ease,border-color .15s ease,background-color .15s ease,box-shadow .15s ease,transform .15s ease,opacity .15s ease}.workspace-area-body.drag-active .drop-slot{height:.65rem;border-color:var(--p-surface-300);background:color-mix(in srgb,var(--p-surface-100) 55%,transparent);opacity:.28;transform:scaleX(.98)}.workspace-area-body.drag-active .drop-slot.drop-slot-disabled{opacity:0;height:.4rem;pointer-events:none}.empty-area.p-droppable-enter{border-color:var(--p-primary-400);background:var(--p-primary-50)}.drop-slot.p-droppable-enter,.workspace-area-body.drag-active .drop-slot:hover,.workspace-area-body.drag-active .drop-slot.drop-slot-active{height:2.5rem;border-width:1px;border-color:color-mix(in srgb,var(--p-primary-500) 55%,var(--p-surface-300));background:color-mix(in srgb,var(--p-primary-50) 45%,transparent);box-shadow:0 0 0 2px color-mix(in srgb,var(--p-primary-300) 22%,transparent);opacity:1;transform:scaleX(1.01)}\n"] }]
1490
1454
  }], ctorParameters: () => [], propDecorators: { levelId: [{ type: i0.Input, args: [{ isSignal: true, alias: "levelId", required: false }] }], showHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "showHeader", required: false }] }], autoSave: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoSave", required: false }] }] } });
1491
1455
 
1492
1456
  /**