@memberjunction/ng-explorer-settings 6.1.4 → 6.2.0-edge.1

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.
Files changed (77) hide show
  1. package/dist/lib/account-info/account-info.component.d.ts +1 -1
  2. package/dist/lib/account-info/account-info.component.js +2 -2
  3. package/dist/lib/account-info/account-info.component.js.map +1 -1
  4. package/dist/lib/application-management/application-dialog/application-dialog.component.d.ts +93 -10
  5. package/dist/lib/application-management/application-dialog/application-dialog.component.d.ts.map +1 -1
  6. package/dist/lib/application-management/application-dialog/application-dialog.component.js +232 -80
  7. package/dist/lib/application-management/application-dialog/application-dialog.component.js.map +1 -1
  8. package/dist/lib/application-management/application-management.component.d.ts +94 -11
  9. package/dist/lib/application-management/application-management.component.d.ts.map +1 -1
  10. package/dist/lib/application-management/application-management.component.js +231 -67
  11. package/dist/lib/application-management/application-management.component.js.map +1 -1
  12. package/dist/lib/application-settings/application-settings.component.d.ts +4 -4
  13. package/dist/lib/application-settings/application-settings.component.js +10 -10
  14. package/dist/lib/application-settings/application-settings.component.js.map +1 -1
  15. package/dist/lib/entity-permissions/entity-permissions.component.d.ts +88 -10
  16. package/dist/lib/entity-permissions/entity-permissions.component.d.ts.map +1 -1
  17. package/dist/lib/entity-permissions/entity-permissions.component.js +219 -63
  18. package/dist/lib/entity-permissions/entity-permissions.component.js.map +1 -1
  19. package/dist/lib/entity-permissions/permission-dialog/permission-dialog.component.d.ts +44 -6
  20. package/dist/lib/entity-permissions/permission-dialog/permission-dialog.component.d.ts.map +1 -1
  21. package/dist/lib/entity-permissions/permission-dialog/permission-dialog.component.js +117 -43
  22. package/dist/lib/entity-permissions/permission-dialog/permission-dialog.component.js.map +1 -1
  23. package/dist/lib/notification-preferences/notification-preferences.component.d.ts +25 -3
  24. package/dist/lib/notification-preferences/notification-preferences.component.d.ts.map +1 -1
  25. package/dist/lib/notification-preferences/notification-preferences.component.js +62 -18
  26. package/dist/lib/notification-preferences/notification-preferences.component.js.map +1 -1
  27. package/dist/lib/role-management/role-dialog/role-dialog.component.d.ts +32 -4
  28. package/dist/lib/role-management/role-dialog/role-dialog.component.d.ts.map +1 -1
  29. package/dist/lib/role-management/role-dialog/role-dialog.component.js +84 -30
  30. package/dist/lib/role-management/role-dialog/role-dialog.component.js.map +1 -1
  31. package/dist/lib/role-management/role-management-agent-context.d.ts +12 -4
  32. package/dist/lib/role-management/role-management-agent-context.d.ts.map +1 -1
  33. package/dist/lib/role-management/role-management-agent-context.js +26 -10
  34. package/dist/lib/role-management/role-management-agent-context.js.map +1 -1
  35. package/dist/lib/role-management/role-management.component.d.ts +95 -11
  36. package/dist/lib/role-management/role-management.component.d.ts.map +1 -1
  37. package/dist/lib/role-management/role-management.component.js +259 -91
  38. package/dist/lib/role-management/role-management.component.js.map +1 -1
  39. package/dist/lib/settings/settings.component.d.ts +87 -11
  40. package/dist/lib/settings/settings.component.d.ts.map +1 -1
  41. package/dist/lib/settings/settings.component.js +211 -65
  42. package/dist/lib/settings/settings.component.js.map +1 -1
  43. package/dist/lib/shared/settings-card.component.d.ts +24 -4
  44. package/dist/lib/shared/settings-card.component.d.ts.map +1 -1
  45. package/dist/lib/shared/settings-card.component.js +46 -6
  46. package/dist/lib/shared/settings-card.component.js.map +1 -1
  47. package/dist/lib/sql-logging/sql-logging.component.d.ts +172 -18
  48. package/dist/lib/sql-logging/sql-logging.component.d.ts.map +1 -1
  49. package/dist/lib/sql-logging/sql-logging.component.js +320 -108
  50. package/dist/lib/sql-logging/sql-logging.component.js.map +1 -1
  51. package/dist/lib/user-app-config/user-app-config-content.component.js +3 -3
  52. package/dist/lib/user-app-config/user-app-config-content.component.js.map +1 -1
  53. package/dist/lib/user-app-config/user-app-config-reorder.d.ts +4 -0
  54. package/dist/lib/user-app-config/user-app-config-reorder.d.ts.map +1 -1
  55. package/dist/lib/user-app-config/user-app-config-reorder.js +11 -3
  56. package/dist/lib/user-app-config/user-app-config-reorder.js.map +1 -1
  57. package/dist/lib/user-management/transaction-group-refusals.d.ts +45 -0
  58. package/dist/lib/user-management/transaction-group-refusals.d.ts.map +1 -0
  59. package/dist/lib/user-management/transaction-group-refusals.js +49 -0
  60. package/dist/lib/user-management/transaction-group-refusals.js.map +1 -0
  61. package/dist/lib/user-management/user-dialog/user-dialog.component.d.ts +44 -6
  62. package/dist/lib/user-management/user-dialog/user-dialog.component.d.ts.map +1 -1
  63. package/dist/lib/user-management/user-dialog/user-dialog.component.js +134 -45
  64. package/dist/lib/user-management/user-dialog/user-dialog.component.js.map +1 -1
  65. package/dist/lib/user-management/user-management-agent-context.d.ts +10 -0
  66. package/dist/lib/user-management/user-management-agent-context.d.ts.map +1 -1
  67. package/dist/lib/user-management/user-management-agent-context.js +26 -6
  68. package/dist/lib/user-management/user-management-agent-context.js.map +1 -1
  69. package/dist/lib/user-management/user-management.component.d.ts +174 -16
  70. package/dist/lib/user-management/user-management.component.d.ts.map +1 -1
  71. package/dist/lib/user-management/user-management.component.js +501 -177
  72. package/dist/lib/user-management/user-management.component.js.map +1 -1
  73. package/dist/lib/user-profile-settings/user-profile-settings.component.d.ts +97 -15
  74. package/dist/lib/user-profile-settings/user-profile-settings.component.d.ts.map +1 -1
  75. package/dist/lib/user-profile-settings/user-profile-settings.component.js +280 -116
  76. package/dist/lib/user-profile-settings/user-profile-settings.component.js.map +1 -1
  77. package/package.json +20 -20
@@ -94,9 +94,10 @@ function ApplicationDialogComponent_Conditional_0_Conditional_36_For_5_Template(
94
94
  i0.ɵɵelementEnd()()();
95
95
  } if (rf & 2) {
96
96
  const config_r5 = ctx.$implicit;
97
+ const ctx_r1 = i0.ɵɵnextContext(3);
97
98
  i0.ɵɵclassProp("is-new", config_r5.isNew)("has-changes", config_r5.hasChanges);
98
99
  i0.ɵɵadvance(7);
99
- i0.ɵɵtextInterpolate1(" ", config_r5.entity.Name, " ");
100
+ i0.ɵɵtextInterpolate1(" ", ctx_r1.getEntityDisplayName(config_r5.entity), " ");
100
101
  i0.ɵɵadvance();
101
102
  i0.ɵɵconditional(config_r5.entity.Description ? 8 : -1);
102
103
  i0.ɵɵadvance(4);
@@ -107,7 +108,7 @@ function ApplicationDialogComponent_Conditional_0_Conditional_36_For_5_Template(
107
108
  i0.ɵɵadvance();
108
109
  i0.ɵɵtextInterpolate(config_r5.sequence);
109
110
  i0.ɵɵadvance(2);
110
- i0.ɵɵattribute("aria-label", "Remove " + config_r5.entity.Name);
111
+ i0.ɵɵattribute("aria-label", "Remove " + ctx_r1.getEntityDisplayName(config_r5.entity));
111
112
  } }
112
113
  function ApplicationDialogComponent_Conditional_0_Conditional_36_Template(rf, ctx) { if (rf & 1) {
113
114
  const _r3 = i0.ɵɵgetCurrentView();
@@ -153,9 +154,10 @@ function ApplicationDialogComponent_Conditional_0_Conditional_38_Conditional_8_F
153
154
  i0.ɵɵelementEnd()()();
154
155
  } if (rf & 2) {
155
156
  const entity_r9 = ctx.$implicit;
156
- i0.ɵɵattribute("aria-label", "Add " + entity_r9.Name);
157
+ const ctx_r1 = i0.ɵɵnextContext(4);
158
+ i0.ɵɵattribute("aria-label", "Add " + ctx_r1.getEntityDisplayName(entity_r9));
157
159
  i0.ɵɵadvance(4);
158
- i0.ɵɵtextInterpolate(entity_r9.Name);
160
+ i0.ɵɵtextInterpolate(ctx_r1.getEntityDisplayName(entity_r9));
159
161
  } }
160
162
  function ApplicationDialogComponent_Conditional_0_Conditional_38_Conditional_8_Template(rf, ctx) { if (rf & 1) {
161
163
  i0.ɵɵelementStart(0, "div", 66);
@@ -375,33 +377,113 @@ function ApplicationDialogComponent_Conditional_0_Template(rf, ctx) { if (rf & 1
375
377
  i0.ɵɵconditional(ctx_r1.isLoading ? 43 : 44);
376
378
  } }
377
379
  export class ApplicationDialogComponent extends BaseAngularComponent {
378
- data = null;
379
- visible = false;
380
- result = new EventEmitter();
380
+ Data = null;
381
+ /** @deprecated Use {@link Data}. */
382
+ set data(value) {
383
+ this.Data = value;
384
+ }
385
+ /** @deprecated Use {@link Data}. */
386
+ get data() {
387
+ return this.Data;
388
+ }
389
+ Visible = false;
390
+ /** @deprecated Use {@link Visible}. */
391
+ set visible(value) {
392
+ this.Visible = value;
393
+ }
394
+ /** @deprecated Use {@link Visible}. */
395
+ get visible() {
396
+ return this.Visible;
397
+ }
398
+ Result = new EventEmitter();
399
+ /**
400
+ * @deprecated Use {@link Result}.
401
+ *
402
+ * The same emitter under the old binding name, so a template still binding
403
+ * (result) keeps working. Must stay AFTER Result: class fields
404
+ * initialise in order, and the other way round this captures undefined.
405
+ */
406
+ result = this.Result;
381
407
  fb = inject(FormBuilder);
382
408
  cdr = inject(ChangeDetectorRef);
383
409
  ngZone = inject(NgZone);
384
410
  get metadata() { return this.ProviderToUse; }
385
- applicationForm;
411
+ ApplicationForm;
412
+ /** @deprecated Use {@link ApplicationForm}. */
413
+ get applicationForm() {
414
+ return this.ApplicationForm;
415
+ }
416
+ /** @deprecated Use {@link ApplicationForm}. */
417
+ set applicationForm(value) {
418
+ this.ApplicationForm = value;
419
+ }
386
420
  isLoading = false;
387
421
  error = null;
388
422
  // Entity management
389
- applicationEntities = [];
390
- availableEntities = [];
391
- allEntities = [];
423
+ ApplicationEntities = [];
424
+ /** @deprecated Use {@link ApplicationEntities}. */
425
+ get applicationEntities() {
426
+ return this.ApplicationEntities;
427
+ }
428
+ /** @deprecated Use {@link ApplicationEntities}. */
429
+ set applicationEntities(value) {
430
+ this.ApplicationEntities = value;
431
+ }
432
+ AvailableEntities = [];
433
+ /** @deprecated Use {@link AvailableEntities}. */
434
+ get availableEntities() {
435
+ return this.AvailableEntities;
436
+ }
437
+ /** @deprecated Use {@link AvailableEntities}. */
438
+ set availableEntities(value) {
439
+ this.AvailableEntities = value;
440
+ }
441
+ AllEntities = [];
442
+ /** @deprecated Use {@link AllEntities}. */
443
+ get allEntities() {
444
+ return this.AllEntities;
445
+ }
446
+ /** @deprecated Use {@link AllEntities}. */
447
+ set allEntities(value) {
448
+ this.AllEntities = value;
449
+ }
392
450
  // Search filter for available entities
393
- entitySearchTerm = '';
451
+ EntitySearchTerm = '';
452
+ /** @deprecated Use {@link EntitySearchTerm}. */
453
+ get entitySearchTerm() {
454
+ return this.EntitySearchTerm;
455
+ }
456
+ /** @deprecated Use {@link EntitySearchTerm}. */
457
+ set entitySearchTerm(value) {
458
+ this.EntitySearchTerm = value;
459
+ }
394
460
  // Section expansion state
395
- sectionExpanded = {
461
+ SectionExpanded = {
396
462
  basicInfo: true,
397
463
  entities: true,
398
464
  systemInfo: false
399
465
  };
466
+ /** @deprecated Use {@link SectionExpanded}. */
467
+ get sectionExpanded() {
468
+ return this.SectionExpanded;
469
+ }
470
+ /** @deprecated Use {@link SectionExpanded}. */
471
+ set sectionExpanded(value) {
472
+ this.SectionExpanded = value;
473
+ }
400
474
  // Fullscreen state
401
- isFullscreen = false;
475
+ IsFullscreen = false;
476
+ /** @deprecated Use {@link IsFullscreen}. */
477
+ get isFullscreen() {
478
+ return this.IsFullscreen;
479
+ }
480
+ /** @deprecated Use {@link IsFullscreen}. */
481
+ set isFullscreen(value) {
482
+ this.IsFullscreen = value;
483
+ }
402
484
  constructor() {
403
485
  super();
404
- this.applicationForm = this.fb.group({
486
+ this.ApplicationForm = this.fb.group({
405
487
  name: ['', [Validators.required, Validators.maxLength(100)]],
406
488
  description: ['']
407
489
  });
@@ -410,7 +492,7 @@ export class ApplicationDialogComponent extends BaseAngularComponent {
410
492
  // Initial setup
411
493
  }
412
494
  ngOnChanges(changes) {
413
- if (changes['visible'] && this.visible) {
495
+ if (changes['visible'] && this.Visible) {
414
496
  this.initializeDialog();
415
497
  }
416
498
  }
@@ -418,14 +500,14 @@ export class ApplicationDialogComponent extends BaseAngularComponent {
418
500
  // Cleanup if needed
419
501
  }
420
502
  async initializeDialog() {
421
- if (!this.visible)
503
+ if (!this.Visible)
422
504
  return;
423
505
  try {
424
506
  this.isLoading = true;
425
507
  this.error = null;
426
508
  // Load all entities first
427
509
  await this.loadAllEntities();
428
- if (this.data?.application && this.isEditMode) {
510
+ if (this.Data?.application && this.IsEditMode) {
429
511
  await this.loadApplicationData();
430
512
  }
431
513
  else {
@@ -453,34 +535,42 @@ export class ApplicationDialogComponent extends BaseAngularComponent {
453
535
  ResultType: 'entity_object',
454
536
  OrderBy: 'Name ASC'
455
537
  });
456
- this.allEntities = result.Success ? result.Results : [];
538
+ this.AllEntities = result.Success ? result.Results : [];
457
539
  }
458
540
  resetForm() {
459
- this.applicationForm.reset({
541
+ this.ApplicationForm.reset({
460
542
  name: '',
461
543
  description: ''
462
544
  });
463
- this.applicationEntities = [];
464
- this.availableEntities = [...this.allEntities];
465
- this.entitySearchTerm = '';
545
+ this.ApplicationEntities = [];
546
+ this.AvailableEntities = [...this.AllEntities];
547
+ this.EntitySearchTerm = '';
466
548
  this.error = null;
467
549
  }
468
550
  onEscapeKey() {
469
- if (this.visible) {
551
+ if (this.Visible) {
470
552
  this.onCancel();
471
553
  }
472
554
  }
555
+ get WindowTitle() {
556
+ return this.IsEditMode ? 'Edit Application' : 'Create New Application';
557
+ }
558
+ /** @deprecated Use {@link WindowTitle}. */
473
559
  get windowTitle() {
474
- return this.isEditMode ? 'Edit Application' : 'Create New Application';
560
+ return this.WindowTitle;
561
+ }
562
+ get IsEditMode() {
563
+ return this.Data?.mode === 'edit';
475
564
  }
565
+ /** @deprecated Use {@link IsEditMode}. */
476
566
  get isEditMode() {
477
- return this.data?.mode === 'edit';
567
+ return this.IsEditMode;
478
568
  }
479
569
  async loadApplicationData() {
480
- if (!this.data?.application)
570
+ if (!this.Data?.application)
481
571
  return;
482
- const app = this.data.application;
483
- this.applicationForm.patchValue({
572
+ const app = this.Data.application;
573
+ this.ApplicationForm.patchValue({
484
574
  name: app.Name,
485
575
  description: app.Description
486
576
  });
@@ -497,12 +587,12 @@ export class ApplicationDialogComponent extends BaseAngularComponent {
497
587
  OrderBy: 'Sequence ASC'
498
588
  });
499
589
  if (result.Success && result.Results) {
500
- this.applicationEntities = [];
590
+ this.ApplicationEntities = [];
501
591
  const usedEntityIds = new Set();
502
592
  for (const appEntity of result.Results) {
503
- const entity = this.allEntities.find(e => UUIDsEqual(e.ID, appEntity.EntityID));
593
+ const entity = this.AllEntities.find(e => UUIDsEqual(e.ID, appEntity.EntityID));
504
594
  if (entity) {
505
- this.applicationEntities.push({
595
+ this.ApplicationEntities.push({
506
596
  entity,
507
597
  applicationEntity: appEntity,
508
598
  sequence: appEntity.Sequence || 0,
@@ -514,19 +604,19 @@ export class ApplicationDialogComponent extends BaseAngularComponent {
514
604
  }
515
605
  }
516
606
  // Set available entities (excluding already assigned ones)
517
- this.availableEntities = this.allEntities.filter(e => !usedEntityIds.has(e.ID));
607
+ this.AvailableEntities = this.AllEntities.filter(e => !usedEntityIds.has(e.ID));
518
608
  }
519
609
  }
520
610
  catch (error) {
521
611
  console.warn('Failed to load application entities:', error);
522
- this.availableEntities = [...this.allEntities];
612
+ this.AvailableEntities = [...this.AllEntities];
523
613
  }
524
614
  }
525
- addEntity(entity) {
615
+ AddEntity(entity) {
526
616
  // Add entity to application
527
- this.applicationEntities.push({
617
+ this.ApplicationEntities.push({
528
618
  entity,
529
- sequence: this.applicationEntities.length + 1,
619
+ sequence: this.ApplicationEntities.length + 1,
530
620
  defaultForNewUser: false,
531
621
  isNew: true,
532
622
  hasChanges: false
@@ -534,91 +624,143 @@ export class ApplicationDialogComponent extends BaseAngularComponent {
534
624
  // Update all sequences to be consecutive
535
625
  this.updateSequences();
536
626
  // Remove from available entities
537
- this.availableEntities = this.availableEntities.filter(e => !UUIDsEqual(e.ID, entity.ID));
627
+ this.AvailableEntities = this.AvailableEntities.filter(e => !UUIDsEqual(e.ID, entity.ID));
538
628
  }
539
- removeEntity(config) {
629
+ /** @deprecated Use {@link AddEntity}. */
630
+ addEntity(entity) {
631
+ return this.AddEntity(entity);
632
+ }
633
+ RemoveEntity(config) {
540
634
  // Remove from application entities
541
- this.applicationEntities = this.applicationEntities.filter(ae => !UUIDsEqual(ae.entity.ID, config.entity.ID));
635
+ this.ApplicationEntities = this.ApplicationEntities.filter(ae => !UUIDsEqual(ae.entity.ID, config.entity.ID));
542
636
  // Update all sequences to be consecutive
543
637
  this.updateSequences();
544
638
  // Add back to available entities if not already there
545
- if (!this.availableEntities.find(e => UUIDsEqual(e.ID, config.entity.ID))) {
546
- this.availableEntities.push(config.entity);
547
- this.availableEntities.sort((a, b) => (a.Name || '').localeCompare(b.Name || ''));
639
+ if (!this.AvailableEntities.find(e => UUIDsEqual(e.ID, config.entity.ID))) {
640
+ this.AvailableEntities.push(config.entity);
641
+ this.AvailableEntities.sort((a, b) => (a.Name || '').localeCompare(b.Name || ''));
548
642
  }
549
643
  }
550
- moveEntityUp(index) {
644
+ /** @deprecated Use {@link RemoveEntity}. */
645
+ removeEntity(config) {
646
+ return this.RemoveEntity(config);
647
+ }
648
+ MoveEntityUp(index) {
551
649
  if (index > 0) {
552
- const temp = this.applicationEntities[index];
553
- this.applicationEntities[index] = this.applicationEntities[index - 1];
554
- this.applicationEntities[index - 1] = temp;
650
+ const temp = this.ApplicationEntities[index];
651
+ this.ApplicationEntities[index] = this.ApplicationEntities[index - 1];
652
+ this.ApplicationEntities[index - 1] = temp;
555
653
  this.updateSequences();
556
654
  }
557
655
  }
558
- moveEntityDown(index) {
559
- if (index < this.applicationEntities.length - 1) {
560
- const temp = this.applicationEntities[index];
561
- this.applicationEntities[index] = this.applicationEntities[index + 1];
562
- this.applicationEntities[index + 1] = temp;
656
+ /** @deprecated Use {@link MoveEntityUp}. */
657
+ moveEntityUp(index) {
658
+ return this.MoveEntityUp(index);
659
+ }
660
+ MoveEntityDown(index) {
661
+ if (index < this.ApplicationEntities.length - 1) {
662
+ const temp = this.ApplicationEntities[index];
663
+ this.ApplicationEntities[index] = this.ApplicationEntities[index + 1];
664
+ this.ApplicationEntities[index + 1] = temp;
563
665
  this.updateSequences();
564
666
  }
565
667
  }
668
+ /** @deprecated Use {@link MoveEntityDown}. */
669
+ moveEntityDown(index) {
670
+ return this.MoveEntityDown(index);
671
+ }
566
672
  updateSequences() {
567
- this.applicationEntities.forEach((config, index) => {
673
+ this.ApplicationEntities.forEach((config, index) => {
568
674
  config.sequence = index + 1;
569
675
  if (!config.isNew) {
570
676
  config.hasChanges = true;
571
677
  }
572
678
  });
573
679
  }
574
- onDefaultForNewUserChange(config) {
680
+ OnDefaultForNewUserChange(config) {
575
681
  if (!config.isNew) {
576
682
  config.hasChanges = true;
577
683
  }
578
684
  }
685
+ /** @deprecated Use {@link OnDefaultForNewUserChange}. */
686
+ onDefaultForNewUserChange(config) {
687
+ return this.OnDefaultForNewUserChange(config);
688
+ }
689
+ get HasEntityChanges() {
690
+ return this.ApplicationEntities.some(ae => ae.isNew || ae.hasChanges);
691
+ }
692
+ /** @deprecated Use {@link HasEntityChanges}. */
579
693
  get hasEntityChanges() {
580
- return this.applicationEntities.some(ae => ae.isNew || ae.hasChanges);
694
+ return this.HasEntityChanges;
581
695
  }
582
696
  // Filtered available entities based on search term
583
- get filteredAvailableEntities() {
584
- if (!this.entitySearchTerm || !this.entitySearchTerm.trim()) {
585
- return this.availableEntities;
697
+ get FilteredAvailableEntities() {
698
+ if (!this.EntitySearchTerm || !this.EntitySearchTerm.trim()) {
699
+ return this.AvailableEntities;
586
700
  }
587
- const searchLower = this.entitySearchTerm.toLowerCase().trim();
588
- return this.availableEntities.filter(entity => (entity.Name || '').toLowerCase().includes(searchLower) ||
701
+ const searchLower = this.EntitySearchTerm.toLowerCase().trim();
702
+ return this.AvailableEntities.filter(entity => (entity.DisplayName || '').toLowerCase().includes(searchLower) ||
703
+ (entity.Name || '').toLowerCase().includes(searchLower) ||
589
704
  (entity.Description || '').toLowerCase().includes(searchLower));
590
705
  }
591
- onEntitySearchChange(event) {
706
+ /** @deprecated Use {@link FilteredAvailableEntities}. */
707
+ get filteredAvailableEntities() {
708
+ return this.FilteredAvailableEntities;
709
+ }
710
+ GetEntityDisplayName(entity) {
711
+ return entity.DisplayName || entity.Name;
712
+ }
713
+ /** @deprecated Use {@link GetEntityDisplayName}. */
714
+ getEntityDisplayName(entity) {
715
+ return this.GetEntityDisplayName(entity);
716
+ }
717
+ OnEntitySearchChange(event) {
592
718
  const value = event.target.value;
593
- this.entitySearchTerm = value;
719
+ this.EntitySearchTerm = value;
720
+ }
721
+ /** @deprecated Use {@link OnEntitySearchChange}. */
722
+ onEntitySearchChange(event) {
723
+ return this.OnEntitySearchChange(event);
724
+ }
725
+ ClearEntitySearch() {
726
+ this.EntitySearchTerm = '';
594
727
  }
728
+ /** @deprecated Use {@link ClearEntitySearch}. */
595
729
  clearEntitySearch() {
596
- this.entitySearchTerm = '';
730
+ return this.ClearEntitySearch();
597
731
  }
598
732
  toggleSection(section) {
599
- this.sectionExpanded[section] = !this.sectionExpanded[section];
733
+ this.SectionExpanded[section] = !this.SectionExpanded[section];
600
734
  }
735
+ ToggleFullscreen() {
736
+ this.IsFullscreen = !this.IsFullscreen;
737
+ }
738
+ /** @deprecated Use {@link ToggleFullscreen}. */
601
739
  toggleFullscreen() {
602
- this.isFullscreen = !this.isFullscreen;
740
+ return this.ToggleFullscreen();
603
741
  }
604
- onEntityDrop(event) {
742
+ OnEntityDrop(event) {
605
743
  if (event.previousIndex !== event.currentIndex) {
606
- moveItemInArray(this.applicationEntities, event.previousIndex, event.currentIndex);
744
+ moveItemInArray(this.ApplicationEntities, event.previousIndex, event.currentIndex);
607
745
  this.updateSequences();
608
746
  }
609
747
  }
610
- async onSubmit() {
611
- if (this.applicationForm.invalid) {
612
- this.markFormGroupTouched(this.applicationForm);
748
+ /** @deprecated Use {@link OnEntityDrop}. */
749
+ onEntityDrop(event) {
750
+ return this.OnEntityDrop(event);
751
+ }
752
+ async OnSubmit() {
753
+ if (this.ApplicationForm.invalid) {
754
+ this.markFormGroupTouched(this.ApplicationForm);
613
755
  return;
614
756
  }
615
757
  this.isLoading = true;
616
758
  this.error = null;
617
759
  try {
618
760
  let application;
619
- if (this.isEditMode && this.data?.application) {
761
+ if (this.IsEditMode && this.Data?.application) {
620
762
  // Edit existing application
621
- application = this.data.application;
763
+ application = this.Data.application;
622
764
  }
623
765
  else {
624
766
  // Create new application
@@ -626,7 +768,7 @@ export class ApplicationDialogComponent extends BaseAngularComponent {
626
768
  application.NewRecord();
627
769
  }
628
770
  // Update application properties
629
- const formValue = this.applicationForm.value;
771
+ const formValue = this.ApplicationForm.value;
630
772
  application.Name = formValue.name;
631
773
  application.Description = formValue.description || null;
632
774
  // Save application
@@ -635,10 +777,10 @@ export class ApplicationDialogComponent extends BaseAngularComponent {
635
777
  throw new Error(application.LatestResult?.Message || 'Failed to save application');
636
778
  }
637
779
  // Save application entities if there are changes
638
- if (this.hasEntityChanges) {
780
+ if (this.HasEntityChanges) {
639
781
  await this.saveApplicationEntities(application.ID);
640
782
  }
641
- this.result.emit({ action: 'save', application });
783
+ this.Result.emit({ action: 'save', application });
642
784
  }
643
785
  catch (error) {
644
786
  console.error('Error saving application:', error);
@@ -654,9 +796,13 @@ export class ApplicationDialogComponent extends BaseAngularComponent {
654
796
  });
655
797
  }
656
798
  }
799
+ /** @deprecated Use {@link OnSubmit}. */
800
+ async onSubmit() {
801
+ return this.OnSubmit();
802
+ }
657
803
  async saveApplicationEntities(applicationId) {
658
804
  // Save or update each MJApplicationEntity record
659
- for (const config of this.applicationEntities) {
805
+ for (const config of this.ApplicationEntities) {
660
806
  if (config.isNew || config.hasChanges) {
661
807
  let appEntity;
662
808
  if (config.isNew) {
@@ -683,7 +829,7 @@ export class ApplicationDialogComponent extends BaseAngularComponent {
683
829
  }
684
830
  }
685
831
  onCancel() {
686
- this.result.emit({ action: 'cancel' });
832
+ this.Result.emit({ action: 'cancel' });
687
833
  }
688
834
  markFormGroupTouched(formGroup) {
689
835
  Object.keys(formGroup.controls).forEach(key => {
@@ -694,7 +840,7 @@ export class ApplicationDialogComponent extends BaseAngularComponent {
694
840
  static ɵfac = function ApplicationDialogComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ApplicationDialogComponent)(); };
695
841
  static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ApplicationDialogComponent, selectors: [["mj-application-dialog"]], hostBindings: function ApplicationDialogComponent_HostBindings(rf, ctx) { if (rf & 1) {
696
842
  i0.ɵɵlistener("keydown.escape", function ApplicationDialogComponent_keydown_escape_HostBindingHandler() { return ctx.onEscapeKey(); }, i0.ɵɵresolveDocument);
697
- } }, inputs: { data: "data", visible: "visible" }, outputs: { result: "result" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 1, vars: 1, consts: [["role", "presentation", 1, "modal-backdrop"], ["role", "presentation", 1, "modal-backdrop", 3, "click"], ["role", "dialog", "aria-modal", "true", "aria-labelledby", "application-dialog-title", "aria-describedby", "application-dialog-description", 1, "modal-dialog", 3, "click"], [1, "modal-header"], [1, "modal-header-content"], ["id", "application-dialog-title", 1, "modal-title"], ["aria-hidden", "true", 1, "fa-solid"], ["id", "application-dialog-description", 1, "modal-subtitle"], [1, "modal-header-actions"], ["type", "button", 1, "modal-action-btn", 3, "click"], ["aria-label", "Close dialog", "type", "button", 1, "modal-close", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-times"], [1, "modal-body"], [3, "ngSubmit", "formGroup"], [1, "form-section"], [1, "app-dialog-section", 3, "ExpandedChange", "Expanded"], ["mjAccordionTitle", ""], [1, "section-content"], [1, "form-grid"], [1, "form-field"], ["for", "app-name", 1, "field-label", "required"], ["id", "app-name", "type", "text", "formControlName", "name", "placeholder", "My Application", "aria-describedby", "app-name-error", 1, "field-input"], ["id", "app-name-error", "role", "alert", 1, "field-error"], ["for", "app-description", 1, "field-label"], ["id", "app-description", "formControlName", "description", "placeholder", "Describe the application's purpose and functionality...", "rows", "4", 1, "field-textarea"], [1, "field-hint"], [1, "assigned-entities"], [1, "no-entities"], [1, "available-entities"], [1, "all-assigned"], [1, "app-dialog-section", 3, "Expanded"], [1, "modal-footer"], ["type", "submit", "mjButton", "", "variant", "primary", 3, "click", "disabled"], ["type", "button", "mjButton", "", 3, "click"], ["Variant", "error", 3, "Message"], [1, "app-dialog-section-title"], [1, "section-title"], ["aria-hidden", "true", 1, "fa-solid", "fa-info-circle"], [1, "section-description"], ["aria-hidden", "true", 1, "fa-solid", "fa-exclamation-circle"], ["aria-hidden", "true", 1, "fa-solid", "fa-database"], [1, "subsection-title"], ["role", "list", "cdkDropList", "", 1, "entities-list", 3, "cdkDropListDropped"], ["role", "listitem", "cdkDrag", "", 1, "entity-item", 3, "is-new", "has-changes"], ["role", "listitem", "cdkDrag", "", 1, "entity-item"], ["aria-hidden", "true", 1, "fa-solid", "fa-grip-vertical", "drag-handle"], [1, "entity-info"], [1, "entity-icon"], ["aria-hidden", "true", 1, "fa-solid", "fa-table"], [1, "entity-details"], [1, "entity-name"], [1, "fa-solid", "fa-info-circle", "entity-info-icon", 3, "title"], [1, "entity-config"], [1, "config-item"], [1, "config-label"], ["type", "checkbox", 1, "config-checkbox", 3, "ngModelChange", "change", "ngModel", "ngModelOptions"], [1, "checkbox-text"], [1, "sequence-badge"], [1, "entity-actions"], ["type", "button", "title", "Remove entity", 1, "btn-icon", "btn-danger", 3, "click"], [1, "empty-subtext"], [1, "available-entities-header"], [1, "entity-search"], ["aria-hidden", "true", 1, "fa-solid", "fa-search", "entity-search-icon"], ["type", "text", "placeholder", "Search entities...", "aria-label", "Search available entities", 1, "entity-search-input", 3, "input", "value"], ["type", "button", "aria-label", "Clear search", 1, "entity-search-clear"], ["role", "list", 1, "entities-grid"], [1, "no-search-results"], ["type", "button", "aria-label", "Clear search", 1, "entity-search-clear", 3, "click"], ["type", "button", "role", "listitem", 1, "entity-chip"], ["type", "button", "role", "listitem", 1, "entity-chip", 3, "click"], [1, "chip-content"], ["aria-hidden", "true", 1, "fa-solid", "fa-plus"], [1, "chip-name"], ["aria-hidden", "true", 1, "fa-solid", "fa-search"], ["aria-hidden", "true", 1, "fa-solid", "fa-check-circle"], [1, "info-grid"], [1, "info-item"], [1, "info-label"], [1, "info-value"], ["aria-hidden", "true", 1, "fa-solid", "fa-spinner", "fa-spin"], ["aria-hidden", "true", 1, "fa-solid", "fa-save"]], template: function ApplicationDialogComponent_Template(rf, ctx) { if (rf & 1) {
843
+ } }, inputs: { Data: "Data", data: "data", Visible: "Visible", visible: "visible" }, outputs: { Result: "Result", result: "result" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 1, vars: 1, consts: [["role", "presentation", 1, "modal-backdrop"], ["role", "presentation", 1, "modal-backdrop", 3, "click"], ["role", "dialog", "aria-modal", "true", "aria-labelledby", "application-dialog-title", "aria-describedby", "application-dialog-description", 1, "modal-dialog", 3, "click"], [1, "modal-header"], [1, "modal-header-content"], ["id", "application-dialog-title", 1, "modal-title"], ["aria-hidden", "true", 1, "fa-solid"], ["id", "application-dialog-description", 1, "modal-subtitle"], [1, "modal-header-actions"], ["type", "button", 1, "modal-action-btn", 3, "click"], ["aria-label", "Close dialog", "type", "button", 1, "modal-close", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-times"], [1, "modal-body"], [3, "ngSubmit", "formGroup"], [1, "form-section"], [1, "app-dialog-section", 3, "ExpandedChange", "Expanded"], ["mjAccordionTitle", ""], [1, "section-content"], [1, "form-grid"], [1, "form-field"], ["for", "app-name", 1, "field-label", "required"], ["id", "app-name", "type", "text", "formControlName", "name", "placeholder", "My Application", "aria-describedby", "app-name-error", 1, "field-input"], ["id", "app-name-error", "role", "alert", 1, "field-error"], ["for", "app-description", 1, "field-label"], ["id", "app-description", "formControlName", "description", "placeholder", "Describe the application's purpose and functionality...", "rows", "4", 1, "field-textarea"], [1, "field-hint"], [1, "assigned-entities"], [1, "no-entities"], [1, "available-entities"], [1, "all-assigned"], [1, "app-dialog-section", 3, "Expanded"], [1, "modal-footer"], ["type", "submit", "mjButton", "", "variant", "primary", 3, "click", "disabled"], ["type", "button", "mjButton", "", 3, "click"], ["Variant", "error", 3, "Message"], [1, "app-dialog-section-title"], [1, "section-title"], ["aria-hidden", "true", 1, "fa-solid", "fa-info-circle"], [1, "section-description"], ["aria-hidden", "true", 1, "fa-solid", "fa-exclamation-circle"], ["aria-hidden", "true", 1, "fa-solid", "fa-database"], [1, "subsection-title"], ["role", "list", "cdkDropList", "", 1, "entities-list", 3, "cdkDropListDropped"], ["role", "listitem", "cdkDrag", "", 1, "entity-item", 3, "is-new", "has-changes"], ["role", "listitem", "cdkDrag", "", 1, "entity-item"], ["aria-hidden", "true", 1, "fa-solid", "fa-grip-vertical", "drag-handle"], [1, "entity-info"], [1, "entity-icon"], ["aria-hidden", "true", 1, "fa-solid", "fa-table"], [1, "entity-details"], [1, "entity-name"], [1, "fa-solid", "fa-info-circle", "entity-info-icon", 3, "title"], [1, "entity-config"], [1, "config-item"], [1, "config-label"], ["type", "checkbox", 1, "config-checkbox", 3, "ngModelChange", "change", "ngModel", "ngModelOptions"], [1, "checkbox-text"], [1, "sequence-badge"], [1, "entity-actions"], ["type", "button", "title", "Remove entity", 1, "btn-icon", "btn-danger", 3, "click"], [1, "empty-subtext"], [1, "available-entities-header"], [1, "entity-search"], ["aria-hidden", "true", 1, "fa-solid", "fa-search", "entity-search-icon"], ["type", "text", "placeholder", "Search entities...", "aria-label", "Search available entities", 1, "entity-search-input", 3, "input", "value"], ["type", "button", "aria-label", "Clear search", 1, "entity-search-clear"], ["role", "list", 1, "entities-grid"], [1, "no-search-results"], ["type", "button", "aria-label", "Clear search", 1, "entity-search-clear", 3, "click"], ["type", "button", "role", "listitem", 1, "entity-chip"], ["type", "button", "role", "listitem", 1, "entity-chip", 3, "click"], [1, "chip-content"], ["aria-hidden", "true", 1, "fa-solid", "fa-plus"], [1, "chip-name"], ["aria-hidden", "true", 1, "fa-solid", "fa-search"], ["aria-hidden", "true", 1, "fa-solid", "fa-check-circle"], [1, "info-grid"], [1, "info-item"], [1, "info-label"], [1, "info-value"], ["aria-hidden", "true", 1, "fa-solid", "fa-spinner", "fa-spin"], ["aria-hidden", "true", 1, "fa-solid", "fa-save"]], template: function ApplicationDialogComponent_Template(rf, ctx) { if (rf & 1) {
698
844
  i0.ɵɵconditionalCreate(0, ApplicationDialogComponent_Conditional_0_Template, 47, 31, "div", 0);
699
845
  } if (rf & 2) {
700
846
  i0.ɵɵconditional(ctx.visible ? 0 : -1);
@@ -702,11 +848,17 @@ export class ApplicationDialogComponent extends BaseAngularComponent {
702
848
  }
703
849
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ApplicationDialogComponent, [{
704
850
  type: Component,
705
- args: [{ standalone: false, selector: 'mj-application-dialog', template: "@if (visible) {\n <div class=\"modal-backdrop\" (click)=\"onCancel()\" role=\"presentation\">\n <div\n class=\"modal-dialog\"\n [class.fullscreen]=\"isFullscreen\"\n (click)=\"$event.stopPropagation()\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"application-dialog-title\"\n aria-describedby=\"application-dialog-description\"\n >\n <!-- Modal Header -->\n <div class=\"modal-header\" [class.create-mode]=\"!isEditMode\" [class.edit-mode]=\"isEditMode\">\n <div class=\"modal-header-content\">\n <h2 class=\"modal-title\" id=\"application-dialog-title\">\n <i class=\"fa-solid\" [class.fa-plus]=\"!isEditMode\" [class.fa-layer-group]=\"isEditMode\" aria-hidden=\"true\"></i>\n {{ isEditMode ? 'Edit Application' : 'Create New Application' }}\n </h2>\n <p class=\"modal-subtitle\" id=\"application-dialog-description\">\n {{ isEditMode ? 'Update application information and settings' : 'Add a new application to the system' }}\n </p>\n </div>\n <div class=\"modal-header-actions\">\n <button\n class=\"modal-action-btn\"\n (click)=\"toggleFullscreen()\"\n [attr.aria-label]=\"isFullscreen ? 'Exit fullscreen' : 'Enter fullscreen'\"\n type=\"button\"\n >\n <i class=\"fa-solid\" [class.fa-compress]=\"isFullscreen\" [class.fa-expand]=\"!isFullscreen\" aria-hidden=\"true\"></i>\n </button>\n <button\n class=\"modal-close\"\n (click)=\"onCancel()\"\n aria-label=\"Close dialog\"\n type=\"button\"\n >\n <i class=\"fa-solid fa-times\" aria-hidden=\"true\"></i>\n </button>\n </div>\n </div>\n\n <!-- Modal Body -->\n <div class=\"modal-body\">\n <form [formGroup]=\"applicationForm\" (ngSubmit)=\"onSubmit()\">\n <!-- Error Alert -->\n @if (error) {\n <div class=\"form-section\">\n <mj-alert Variant=\"error\" [Message]=\"error\" />\n </div>\n }\n\n <!-- Basic Information Section -->\n <mj-accordion-panel class=\"app-dialog-section\" [Expanded]=\"sectionExpanded.basicInfo\" (ExpandedChange)=\"toggleSection('basicInfo')\">\n <ng-template mjAccordionTitle>\n <span class=\"app-dialog-section-title\">\n <span class=\"section-title\">\n <i class=\"fa-solid fa-info-circle\" aria-hidden=\"true\"></i>\n Application Information\n </span>\n <span class=\"section-description\">Define the application's basic properties</span>\n </span>\n </ng-template>\n\n <div class=\"section-content\">\n <div class=\"form-grid\">\n <div class=\"form-field\">\n <label class=\"field-label required\" for=\"app-name\">Application Name</label>\n <input\n id=\"app-name\"\n type=\"text\"\n class=\"field-input\"\n formControlName=\"name\"\n placeholder=\"My Application\"\n [class.error]=\"applicationForm.get('name')?.invalid && applicationForm.get('name')?.touched\"\n [attr.aria-invalid]=\"applicationForm.get('name')?.invalid && applicationForm.get('name')?.touched\"\n aria-describedby=\"app-name-error\"\n />\n @if (applicationForm.get('name')?.invalid && applicationForm.get('name')?.touched) {\n <div class=\"field-error\" id=\"app-name-error\" role=\"alert\">\n <i class=\"fa-solid fa-exclamation-circle\" aria-hidden=\"true\"></i>\n @if (applicationForm.get('name')?.errors?.['required']) {\n Application name is required\n }\n @if (applicationForm.get('name')?.errors?.['maxlength']) {\n Application name cannot exceed 100 characters\n }\n </div>\n }\n </div>\n\n <div class=\"form-field\">\n <label class=\"field-label\" for=\"app-description\">Description</label>\n <textarea\n id=\"app-description\"\n class=\"field-textarea\"\n formControlName=\"description\"\n placeholder=\"Describe the application's purpose and functionality...\"\n rows=\"4\"\n ></textarea>\n <div class=\"field-hint\">\n Provide a clear description of what this application does and its main features.\n </div>\n </div>\n </div>\n </div>\n </mj-accordion-panel>\n\n <!-- Entity Management Section -->\n <mj-accordion-panel class=\"app-dialog-section\" [Expanded]=\"sectionExpanded.entities\" (ExpandedChange)=\"toggleSection('entities')\">\n <ng-template mjAccordionTitle>\n <span class=\"app-dialog-section-title\">\n <span class=\"section-title\">\n <i class=\"fa-solid fa-database\" aria-hidden=\"true\"></i>\n Application Entities\n </span>\n <span class=\"section-description\">Manage which entities are included in this application</span>\n </span>\n </ng-template>\n\n <div class=\"section-content\">\n <div class=\"form-grid\">\n <!-- Assigned Entities -->\n @if (applicationEntities.length > 0) {\n <div class=\"assigned-entities\">\n <h4 class=\"subsection-title\">Assigned Entities ({{ applicationEntities.length }})</h4>\n <div class=\"entities-list\"\n role=\"list\"\n cdkDropList\n (cdkDropListDropped)=\"onEntityDrop($event)\">\n @for (config of applicationEntities; track config.entity.ID; let i = $index) {\n <div\n class=\"entity-item\"\n [class.is-new]=\"config.isNew\"\n [class.has-changes]=\"config.hasChanges\"\n role=\"listitem\"\n cdkDrag\n >\n <i class=\"fa-solid fa-grip-vertical drag-handle\" aria-hidden=\"true\"></i>\n <div class=\"entity-info\">\n <div class=\"entity-icon\">\n <i class=\"fa-solid fa-table\" aria-hidden=\"true\"></i>\n </div>\n <div class=\"entity-details\">\n <div class=\"entity-name\">\n {{ config.entity.Name }}\n @if (config.entity.Description) {\n <i\n class=\"fa-solid fa-info-circle entity-info-icon\"\n [title]=\"config.entity.Description\"\n [attr.aria-label]=\"'Entity description: ' + config.entity.Description\"\n ></i>\n }\n </div>\n </div>\n </div>\n\n <div class=\"entity-config\">\n <div class=\"config-item\">\n <label class=\"config-label\">\n <input\n type=\"checkbox\"\n [(ngModel)]=\"config.defaultForNewUser\"\n [ngModelOptions]=\"{standalone: true}\"\n (change)=\"onDefaultForNewUserChange(config)\"\n class=\"config-checkbox\"\n />\n <span class=\"checkbox-text\">Default for new users</span>\n </label>\n </div>\n <div class=\"sequence-badge\" [attr.aria-label]=\"'Sequence ' + config.sequence\">{{ config.sequence }}</div>\n </div>\n\n <div class=\"entity-actions\">\n <button\n type=\"button\"\n class=\"btn-icon btn-danger\"\n (click)=\"removeEntity(config)\"\n title=\"Remove entity\"\n [attr.aria-label]=\"'Remove ' + config.entity.Name\"\n >\n <i class=\"fa-solid fa-times\" aria-hidden=\"true\"></i>\n </button>\n </div>\n </div>\n }\n </div>\n </div>\n } @else {\n <div class=\"no-entities\">\n <i class=\"fa-solid fa-database\" aria-hidden=\"true\"></i>\n <p>No entities assigned to this application</p>\n <p class=\"empty-subtext\">Add entities from the available list below</p>\n </div>\n }\n\n <!-- Available Entities -->\n @if (availableEntities.length > 0) {\n <div class=\"available-entities\">\n <div class=\"available-entities-header\">\n <h4 class=\"subsection-title\">Available Entities ({{ filteredAvailableEntities.length }} of {{ availableEntities.length }})</h4>\n <div class=\"entity-search\">\n <i class=\"fa-solid fa-search entity-search-icon\" aria-hidden=\"true\"></i>\n <input\n type=\"text\"\n class=\"entity-search-input\"\n placeholder=\"Search entities...\"\n [value]=\"entitySearchTerm\"\n (input)=\"onEntitySearchChange($event)\"\n aria-label=\"Search available entities\"\n />\n @if (entitySearchTerm) {\n <button\n type=\"button\"\n class=\"entity-search-clear\"\n (click)=\"clearEntitySearch()\"\n aria-label=\"Clear search\"\n >\n <i class=\"fa-solid fa-times\" aria-hidden=\"true\"></i>\n </button>\n }\n </div>\n </div>\n @if (filteredAvailableEntities.length > 0) {\n <div class=\"entities-grid\" role=\"list\">\n @for (entity of filteredAvailableEntities; track entity.ID) {\n <button\n type=\"button\"\n class=\"entity-chip\"\n (click)=\"addEntity(entity)\"\n role=\"listitem\"\n [attr.aria-label]=\"'Add ' + entity.Name\"\n >\n <div class=\"chip-content\">\n <i class=\"fa-solid fa-plus\" aria-hidden=\"true\"></i>\n <span class=\"chip-name\">{{ entity.Name }}</span>\n </div>\n </button>\n }\n </div>\n } @else {\n <div class=\"no-search-results\">\n <i class=\"fa-solid fa-search\" aria-hidden=\"true\"></i>\n <p>No entities match \"{{ entitySearchTerm }}\"</p>\n </div>\n }\n </div>\n } @else {\n <div class=\"all-assigned\">\n <i class=\"fa-solid fa-check-circle\" aria-hidden=\"true\"></i>\n <p>All entities have been assigned to this application</p>\n </div>\n }\n </div>\n </div>\n </mj-accordion-panel>\n\n <!-- System Information Section (Edit Mode Only) -->\n @if (isEditMode) {\n <mj-accordion-panel class=\"app-dialog-section\" [Expanded]=\"sectionExpanded.systemInfo\" (ExpandedChange)=\"toggleSection('systemInfo')\">\n <ng-template mjAccordionTitle>\n <span class=\"app-dialog-section-title\">\n <span class=\"section-title\">\n <i class=\"fa-solid fa-info-circle\" aria-hidden=\"true\"></i>\n System Information\n </span>\n <span class=\"section-description\">Application metadata and audit information</span>\n </span>\n </ng-template>\n\n <div class=\"section-content\">\n <div class=\"form-grid\">\n <div class=\"info-grid\">\n <div class=\"info-item\">\n <span class=\"info-label\">Created</span>\n <span class=\"info-value\">{{ data?.application?.__mj_CreatedAt | date:'medium' }}</span>\n </div>\n <div class=\"info-item\">\n <span class=\"info-label\">Last Updated</span>\n <span class=\"info-value\">{{ data?.application?.__mj_UpdatedAt | date:'medium' }}</span>\n </div>\n <div class=\"info-item\">\n <span class=\"info-label\">Application ID</span>\n <span class=\"info-value\">{{ data?.application?.ID }}</span>\n </div>\n <div class=\"info-item\">\n <span class=\"info-label\">Total Entities</span>\n <span class=\"info-value\">{{ applicationEntities.length }}</span>\n </div>\n </div>\n </div>\n </div>\n </mj-accordion-panel>\n }\n </form>\n </div>\n\n <!-- Modal Footer - Primary and Cancel buttons on RIGHT -->\n <div class=\"modal-footer\">\n <button\n type=\"submit\"\n mjButton variant=\"primary\"\n [disabled]=\"applicationForm.invalid || isLoading\"\n (click)=\"onSubmit()\"\n [attr.aria-busy]=\"isLoading\"\n >\n @if (isLoading) {\n <i class=\"fa-solid fa-spinner fa-spin\" aria-hidden=\"true\"></i>\n Saving...\n } @else {\n <i class=\"fa-solid fa-save\" aria-hidden=\"true\"></i>\n {{ isEditMode ? 'Update Application' : 'Create Application' }}\n }\n </button>\n <button type=\"button\" mjButton (click)=\"onCancel()\">\n Cancel\n </button>\n </div>\n </div>\n </div>\n}\n", styles: ["/* =============================================================================\n Application Dialog Component\n Uses MJ Design Tokens (--mj-*)\n ============================================================================= */\n\n/* -----------------------------------------------------------------------------\n Modal Backdrop & Container\n ----------------------------------------------------------------------------- */\n.modal-backdrop {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.4);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n animation: fadeIn 0.2s cubic-bezier(0, 0, 0.2, 1);\n padding: 1rem;\n}\n\n.modal-dialog {\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-2xl);\n box-shadow: var(--mj-shadow-2xl);\n max-width: 900px;\n width: 100%;\n max-height: 90vh;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n animation: slideUp 0.3s cubic-bezier(0, 0, 0.2, 1);\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n/* Fullscreen mode */\n.modal-dialog.fullscreen {\n max-width: 100vw;\n width: 100vw;\n max-height: 100vh;\n height: 100vh;\n border-radius: 0;\n margin: 0;\n}\n\n/* -----------------------------------------------------------------------------\n Modal Header\n ----------------------------------------------------------------------------- */\n.modal-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n padding: 1.5rem 1.5rem 1rem 1.5rem;\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n flex-shrink: 0;\n}\n\n.modal-header-content {\n flex: 1;\n min-width: 0;\n}\n\n.modal-header .modal-title {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 1.375rem;\n font-weight: 600;\n color: var(--mj-brand-on-primary);\n margin: 0;\n}\n\n.modal-header .modal-title i {\n width: 40px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: rgba(255, 255, 255, 0.2);\n border-radius: var(--mj-radius-lg);\n font-size: 1.125rem;\n flex-shrink: 0;\n}\n\n/* Create mode - Plus icon with inverted styling */\n.modal-header.create-mode .modal-title i {\n background: var(--mj-brand-on-primary);\n color: var(--mj-brand-primary);\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n}\n\n/* Edit mode - Grid icon with semi-transparent background */\n.modal-header.edit-mode .modal-title i {\n background: rgba(255, 255, 255, 0.2);\n color: var(--mj-brand-on-primary);\n}\n\n/* Modal Header Actions */\n.modal-header-actions {\n display: flex;\n gap: 0.5rem;\n align-items: center;\n flex-shrink: 0;\n margin-left: 0.5rem;\n}\n\n.modal-action-btn {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-brand-on-primary);\n font-size: 1.125rem;\n cursor: pointer;\n border-radius: var(--mj-radius-full);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.modal-action-btn:hover {\n background: rgba(255, 255, 255, 0.15);\n}\n\n.modal-action-btn:focus-visible {\n outline: 2px solid var(--mj-brand-on-primary);\n outline-offset: 2px;\n}\n\n.modal-header .modal-subtitle {\n margin: 0.375rem 0 0 0;\n font-size: 0.8125rem;\n color: var(--mj-brand-on-primary);\n opacity: 0.85;\n}\n\n.modal-header .modal-close {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-brand-on-primary);\n font-size: 1.25rem;\n cursor: pointer;\n border-radius: var(--mj-radius-full);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n margin-left: 0.5rem;\n}\n\n.modal-header .modal-close:hover {\n background: rgba(255, 255, 255, 0.15);\n}\n\n.modal-header .modal-close:focus-visible {\n outline: 2px solid var(--mj-brand-on-primary);\n outline-offset: 2px;\n}\n\n/* -----------------------------------------------------------------------------\n Modal Body\n ----------------------------------------------------------------------------- */\n.modal-body {\n flex: 1;\n overflow-y: auto;\n -webkit-overflow-scrolling: touch;\n padding: 0;\n background: var(--mj-bg-page);\n}\n\n/* -----------------------------------------------------------------------------\n Modal Footer - Primary and Cancel buttons on RIGHT\n ----------------------------------------------------------------------------- */\n.modal-footer {\n display: flex;\n justify-content: flex-end;\n gap: 0.75rem;\n padding: 1.25rem 1.5rem;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n flex-shrink: 0;\n}\n\n/* -----------------------------------------------------------------------------\n Form Sections (Fieldset)\n ----------------------------------------------------------------------------- */\n.form-section {\n border: none;\n margin: 0;\n padding: 1.5rem;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.form-section:last-of-type {\n border-bottom: none;\n}\n\n/* -----------------------------------------------------------------------------\n Collapsible Sections \u2014 now <mj-accordion-panel>. The bespoke fieldset/legend\n chrome (.section-header / .section-title-row / .chevron-icon) was removed; the\n title (icon + title + description) is projected into the accordion title slot.\n ----------------------------------------------------------------------------- */\n.app-dialog-section-title {\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n min-width: 0;\n}\n\n.app-dialog-section-title .section-title {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n font-size: 1.0625rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.app-dialog-section-title .section-title i {\n color: var(--mj-brand-primary);\n font-size: 0.875rem;\n}\n\n.app-dialog-section-title .section-description {\n font-size: 0.8125rem;\n color: var(--mj-text-secondary);\n font-weight: normal;\n}\n\n.section-content {\n animation: expandSection 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n@keyframes expandSection {\n from {\n opacity: 0;\n transform: translateY(-8px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n/* -----------------------------------------------------------------------------\n Form Grid Layout\n ----------------------------------------------------------------------------- */\n.form-grid {\n display: grid;\n gap: 1.25rem;\n}\n\n.form-row {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 1.25rem;\n}\n\n/* -----------------------------------------------------------------------------\n Form Fields\n ----------------------------------------------------------------------------- */\n.form-field {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.form-field .field-label {\n font-size: 0.8125rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.form-field .field-label.required::after {\n content: ' *';\n color: var(--mj-status-error);\n}\n\n.form-field .field-input,\n.form-field .field-select,\n.form-field .field-textarea {\n width: 100%;\n min-height: 44px;\n padding: 0.75rem 1rem;\n border: 1px solid var(--mj-border-strong);\n border-radius: var(--mj-radius-md);\n font-size: 0.9375rem;\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n transition: border-color 0.2s ease, box-shadow 0.2s ease;\n}\n\n.form-field .field-input:focus,\n.form-field .field-select:focus,\n.form-field .field-textarea:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n}\n\n.form-field .field-input.error,\n.form-field .field-select.error,\n.form-field .field-textarea.error {\n border-color: var(--mj-status-error);\n}\n\n.form-field .field-input.error:focus,\n.form-field .field-select.error:focus,\n.form-field .field-textarea.error:focus {\n border-color: var(--mj-status-error);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-error) 12%, transparent);\n}\n\n.form-field .field-input::placeholder,\n.form-field .field-textarea::placeholder {\n color: var(--mj-text-secondary);\n}\n\n.form-field .field-textarea {\n min-height: 100px;\n resize: vertical;\n line-height: 1.5;\n}\n\n.form-field .field-error {\n margin-top: 0.25rem;\n font-size: 0.8125rem;\n color: var(--mj-status-error);\n display: flex;\n align-items: center;\n gap: 0.25rem;\n}\n\n.form-field .field-error i {\n font-size: 0.625rem;\n}\n\n.form-field .field-hint {\n font-size: 0.8125rem;\n color: var(--mj-text-secondary);\n line-height: 1.4;\n}\n\n/* -----------------------------------------------------------------------------\n Entity Management Styles\n ----------------------------------------------------------------------------- */\n.subsection-title {\n font-size: 0.9375rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 1rem 0;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n\n.assigned-entities {\n margin-bottom: 1.5rem;\n}\n\n.assigned-entities .entities-list {\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n overflow: hidden;\n background: var(--mj-bg-page);\n}\n\n.entity-item {\n display: flex;\n align-items: center;\n padding: 1rem 1.25rem;\n border-bottom: 1px solid var(--mj-bg-surface);\n transition: all 0.15s ease;\n}\n\n.entity-item:last-child {\n border-bottom: none;\n}\n\n.entity-item:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.entity-item.is-new {\n background: color-mix(in srgb, var(--mj-status-success) 8%, transparent);\n border-left: 3px solid var(--mj-status-success);\n}\n\n.entity-item.has-changes {\n background: color-mix(in srgb, var(--mj-status-warning) 8%, transparent);\n border-left: 3px solid var(--mj-status-warning);\n}\n\n.entity-item .entity-info {\n display: flex;\n align-items: center;\n gap: 1rem;\n flex: 1;\n min-width: 0;\n}\n\n.entity-item .entity-info .entity-icon {\n width: 40px;\n height: 40px;\n background: var(--mj-brand-accent-subtle);\n border-radius: var(--mj-radius-md);\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-brand-primary);\n flex-shrink: 0;\n}\n\n.entity-item .entity-info .entity-details {\n flex: 1;\n min-width: 0;\n}\n\n.entity-item .entity-info .entity-details .entity-name {\n font-size: 0.9375rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-bottom: 0.125rem;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n\n.entity-item .entity-info .entity-details .entity-name .entity-info-icon {\n color: var(--mj-status-warning);\n font-size: 0.875rem;\n cursor: help;\n opacity: 0.7;\n transition: all 0.15s ease;\n}\n\n.entity-item .entity-info .entity-details .entity-name .entity-info-icon:hover {\n opacity: 1;\n transform: scale(1.1);\n}\n\n.entity-item .entity-config {\n display: flex;\n align-items: center;\n gap: 1.5rem;\n margin: 0 1.5rem;\n}\n\n.entity-item .entity-config .config-item .config-label {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n cursor: pointer;\n font-size: 0.8125rem;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n.entity-item .entity-config .config-item .config-label .config-checkbox {\n width: 18px;\n height: 18px;\n cursor: pointer;\n accent-color: var(--mj-brand-primary);\n}\n\n.entity-item .entity-config .sequence-badge {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n padding: 0.25rem 0.5rem;\n border-radius: var(--mj-radius-sm);\n font-size: 0.75rem;\n font-weight: 600;\n min-width: 24px;\n text-align: center;\n}\n\n.entity-item .entity-actions {\n display: flex;\n gap: 0.25rem;\n}\n\n/* -----------------------------------------------------------------------------\n Drag and Drop Styles\n ----------------------------------------------------------------------------- */\n.drag-handle {\n color: var(--mj-text-secondary);\n cursor: grab;\n margin-right: 0.75rem;\n font-size: 1rem;\n transition: color 0.2s ease;\n flex-shrink: 0;\n}\n\n.drag-handle:hover {\n color: var(--mj-brand-primary);\n}\n\n.drag-handle:active {\n cursor: grabbing;\n}\n\n.entity-item.cdk-drag-preview {\n box-shadow: var(--mj-shadow-xl);\n transform: rotate(1deg);\n opacity: 0.9;\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-page);\n}\n\n.entity-item.cdk-drag-placeholder {\n opacity: 0.4;\n border-style: dashed;\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface-sunken);\n}\n\n.entity-item.cdk-drag-animating {\n transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);\n}\n\n.entities-list.cdk-drop-list-dragging .entity-item:not(.cdk-drag-placeholder) {\n transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);\n}\n\n/* -----------------------------------------------------------------------------\n Empty States\n ----------------------------------------------------------------------------- */\n.no-entities,\n.all-assigned {\n text-align: center;\n padding: 2rem;\n color: var(--mj-text-secondary);\n}\n\n.no-entities i,\n.all-assigned i {\n font-size: 2rem;\n color: var(--mj-border-default);\n margin-bottom: 1rem;\n display: block;\n}\n\n.no-entities p,\n.all-assigned p {\n margin: 0 0 0.25rem 0;\n font-size: 0.9375rem;\n}\n\n.no-entities .empty-subtext,\n.all-assigned .empty-subtext {\n font-size: 0.8125rem;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n/* -----------------------------------------------------------------------------\n Available Entities Section\n ----------------------------------------------------------------------------- */\n.available-entities-header {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n margin-bottom: 1rem;\n}\n\n@media (min-width: 640px) {\n .available-entities-header {\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n }\n}\n\n.available-entities-header .subsection-title {\n margin: 0;\n}\n\n/* Entity Search Bar - Enhanced prominent search */\n.entity-search {\n position: relative;\n min-width: 200px;\n max-width: 100%;\n width: 100%;\n}\n\n@media (min-width: 640px) {\n .entity-search {\n min-width: 280px;\n max-width: 400px;\n width: auto;\n }\n}\n\n@media (min-width: 768px) {\n .entity-search {\n min-width: 320px;\n max-width: 450px;\n }\n}\n\n.entity-search .entity-search-icon {\n position: absolute;\n left: 1rem;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-secondary);\n font-size: 1rem;\n pointer-events: none;\n transition: color 0.2s ease;\n}\n\n@media (min-width: 768px) {\n .entity-search .entity-search-icon {\n left: 1.125rem;\n font-size: 1.125rem;\n }\n}\n\n.entity-search .entity-search-input {\n width: 100%;\n padding: 0.875rem 2.75rem 0.875rem 2.75rem;\n border: 2px solid var(--mj-border-strong);\n border-radius: var(--mj-radius-full);\n font-size: 1rem;\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n transition: border-color 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease;\n min-height: 48px;\n box-shadow: var(--mj-shadow-sm);\n}\n\n@media (min-width: 768px) {\n .entity-search .entity-search-input {\n padding: 1rem 3rem 1rem 3rem;\n min-height: 52px;\n font-size: 1.0625rem;\n border-radius: var(--mj-radius-full);\n }\n}\n\n.entity-search .entity-search-input::placeholder {\n color: var(--mj-text-secondary);\n}\n\n.entity-search .entity-search-input:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface-sunken);\n}\n\n.entity-search .entity-search-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: var(--mj-shadow-md), 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n background: var(--mj-bg-page);\n}\n\n.entity-search:focus-within .entity-search-icon {\n color: var(--mj-brand-primary);\n}\n\n.entity-search .entity-search-clear {\n position: absolute;\n right: 0.75rem;\n top: 50%;\n transform: translateY(-50%);\n padding: 0.375rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n cursor: pointer;\n border-radius: var(--mj-radius-full);\n display: flex;\n align-items: center;\n justify-content: center;\n min-width: 28px;\n min-height: 28px;\n transition: all 0.15s ease;\n}\n\n@media (min-width: 768px) {\n .entity-search .entity-search-clear {\n right: 0.875rem;\n min-width: 32px;\n min-height: 32px;\n }\n}\n\n.entity-search .entity-search-clear:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n/* No Search Results State */\n.no-search-results {\n text-align: center;\n padding: 1.5rem;\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-md);\n}\n\n.no-search-results i {\n font-size: 1.5rem;\n color: var(--mj-border-default);\n margin-bottom: 0.5rem;\n display: block;\n}\n\n.no-search-results p {\n margin: 0;\n font-size: 0.8125rem;\n}\n\n/* -----------------------------------------------------------------------------\n Available Entities Grid\n ----------------------------------------------------------------------------- */\n.available-entities .entities-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));\n gap: 0.5rem;\n}\n\n.entity-chip {\n padding: 0.75rem 1rem;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-page);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.entity-chip .chip-content {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n\n.entity-chip .chip-content i {\n color: var(--mj-brand-primary);\n font-size: 0.875rem;\n}\n\n.entity-chip .chip-content .chip-name {\n font-size: 0.8125rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.entity-chip:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-brand-accent-subtle);\n transform: translateY(-1px);\n box-shadow: var(--mj-shadow-sm);\n}\n\n/* -----------------------------------------------------------------------------\n Info Grid for System Information\n ----------------------------------------------------------------------------- */\n.info-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));\n gap: 1rem;\n}\n\n.info-grid .info-item {\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n}\n\n.info-grid .info-item .info-label {\n font-size: 0.6875rem;\n font-weight: 500;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.info-grid .info-item .info-value {\n font-size: 0.9375rem;\n color: var(--mj-text-primary);\n}\n\n/* -----------------------------------------------------------------------------\n Button Icon Styles\n ----------------------------------------------------------------------------- */\n.btn-icon {\n width: 36px;\n height: 36px;\n border: none;\n border-radius: var(--mj-radius-full);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 0.875rem;\n}\n\n.btn-icon:disabled {\n opacity: 0.38;\n cursor: not-allowed;\n}\n\n.btn-icon.btn-neutral {\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n}\n\n.btn-icon.btn-neutral:hover:not(:disabled) {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.btn-icon.btn-danger {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error);\n}\n\n.btn-icon.btn-danger:hover:not(:disabled) {\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n}\n\n/* Add/Create Icon Button */\n.btn-icon.btn-add {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.btn-icon.btn-add:hover:not(:disabled) {\n background: var(--mj-brand-primary-light);\n box-shadow: var(--mj-shadow-md);\n}\n\n.btn-icon.btn-add:active:not(:disabled) {\n background: var(--mj-brand-primary-light);\n transform: scale(0.95);\n}\n\n/* -----------------------------------------------------------------------------\n Icon Wrapper - Prominent display icons\n ----------------------------------------------------------------------------- */\n.icon-wrapper {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.icon-wrapper-sm {\n width: 32px;\n height: 32px;\n border-radius: var(--mj-radius-md);\n font-size: 0.875rem;\n}\n\n.icon-wrapper-md {\n width: 40px;\n height: 40px;\n border-radius: var(--mj-radius-md);\n font-size: 1rem;\n}\n\n.icon-wrapper-lg {\n width: 48px;\n height: 48px;\n border-radius: var(--mj-radius-lg);\n font-size: 1.25rem;\n}\n\n.icon-wrapper-xl {\n width: 56px;\n height: 56px;\n border-radius: var(--mj-radius-lg);\n font-size: 1.5rem;\n}\n\n/* Icon wrapper color variants */\n.icon-wrapper-primary {\n background: var(--mj-brand-accent-subtle);\n color: var(--mj-brand-primary);\n}\n\n.icon-wrapper-secondary {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning);\n}\n\n.icon-wrapper-tertiary {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success);\n}\n\n.icon-wrapper-error {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error);\n}\n\n/* Inverted icon wrapper (for dark backgrounds) */\n.icon-wrapper-inverted {\n background: var(--mj-brand-on-primary);\n color: var(--mj-brand-primary);\n}\n\n/* Buttons use the global `mjButton` directive (variant/size inputs) \u2014 no\n component-scoped `.mj-btn` overrides (they would collide with the directive). */\n\n/* -----------------------------------------------------------------------------\n Animations\n ----------------------------------------------------------------------------- */\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n@keyframes slideUp {\n from {\n transform: translateY(20px);\n opacity: 0;\n }\n to {\n transform: translateY(0);\n opacity: 1;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Focus Indicators - Accessibility\n ----------------------------------------------------------------------------- */\n.field-input:focus-visible,\n.field-select:focus-visible,\n.field-textarea:focus-visible,\n.btn-icon:focus-visible,\n.entity-chip:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n/* -----------------------------------------------------------------------------\n Reduced Motion Support\n ----------------------------------------------------------------------------- */\n@media (prefers-reduced-motion: reduce) {\n *,\n *::before,\n *::after {\n animation-duration: 0.01ms !important;\n animation-iteration-count: 1 !important;\n transition-duration: 0.01ms !important;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Responsive Design - Mobile (< 640px)\n ----------------------------------------------------------------------------- */\n@media (max-width: 639px) {\n .modal-backdrop {\n padding: 0.5rem;\n }\n\n .modal-dialog {\n border-radius: var(--mj-radius-2xl);\n max-height: 95vh;\n }\n\n /* Fullscreen mode on mobile */\n .modal-dialog.fullscreen {\n border-radius: 0;\n max-height: 100vh;\n }\n\n .modal-header {\n padding: 1.25rem 1rem 1rem 1rem;\n }\n\n .modal-header .modal-title {\n font-size: 1.125rem;\n }\n\n .modal-header .modal-close {\n border-radius: var(--mj-radius-full);\n }\n\n /* Modal title icon on mobile */\n .modal-header .modal-title i {\n width: 36px;\n height: 36px;\n font-size: 1rem;\n }\n\n /* Icon wrappers on mobile - slightly smaller */\n .icon-wrapper-lg {\n width: 40px;\n height: 40px;\n font-size: 1rem;\n }\n\n .icon-wrapper-xl {\n width: 48px;\n height: 48px;\n font-size: 1.25rem;\n }\n\n /* Add button on mobile */\n .btn-icon.btn-add {\n border-radius: var(--mj-radius-full);\n }\n\n .form-section {\n padding: 1.25rem 1rem;\n }\n\n .form-row {\n grid-template-columns: 1fr;\n gap: 1rem;\n }\n\n .modal-footer {\n padding: 1rem;\n flex-direction: column;\n }\n\n /* Full-width footer buttons on mobile \u2014 wrapper-scoped layout only, so the\n global mjButton directive still owns each button's appearance/shape. */\n .modal-footer button {\n width: 100%;\n justify-content: center;\n }\n\n /* Entity item mobile layout */\n .entity-item {\n flex-direction: column;\n align-items: stretch;\n gap: 0.75rem;\n padding: 0.875rem 1rem;\n position: relative;\n }\n\n /* Drag handle on mobile - Keep visible and touch-friendly */\n .drag-handle {\n position: static;\n margin-right: 0.75rem;\n margin-bottom: 0.5rem;\n font-size: 1.25rem;\n color: var(--mj-brand-primary);\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n padding: 0.5rem;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-md);\n cursor: grab;\n }\n\n .drag-handle:active {\n cursor: grabbing;\n background: var(--mj-brand-accent-subtle);\n }\n\n .entity-item .entity-info {\n gap: 0.75rem;\n }\n\n .entity-item .entity-info .entity-icon {\n width: 36px;\n height: 36px;\n font-size: 0.875rem;\n border-radius: var(--mj-radius-md);\n }\n\n .entity-item .entity-info .entity-details .entity-name {\n font-size: 0.875rem;\n word-break: break-word;\n overflow-wrap: break-word;\n line-height: 1.3;\n flex-wrap: wrap;\n }\n\n .entity-item .entity-config {\n margin: 0;\n width: 100%;\n justify-content: space-between;\n flex-wrap: wrap;\n gap: 0.75rem;\n }\n\n .entity-item .entity-config .config-item .config-label {\n font-size: 0.8125rem;\n }\n\n .entity-item .entity-actions {\n width: 100%;\n justify-content: flex-end;\n gap: 0.5rem;\n }\n\n /* Entity chips in mobile */\n .available-entities .entities-grid {\n grid-template-columns: 1fr;\n }\n\n .entity-chip {\n padding: 0.625rem 0.875rem;\n border-radius: var(--mj-radius-md);\n }\n\n .entity-chip .chip-content .chip-name {\n font-size: 0.75rem;\n word-break: break-word;\n }\n\n /* Entity search on mobile - still prominent */\n .entity-search {\n max-width: none;\n width: 100%;\n }\n\n .entity-search .entity-search-input {\n padding: 0.75rem 2.5rem 0.75rem 2.5rem;\n min-height: 44px;\n font-size: 0.9375rem;\n border-radius: var(--mj-radius-full);\n }\n\n .entity-search .entity-search-icon {\n left: 0.875rem;\n font-size: 0.875rem;\n }\n\n .entity-search .entity-search-clear {\n right: 0.625rem;\n border-radius: var(--mj-radius-full);\n }\n\n .info-grid {\n grid-template-columns: 1fr 1fr;\n }\n\n /* Icon buttons on mobile - keep rounded */\n .btn-icon {\n border-radius: var(--mj-radius-full);\n }\n}\n\n/* Tablet Portrait (640px - 767px) */\n@media (min-width: 640px) {\n .modal-dialog {\n max-width: 650px;\n }\n\n .available-entities .entities-grid {\n grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));\n }\n}\n\n/* Tablet Landscape (768px - 1023px) */\n@media (min-width: 768px) {\n .modal-dialog {\n max-width: 800px;\n }\n\n .modal-header {\n padding: 1.5rem 2rem 1.25rem 2rem;\n }\n\n .form-section {\n padding: 1.75rem 2rem;\n }\n\n .modal-footer {\n padding: 1.25rem 2rem;\n }\n}\n\n/* Laptop (1024px+) */\n@media (min-width: 1024px) {\n .modal-dialog {\n max-width: 900px;\n }\n\n .available-entities .entities-grid {\n grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));\n }\n}\n"] }]
706
- }], () => [], { data: [{
851
+ args: [{ standalone: false, selector: 'mj-application-dialog', template: "@if (visible) {\n <div class=\"modal-backdrop\" (click)=\"onCancel()\" role=\"presentation\">\n <div\n class=\"modal-dialog\"\n [class.fullscreen]=\"isFullscreen\"\n (click)=\"$event.stopPropagation()\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"application-dialog-title\"\n aria-describedby=\"application-dialog-description\"\n >\n <!-- Modal Header -->\n <div class=\"modal-header\" [class.create-mode]=\"!isEditMode\" [class.edit-mode]=\"isEditMode\">\n <div class=\"modal-header-content\">\n <h2 class=\"modal-title\" id=\"application-dialog-title\">\n <i class=\"fa-solid\" [class.fa-plus]=\"!isEditMode\" [class.fa-layer-group]=\"isEditMode\" aria-hidden=\"true\"></i>\n {{ isEditMode ? 'Edit Application' : 'Create New Application' }}\n </h2>\n <p class=\"modal-subtitle\" id=\"application-dialog-description\">\n {{ isEditMode ? 'Update application information and settings' : 'Add a new application to the system' }}\n </p>\n </div>\n <div class=\"modal-header-actions\">\n <button\n class=\"modal-action-btn\"\n (click)=\"toggleFullscreen()\"\n [attr.aria-label]=\"isFullscreen ? 'Exit fullscreen' : 'Enter fullscreen'\"\n type=\"button\"\n >\n <i class=\"fa-solid\" [class.fa-compress]=\"isFullscreen\" [class.fa-expand]=\"!isFullscreen\" aria-hidden=\"true\"></i>\n </button>\n <button\n class=\"modal-close\"\n (click)=\"onCancel()\"\n aria-label=\"Close dialog\"\n type=\"button\"\n >\n <i class=\"fa-solid fa-times\" aria-hidden=\"true\"></i>\n </button>\n </div>\n </div>\n\n <!-- Modal Body -->\n <div class=\"modal-body\">\n <form [formGroup]=\"applicationForm\" (ngSubmit)=\"onSubmit()\">\n <!-- Error Alert -->\n @if (error) {\n <div class=\"form-section\">\n <mj-alert Variant=\"error\" [Message]=\"error\" />\n </div>\n }\n\n <!-- Basic Information Section -->\n <mj-accordion-panel class=\"app-dialog-section\" [Expanded]=\"sectionExpanded.basicInfo\" (ExpandedChange)=\"toggleSection('basicInfo')\">\n <ng-template mjAccordionTitle>\n <span class=\"app-dialog-section-title\">\n <span class=\"section-title\">\n <i class=\"fa-solid fa-info-circle\" aria-hidden=\"true\"></i>\n Application Information\n </span>\n <span class=\"section-description\">Define the application's basic properties</span>\n </span>\n </ng-template>\n\n <div class=\"section-content\">\n <div class=\"form-grid\">\n <div class=\"form-field\">\n <label class=\"field-label required\" for=\"app-name\">Application Name</label>\n <input\n id=\"app-name\"\n type=\"text\"\n class=\"field-input\"\n formControlName=\"name\"\n placeholder=\"My Application\"\n [class.error]=\"applicationForm.get('name')?.invalid && applicationForm.get('name')?.touched\"\n [attr.aria-invalid]=\"applicationForm.get('name')?.invalid && applicationForm.get('name')?.touched\"\n aria-describedby=\"app-name-error\"\n />\n @if (applicationForm.get('name')?.invalid && applicationForm.get('name')?.touched) {\n <div class=\"field-error\" id=\"app-name-error\" role=\"alert\">\n <i class=\"fa-solid fa-exclamation-circle\" aria-hidden=\"true\"></i>\n @if (applicationForm.get('name')?.errors?.['required']) {\n Application name is required\n }\n @if (applicationForm.get('name')?.errors?.['maxlength']) {\n Application name cannot exceed 100 characters\n }\n </div>\n }\n </div>\n\n <div class=\"form-field\">\n <label class=\"field-label\" for=\"app-description\">Description</label>\n <textarea\n id=\"app-description\"\n class=\"field-textarea\"\n formControlName=\"description\"\n placeholder=\"Describe the application's purpose and functionality...\"\n rows=\"4\"\n ></textarea>\n <div class=\"field-hint\">\n Provide a clear description of what this application does and its main features.\n </div>\n </div>\n </div>\n </div>\n </mj-accordion-panel>\n\n <!-- Entity Management Section -->\n <mj-accordion-panel class=\"app-dialog-section\" [Expanded]=\"sectionExpanded.entities\" (ExpandedChange)=\"toggleSection('entities')\">\n <ng-template mjAccordionTitle>\n <span class=\"app-dialog-section-title\">\n <span class=\"section-title\">\n <i class=\"fa-solid fa-database\" aria-hidden=\"true\"></i>\n Application Entities\n </span>\n <span class=\"section-description\">Manage which entities are included in this application</span>\n </span>\n </ng-template>\n\n <div class=\"section-content\">\n <div class=\"form-grid\">\n <!-- Assigned Entities -->\n @if (applicationEntities.length > 0) {\n <div class=\"assigned-entities\">\n <h4 class=\"subsection-title\">Assigned Entities ({{ applicationEntities.length }})</h4>\n <div class=\"entities-list\"\n role=\"list\"\n cdkDropList\n (cdkDropListDropped)=\"onEntityDrop($event)\">\n @for (config of applicationEntities; track config.entity.ID; let i = $index) {\n <div\n class=\"entity-item\"\n [class.is-new]=\"config.isNew\"\n [class.has-changes]=\"config.hasChanges\"\n role=\"listitem\"\n cdkDrag\n >\n <i class=\"fa-solid fa-grip-vertical drag-handle\" aria-hidden=\"true\"></i>\n <div class=\"entity-info\">\n <div class=\"entity-icon\">\n <i class=\"fa-solid fa-table\" aria-hidden=\"true\"></i>\n </div>\n <div class=\"entity-details\">\n <div class=\"entity-name\">\n {{ getEntityDisplayName(config.entity) }}\n @if (config.entity.Description) {\n <i\n class=\"fa-solid fa-info-circle entity-info-icon\"\n [title]=\"config.entity.Description\"\n [attr.aria-label]=\"'Entity description: ' + config.entity.Description\"\n ></i>\n }\n </div>\n </div>\n </div>\n\n <div class=\"entity-config\">\n <div class=\"config-item\">\n <label class=\"config-label\">\n <input\n type=\"checkbox\"\n [(ngModel)]=\"config.defaultForNewUser\"\n [ngModelOptions]=\"{standalone: true}\"\n (change)=\"onDefaultForNewUserChange(config)\"\n class=\"config-checkbox\"\n />\n <span class=\"checkbox-text\">Default for new users</span>\n </label>\n </div>\n <div class=\"sequence-badge\" [attr.aria-label]=\"'Sequence ' + config.sequence\">{{ config.sequence }}</div>\n </div>\n\n <div class=\"entity-actions\">\n <button\n type=\"button\"\n class=\"btn-icon btn-danger\"\n (click)=\"removeEntity(config)\"\n title=\"Remove entity\"\n [attr.aria-label]=\"'Remove ' + getEntityDisplayName(config.entity)\"\n >\n <i class=\"fa-solid fa-times\" aria-hidden=\"true\"></i>\n </button>\n </div>\n </div>\n }\n </div>\n </div>\n } @else {\n <div class=\"no-entities\">\n <i class=\"fa-solid fa-database\" aria-hidden=\"true\"></i>\n <p>No entities assigned to this application</p>\n <p class=\"empty-subtext\">Add entities from the available list below</p>\n </div>\n }\n\n <!-- Available Entities -->\n @if (availableEntities.length > 0) {\n <div class=\"available-entities\">\n <div class=\"available-entities-header\">\n <h4 class=\"subsection-title\">Available Entities ({{ filteredAvailableEntities.length }} of {{ availableEntities.length }})</h4>\n <div class=\"entity-search\">\n <i class=\"fa-solid fa-search entity-search-icon\" aria-hidden=\"true\"></i>\n <input\n type=\"text\"\n class=\"entity-search-input\"\n placeholder=\"Search entities...\"\n [value]=\"entitySearchTerm\"\n (input)=\"onEntitySearchChange($event)\"\n aria-label=\"Search available entities\"\n />\n @if (entitySearchTerm) {\n <button\n type=\"button\"\n class=\"entity-search-clear\"\n (click)=\"clearEntitySearch()\"\n aria-label=\"Clear search\"\n >\n <i class=\"fa-solid fa-times\" aria-hidden=\"true\"></i>\n </button>\n }\n </div>\n </div>\n @if (filteredAvailableEntities.length > 0) {\n <div class=\"entities-grid\" role=\"list\">\n @for (entity of filteredAvailableEntities; track entity.ID) {\n <button\n type=\"button\"\n class=\"entity-chip\"\n (click)=\"addEntity(entity)\"\n role=\"listitem\"\n [attr.aria-label]=\"'Add ' + getEntityDisplayName(entity)\"\n >\n <div class=\"chip-content\">\n <i class=\"fa-solid fa-plus\" aria-hidden=\"true\"></i>\n <span class=\"chip-name\">{{ getEntityDisplayName(entity) }}</span>\n </div>\n </button>\n }\n </div>\n } @else {\n <div class=\"no-search-results\">\n <i class=\"fa-solid fa-search\" aria-hidden=\"true\"></i>\n <p>No entities match \"{{ entitySearchTerm }}\"</p>\n </div>\n }\n </div>\n } @else {\n <div class=\"all-assigned\">\n <i class=\"fa-solid fa-check-circle\" aria-hidden=\"true\"></i>\n <p>All entities have been assigned to this application</p>\n </div>\n }\n </div>\n </div>\n </mj-accordion-panel>\n\n <!-- System Information Section (Edit Mode Only) -->\n @if (isEditMode) {\n <mj-accordion-panel class=\"app-dialog-section\" [Expanded]=\"sectionExpanded.systemInfo\" (ExpandedChange)=\"toggleSection('systemInfo')\">\n <ng-template mjAccordionTitle>\n <span class=\"app-dialog-section-title\">\n <span class=\"section-title\">\n <i class=\"fa-solid fa-info-circle\" aria-hidden=\"true\"></i>\n System Information\n </span>\n <span class=\"section-description\">Application metadata and audit information</span>\n </span>\n </ng-template>\n\n <div class=\"section-content\">\n <div class=\"form-grid\">\n <div class=\"info-grid\">\n <div class=\"info-item\">\n <span class=\"info-label\">Created</span>\n <span class=\"info-value\">{{ data?.application?.__mj_CreatedAt | date:'medium' }}</span>\n </div>\n <div class=\"info-item\">\n <span class=\"info-label\">Last Updated</span>\n <span class=\"info-value\">{{ data?.application?.__mj_UpdatedAt | date:'medium' }}</span>\n </div>\n <div class=\"info-item\">\n <span class=\"info-label\">Application ID</span>\n <span class=\"info-value\">{{ data?.application?.ID }}</span>\n </div>\n <div class=\"info-item\">\n <span class=\"info-label\">Total Entities</span>\n <span class=\"info-value\">{{ applicationEntities.length }}</span>\n </div>\n </div>\n </div>\n </div>\n </mj-accordion-panel>\n }\n </form>\n </div>\n\n <!-- Modal Footer - Primary and Cancel buttons on RIGHT -->\n <div class=\"modal-footer\">\n <button\n type=\"submit\"\n mjButton variant=\"primary\"\n [disabled]=\"applicationForm.invalid || isLoading\"\n (click)=\"onSubmit()\"\n [attr.aria-busy]=\"isLoading\"\n >\n @if (isLoading) {\n <i class=\"fa-solid fa-spinner fa-spin\" aria-hidden=\"true\"></i>\n Saving...\n } @else {\n <i class=\"fa-solid fa-save\" aria-hidden=\"true\"></i>\n {{ isEditMode ? 'Update Application' : 'Create Application' }}\n }\n </button>\n <button type=\"button\" mjButton (click)=\"onCancel()\">\n Cancel\n </button>\n </div>\n </div>\n </div>\n}\n", styles: ["/* =============================================================================\n Application Dialog Component\n Uses MJ Design Tokens (--mj-*)\n ============================================================================= */\n\n/* -----------------------------------------------------------------------------\n Modal Backdrop & Container\n ----------------------------------------------------------------------------- */\n.modal-backdrop {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.4);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n animation: fadeIn 0.2s cubic-bezier(0, 0, 0.2, 1);\n padding: 1rem;\n}\n\n.modal-dialog {\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-2xl);\n box-shadow: var(--mj-shadow-2xl);\n max-width: 900px;\n width: 100%;\n max-height: 90vh;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n animation: slideUp 0.3s cubic-bezier(0, 0, 0.2, 1);\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n/* Fullscreen mode */\n.modal-dialog.fullscreen {\n max-width: 100vw;\n width: 100vw;\n max-height: 100vh;\n height: 100vh;\n border-radius: 0;\n margin: 0;\n}\n\n/* -----------------------------------------------------------------------------\n Modal Header\n ----------------------------------------------------------------------------- */\n.modal-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n padding: 1.5rem 1.5rem 1rem 1.5rem;\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n flex-shrink: 0;\n}\n\n.modal-header-content {\n flex: 1;\n min-width: 0;\n}\n\n.modal-header .modal-title {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 1.375rem;\n font-weight: 600;\n color: var(--mj-brand-on-primary);\n margin: 0;\n}\n\n.modal-header .modal-title i {\n width: 40px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: rgba(255, 255, 255, 0.2);\n border-radius: var(--mj-radius-lg);\n font-size: 1.125rem;\n flex-shrink: 0;\n}\n\n/* Create mode - Plus icon with inverted styling */\n.modal-header.create-mode .modal-title i {\n background: var(--mj-brand-on-primary);\n color: var(--mj-brand-primary);\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n}\n\n/* Edit mode - Grid icon with semi-transparent background */\n.modal-header.edit-mode .modal-title i {\n background: rgba(255, 255, 255, 0.2);\n color: var(--mj-brand-on-primary);\n}\n\n/* Modal Header Actions */\n.modal-header-actions {\n display: flex;\n gap: 0.5rem;\n align-items: center;\n flex-shrink: 0;\n margin-left: 0.5rem;\n}\n\n.modal-action-btn {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-brand-on-primary);\n font-size: 1.125rem;\n cursor: pointer;\n border-radius: var(--mj-radius-full);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.modal-action-btn:hover {\n background: rgba(255, 255, 255, 0.15);\n}\n\n.modal-action-btn:focus-visible {\n outline: 2px solid var(--mj-brand-on-primary);\n outline-offset: 2px;\n}\n\n.modal-header .modal-subtitle {\n margin: 0.375rem 0 0 0;\n font-size: 0.8125rem;\n color: var(--mj-brand-on-primary);\n opacity: 0.85;\n}\n\n.modal-header .modal-close {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-brand-on-primary);\n font-size: 1.25rem;\n cursor: pointer;\n border-radius: var(--mj-radius-full);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n margin-left: 0.5rem;\n}\n\n.modal-header .modal-close:hover {\n background: rgba(255, 255, 255, 0.15);\n}\n\n.modal-header .modal-close:focus-visible {\n outline: 2px solid var(--mj-brand-on-primary);\n outline-offset: 2px;\n}\n\n/* -----------------------------------------------------------------------------\n Modal Body\n ----------------------------------------------------------------------------- */\n.modal-body {\n flex: 1;\n overflow-y: auto;\n -webkit-overflow-scrolling: touch;\n padding: 0;\n background: var(--mj-bg-page);\n}\n\n/* -----------------------------------------------------------------------------\n Modal Footer - Primary and Cancel buttons on RIGHT\n ----------------------------------------------------------------------------- */\n.modal-footer {\n display: flex;\n justify-content: flex-end;\n gap: 0.75rem;\n padding: 1.25rem 1.5rem;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n flex-shrink: 0;\n}\n\n/* -----------------------------------------------------------------------------\n Form Sections (Fieldset)\n ----------------------------------------------------------------------------- */\n.form-section {\n border: none;\n margin: 0;\n padding: 1.5rem;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.form-section:last-of-type {\n border-bottom: none;\n}\n\n/* -----------------------------------------------------------------------------\n Collapsible Sections \u2014 now <mj-accordion-panel>. The bespoke fieldset/legend\n chrome (.section-header / .section-title-row / .chevron-icon) was removed; the\n title (icon + title + description) is projected into the accordion title slot.\n ----------------------------------------------------------------------------- */\n.app-dialog-section-title {\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n min-width: 0;\n}\n\n.app-dialog-section-title .section-title {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n font-size: 1.0625rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.app-dialog-section-title .section-title i {\n color: var(--mj-brand-primary);\n font-size: 0.875rem;\n}\n\n.app-dialog-section-title .section-description {\n font-size: 0.8125rem;\n color: var(--mj-text-secondary);\n font-weight: normal;\n}\n\n.section-content {\n animation: expandSection 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n@keyframes expandSection {\n from {\n opacity: 0;\n transform: translateY(-8px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n/* -----------------------------------------------------------------------------\n Form Grid Layout\n ----------------------------------------------------------------------------- */\n.form-grid {\n display: grid;\n gap: 1.25rem;\n}\n\n.form-row {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 1.25rem;\n}\n\n/* -----------------------------------------------------------------------------\n Form Fields\n ----------------------------------------------------------------------------- */\n.form-field {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.form-field .field-label {\n font-size: 0.8125rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.form-field .field-label.required::after {\n content: ' *';\n color: var(--mj-status-error);\n}\n\n.form-field .field-input,\n.form-field .field-select,\n.form-field .field-textarea {\n width: 100%;\n min-height: 44px;\n padding: 0.75rem 1rem;\n border: 1px solid var(--mj-border-strong);\n border-radius: var(--mj-radius-md);\n font-size: 0.9375rem;\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n transition: border-color 0.2s ease, box-shadow 0.2s ease;\n}\n\n.form-field .field-input:focus,\n.form-field .field-select:focus,\n.form-field .field-textarea:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n}\n\n.form-field .field-input.error,\n.form-field .field-select.error,\n.form-field .field-textarea.error {\n border-color: var(--mj-status-error);\n}\n\n.form-field .field-input.error:focus,\n.form-field .field-select.error:focus,\n.form-field .field-textarea.error:focus {\n border-color: var(--mj-status-error);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-error) 12%, transparent);\n}\n\n.form-field .field-input::placeholder,\n.form-field .field-textarea::placeholder {\n color: var(--mj-text-secondary);\n}\n\n.form-field .field-textarea {\n min-height: 100px;\n resize: vertical;\n line-height: 1.5;\n}\n\n.form-field .field-error {\n margin-top: 0.25rem;\n font-size: 0.8125rem;\n color: var(--mj-status-error);\n display: flex;\n align-items: center;\n gap: 0.25rem;\n}\n\n.form-field .field-error i {\n font-size: 0.625rem;\n}\n\n.form-field .field-hint {\n font-size: 0.8125rem;\n color: var(--mj-text-secondary);\n line-height: 1.4;\n}\n\n/* -----------------------------------------------------------------------------\n Entity Management Styles\n ----------------------------------------------------------------------------- */\n.subsection-title {\n font-size: 0.9375rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 1rem 0;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n\n.assigned-entities {\n margin-bottom: 1.5rem;\n}\n\n.assigned-entities .entities-list {\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n overflow: hidden;\n background: var(--mj-bg-page);\n}\n\n.entity-item {\n display: flex;\n align-items: center;\n padding: 1rem 1.25rem;\n border-bottom: 1px solid var(--mj-bg-surface);\n transition: all 0.15s ease;\n}\n\n.entity-item:last-child {\n border-bottom: none;\n}\n\n.entity-item:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.entity-item.is-new {\n background: color-mix(in srgb, var(--mj-status-success) 8%, transparent);\n border-left: 3px solid var(--mj-status-success);\n}\n\n.entity-item.has-changes {\n background: color-mix(in srgb, var(--mj-status-warning) 8%, transparent);\n border-left: 3px solid var(--mj-status-warning);\n}\n\n.entity-item .entity-info {\n display: flex;\n align-items: center;\n gap: 1rem;\n flex: 1;\n min-width: 0;\n}\n\n.entity-item .entity-info .entity-icon {\n width: 40px;\n height: 40px;\n background: var(--mj-brand-accent-subtle);\n border-radius: var(--mj-radius-md);\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-brand-primary);\n flex-shrink: 0;\n}\n\n.entity-item .entity-info .entity-details {\n flex: 1;\n min-width: 0;\n}\n\n.entity-item .entity-info .entity-details .entity-name {\n font-size: 0.9375rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-bottom: 0.125rem;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n\n.entity-item .entity-info .entity-details .entity-name .entity-info-icon {\n color: var(--mj-status-warning);\n font-size: 0.875rem;\n cursor: help;\n opacity: 0.7;\n transition: all 0.15s ease;\n}\n\n.entity-item .entity-info .entity-details .entity-name .entity-info-icon:hover {\n opacity: 1;\n transform: scale(1.1);\n}\n\n.entity-item .entity-config {\n display: flex;\n align-items: center;\n gap: 1.5rem;\n margin: 0 1.5rem;\n}\n\n.entity-item .entity-config .config-item .config-label {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n cursor: pointer;\n font-size: 0.8125rem;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n.entity-item .entity-config .config-item .config-label .config-checkbox {\n width: 18px;\n height: 18px;\n cursor: pointer;\n accent-color: var(--mj-brand-primary);\n}\n\n.entity-item .entity-config .sequence-badge {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n padding: 0.25rem 0.5rem;\n border-radius: var(--mj-radius-sm);\n font-size: 0.75rem;\n font-weight: 600;\n min-width: 24px;\n text-align: center;\n}\n\n.entity-item .entity-actions {\n display: flex;\n gap: 0.25rem;\n}\n\n/* -----------------------------------------------------------------------------\n Drag and Drop Styles\n ----------------------------------------------------------------------------- */\n.drag-handle {\n color: var(--mj-text-secondary);\n cursor: grab;\n margin-right: 0.75rem;\n font-size: 1rem;\n transition: color 0.2s ease;\n flex-shrink: 0;\n}\n\n.drag-handle:hover {\n color: var(--mj-brand-primary);\n}\n\n.drag-handle:active {\n cursor: grabbing;\n}\n\n.entity-item.cdk-drag-preview {\n box-shadow: var(--mj-shadow-xl);\n transform: rotate(1deg);\n opacity: 0.9;\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-page);\n}\n\n.entity-item.cdk-drag-placeholder {\n opacity: 0.4;\n border-style: dashed;\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface-sunken);\n}\n\n.entity-item.cdk-drag-animating {\n transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);\n}\n\n.entities-list.cdk-drop-list-dragging .entity-item:not(.cdk-drag-placeholder) {\n transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);\n}\n\n/* -----------------------------------------------------------------------------\n Empty States\n ----------------------------------------------------------------------------- */\n.no-entities,\n.all-assigned {\n text-align: center;\n padding: 2rem;\n color: var(--mj-text-secondary);\n}\n\n.no-entities i,\n.all-assigned i {\n font-size: 2rem;\n color: var(--mj-border-default);\n margin-bottom: 1rem;\n display: block;\n}\n\n.no-entities p,\n.all-assigned p {\n margin: 0 0 0.25rem 0;\n font-size: 0.9375rem;\n}\n\n.no-entities .empty-subtext,\n.all-assigned .empty-subtext {\n font-size: 0.8125rem;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n/* -----------------------------------------------------------------------------\n Available Entities Section\n ----------------------------------------------------------------------------- */\n.available-entities-header {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n margin-bottom: 1rem;\n}\n\n@media (min-width: 640px) {\n .available-entities-header {\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n }\n}\n\n.available-entities-header .subsection-title {\n margin: 0;\n}\n\n/* Entity Search Bar - Enhanced prominent search */\n.entity-search {\n position: relative;\n min-width: 200px;\n max-width: 100%;\n width: 100%;\n}\n\n@media (min-width: 640px) {\n .entity-search {\n min-width: 280px;\n max-width: 400px;\n width: auto;\n }\n}\n\n@media (min-width: 768px) {\n .entity-search {\n min-width: 320px;\n max-width: 450px;\n }\n}\n\n.entity-search .entity-search-icon {\n position: absolute;\n left: 1rem;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-secondary);\n font-size: 1rem;\n pointer-events: none;\n transition: color 0.2s ease;\n}\n\n@media (min-width: 768px) {\n .entity-search .entity-search-icon {\n left: 1.125rem;\n font-size: 1.125rem;\n }\n}\n\n.entity-search .entity-search-input {\n width: 100%;\n padding: 0.875rem 2.75rem 0.875rem 2.75rem;\n border: 2px solid var(--mj-border-strong);\n border-radius: var(--mj-radius-full);\n font-size: 1rem;\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n transition: border-color 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease;\n min-height: 48px;\n box-shadow: var(--mj-shadow-sm);\n}\n\n@media (min-width: 768px) {\n .entity-search .entity-search-input {\n padding: 1rem 3rem 1rem 3rem;\n min-height: 52px;\n font-size: 1.0625rem;\n border-radius: var(--mj-radius-full);\n }\n}\n\n.entity-search .entity-search-input::placeholder {\n color: var(--mj-text-secondary);\n}\n\n.entity-search .entity-search-input:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface-sunken);\n}\n\n.entity-search .entity-search-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: var(--mj-shadow-md), 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n background: var(--mj-bg-page);\n}\n\n.entity-search:focus-within .entity-search-icon {\n color: var(--mj-brand-primary);\n}\n\n.entity-search .entity-search-clear {\n position: absolute;\n right: 0.75rem;\n top: 50%;\n transform: translateY(-50%);\n padding: 0.375rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n cursor: pointer;\n border-radius: var(--mj-radius-full);\n display: flex;\n align-items: center;\n justify-content: center;\n min-width: 28px;\n min-height: 28px;\n transition: all 0.15s ease;\n}\n\n@media (min-width: 768px) {\n .entity-search .entity-search-clear {\n right: 0.875rem;\n min-width: 32px;\n min-height: 32px;\n }\n}\n\n.entity-search .entity-search-clear:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n/* No Search Results State */\n.no-search-results {\n text-align: center;\n padding: 1.5rem;\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-md);\n}\n\n.no-search-results i {\n font-size: 1.5rem;\n color: var(--mj-border-default);\n margin-bottom: 0.5rem;\n display: block;\n}\n\n.no-search-results p {\n margin: 0;\n font-size: 0.8125rem;\n}\n\n/* -----------------------------------------------------------------------------\n Available Entities Grid\n ----------------------------------------------------------------------------- */\n.available-entities .entities-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));\n gap: 0.5rem;\n}\n\n.entity-chip {\n padding: 0.75rem 1rem;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-page);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.entity-chip .chip-content {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n\n.entity-chip .chip-content i {\n color: var(--mj-brand-primary);\n font-size: 0.875rem;\n}\n\n.entity-chip .chip-content .chip-name {\n font-size: 0.8125rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.entity-chip:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-brand-accent-subtle);\n transform: translateY(-1px);\n box-shadow: var(--mj-shadow-sm);\n}\n\n/* -----------------------------------------------------------------------------\n Info Grid for System Information\n ----------------------------------------------------------------------------- */\n.info-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));\n gap: 1rem;\n}\n\n.info-grid .info-item {\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n}\n\n.info-grid .info-item .info-label {\n font-size: 0.6875rem;\n font-weight: 500;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.info-grid .info-item .info-value {\n font-size: 0.9375rem;\n color: var(--mj-text-primary);\n}\n\n/* -----------------------------------------------------------------------------\n Button Icon Styles\n ----------------------------------------------------------------------------- */\n.btn-icon {\n width: 36px;\n height: 36px;\n border: none;\n border-radius: var(--mj-radius-full);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 0.875rem;\n}\n\n.btn-icon:disabled {\n opacity: 0.38;\n cursor: not-allowed;\n}\n\n.btn-icon.btn-neutral {\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n}\n\n.btn-icon.btn-neutral:hover:not(:disabled) {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.btn-icon.btn-danger {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error);\n}\n\n.btn-icon.btn-danger:hover:not(:disabled) {\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n}\n\n/* Add/Create Icon Button */\n.btn-icon.btn-add {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.btn-icon.btn-add:hover:not(:disabled) {\n background: var(--mj-brand-primary-light);\n box-shadow: var(--mj-shadow-md);\n}\n\n.btn-icon.btn-add:active:not(:disabled) {\n background: var(--mj-brand-primary-light);\n transform: scale(0.95);\n}\n\n/* -----------------------------------------------------------------------------\n Icon Wrapper - Prominent display icons\n ----------------------------------------------------------------------------- */\n.icon-wrapper {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.icon-wrapper-sm {\n width: 32px;\n height: 32px;\n border-radius: var(--mj-radius-md);\n font-size: 0.875rem;\n}\n\n.icon-wrapper-md {\n width: 40px;\n height: 40px;\n border-radius: var(--mj-radius-md);\n font-size: 1rem;\n}\n\n.icon-wrapper-lg {\n width: 48px;\n height: 48px;\n border-radius: var(--mj-radius-lg);\n font-size: 1.25rem;\n}\n\n.icon-wrapper-xl {\n width: 56px;\n height: 56px;\n border-radius: var(--mj-radius-lg);\n font-size: 1.5rem;\n}\n\n/* Icon wrapper color variants */\n.icon-wrapper-primary {\n background: var(--mj-brand-accent-subtle);\n color: var(--mj-brand-primary);\n}\n\n.icon-wrapper-secondary {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning);\n}\n\n.icon-wrapper-tertiary {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success);\n}\n\n.icon-wrapper-error {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error);\n}\n\n/* Inverted icon wrapper (for dark backgrounds) */\n.icon-wrapper-inverted {\n background: var(--mj-brand-on-primary);\n color: var(--mj-brand-primary);\n}\n\n/* Buttons use the global `mjButton` directive (variant/size inputs) \u2014 no\n component-scoped `.mj-btn` overrides (they would collide with the directive). */\n\n/* -----------------------------------------------------------------------------\n Animations\n ----------------------------------------------------------------------------- */\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n@keyframes slideUp {\n from {\n transform: translateY(20px);\n opacity: 0;\n }\n to {\n transform: translateY(0);\n opacity: 1;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Focus Indicators - Accessibility\n ----------------------------------------------------------------------------- */\n.field-input:focus-visible,\n.field-select:focus-visible,\n.field-textarea:focus-visible,\n.btn-icon:focus-visible,\n.entity-chip:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n/* -----------------------------------------------------------------------------\n Reduced Motion Support\n ----------------------------------------------------------------------------- */\n@media (prefers-reduced-motion: reduce) {\n *,\n *::before,\n *::after {\n animation-duration: 0.01ms !important;\n animation-iteration-count: 1 !important;\n transition-duration: 0.01ms !important;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Responsive Design - Mobile (< 640px)\n ----------------------------------------------------------------------------- */\n@media (max-width: 639px) {\n .modal-backdrop {\n padding: 0.5rem;\n }\n\n .modal-dialog {\n border-radius: var(--mj-radius-2xl);\n max-height: 95vh;\n }\n\n /* Fullscreen mode on mobile */\n .modal-dialog.fullscreen {\n border-radius: 0;\n max-height: 100vh;\n }\n\n .modal-header {\n padding: 1.25rem 1rem 1rem 1rem;\n }\n\n .modal-header .modal-title {\n font-size: 1.125rem;\n }\n\n .modal-header .modal-close {\n border-radius: var(--mj-radius-full);\n }\n\n /* Modal title icon on mobile */\n .modal-header .modal-title i {\n width: 36px;\n height: 36px;\n font-size: 1rem;\n }\n\n /* Icon wrappers on mobile - slightly smaller */\n .icon-wrapper-lg {\n width: 40px;\n height: 40px;\n font-size: 1rem;\n }\n\n .icon-wrapper-xl {\n width: 48px;\n height: 48px;\n font-size: 1.25rem;\n }\n\n /* Add button on mobile */\n .btn-icon.btn-add {\n border-radius: var(--mj-radius-full);\n }\n\n .form-section {\n padding: 1.25rem 1rem;\n }\n\n .form-row {\n grid-template-columns: 1fr;\n gap: 1rem;\n }\n\n .modal-footer {\n padding: 1rem;\n flex-direction: column;\n }\n\n /* Full-width footer buttons on mobile \u2014 wrapper-scoped layout only, so the\n global mjButton directive still owns each button's appearance/shape. */\n .modal-footer button {\n width: 100%;\n justify-content: center;\n }\n\n /* Entity item mobile layout */\n .entity-item {\n flex-direction: column;\n align-items: stretch;\n gap: 0.75rem;\n padding: 0.875rem 1rem;\n position: relative;\n }\n\n /* Drag handle on mobile - Keep visible and touch-friendly */\n .drag-handle {\n position: static;\n margin-right: 0.75rem;\n margin-bottom: 0.5rem;\n font-size: 1.25rem;\n color: var(--mj-brand-primary);\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n padding: 0.5rem;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-md);\n cursor: grab;\n }\n\n .drag-handle:active {\n cursor: grabbing;\n background: var(--mj-brand-accent-subtle);\n }\n\n .entity-item .entity-info {\n gap: 0.75rem;\n }\n\n .entity-item .entity-info .entity-icon {\n width: 36px;\n height: 36px;\n font-size: 0.875rem;\n border-radius: var(--mj-radius-md);\n }\n\n .entity-item .entity-info .entity-details .entity-name {\n font-size: 0.875rem;\n word-break: break-word;\n overflow-wrap: break-word;\n line-height: 1.3;\n flex-wrap: wrap;\n }\n\n .entity-item .entity-config {\n margin: 0;\n width: 100%;\n justify-content: space-between;\n flex-wrap: wrap;\n gap: 0.75rem;\n }\n\n .entity-item .entity-config .config-item .config-label {\n font-size: 0.8125rem;\n }\n\n .entity-item .entity-actions {\n width: 100%;\n justify-content: flex-end;\n gap: 0.5rem;\n }\n\n /* Entity chips in mobile */\n .available-entities .entities-grid {\n grid-template-columns: 1fr;\n }\n\n .entity-chip {\n padding: 0.625rem 0.875rem;\n border-radius: var(--mj-radius-md);\n }\n\n .entity-chip .chip-content .chip-name {\n font-size: 0.75rem;\n word-break: break-word;\n }\n\n /* Entity search on mobile - still prominent */\n .entity-search {\n max-width: none;\n width: 100%;\n }\n\n .entity-search .entity-search-input {\n padding: 0.75rem 2.5rem 0.75rem 2.5rem;\n min-height: 44px;\n font-size: 0.9375rem;\n border-radius: var(--mj-radius-full);\n }\n\n .entity-search .entity-search-icon {\n left: 0.875rem;\n font-size: 0.875rem;\n }\n\n .entity-search .entity-search-clear {\n right: 0.625rem;\n border-radius: var(--mj-radius-full);\n }\n\n .info-grid {\n grid-template-columns: 1fr 1fr;\n }\n\n /* Icon buttons on mobile - keep rounded */\n .btn-icon {\n border-radius: var(--mj-radius-full);\n }\n}\n\n/* Tablet Portrait (640px - 767px) */\n@media (min-width: 640px) {\n .modal-dialog {\n max-width: 650px;\n }\n\n .available-entities .entities-grid {\n grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));\n }\n}\n\n/* Tablet Landscape (768px - 1023px) */\n@media (min-width: 768px) {\n .modal-dialog {\n max-width: 800px;\n }\n\n .modal-header {\n padding: 1.5rem 2rem 1.25rem 2rem;\n }\n\n .form-section {\n padding: 1.75rem 2rem;\n }\n\n .modal-footer {\n padding: 1.25rem 2rem;\n }\n}\n\n/* Laptop (1024px+) */\n@media (min-width: 1024px) {\n .modal-dialog {\n max-width: 900px;\n }\n\n .available-entities .entities-grid {\n grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));\n }\n}\n"] }]
852
+ }], () => [], { Data: [{
853
+ type: Input
854
+ }], data: [{
855
+ type: Input
856
+ }], Visible: [{
707
857
  type: Input
708
858
  }], visible: [{
709
859
  type: Input
860
+ }], Result: [{
861
+ type: Output
710
862
  }], result: [{
711
863
  type: Output
712
864
  }], onEscapeKey: [{