@memberjunction/ng-explorer-settings 6.2.0-edge.0 → 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.
- package/dist/lib/account-info/account-info.component.d.ts +1 -1
- package/dist/lib/account-info/account-info.component.js +2 -2
- package/dist/lib/account-info/account-info.component.js.map +1 -1
- package/dist/lib/application-management/application-dialog/application-dialog.component.d.ts +92 -10
- package/dist/lib/application-management/application-dialog/application-dialog.component.d.ts.map +1 -1
- package/dist/lib/application-management/application-dialog/application-dialog.component.js +222 -76
- package/dist/lib/application-management/application-dialog/application-dialog.component.js.map +1 -1
- package/dist/lib/application-management/application-management.component.d.ts +92 -10
- package/dist/lib/application-management/application-management.component.d.ts.map +1 -1
- package/dist/lib/application-management/application-management.component.js +229 -65
- package/dist/lib/application-management/application-management.component.js.map +1 -1
- package/dist/lib/application-settings/application-settings.component.d.ts +4 -4
- package/dist/lib/application-settings/application-settings.component.js +10 -10
- package/dist/lib/application-settings/application-settings.component.js.map +1 -1
- package/dist/lib/entity-permissions/entity-permissions.component.d.ts +88 -10
- package/dist/lib/entity-permissions/entity-permissions.component.d.ts.map +1 -1
- package/dist/lib/entity-permissions/entity-permissions.component.js +219 -63
- package/dist/lib/entity-permissions/entity-permissions.component.js.map +1 -1
- package/dist/lib/entity-permissions/permission-dialog/permission-dialog.component.d.ts +44 -6
- package/dist/lib/entity-permissions/permission-dialog/permission-dialog.component.d.ts.map +1 -1
- package/dist/lib/entity-permissions/permission-dialog/permission-dialog.component.js +117 -43
- package/dist/lib/entity-permissions/permission-dialog/permission-dialog.component.js.map +1 -1
- package/dist/lib/notification-preferences/notification-preferences.component.d.ts +25 -3
- package/dist/lib/notification-preferences/notification-preferences.component.d.ts.map +1 -1
- package/dist/lib/notification-preferences/notification-preferences.component.js +62 -18
- package/dist/lib/notification-preferences/notification-preferences.component.js.map +1 -1
- package/dist/lib/role-management/role-dialog/role-dialog.component.d.ts +32 -4
- package/dist/lib/role-management/role-dialog/role-dialog.component.d.ts.map +1 -1
- package/dist/lib/role-management/role-dialog/role-dialog.component.js +84 -30
- package/dist/lib/role-management/role-dialog/role-dialog.component.js.map +1 -1
- package/dist/lib/role-management/role-management-agent-context.d.ts +12 -4
- package/dist/lib/role-management/role-management-agent-context.d.ts.map +1 -1
- package/dist/lib/role-management/role-management-agent-context.js +26 -10
- package/dist/lib/role-management/role-management-agent-context.js.map +1 -1
- package/dist/lib/role-management/role-management.component.d.ts +95 -11
- package/dist/lib/role-management/role-management.component.d.ts.map +1 -1
- package/dist/lib/role-management/role-management.component.js +259 -91
- package/dist/lib/role-management/role-management.component.js.map +1 -1
- package/dist/lib/settings/settings.component.d.ts +87 -11
- package/dist/lib/settings/settings.component.d.ts.map +1 -1
- package/dist/lib/settings/settings.component.js +211 -65
- package/dist/lib/settings/settings.component.js.map +1 -1
- package/dist/lib/shared/settings-card.component.d.ts +24 -4
- package/dist/lib/shared/settings-card.component.d.ts.map +1 -1
- package/dist/lib/shared/settings-card.component.js +46 -6
- package/dist/lib/shared/settings-card.component.js.map +1 -1
- package/dist/lib/sql-logging/sql-logging.component.d.ts +172 -18
- package/dist/lib/sql-logging/sql-logging.component.d.ts.map +1 -1
- package/dist/lib/sql-logging/sql-logging.component.js +320 -108
- package/dist/lib/sql-logging/sql-logging.component.js.map +1 -1
- package/dist/lib/user-app-config/user-app-config-content.component.js +3 -3
- package/dist/lib/user-app-config/user-app-config-content.component.js.map +1 -1
- package/dist/lib/user-app-config/user-app-config-reorder.d.ts +4 -0
- package/dist/lib/user-app-config/user-app-config-reorder.d.ts.map +1 -1
- package/dist/lib/user-app-config/user-app-config-reorder.js +11 -3
- package/dist/lib/user-app-config/user-app-config-reorder.js.map +1 -1
- package/dist/lib/user-management/transaction-group-refusals.d.ts +4 -2
- package/dist/lib/user-management/transaction-group-refusals.d.ts.map +1 -1
- package/dist/lib/user-management/transaction-group-refusals.js +7 -3
- package/dist/lib/user-management/transaction-group-refusals.js.map +1 -1
- package/dist/lib/user-management/user-dialog/user-dialog.component.d.ts +44 -6
- package/dist/lib/user-management/user-dialog/user-dialog.component.d.ts.map +1 -1
- package/dist/lib/user-management/user-dialog/user-dialog.component.js +121 -47
- package/dist/lib/user-management/user-dialog/user-dialog.component.js.map +1 -1
- package/dist/lib/user-management/user-management-agent-context.d.ts +10 -0
- package/dist/lib/user-management/user-management-agent-context.d.ts.map +1 -1
- package/dist/lib/user-management/user-management-agent-context.js +26 -6
- package/dist/lib/user-management/user-management-agent-context.js.map +1 -1
- package/dist/lib/user-management/user-management.component.d.ts +174 -16
- package/dist/lib/user-management/user-management.component.d.ts.map +1 -1
- package/dist/lib/user-management/user-management.component.js +480 -171
- package/dist/lib/user-management/user-management.component.js.map +1 -1
- package/dist/lib/user-profile-settings/user-profile-settings.component.d.ts +97 -15
- package/dist/lib/user-profile-settings/user-profile-settings.component.d.ts.map +1 -1
- package/dist/lib/user-profile-settings/user-profile-settings.component.js +280 -116
- package/dist/lib/user-profile-settings/user-profile-settings.component.js.map +1 -1
- package/package.json +20 -20
|
@@ -377,33 +377,113 @@ function ApplicationDialogComponent_Conditional_0_Template(rf, ctx) { if (rf & 1
|
|
|
377
377
|
i0.ɵɵconditional(ctx_r1.isLoading ? 43 : 44);
|
|
378
378
|
} }
|
|
379
379
|
export class ApplicationDialogComponent extends BaseAngularComponent {
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
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;
|
|
383
407
|
fb = inject(FormBuilder);
|
|
384
408
|
cdr = inject(ChangeDetectorRef);
|
|
385
409
|
ngZone = inject(NgZone);
|
|
386
410
|
get metadata() { return this.ProviderToUse; }
|
|
387
|
-
|
|
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
|
+
}
|
|
388
420
|
isLoading = false;
|
|
389
421
|
error = null;
|
|
390
422
|
// Entity management
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
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
|
+
}
|
|
394
450
|
// Search filter for available entities
|
|
395
|
-
|
|
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
|
+
}
|
|
396
460
|
// Section expansion state
|
|
397
|
-
|
|
461
|
+
SectionExpanded = {
|
|
398
462
|
basicInfo: true,
|
|
399
463
|
entities: true,
|
|
400
464
|
systemInfo: false
|
|
401
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
|
+
}
|
|
402
474
|
// Fullscreen state
|
|
403
|
-
|
|
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
|
+
}
|
|
404
484
|
constructor() {
|
|
405
485
|
super();
|
|
406
|
-
this.
|
|
486
|
+
this.ApplicationForm = this.fb.group({
|
|
407
487
|
name: ['', [Validators.required, Validators.maxLength(100)]],
|
|
408
488
|
description: ['']
|
|
409
489
|
});
|
|
@@ -412,7 +492,7 @@ export class ApplicationDialogComponent extends BaseAngularComponent {
|
|
|
412
492
|
// Initial setup
|
|
413
493
|
}
|
|
414
494
|
ngOnChanges(changes) {
|
|
415
|
-
if (changes['visible'] && this.
|
|
495
|
+
if (changes['visible'] && this.Visible) {
|
|
416
496
|
this.initializeDialog();
|
|
417
497
|
}
|
|
418
498
|
}
|
|
@@ -420,14 +500,14 @@ export class ApplicationDialogComponent extends BaseAngularComponent {
|
|
|
420
500
|
// Cleanup if needed
|
|
421
501
|
}
|
|
422
502
|
async initializeDialog() {
|
|
423
|
-
if (!this.
|
|
503
|
+
if (!this.Visible)
|
|
424
504
|
return;
|
|
425
505
|
try {
|
|
426
506
|
this.isLoading = true;
|
|
427
507
|
this.error = null;
|
|
428
508
|
// Load all entities first
|
|
429
509
|
await this.loadAllEntities();
|
|
430
|
-
if (this.
|
|
510
|
+
if (this.Data?.application && this.IsEditMode) {
|
|
431
511
|
await this.loadApplicationData();
|
|
432
512
|
}
|
|
433
513
|
else {
|
|
@@ -455,34 +535,42 @@ export class ApplicationDialogComponent extends BaseAngularComponent {
|
|
|
455
535
|
ResultType: 'entity_object',
|
|
456
536
|
OrderBy: 'Name ASC'
|
|
457
537
|
});
|
|
458
|
-
this.
|
|
538
|
+
this.AllEntities = result.Success ? result.Results : [];
|
|
459
539
|
}
|
|
460
540
|
resetForm() {
|
|
461
|
-
this.
|
|
541
|
+
this.ApplicationForm.reset({
|
|
462
542
|
name: '',
|
|
463
543
|
description: ''
|
|
464
544
|
});
|
|
465
|
-
this.
|
|
466
|
-
this.
|
|
467
|
-
this.
|
|
545
|
+
this.ApplicationEntities = [];
|
|
546
|
+
this.AvailableEntities = [...this.AllEntities];
|
|
547
|
+
this.EntitySearchTerm = '';
|
|
468
548
|
this.error = null;
|
|
469
549
|
}
|
|
470
550
|
onEscapeKey() {
|
|
471
|
-
if (this.
|
|
551
|
+
if (this.Visible) {
|
|
472
552
|
this.onCancel();
|
|
473
553
|
}
|
|
474
554
|
}
|
|
555
|
+
get WindowTitle() {
|
|
556
|
+
return this.IsEditMode ? 'Edit Application' : 'Create New Application';
|
|
557
|
+
}
|
|
558
|
+
/** @deprecated Use {@link WindowTitle}. */
|
|
475
559
|
get windowTitle() {
|
|
476
|
-
return this.
|
|
560
|
+
return this.WindowTitle;
|
|
561
|
+
}
|
|
562
|
+
get IsEditMode() {
|
|
563
|
+
return this.Data?.mode === 'edit';
|
|
477
564
|
}
|
|
565
|
+
/** @deprecated Use {@link IsEditMode}. */
|
|
478
566
|
get isEditMode() {
|
|
479
|
-
return this.
|
|
567
|
+
return this.IsEditMode;
|
|
480
568
|
}
|
|
481
569
|
async loadApplicationData() {
|
|
482
|
-
if (!this.
|
|
570
|
+
if (!this.Data?.application)
|
|
483
571
|
return;
|
|
484
|
-
const app = this.
|
|
485
|
-
this.
|
|
572
|
+
const app = this.Data.application;
|
|
573
|
+
this.ApplicationForm.patchValue({
|
|
486
574
|
name: app.Name,
|
|
487
575
|
description: app.Description
|
|
488
576
|
});
|
|
@@ -499,12 +587,12 @@ export class ApplicationDialogComponent extends BaseAngularComponent {
|
|
|
499
587
|
OrderBy: 'Sequence ASC'
|
|
500
588
|
});
|
|
501
589
|
if (result.Success && result.Results) {
|
|
502
|
-
this.
|
|
590
|
+
this.ApplicationEntities = [];
|
|
503
591
|
const usedEntityIds = new Set();
|
|
504
592
|
for (const appEntity of result.Results) {
|
|
505
|
-
const entity = this.
|
|
593
|
+
const entity = this.AllEntities.find(e => UUIDsEqual(e.ID, appEntity.EntityID));
|
|
506
594
|
if (entity) {
|
|
507
|
-
this.
|
|
595
|
+
this.ApplicationEntities.push({
|
|
508
596
|
entity,
|
|
509
597
|
applicationEntity: appEntity,
|
|
510
598
|
sequence: appEntity.Sequence || 0,
|
|
@@ -516,19 +604,19 @@ export class ApplicationDialogComponent extends BaseAngularComponent {
|
|
|
516
604
|
}
|
|
517
605
|
}
|
|
518
606
|
// Set available entities (excluding already assigned ones)
|
|
519
|
-
this.
|
|
607
|
+
this.AvailableEntities = this.AllEntities.filter(e => !usedEntityIds.has(e.ID));
|
|
520
608
|
}
|
|
521
609
|
}
|
|
522
610
|
catch (error) {
|
|
523
611
|
console.warn('Failed to load application entities:', error);
|
|
524
|
-
this.
|
|
612
|
+
this.AvailableEntities = [...this.AllEntities];
|
|
525
613
|
}
|
|
526
614
|
}
|
|
527
|
-
|
|
615
|
+
AddEntity(entity) {
|
|
528
616
|
// Add entity to application
|
|
529
|
-
this.
|
|
617
|
+
this.ApplicationEntities.push({
|
|
530
618
|
entity,
|
|
531
|
-
sequence: this.
|
|
619
|
+
sequence: this.ApplicationEntities.length + 1,
|
|
532
620
|
defaultForNewUser: false,
|
|
533
621
|
isNew: true,
|
|
534
622
|
hasChanges: false
|
|
@@ -536,95 +624,143 @@ export class ApplicationDialogComponent extends BaseAngularComponent {
|
|
|
536
624
|
// Update all sequences to be consecutive
|
|
537
625
|
this.updateSequences();
|
|
538
626
|
// Remove from available entities
|
|
539
|
-
this.
|
|
627
|
+
this.AvailableEntities = this.AvailableEntities.filter(e => !UUIDsEqual(e.ID, entity.ID));
|
|
540
628
|
}
|
|
541
|
-
|
|
629
|
+
/** @deprecated Use {@link AddEntity}. */
|
|
630
|
+
addEntity(entity) {
|
|
631
|
+
return this.AddEntity(entity);
|
|
632
|
+
}
|
|
633
|
+
RemoveEntity(config) {
|
|
542
634
|
// Remove from application entities
|
|
543
|
-
this.
|
|
635
|
+
this.ApplicationEntities = this.ApplicationEntities.filter(ae => !UUIDsEqual(ae.entity.ID, config.entity.ID));
|
|
544
636
|
// Update all sequences to be consecutive
|
|
545
637
|
this.updateSequences();
|
|
546
638
|
// Add back to available entities if not already there
|
|
547
|
-
if (!this.
|
|
548
|
-
this.
|
|
549
|
-
this.
|
|
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 || ''));
|
|
550
642
|
}
|
|
551
643
|
}
|
|
552
|
-
|
|
644
|
+
/** @deprecated Use {@link RemoveEntity}. */
|
|
645
|
+
removeEntity(config) {
|
|
646
|
+
return this.RemoveEntity(config);
|
|
647
|
+
}
|
|
648
|
+
MoveEntityUp(index) {
|
|
553
649
|
if (index > 0) {
|
|
554
|
-
const temp = this.
|
|
555
|
-
this.
|
|
556
|
-
this.
|
|
650
|
+
const temp = this.ApplicationEntities[index];
|
|
651
|
+
this.ApplicationEntities[index] = this.ApplicationEntities[index - 1];
|
|
652
|
+
this.ApplicationEntities[index - 1] = temp;
|
|
557
653
|
this.updateSequences();
|
|
558
654
|
}
|
|
559
655
|
}
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
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;
|
|
565
665
|
this.updateSequences();
|
|
566
666
|
}
|
|
567
667
|
}
|
|
668
|
+
/** @deprecated Use {@link MoveEntityDown}. */
|
|
669
|
+
moveEntityDown(index) {
|
|
670
|
+
return this.MoveEntityDown(index);
|
|
671
|
+
}
|
|
568
672
|
updateSequences() {
|
|
569
|
-
this.
|
|
673
|
+
this.ApplicationEntities.forEach((config, index) => {
|
|
570
674
|
config.sequence = index + 1;
|
|
571
675
|
if (!config.isNew) {
|
|
572
676
|
config.hasChanges = true;
|
|
573
677
|
}
|
|
574
678
|
});
|
|
575
679
|
}
|
|
576
|
-
|
|
680
|
+
OnDefaultForNewUserChange(config) {
|
|
577
681
|
if (!config.isNew) {
|
|
578
682
|
config.hasChanges = true;
|
|
579
683
|
}
|
|
580
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}. */
|
|
581
693
|
get hasEntityChanges() {
|
|
582
|
-
return this.
|
|
694
|
+
return this.HasEntityChanges;
|
|
583
695
|
}
|
|
584
696
|
// Filtered available entities based on search term
|
|
585
|
-
get
|
|
586
|
-
if (!this.
|
|
587
|
-
return this.
|
|
697
|
+
get FilteredAvailableEntities() {
|
|
698
|
+
if (!this.EntitySearchTerm || !this.EntitySearchTerm.trim()) {
|
|
699
|
+
return this.AvailableEntities;
|
|
588
700
|
}
|
|
589
|
-
const searchLower = this.
|
|
590
|
-
return this.
|
|
701
|
+
const searchLower = this.EntitySearchTerm.toLowerCase().trim();
|
|
702
|
+
return this.AvailableEntities.filter(entity => (entity.DisplayName || '').toLowerCase().includes(searchLower) ||
|
|
591
703
|
(entity.Name || '').toLowerCase().includes(searchLower) ||
|
|
592
704
|
(entity.Description || '').toLowerCase().includes(searchLower));
|
|
593
705
|
}
|
|
594
|
-
|
|
706
|
+
/** @deprecated Use {@link FilteredAvailableEntities}. */
|
|
707
|
+
get filteredAvailableEntities() {
|
|
708
|
+
return this.FilteredAvailableEntities;
|
|
709
|
+
}
|
|
710
|
+
GetEntityDisplayName(entity) {
|
|
595
711
|
return entity.DisplayName || entity.Name;
|
|
596
712
|
}
|
|
597
|
-
|
|
713
|
+
/** @deprecated Use {@link GetEntityDisplayName}. */
|
|
714
|
+
getEntityDisplayName(entity) {
|
|
715
|
+
return this.GetEntityDisplayName(entity);
|
|
716
|
+
}
|
|
717
|
+
OnEntitySearchChange(event) {
|
|
598
718
|
const value = event.target.value;
|
|
599
|
-
this.
|
|
719
|
+
this.EntitySearchTerm = value;
|
|
720
|
+
}
|
|
721
|
+
/** @deprecated Use {@link OnEntitySearchChange}. */
|
|
722
|
+
onEntitySearchChange(event) {
|
|
723
|
+
return this.OnEntitySearchChange(event);
|
|
724
|
+
}
|
|
725
|
+
ClearEntitySearch() {
|
|
726
|
+
this.EntitySearchTerm = '';
|
|
600
727
|
}
|
|
728
|
+
/** @deprecated Use {@link ClearEntitySearch}. */
|
|
601
729
|
clearEntitySearch() {
|
|
602
|
-
this.
|
|
730
|
+
return this.ClearEntitySearch();
|
|
603
731
|
}
|
|
604
732
|
toggleSection(section) {
|
|
605
|
-
this.
|
|
733
|
+
this.SectionExpanded[section] = !this.SectionExpanded[section];
|
|
606
734
|
}
|
|
735
|
+
ToggleFullscreen() {
|
|
736
|
+
this.IsFullscreen = !this.IsFullscreen;
|
|
737
|
+
}
|
|
738
|
+
/** @deprecated Use {@link ToggleFullscreen}. */
|
|
607
739
|
toggleFullscreen() {
|
|
608
|
-
|
|
740
|
+
return this.ToggleFullscreen();
|
|
609
741
|
}
|
|
610
|
-
|
|
742
|
+
OnEntityDrop(event) {
|
|
611
743
|
if (event.previousIndex !== event.currentIndex) {
|
|
612
|
-
moveItemInArray(this.
|
|
744
|
+
moveItemInArray(this.ApplicationEntities, event.previousIndex, event.currentIndex);
|
|
613
745
|
this.updateSequences();
|
|
614
746
|
}
|
|
615
747
|
}
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
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);
|
|
619
755
|
return;
|
|
620
756
|
}
|
|
621
757
|
this.isLoading = true;
|
|
622
758
|
this.error = null;
|
|
623
759
|
try {
|
|
624
760
|
let application;
|
|
625
|
-
if (this.
|
|
761
|
+
if (this.IsEditMode && this.Data?.application) {
|
|
626
762
|
// Edit existing application
|
|
627
|
-
application = this.
|
|
763
|
+
application = this.Data.application;
|
|
628
764
|
}
|
|
629
765
|
else {
|
|
630
766
|
// Create new application
|
|
@@ -632,7 +768,7 @@ export class ApplicationDialogComponent extends BaseAngularComponent {
|
|
|
632
768
|
application.NewRecord();
|
|
633
769
|
}
|
|
634
770
|
// Update application properties
|
|
635
|
-
const formValue = this.
|
|
771
|
+
const formValue = this.ApplicationForm.value;
|
|
636
772
|
application.Name = formValue.name;
|
|
637
773
|
application.Description = formValue.description || null;
|
|
638
774
|
// Save application
|
|
@@ -641,10 +777,10 @@ export class ApplicationDialogComponent extends BaseAngularComponent {
|
|
|
641
777
|
throw new Error(application.LatestResult?.Message || 'Failed to save application');
|
|
642
778
|
}
|
|
643
779
|
// Save application entities if there are changes
|
|
644
|
-
if (this.
|
|
780
|
+
if (this.HasEntityChanges) {
|
|
645
781
|
await this.saveApplicationEntities(application.ID);
|
|
646
782
|
}
|
|
647
|
-
this.
|
|
783
|
+
this.Result.emit({ action: 'save', application });
|
|
648
784
|
}
|
|
649
785
|
catch (error) {
|
|
650
786
|
console.error('Error saving application:', error);
|
|
@@ -660,9 +796,13 @@ export class ApplicationDialogComponent extends BaseAngularComponent {
|
|
|
660
796
|
});
|
|
661
797
|
}
|
|
662
798
|
}
|
|
799
|
+
/** @deprecated Use {@link OnSubmit}. */
|
|
800
|
+
async onSubmit() {
|
|
801
|
+
return this.OnSubmit();
|
|
802
|
+
}
|
|
663
803
|
async saveApplicationEntities(applicationId) {
|
|
664
804
|
// Save or update each MJApplicationEntity record
|
|
665
|
-
for (const config of this.
|
|
805
|
+
for (const config of this.ApplicationEntities) {
|
|
666
806
|
if (config.isNew || config.hasChanges) {
|
|
667
807
|
let appEntity;
|
|
668
808
|
if (config.isNew) {
|
|
@@ -689,7 +829,7 @@ export class ApplicationDialogComponent extends BaseAngularComponent {
|
|
|
689
829
|
}
|
|
690
830
|
}
|
|
691
831
|
onCancel() {
|
|
692
|
-
this.
|
|
832
|
+
this.Result.emit({ action: 'cancel' });
|
|
693
833
|
}
|
|
694
834
|
markFormGroupTouched(formGroup) {
|
|
695
835
|
Object.keys(formGroup.controls).forEach(key => {
|
|
@@ -700,7 +840,7 @@ export class ApplicationDialogComponent extends BaseAngularComponent {
|
|
|
700
840
|
static ɵfac = function ApplicationDialogComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ApplicationDialogComponent)(); };
|
|
701
841
|
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ApplicationDialogComponent, selectors: [["mj-application-dialog"]], hostBindings: function ApplicationDialogComponent_HostBindings(rf, ctx) { if (rf & 1) {
|
|
702
842
|
i0.ɵɵlistener("keydown.escape", function ApplicationDialogComponent_keydown_escape_HostBindingHandler() { return ctx.onEscapeKey(); }, i0.ɵɵresolveDocument);
|
|
703
|
-
} }, 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) {
|
|
704
844
|
i0.ɵɵconditionalCreate(0, ApplicationDialogComponent_Conditional_0_Template, 47, 31, "div", 0);
|
|
705
845
|
} if (rf & 2) {
|
|
706
846
|
i0.ɵɵconditional(ctx.visible ? 0 : -1);
|
|
@@ -709,10 +849,16 @@ export class ApplicationDialogComponent extends BaseAngularComponent {
|
|
|
709
849
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ApplicationDialogComponent, [{
|
|
710
850
|
type: Component,
|
|
711
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"] }]
|
|
712
|
-
}], () => [], {
|
|
852
|
+
}], () => [], { Data: [{
|
|
853
|
+
type: Input
|
|
854
|
+
}], data: [{
|
|
855
|
+
type: Input
|
|
856
|
+
}], Visible: [{
|
|
713
857
|
type: Input
|
|
714
858
|
}], visible: [{
|
|
715
859
|
type: Input
|
|
860
|
+
}], Result: [{
|
|
861
|
+
type: Output
|
|
716
862
|
}], result: [{
|
|
717
863
|
type: Output
|
|
718
864
|
}], onEscapeKey: [{
|