@memberjunction/ng-base-forms 5.23.0 → 5.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,28 +1,33 @@
1
- import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, ChangeDetectorRef, inject, NgZone, ContentChildren, ViewEncapsulation } from '@angular/core';
1
+ import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, ChangeDetectorRef, inject, NgZone, ContentChildren, ViewChild, ViewEncapsulation } from '@angular/core';
2
+ import { CompositeKey, Metadata, RunView } from '@memberjunction/core';
3
+ import { UserInfoEngine } from '@memberjunction/core-entities';
2
4
  import { Subject } from 'rxjs';
3
5
  import { takeUntil } from 'rxjs/operators';
4
6
  import { DEFAULT_TOOLBAR_CONFIG } from '../types/toolbar-config';
5
7
  import { MjCollapsiblePanelComponent } from '../panel/collapsible-panel.component';
6
8
  import { BeforeHistoryViewEventArgs, BeforeListManagementEventArgs } from '../types/form-events';
9
+ import { RecordChangesComponent } from '@memberjunction/ng-record-changes';
10
+ import { MJNotificationService } from '@memberjunction/ng-notifications';
7
11
  import * as i0 from "@angular/core";
8
12
  import * as i1 from "@memberjunction/ng-record-changes";
9
13
  import * as i2 from "@memberjunction/ng-list-management";
10
- import * as i3 from "../toolbar/form-toolbar.component";
11
- import * as i4 from "../section-manager/section-manager.component";
12
- import * as i5 from "../isa-related-panel/isa-related-panel.component";
14
+ import * as i3 from "@memberjunction/ng-record-tags";
15
+ import * as i4 from "../toolbar/form-toolbar.component";
16
+ import * as i5 from "../section-manager/section-manager.component";
17
+ import * as i6 from "../isa-related-panel/isa-related-panel.component";
13
18
  const _c0 = [[["", "before-toolbar", ""]], "*"];
14
19
  const _c1 = ["[before-toolbar]", "*"];
15
20
  const _c2 = a0 => [a0];
16
21
  const _c3 = (a0, a1, a2) => ({ mode: "manage", entityId: a0, entityName: a1, recordIds: a2, allowCreate: true });
17
22
  function MjRecordFormContainerComponent_Conditional_7_Template(rf, ctx) { if (rf & 1) {
18
23
  const _r1 = i0.ɵɵgetCurrentView();
19
- i0.ɵɵelementStart(0, "div", 5)(1, "div", 10);
20
- i0.ɵɵelement(2, "i", 11);
24
+ i0.ɵɵelementStart(0, "div", 5)(1, "div", 11);
25
+ i0.ɵɵelement(2, "i", 12);
21
26
  i0.ɵɵelementEnd();
22
- i0.ɵɵelementStart(3, "h3", 12);
27
+ i0.ɵɵelementStart(3, "h3", 13);
23
28
  i0.ɵɵtext(4, "No sections found");
24
29
  i0.ɵɵelementEnd();
25
- i0.ɵɵelementStart(5, "p", 13);
30
+ i0.ɵɵelementStart(5, "p", 14);
26
31
  i0.ɵɵtext(6, " No sections match \"");
27
32
  i0.ɵɵelementStart(7, "strong");
28
33
  i0.ɵɵtext(8);
@@ -30,7 +35,7 @@ function MjRecordFormContainerComponent_Conditional_7_Template(rf, ctx) { if (rf
30
35
  i0.ɵɵtext(9, "\". ");
31
36
  i0.ɵɵelement(10, "br");
32
37
  i0.ɵɵtext(11, "Try a different search term or ");
33
- i0.ɵɵelementStart(12, "a", 14);
38
+ i0.ɵɵelementStart(12, "a", 15);
34
39
  i0.ɵɵlistener("click", function MjRecordFormContainerComponent_Conditional_7_Template_a_click_12_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); ctx_r1.OnFilterChange(""); return i0.ɵɵresetView($event.preventDefault()); });
35
40
  i0.ɵɵtext(13, "clear the search");
36
41
  i0.ɵɵelementEnd();
@@ -43,17 +48,26 @@ function MjRecordFormContainerComponent_Conditional_7_Template(rf, ctx) { if (rf
43
48
  } }
44
49
  function MjRecordFormContainerComponent_Conditional_9_Template(rf, ctx) { if (rf & 1) {
45
50
  const _r3 = i0.ɵɵgetCurrentView();
46
- i0.ɵɵelementStart(0, "mj-record-changes", 15);
47
- i0.ɵɵlistener("dialogClosed", function MjRecordFormContainerComponent_Conditional_9_Template_mj_record_changes_dialogClosed_0_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnRecordChangesClosed()); });
51
+ i0.ɵɵelementStart(0, "mj-record-changes", 16);
52
+ i0.ɵɵlistener("RestoreRequested", function MjRecordFormContainerComponent_Conditional_9_Template_mj_record_changes_RestoreRequested_0_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnRestoreRequested($event)); })("dialogClosed", function MjRecordFormContainerComponent_Conditional_9_Template_mj_record_changes_dialogClosed_0_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnRecordChangesClosed()); });
48
53
  i0.ɵɵelementEnd();
49
54
  } if (rf & 2) {
50
55
  const ctx_r1 = i0.ɵɵnextContext();
51
- i0.ɵɵproperty("record", ctx_r1.EffectiveRecord);
56
+ i0.ɵɵproperty("record", ctx_r1.EffectiveRecord)("AllowRestore", ctx_r1.EffectiveUserCanEdit);
52
57
  } }
53
58
  function MjRecordFormContainerComponent_Conditional_10_Template(rf, ctx) { if (rf & 1) {
54
59
  const _r4 = i0.ɵɵgetCurrentView();
55
- i0.ɵɵelementStart(0, "mj-list-management-dialog", 16);
56
- i0.ɵɵlistener("complete", function MjRecordFormContainerComponent_Conditional_10_Template_mj_list_management_dialog_complete_0_listener() { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnListManagementClosed()); })("cancel", function MjRecordFormContainerComponent_Conditional_10_Template_mj_list_management_dialog_cancel_0_listener() { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnListManagementClosed()); });
60
+ i0.ɵɵelementStart(0, "mj-record-tags", 17);
61
+ i0.ɵɵlistener("PanelClosed", function MjRecordFormContainerComponent_Conditional_10_Template_mj_record_tags_PanelClosed_0_listener() { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnTagsPanelClosed()); })("TagCountChanged", function MjRecordFormContainerComponent_Conditional_10_Template_mj_record_tags_TagCountChanged_0_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnTagCountChanged($event)); })("RecordNavigate", function MjRecordFormContainerComponent_Conditional_10_Template_mj_record_tags_RecordNavigate_0_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnTagsRecordNavigate($event)); })("WidthChanged", function MjRecordFormContainerComponent_Conditional_10_Template_mj_record_tags_WidthChanged_0_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnTagsPanelWidthChanged($event)); });
62
+ i0.ɵɵelementEnd();
63
+ } if (rf & 2) {
64
+ const ctx_r1 = i0.ɵɵnextContext();
65
+ i0.ɵɵproperty("Record", ctx_r1.EffectiveRecord)("WidthPx", ctx_r1.TagsPanelWidth);
66
+ } }
67
+ function MjRecordFormContainerComponent_Conditional_11_Template(rf, ctx) { if (rf & 1) {
68
+ const _r5 = i0.ɵɵgetCurrentView();
69
+ i0.ɵɵelementStart(0, "mj-list-management-dialog", 18);
70
+ i0.ɵɵlistener("complete", function MjRecordFormContainerComponent_Conditional_11_Template_mj_list_management_dialog_complete_0_listener() { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnListManagementClosed()); })("cancel", function MjRecordFormContainerComponent_Conditional_11_Template_mj_list_management_dialog_cancel_0_listener() { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnListManagementClosed()); });
57
71
  i0.ɵɵelementEnd();
58
72
  } if (rf & 2) {
59
73
  const ctx_r1 = i0.ɵɵnextContext();
@@ -92,11 +106,23 @@ function MjRecordFormContainerComponent_Conditional_10_Template(rf, ctx) { if (r
92
106
  export class MjRecordFormContainerComponent {
93
107
  cdr = inject(ChangeDetectorRef);
94
108
  ngZone = inject(NgZone);
109
+ notificationService = inject(MJNotificationService);
95
110
  destroy$ = new Subject();
96
111
  panelNavReset$ = new Subject();
97
112
  // ---- Internal State ----
113
+ /** Reference to the record changes drawer (when visible) for triggering refresh after save */
114
+ recordChangesDrawer;
98
115
  /** Controls visibility of record changes drawer */
99
116
  ShowRecordChanges = false;
117
+ /** Controls visibility of tags panel */
118
+ ShowTagsPanel = false;
119
+ /** Persisted tags panel width */
120
+ TagsPanelWidth = 0;
121
+ static TAGS_WIDTH_KEY = 'MJ_TagsPanel_Width';
122
+ /** Number of tags on this record */
123
+ TagCount = 0;
124
+ /** Number of tracked record change versions for this record */
125
+ VersionCount = 0;
100
126
  /** Controls visibility of list management dialog */
101
127
  ShowListManagement = false;
102
128
  /** Controls visibility of section manager drawer */
@@ -282,6 +308,10 @@ export class MjRecordFormContainerComponent {
282
308
  }
283
309
  // ---- Lifecycle ----
284
310
  ngAfterContentInit() {
311
+ // Load saved tags panel width
312
+ const savedWidth = UserInfoEngine.Instance.GetSetting(MjRecordFormContainerComponent.TAGS_WIDTH_KEY);
313
+ if (savedWidth)
314
+ this.TagsPanelWidth = parseInt(savedWidth, 10) || 0;
285
315
  // Subscribe to panel Navigate events and relay them
286
316
  this.SubscribeToPanelNavigateEvents();
287
317
  // Watch for panel changes to update counts and re-subscribe
@@ -291,6 +321,7 @@ export class MjRecordFormContainerComponent {
291
321
  });
292
322
  // Watch for changes to record dirty state
293
323
  this.watchRecordChanges();
324
+ // Badge counts are loaded when the form emits RecordReady (see SubscribeToPanelNavigateEvents)
294
325
  }
295
326
  ngOnDestroy() {
296
327
  this.panelNavReset$.next();
@@ -304,6 +335,12 @@ export class MjRecordFormContainerComponent {
304
335
  */
305
336
  SubscribeToPanelNavigateEvents() {
306
337
  this.panelNavReset$.next(); // tear down previous subscriptions
338
+ // Subscribe to RecordReady on the form component — fires once after record is fully initialized
339
+ if (this.fc) {
340
+ this.fc.RecordReady.pipe(takeUntil(this.panelNavReset$)).subscribe(() => {
341
+ this.LoadBadgeCounts();
342
+ });
343
+ }
307
344
  this.Panels.forEach(panel => {
308
345
  panel.Navigate.pipe(takeUntil(this.panelNavReset$)).subscribe((event) => {
309
346
  this.Navigate.emit(event);
@@ -324,6 +361,70 @@ export class MjRecordFormContainerComponent {
324
361
  // Cleanup on destroy
325
362
  this.destroy$.subscribe(() => clearInterval(checkInterval));
326
363
  }
364
+ // ---- Badge Count Loading ----
365
+ /**
366
+ * Loads tag count and record change version count for toolbar badges.
367
+ * Both queries run in parallel for performance.
368
+ */
369
+ badgeCountsLoaded = false;
370
+ LoadBadgeCounts() {
371
+ if (this.badgeCountsLoaded)
372
+ return;
373
+ const record = this.EffectiveRecord;
374
+ if (!record?.EntityInfo)
375
+ return;
376
+ this.badgeCountsLoaded = true;
377
+ // Fire both queries in parallel — no await needed, they update state async
378
+ this.LoadTagCount(record);
379
+ this.LoadVersionCount(record);
380
+ }
381
+ /**
382
+ * Queries the count of tagged items for the current entity + record
383
+ * and updates the TagCount badge on the toolbar.
384
+ */
385
+ async LoadTagCount(record) {
386
+ try {
387
+ const rv = new RunView();
388
+ // Don't narrow Fields — the server caches RunView results by entity+filter (ignoring Fields),
389
+ // so a narrow query here would poison the cache for the subsequent full-field load in the Tags panel.
390
+ const result = await rv.RunView({
391
+ EntityName: 'MJ: Tagged Items',
392
+ ExtraFilter: `EntityID='${record.EntityInfo.ID}' AND RecordID='${record.PrimaryKey.Values()}'`,
393
+ ResultType: 'simple'
394
+ });
395
+ if (result.Success) {
396
+ this.TagCount = result.Results.length;
397
+ this.cdr.detectChanges();
398
+ }
399
+ }
400
+ catch {
401
+ // Non-critical — badge just stays at 0
402
+ }
403
+ }
404
+ /**
405
+ * Queries the count of record change entries for the current entity + record
406
+ * and updates the VersionCount badge on the toolbar.
407
+ */
408
+ async LoadVersionCount(record) {
409
+ if (!record.EntityInfo.TrackRecordChanges)
410
+ return;
411
+ try {
412
+ const rv = new RunView();
413
+ const result = await rv.RunView({
414
+ EntityName: 'MJ: Record Changes',
415
+ Fields: ['ID'],
416
+ ExtraFilter: `EntityID='${record.EntityInfo.ID}' AND RecordID='${record.PrimaryKey.ToConcatenatedString()}'`,
417
+ ResultType: 'simple'
418
+ });
419
+ if (result.Success) {
420
+ this.VersionCount = result.Results.length;
421
+ this.cdr.detectChanges();
422
+ }
423
+ }
424
+ catch {
425
+ // Non-critical — badge just stays at 0
426
+ }
427
+ }
327
428
  // ---- Toolbar Event Handlers ----
328
429
  /**
329
430
  * Navigation events are always re-emitted for the host app to handle.
@@ -358,6 +459,8 @@ export class MjRecordFormContainerComponent {
358
459
  this.cdr.markForCheck();
359
460
  try {
360
461
  await this.fc.SaveRecord(true);
462
+ // After successful save, refresh version count badge and record changes drawer
463
+ this.RefreshAfterSave();
361
464
  }
362
465
  finally {
363
466
  // Use microtask timing to avoid ExpressionChangedAfterItHasBeenCheckedError
@@ -372,6 +475,22 @@ export class MjRecordFormContainerComponent {
372
475
  this.SaveRequested.emit();
373
476
  }
374
477
  }
478
+ /**
479
+ * Refreshes the version count badge and record changes drawer after a save.
480
+ * The save operation creates a new RecordChange entry server-side, so we need
481
+ * to update the UI to reflect the new version.
482
+ */
483
+ RefreshAfterSave() {
484
+ const record = this.EffectiveRecord;
485
+ if (!record?.EntityInfo?.TrackRecordChanges)
486
+ return;
487
+ // Refresh version count badge
488
+ this.LoadVersionCount(record);
489
+ // If the record changes drawer is open, refresh it too
490
+ if (this.ShowRecordChanges && this.recordChangesDrawer) {
491
+ this.recordChangesDrawer.Refresh();
492
+ }
493
+ }
375
494
  /**
376
495
  * Cancel: delegate to FormComponent if available, otherwise re-emit.
377
496
  */
@@ -417,9 +536,80 @@ export class MjRecordFormContainerComponent {
417
536
  // Also emit for backward compatibility
418
537
  this.ListManagementRequested.emit();
419
538
  }
539
+ OnTagsPanelToggled() {
540
+ this.ShowTagsPanel = !this.ShowTagsPanel;
541
+ this.cdr.detectChanges();
542
+ }
543
+ OnTagsPanelClosed() {
544
+ this.ShowTagsPanel = false;
545
+ this.cdr.detectChanges();
546
+ // Refresh tag count — tags may have been added/removed while panel was open
547
+ const record = this.EffectiveRecord;
548
+ if (record?.EntityInfo) {
549
+ this.LoadTagCount(record);
550
+ }
551
+ }
552
+ /**
553
+ * Handles live tag count updates from the tags panel component.
554
+ */
555
+ OnTagCountChanged(count) {
556
+ this.TagCount = count;
557
+ this.cdr.markForCheck();
558
+ }
559
+ OnTagsPanelWidthChanged(width) {
560
+ this.TagsPanelWidth = width;
561
+ UserInfoEngine.Instance.SetSettingDebounced(MjRecordFormContainerComponent.TAGS_WIDTH_KEY, String(width));
562
+ }
563
+ OnTagsRecordNavigate(event) {
564
+ const md = new Metadata();
565
+ const entityInfo = md.Entities.find(e => e.Name === event.EntityName);
566
+ const pkey = new CompositeKey();
567
+ if (entityInfo) {
568
+ pkey.LoadFromURLSegment(entityInfo, event.RecordID);
569
+ }
570
+ else {
571
+ pkey.KeyValuePairs = [{ FieldName: 'ID', Value: event.RecordID }];
572
+ }
573
+ this.Navigate.emit({ Kind: 'record', EntityName: event.EntityName, PrimaryKey: pkey });
574
+ }
420
575
  OnRecordChangesClosed() {
421
576
  this.ShowRecordChanges = false;
422
577
  this.cdr.markForCheck();
578
+ // Refresh version count — new changes may have occurred
579
+ const record = this.EffectiveRecord;
580
+ if (record?.EntityInfo) {
581
+ this.LoadVersionCount(record);
582
+ }
583
+ }
584
+ /**
585
+ * Handles a restore request from the record-changes panel.
586
+ * Applies the old field values to the current record, saves, then refreshes version count.
587
+ */
588
+ async OnRestoreRequested(event) {
589
+ const record = this.EffectiveRecord;
590
+ if (!record)
591
+ return;
592
+ try {
593
+ // Apply old values from the version to the current record
594
+ for (const [fieldName, values] of Object.entries(event.FieldChanges)) {
595
+ record.Set(fieldName, values.OldValue);
596
+ }
597
+ // Save the record — this creates a new Record Change entry automatically
598
+ const saved = await record.Save();
599
+ if (saved) {
600
+ this.notificationService.CreateSimpleNotification(`Restored ${Object.keys(event.FieldChanges).length} field(s) from version dated ${new Date(event.ChangedAt).toLocaleDateString()}`, 'info', 3000);
601
+ // Refresh version count since a new change was created by the save
602
+ this.LoadVersionCount(record);
603
+ this.cdr.markForCheck();
604
+ }
605
+ else {
606
+ this.notificationService.CreateSimpleNotification('Failed to save restored values. Please try again.', 'error', 4000);
607
+ }
608
+ }
609
+ catch (err) {
610
+ const message = err instanceof Error ? err.message : 'Unknown error';
611
+ this.notificationService.CreateSimpleNotification(`Restore failed: ${message}`, 'error', 4000);
612
+ }
423
613
  }
424
614
  OnListManagementClosed() {
425
615
  this.ShowListManagement = false;
@@ -498,11 +688,16 @@ export class MjRecordFormContainerComponent {
498
688
  } if (rf & 2) {
499
689
  let _t;
500
690
  i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.Panels = _t);
501
- } }, inputs: { Record: "Record", FormComponent: "FormComponent", EntityInfo: "EntityInfo", EditMode: "EditMode", UserCanEdit: "UserCanEdit", UserCanDelete: "UserCanDelete", IsFavorite: "IsFavorite", FavoriteInitDone: "FavoriteInitDone", IsDirty: "IsDirty", DirtyFieldNames: "DirtyFieldNames", ListCount: "ListCount", IsSaving: "IsSaving", ToolbarConfig: "ToolbarConfig", WidthMode: "WidthMode" }, outputs: { Navigate: "Navigate", EditModeChange: "EditModeChange", BeforeSave: "BeforeSave", SaveRequested: "SaveRequested", BeforeCancel: "BeforeCancel", CancelRequested: "CancelRequested", BeforeDelete: "BeforeDelete", DeleteRequested: "DeleteRequested", FavoriteToggled: "FavoriteToggled", BeforeHistoryView: "BeforeHistoryView", HistoryRequested: "HistoryRequested", BeforeListManagement: "BeforeListManagement", ListManagementRequested: "ListManagementRequested", ShowChangesRequested: "ShowChangesRequested", CustomButtonClick: "CustomButtonClick" }, standalone: false, ngContentSelectors: _c1, decls: 12, vars: 34, consts: [[3, "Navigate", "EditModeChange", "BeforeSave", "SaveRequested", "BeforeCancel", "CancelRequested", "BeforeDelete", "DeleteRequested", "FavoriteToggled", "BeforeHistoryView", "HistoryRequested", "BeforeListManagement", "ListManagementRequested", "ShowChangesRequested", "CustomButtonClick", "FilterChange", "ExpandAllRequested", "CollapseAllRequested", "ShowEmptyFieldsChange", "WidthModeChange", "ResetSectionOrderRequested", "ManageSectionsRequested", "Record", "EditMode", "UserCanEdit", "UserCanDelete", "IsFavorite", "FavoriteInitDone", "IsDirty", "DirtyFieldNames", "ListCount", "EntityInfo", "Config", "IsSaving", "VisibleSectionCount", "TotalSectionCount", "ExpandedSectionCount", "SearchFilter", "ShowEmptyFields", "WidthMode", "HasCustomSectionOrder"], [1, "mj-forms-scroll-area"], [1, "mj-forms-panels-container"], [1, "mj-forms-layout-row"], [1, "mj-forms-all-panels"], [1, "mj-forms-empty-search-state"], [3, "Navigate", "Record", "EditMode", "Collapsed"], [3, "record"], [3, "visible", "config"], [3, "SectionOrderChange", "ResetRequested", "Closed", "Sections", "SectionOrder", "Visible"], [1, "mj-forms-empty-search-icon"], [1, "fa-solid", "fa-magnifying-glass"], [1, "mj-forms-empty-search-title"], [1, "mj-forms-empty-search-message"], ["href", "#", 1, "mj-forms-empty-search-link", 3, "click"], [3, "dialogClosed", "record"], [3, "complete", "cancel", "visible", "config"]], template: function MjRecordFormContainerComponent_Template(rf, ctx) { if (rf & 1) {
691
+ } }, viewQuery: function MjRecordFormContainerComponent_Query(rf, ctx) { if (rf & 1) {
692
+ i0.ɵɵviewQuery(RecordChangesComponent, 5);
693
+ } if (rf & 2) {
694
+ let _t;
695
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.recordChangesDrawer = _t.first);
696
+ } }, inputs: { Record: "Record", FormComponent: "FormComponent", EntityInfo: "EntityInfo", EditMode: "EditMode", UserCanEdit: "UserCanEdit", UserCanDelete: "UserCanDelete", IsFavorite: "IsFavorite", FavoriteInitDone: "FavoriteInitDone", IsDirty: "IsDirty", DirtyFieldNames: "DirtyFieldNames", ListCount: "ListCount", IsSaving: "IsSaving", ToolbarConfig: "ToolbarConfig", WidthMode: "WidthMode" }, outputs: { Navigate: "Navigate", EditModeChange: "EditModeChange", BeforeSave: "BeforeSave", SaveRequested: "SaveRequested", BeforeCancel: "BeforeCancel", CancelRequested: "CancelRequested", BeforeDelete: "BeforeDelete", DeleteRequested: "DeleteRequested", FavoriteToggled: "FavoriteToggled", BeforeHistoryView: "BeforeHistoryView", HistoryRequested: "HistoryRequested", BeforeListManagement: "BeforeListManagement", ListManagementRequested: "ListManagementRequested", ShowChangesRequested: "ShowChangesRequested", CustomButtonClick: "CustomButtonClick" }, standalone: false, ngContentSelectors: _c1, decls: 13, vars: 37, consts: [[3, "Navigate", "EditModeChange", "BeforeSave", "SaveRequested", "BeforeCancel", "CancelRequested", "BeforeDelete", "DeleteRequested", "FavoriteToggled", "BeforeHistoryView", "HistoryRequested", "BeforeListManagement", "ListManagementRequested", "ShowChangesRequested", "CustomButtonClick", "FilterChange", "ExpandAllRequested", "CollapseAllRequested", "ShowEmptyFieldsChange", "WidthModeChange", "ResetSectionOrderRequested", "ManageSectionsRequested", "TagsPanelToggled", "Record", "EditMode", "UserCanEdit", "UserCanDelete", "IsFavorite", "FavoriteInitDone", "IsDirty", "DirtyFieldNames", "ListCount", "TagCount", "VersionCount", "EntityInfo", "Config", "IsSaving", "VisibleSectionCount", "TotalSectionCount", "ExpandedSectionCount", "SearchFilter", "ShowEmptyFields", "WidthMode", "HasCustomSectionOrder"], [1, "mj-forms-scroll-area"], [1, "mj-forms-panels-container"], [1, "mj-forms-layout-row"], [1, "mj-forms-all-panels"], [1, "mj-forms-empty-search-state"], [3, "Navigate", "Record", "EditMode", "Collapsed"], [3, "record", "AllowRestore"], [3, "Record", "WidthPx"], [3, "visible", "config"], [3, "SectionOrderChange", "ResetRequested", "Closed", "Sections", "SectionOrder", "Visible"], [1, "mj-forms-empty-search-icon"], [1, "fa-solid", "fa-magnifying-glass"], [1, "mj-forms-empty-search-title"], [1, "mj-forms-empty-search-message"], ["href", "#", 1, "mj-forms-empty-search-link", 3, "click"], [3, "RestoreRequested", "dialogClosed", "record", "AllowRestore"], [3, "PanelClosed", "TagCountChanged", "RecordNavigate", "WidthChanged", "Record", "WidthPx"], [3, "complete", "cancel", "visible", "config"]], template: function MjRecordFormContainerComponent_Template(rf, ctx) { if (rf & 1) {
502
697
  i0.ɵɵprojectionDef(_c0);
503
698
  i0.ɵɵprojection(0);
504
699
  i0.ɵɵelementStart(1, "mj-form-toolbar", 0);
505
- i0.ɵɵlistener("Navigate", function MjRecordFormContainerComponent_Template_mj_form_toolbar_Navigate_1_listener($event) { return ctx.OnNavigate($event); })("EditModeChange", function MjRecordFormContainerComponent_Template_mj_form_toolbar_EditModeChange_1_listener($event) { return ctx.OnEditModeChange($event); })("BeforeSave", function MjRecordFormContainerComponent_Template_mj_form_toolbar_BeforeSave_1_listener($event) { return ctx.BeforeSave.emit($event); })("SaveRequested", function MjRecordFormContainerComponent_Template_mj_form_toolbar_SaveRequested_1_listener() { return ctx.OnSaveRequested(); })("BeforeCancel", function MjRecordFormContainerComponent_Template_mj_form_toolbar_BeforeCancel_1_listener($event) { return ctx.BeforeCancel.emit($event); })("CancelRequested", function MjRecordFormContainerComponent_Template_mj_form_toolbar_CancelRequested_1_listener() { return ctx.OnCancelRequested(); })("BeforeDelete", function MjRecordFormContainerComponent_Template_mj_form_toolbar_BeforeDelete_1_listener($event) { return ctx.BeforeDelete.emit($event); })("DeleteRequested", function MjRecordFormContainerComponent_Template_mj_form_toolbar_DeleteRequested_1_listener() { return ctx.OnDeleteRequested(); })("FavoriteToggled", function MjRecordFormContainerComponent_Template_mj_form_toolbar_FavoriteToggled_1_listener() { return ctx.OnFavoriteToggled(); })("BeforeHistoryView", function MjRecordFormContainerComponent_Template_mj_form_toolbar_BeforeHistoryView_1_listener($event) { return ctx.BeforeHistoryView.emit($event); })("HistoryRequested", function MjRecordFormContainerComponent_Template_mj_form_toolbar_HistoryRequested_1_listener() { return ctx.OnHistoryRequested(); })("BeforeListManagement", function MjRecordFormContainerComponent_Template_mj_form_toolbar_BeforeListManagement_1_listener($event) { return ctx.BeforeListManagement.emit($event); })("ListManagementRequested", function MjRecordFormContainerComponent_Template_mj_form_toolbar_ListManagementRequested_1_listener() { return ctx.OnListManagementRequested(); })("ShowChangesRequested", function MjRecordFormContainerComponent_Template_mj_form_toolbar_ShowChangesRequested_1_listener() { return ctx.OnShowChangesRequested(); })("CustomButtonClick", function MjRecordFormContainerComponent_Template_mj_form_toolbar_CustomButtonClick_1_listener($event) { return ctx.CustomButtonClick.emit($event); })("FilterChange", function MjRecordFormContainerComponent_Template_mj_form_toolbar_FilterChange_1_listener($event) { return ctx.OnFilterChange($event); })("ExpandAllRequested", function MjRecordFormContainerComponent_Template_mj_form_toolbar_ExpandAllRequested_1_listener() { return ctx.OnExpandAll(); })("CollapseAllRequested", function MjRecordFormContainerComponent_Template_mj_form_toolbar_CollapseAllRequested_1_listener() { return ctx.OnCollapseAll(); })("ShowEmptyFieldsChange", function MjRecordFormContainerComponent_Template_mj_form_toolbar_ShowEmptyFieldsChange_1_listener($event) { return ctx.OnShowEmptyFieldsChange($event); })("WidthModeChange", function MjRecordFormContainerComponent_Template_mj_form_toolbar_WidthModeChange_1_listener($event) { return ctx.OnWidthModeChange($event); })("ResetSectionOrderRequested", function MjRecordFormContainerComponent_Template_mj_form_toolbar_ResetSectionOrderRequested_1_listener() { return ctx.OnResetSectionOrder(); })("ManageSectionsRequested", function MjRecordFormContainerComponent_Template_mj_form_toolbar_ManageSectionsRequested_1_listener() { return ctx.OnManageSections(); });
700
+ i0.ɵɵlistener("Navigate", function MjRecordFormContainerComponent_Template_mj_form_toolbar_Navigate_1_listener($event) { return ctx.OnNavigate($event); })("EditModeChange", function MjRecordFormContainerComponent_Template_mj_form_toolbar_EditModeChange_1_listener($event) { return ctx.OnEditModeChange($event); })("BeforeSave", function MjRecordFormContainerComponent_Template_mj_form_toolbar_BeforeSave_1_listener($event) { return ctx.BeforeSave.emit($event); })("SaveRequested", function MjRecordFormContainerComponent_Template_mj_form_toolbar_SaveRequested_1_listener() { return ctx.OnSaveRequested(); })("BeforeCancel", function MjRecordFormContainerComponent_Template_mj_form_toolbar_BeforeCancel_1_listener($event) { return ctx.BeforeCancel.emit($event); })("CancelRequested", function MjRecordFormContainerComponent_Template_mj_form_toolbar_CancelRequested_1_listener() { return ctx.OnCancelRequested(); })("BeforeDelete", function MjRecordFormContainerComponent_Template_mj_form_toolbar_BeforeDelete_1_listener($event) { return ctx.BeforeDelete.emit($event); })("DeleteRequested", function MjRecordFormContainerComponent_Template_mj_form_toolbar_DeleteRequested_1_listener() { return ctx.OnDeleteRequested(); })("FavoriteToggled", function MjRecordFormContainerComponent_Template_mj_form_toolbar_FavoriteToggled_1_listener() { return ctx.OnFavoriteToggled(); })("BeforeHistoryView", function MjRecordFormContainerComponent_Template_mj_form_toolbar_BeforeHistoryView_1_listener($event) { return ctx.BeforeHistoryView.emit($event); })("HistoryRequested", function MjRecordFormContainerComponent_Template_mj_form_toolbar_HistoryRequested_1_listener() { return ctx.OnHistoryRequested(); })("BeforeListManagement", function MjRecordFormContainerComponent_Template_mj_form_toolbar_BeforeListManagement_1_listener($event) { return ctx.BeforeListManagement.emit($event); })("ListManagementRequested", function MjRecordFormContainerComponent_Template_mj_form_toolbar_ListManagementRequested_1_listener() { return ctx.OnListManagementRequested(); })("ShowChangesRequested", function MjRecordFormContainerComponent_Template_mj_form_toolbar_ShowChangesRequested_1_listener() { return ctx.OnShowChangesRequested(); })("CustomButtonClick", function MjRecordFormContainerComponent_Template_mj_form_toolbar_CustomButtonClick_1_listener($event) { return ctx.CustomButtonClick.emit($event); })("FilterChange", function MjRecordFormContainerComponent_Template_mj_form_toolbar_FilterChange_1_listener($event) { return ctx.OnFilterChange($event); })("ExpandAllRequested", function MjRecordFormContainerComponent_Template_mj_form_toolbar_ExpandAllRequested_1_listener() { return ctx.OnExpandAll(); })("CollapseAllRequested", function MjRecordFormContainerComponent_Template_mj_form_toolbar_CollapseAllRequested_1_listener() { return ctx.OnCollapseAll(); })("ShowEmptyFieldsChange", function MjRecordFormContainerComponent_Template_mj_form_toolbar_ShowEmptyFieldsChange_1_listener($event) { return ctx.OnShowEmptyFieldsChange($event); })("WidthModeChange", function MjRecordFormContainerComponent_Template_mj_form_toolbar_WidthModeChange_1_listener($event) { return ctx.OnWidthModeChange($event); })("ResetSectionOrderRequested", function MjRecordFormContainerComponent_Template_mj_form_toolbar_ResetSectionOrderRequested_1_listener() { return ctx.OnResetSectionOrder(); })("ManageSectionsRequested", function MjRecordFormContainerComponent_Template_mj_form_toolbar_ManageSectionsRequested_1_listener() { return ctx.OnManageSections(); })("TagsPanelToggled", function MjRecordFormContainerComponent_Template_mj_form_toolbar_TagsPanelToggled_1_listener() { return ctx.OnTagsPanelToggled(); });
506
701
  i0.ɵɵelementEnd();
507
702
  i0.ɵɵelementStart(2, "div", 1)(3, "div", 2)(4, "div", 3)(5, "div", 4);
508
703
  i0.ɵɵprojection(6, 1);
@@ -511,14 +706,15 @@ export class MjRecordFormContainerComponent {
511
706
  i0.ɵɵelementStart(8, "mj-isa-related-panel", 6);
512
707
  i0.ɵɵlistener("Navigate", function MjRecordFormContainerComponent_Template_mj_isa_related_panel_Navigate_8_listener($event) { return ctx.OnNavigate($event); });
513
708
  i0.ɵɵelementEnd()()()();
514
- i0.ɵɵconditionalCreate(9, MjRecordFormContainerComponent_Conditional_9_Template, 1, 1, "mj-record-changes", 7);
515
- i0.ɵɵconditionalCreate(10, MjRecordFormContainerComponent_Conditional_10_Template, 1, 8, "mj-list-management-dialog", 8);
516
- i0.ɵɵelementStart(11, "mj-section-manager", 9);
517
- i0.ɵɵlistener("SectionOrderChange", function MjRecordFormContainerComponent_Template_mj_section_manager_SectionOrderChange_11_listener($event) { return ctx.OnSectionOrderChange($event); })("ResetRequested", function MjRecordFormContainerComponent_Template_mj_section_manager_ResetRequested_11_listener() { return ctx.OnSectionManagerReset(); })("Closed", function MjRecordFormContainerComponent_Template_mj_section_manager_Closed_11_listener() { return ctx.OnSectionManagerClosed(); });
709
+ i0.ɵɵconditionalCreate(9, MjRecordFormContainerComponent_Conditional_9_Template, 1, 2, "mj-record-changes", 7);
710
+ i0.ɵɵconditionalCreate(10, MjRecordFormContainerComponent_Conditional_10_Template, 1, 2, "mj-record-tags", 8);
711
+ i0.ɵɵconditionalCreate(11, MjRecordFormContainerComponent_Conditional_11_Template, 1, 8, "mj-list-management-dialog", 9);
712
+ i0.ɵɵelementStart(12, "mj-section-manager", 10);
713
+ i0.ɵɵlistener("SectionOrderChange", function MjRecordFormContainerComponent_Template_mj_section_manager_SectionOrderChange_12_listener($event) { return ctx.OnSectionOrderChange($event); })("ResetRequested", function MjRecordFormContainerComponent_Template_mj_section_manager_ResetRequested_12_listener() { return ctx.OnSectionManagerReset(); })("Closed", function MjRecordFormContainerComponent_Template_mj_section_manager_Closed_12_listener() { return ctx.OnSectionManagerClosed(); });
518
714
  i0.ɵɵelementEnd();
519
715
  } if (rf & 2) {
520
716
  i0.ɵɵadvance();
521
- i0.ɵɵproperty("Record", ctx.EffectiveRecord)("EditMode", ctx.EffectiveEditMode)("UserCanEdit", ctx.EffectiveUserCanEdit)("UserCanDelete", ctx.EffectiveUserCanDelete)("IsFavorite", ctx.EffectiveIsFavorite)("FavoriteInitDone", ctx.EffectiveFavoriteInitDone)("IsDirty", ctx.EffectiveIsDirty)("DirtyFieldNames", ctx.EffectiveDirtyFieldNames)("ListCount", ctx.ListCount)("EntityInfo", ctx.EffectiveEntityInfo)("Config", ctx.ToolbarConfig)("IsSaving", ctx.EffectiveIsSaving)("VisibleSectionCount", ctx.VisibleSectionCount)("TotalSectionCount", ctx.TotalSectionCount)("ExpandedSectionCount", ctx.ExpandedSectionCount)("SearchFilter", ctx.EffectiveSearchFilter)("ShowEmptyFields", ctx.EffectiveShowEmptyFields)("WidthMode", ctx.EffectiveWidthMode)("HasCustomSectionOrder", ctx.EffectiveHasCustomSectionOrder);
717
+ i0.ɵɵproperty("Record", ctx.EffectiveRecord)("EditMode", ctx.EffectiveEditMode)("UserCanEdit", ctx.EffectiveUserCanEdit)("UserCanDelete", ctx.EffectiveUserCanDelete)("IsFavorite", ctx.EffectiveIsFavorite)("FavoriteInitDone", ctx.EffectiveFavoriteInitDone)("IsDirty", ctx.EffectiveIsDirty)("DirtyFieldNames", ctx.EffectiveDirtyFieldNames)("ListCount", ctx.ListCount)("TagCount", ctx.TagCount)("VersionCount", ctx.VersionCount)("EntityInfo", ctx.EffectiveEntityInfo)("Config", ctx.ToolbarConfig)("IsSaving", ctx.EffectiveIsSaving)("VisibleSectionCount", ctx.VisibleSectionCount)("TotalSectionCount", ctx.TotalSectionCount)("ExpandedSectionCount", ctx.ExpandedSectionCount)("SearchFilter", ctx.EffectiveSearchFilter)("ShowEmptyFields", ctx.EffectiveShowEmptyFields)("WidthMode", ctx.EffectiveWidthMode)("HasCustomSectionOrder", ctx.EffectiveHasCustomSectionOrder);
522
718
  i0.ɵɵadvance(2);
523
719
  i0.ɵɵclassProp("mj-forms-panels--full-width", ctx.EffectiveWidthMode === "full-width")("mj-forms-panels--edit-mode", ctx.EffectiveEditMode)("mj-forms-panels--has-isa-panel", ctx.HasIsaRelatedItems);
524
720
  i0.ɵɵadvance(4);
@@ -528,15 +724,20 @@ export class MjRecordFormContainerComponent {
528
724
  i0.ɵɵadvance();
529
725
  i0.ɵɵconditional(ctx.ShowRecordChanges && ctx.EffectiveRecord ? 9 : -1);
530
726
  i0.ɵɵadvance();
531
- i0.ɵɵconditional(ctx.ShowListManagement && ctx.EffectiveRecord ? 10 : -1);
727
+ i0.ɵɵconditional(ctx.ShowTagsPanel && ctx.EffectiveRecord ? 10 : -1);
728
+ i0.ɵɵadvance();
729
+ i0.ɵɵconditional(ctx.ShowListManagement && ctx.EffectiveRecord ? 11 : -1);
532
730
  i0.ɵɵadvance();
533
731
  i0.ɵɵproperty("Sections", ctx.SectionManagerItems)("SectionOrder", ctx.SectionManagerOrder)("Visible", ctx.ShowSectionManager);
534
- } }, dependencies: [i1.RecordChangesComponent, i2.ListManagementDialogComponent, i3.MjFormToolbarComponent, i4.MjSectionManagerComponent, i5.MjIsaRelatedPanelComponent], styles: ["/* ============================================\n RECORD FORM CONTAINER \u2014 uses global --mj-* design tokens\n Top-level wrapper: toolbar + scrollable content\n ============================================ */\nmj-record-form-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n position: relative;\n overflow: hidden;\n}\n\n/* ViewEncapsulation.None fallback \u2014 ensure the element itself constrains overflow */\nmj-record-form-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n position: relative;\n overflow: hidden;\n}\n\n/* ============================================\n SCROLL AREA (full-width so mouse wheel works anywhere)\n ============================================ */\n.mj-forms-scroll-area {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n background: var(--mj-bg-page);\n}\n\n/* ============================================\n PANELS CONTAINER (centered content within scroll area)\n ============================================ */\n.mj-forms-panels-container {\n padding: 24px 32px 48px;\n max-width: 920px;\n margin: 0 auto;\n width: 100%;\n box-sizing: border-box;\n}\n\n/* Widen max-width when ISA side panel is present */\n.mj-forms-panels--has-isa-panel {\n max-width: 1240px;\n}\n\n.mj-forms-panels--full-width {\n max-width: none;\n padding-left: 24px;\n padding-right: 24px;\n}\n\n/* Flex row layout: form panels + optional ISA side panel */\n.mj-forms-layout-row {\n display: flex;\n gap: 20px;\n align-items: flex-start;\n}\n\n/* All panels in a single flex container \u2014 CSS order drives sequencing */\n.mj-forms-all-panels {\n display: flex;\n flex-direction: column;\n gap: 16px;\n flex: 1;\n min-width: 0;\n}\n\n/* Hide related entity panels in edit mode (variant host class on mj-collapsible-panel) */\n.mj-forms-panels--edit-mode .mj-panel--related-entity {\n display: none;\n}\n\n/* ============================================\n EMPTY SEARCH STATE\n ============================================ */\n.mj-forms-empty-search-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 80px 24px;\n text-align: center;\n min-height: 400px;\n}\n\n.mj-forms-empty-search-icon {\n width: 80px;\n height: 80px;\n border-radius: var(--mj-radius-full);\n background: var(--mj-bg-surface-sunken);\n display: flex;\n align-items: center;\n justify-content: center;\n margin-bottom: 24px;\n}\n\n.mj-forms-empty-search-icon i {\n font-size: 32px;\n color: var(--mj-text-muted);\n}\n\n.mj-forms-empty-search-title {\n font-size: var(--mj-text-xl);\n font-weight: var(--mj-font-semibold);\n color: var(--mj-text-primary);\n margin: 0 0 12px 0;\n}\n\n.mj-forms-empty-search-message {\n font-size: var(--mj-text-sm);\n color: var(--mj-text-secondary);\n line-height: 1.6;\n max-width: 400px;\n margin: 0;\n}\n\n.mj-forms-empty-search-message strong {\n color: var(--mj-text-primary);\n font-weight: var(--mj-font-semibold);\n}\n\n.mj-forms-empty-search-link {\n color: var(--mj-brand-primary);\n text-decoration: none;\n font-weight: var(--mj-font-medium);\n}\n\n.mj-forms-empty-search-link:hover {\n text-decoration: underline;\n}\n\n/* ============================================\n RESPONSIVE\n ============================================ */\n@media (max-width: 768px) {\n .mj-forms-panels-container {\n padding: 16px 12px 32px;\n }\n}\n"], encapsulation: 2, changeDetection: 0 });
732
+ } }, dependencies: [i1.RecordChangesComponent, i2.ListManagementDialogComponent, i3.RecordTagsComponent, i4.MjFormToolbarComponent, i5.MjSectionManagerComponent, i6.MjIsaRelatedPanelComponent], styles: ["/* ============================================\n RECORD FORM CONTAINER \u2014 uses global --mj-* design tokens\n Top-level wrapper: toolbar + scrollable content\n ============================================ */\nmj-record-form-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n position: relative;\n overflow: hidden;\n}\n\n/* ViewEncapsulation.None fallback \u2014 ensure the element itself constrains overflow */\nmj-record-form-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n position: relative;\n overflow: hidden;\n}\n\n/* ============================================\n SCROLL AREA (full-width so mouse wheel works anywhere)\n ============================================ */\n.mj-forms-scroll-area {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n background: var(--mj-bg-page);\n}\n\n/* ============================================\n PANELS CONTAINER (centered content within scroll area)\n ============================================ */\n.mj-forms-panels-container {\n padding: 24px 32px 48px;\n max-width: 920px;\n margin: 0 auto;\n width: 100%;\n box-sizing: border-box;\n}\n\n/* Widen max-width when ISA side panel is present */\n.mj-forms-panels--has-isa-panel {\n max-width: 1240px;\n}\n\n.mj-forms-panels--full-width {\n max-width: none;\n padding-left: 24px;\n padding-right: 24px;\n}\n\n/* Flex row layout: form panels + optional ISA side panel */\n.mj-forms-layout-row {\n display: flex;\n gap: 20px;\n align-items: flex-start;\n}\n\n/* All panels in a single flex container \u2014 CSS order drives sequencing */\n.mj-forms-all-panels {\n display: flex;\n flex-direction: column;\n gap: 16px;\n flex: 1;\n min-width: 0;\n}\n\n/* Hide related entity panels in edit mode (variant host class on mj-collapsible-panel) */\n.mj-forms-panels--edit-mode .mj-panel--related-entity {\n display: none;\n}\n\n/* ============================================\n EMPTY SEARCH STATE\n ============================================ */\n.mj-forms-empty-search-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 80px 24px;\n text-align: center;\n min-height: 400px;\n}\n\n.mj-forms-empty-search-icon {\n width: 80px;\n height: 80px;\n border-radius: var(--mj-radius-full);\n background: var(--mj-bg-surface-sunken);\n display: flex;\n align-items: center;\n justify-content: center;\n margin-bottom: 24px;\n}\n\n.mj-forms-empty-search-icon i {\n font-size: 32px;\n color: var(--mj-text-muted);\n}\n\n.mj-forms-empty-search-title {\n font-size: var(--mj-text-xl);\n font-weight: var(--mj-font-semibold);\n color: var(--mj-text-primary);\n margin: 0 0 12px 0;\n}\n\n.mj-forms-empty-search-message {\n font-size: var(--mj-text-sm);\n color: var(--mj-text-secondary);\n line-height: 1.6;\n max-width: 400px;\n margin: 0;\n}\n\n.mj-forms-empty-search-message strong {\n color: var(--mj-text-primary);\n font-weight: var(--mj-font-semibold);\n}\n\n.mj-forms-empty-search-link {\n color: var(--mj-brand-primary);\n text-decoration: none;\n font-weight: var(--mj-font-medium);\n}\n\n.mj-forms-empty-search-link:hover {\n text-decoration: underline;\n}\n\n/* ============================================\n RESPONSIVE\n ============================================ */\n@media (max-width: 768px) {\n .mj-forms-panels-container {\n padding: 16px 12px 32px;\n }\n}\n"], encapsulation: 2, changeDetection: 0 });
535
733
  }
536
734
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MjRecordFormContainerComponent, [{
537
735
  type: Component,
538
- args: [{ standalone: false, selector: 'mj-record-form-container', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<!-- ============================================\n BEFORE-TOOLBAR SLOT\n ============================================ -->\n<ng-content select=\"[before-toolbar]\"></ng-content>\n\n<!-- ============================================\n TOOLBAR (bridges FormComponent state \u2192 toolbar inputs)\n ============================================ -->\n<mj-form-toolbar\n [Record]=\"EffectiveRecord\"\n [EditMode]=\"EffectiveEditMode\"\n [UserCanEdit]=\"EffectiveUserCanEdit\"\n [UserCanDelete]=\"EffectiveUserCanDelete\"\n [IsFavorite]=\"EffectiveIsFavorite\"\n [FavoriteInitDone]=\"EffectiveFavoriteInitDone\"\n [IsDirty]=\"EffectiveIsDirty\"\n [DirtyFieldNames]=\"EffectiveDirtyFieldNames\"\n [ListCount]=\"ListCount\"\n [EntityInfo]=\"EffectiveEntityInfo\"\n [Config]=\"ToolbarConfig\"\n [IsSaving]=\"EffectiveIsSaving\"\n [VisibleSectionCount]=\"VisibleSectionCount\"\n [TotalSectionCount]=\"TotalSectionCount\"\n [ExpandedSectionCount]=\"ExpandedSectionCount\"\n [SearchFilter]=\"EffectiveSearchFilter\"\n [ShowEmptyFields]=\"EffectiveShowEmptyFields\"\n [WidthMode]=\"EffectiveWidthMode\"\n [HasCustomSectionOrder]=\"EffectiveHasCustomSectionOrder\"\n (Navigate)=\"OnNavigate($event)\"\n (EditModeChange)=\"OnEditModeChange($event)\"\n (BeforeSave)=\"BeforeSave.emit($event)\"\n (SaveRequested)=\"OnSaveRequested()\"\n (BeforeCancel)=\"BeforeCancel.emit($event)\"\n (CancelRequested)=\"OnCancelRequested()\"\n (BeforeDelete)=\"BeforeDelete.emit($event)\"\n (DeleteRequested)=\"OnDeleteRequested()\"\n (FavoriteToggled)=\"OnFavoriteToggled()\"\n (BeforeHistoryView)=\"BeforeHistoryView.emit($event)\"\n (HistoryRequested)=\"OnHistoryRequested()\"\n (BeforeListManagement)=\"BeforeListManagement.emit($event)\"\n (ListManagementRequested)=\"OnListManagementRequested()\"\n (ShowChangesRequested)=\"OnShowChangesRequested()\"\n (CustomButtonClick)=\"CustomButtonClick.emit($event)\"\n (FilterChange)=\"OnFilterChange($event)\"\n (ExpandAllRequested)=\"OnExpandAll()\"\n (CollapseAllRequested)=\"OnCollapseAll()\"\n (ShowEmptyFieldsChange)=\"OnShowEmptyFieldsChange($event)\"\n (WidthModeChange)=\"OnWidthModeChange($event)\"\n (ResetSectionOrderRequested)=\"OnResetSectionOrder()\"\n (ManageSectionsRequested)=\"OnManageSections()\">\n</mj-form-toolbar>\n\n<!-- ============================================\n SCROLL AREA (full-width so mouse wheel works anywhere)\n ============================================ -->\n<div class=\"mj-forms-scroll-area\">\n <div class=\"mj-forms-panels-container\"\n [class.mj-forms-panels--full-width]=\"EffectiveWidthMode === 'full-width'\"\n [class.mj-forms-panels--edit-mode]=\"EffectiveEditMode\"\n [class.mj-forms-panels--has-isa-panel]=\"HasIsaRelatedItems\">\n <!-- Flex row: form panels on left, ISA side panel on right -->\n <div class=\"mj-forms-layout-row\">\n <!-- All panels in a single flex container \u2014 CSS order drives sequencing -->\n <div class=\"mj-forms-all-panels\">\n <ng-content></ng-content>\n\n <!-- Empty state when no sections match search -->\n @if (EffectiveSearchFilter && VisibleSectionCount === 0) {\n <div class=\"mj-forms-empty-search-state\">\n <div class=\"mj-forms-empty-search-icon\">\n <i class=\"fa-solid fa-magnifying-glass\"></i>\n </div>\n <h3 class=\"mj-forms-empty-search-title\">No sections found</h3>\n <p class=\"mj-forms-empty-search-message\">\n No sections match \"<strong>{{ EffectiveSearchFilter }}</strong>\".\n <br>Try a different search term or <a href=\"#\" (click)=\"OnFilterChange(''); $event.preventDefault()\" class=\"mj-forms-empty-search-link\">clear the search</a>.\n </p>\n </div>\n }\n </div>\n\n <!-- IS-A Related Records Side Panel -->\n <mj-isa-related-panel\n [Record]=\"EffectiveRecord\"\n [EditMode]=\"EffectiveEditMode\"\n [Collapsed]=\"EffectiveWidthMode === 'full-width'\"\n (Navigate)=\"OnNavigate($event)\">\n </mj-isa-related-panel>\n </div>\n </div>\n</div>\n\n<!-- ============================================\n RECORD CHANGES DRAWER (shown when history button clicked)\n ============================================ -->\n@if (ShowRecordChanges && EffectiveRecord) {\n <mj-record-changes\n [record]=\"EffectiveRecord\"\n (dialogClosed)=\"OnRecordChangesClosed()\">\n </mj-record-changes>\n}\n\n<!-- ============================================\n LIST MANAGEMENT DIALOG (shown when lists button clicked)\n ============================================ -->\n@if (ShowListManagement && EffectiveRecord) {\n <mj-list-management-dialog\n [visible]=\"ShowListManagement\"\n [config]=\"{\n mode: 'manage',\n entityId: EffectiveRecord.EntityInfo.ID,\n entityName: EffectiveRecord.EntityInfo.Name,\n recordIds: [EffectiveRecord.PrimaryKey.Values()[0]],\n allowCreate: true\n }\"\n (complete)=\"OnListManagementClosed()\"\n (cancel)=\"OnListManagementClosed()\">\n </mj-list-management-dialog>\n}\n\n<!-- ============================================\n SECTION MANAGER DRAWER (shown when manage-sections button clicked)\n ============================================ -->\n<mj-section-manager\n [Sections]=\"SectionManagerItems\"\n [SectionOrder]=\"SectionManagerOrder\"\n [Visible]=\"ShowSectionManager\"\n (SectionOrderChange)=\"OnSectionOrderChange($event)\"\n (ResetRequested)=\"OnSectionManagerReset()\"\n (Closed)=\"OnSectionManagerClosed()\">\n</mj-section-manager>\n", styles: ["/* ============================================\n RECORD FORM CONTAINER \u2014 uses global --mj-* design tokens\n Top-level wrapper: toolbar + scrollable content\n ============================================ */\nmj-record-form-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n position: relative;\n overflow: hidden;\n}\n\n/* ViewEncapsulation.None fallback \u2014 ensure the element itself constrains overflow */\nmj-record-form-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n position: relative;\n overflow: hidden;\n}\n\n/* ============================================\n SCROLL AREA (full-width so mouse wheel works anywhere)\n ============================================ */\n.mj-forms-scroll-area {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n background: var(--mj-bg-page);\n}\n\n/* ============================================\n PANELS CONTAINER (centered content within scroll area)\n ============================================ */\n.mj-forms-panels-container {\n padding: 24px 32px 48px;\n max-width: 920px;\n margin: 0 auto;\n width: 100%;\n box-sizing: border-box;\n}\n\n/* Widen max-width when ISA side panel is present */\n.mj-forms-panels--has-isa-panel {\n max-width: 1240px;\n}\n\n.mj-forms-panels--full-width {\n max-width: none;\n padding-left: 24px;\n padding-right: 24px;\n}\n\n/* Flex row layout: form panels + optional ISA side panel */\n.mj-forms-layout-row {\n display: flex;\n gap: 20px;\n align-items: flex-start;\n}\n\n/* All panels in a single flex container \u2014 CSS order drives sequencing */\n.mj-forms-all-panels {\n display: flex;\n flex-direction: column;\n gap: 16px;\n flex: 1;\n min-width: 0;\n}\n\n/* Hide related entity panels in edit mode (variant host class on mj-collapsible-panel) */\n.mj-forms-panels--edit-mode .mj-panel--related-entity {\n display: none;\n}\n\n/* ============================================\n EMPTY SEARCH STATE\n ============================================ */\n.mj-forms-empty-search-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 80px 24px;\n text-align: center;\n min-height: 400px;\n}\n\n.mj-forms-empty-search-icon {\n width: 80px;\n height: 80px;\n border-radius: var(--mj-radius-full);\n background: var(--mj-bg-surface-sunken);\n display: flex;\n align-items: center;\n justify-content: center;\n margin-bottom: 24px;\n}\n\n.mj-forms-empty-search-icon i {\n font-size: 32px;\n color: var(--mj-text-muted);\n}\n\n.mj-forms-empty-search-title {\n font-size: var(--mj-text-xl);\n font-weight: var(--mj-font-semibold);\n color: var(--mj-text-primary);\n margin: 0 0 12px 0;\n}\n\n.mj-forms-empty-search-message {\n font-size: var(--mj-text-sm);\n color: var(--mj-text-secondary);\n line-height: 1.6;\n max-width: 400px;\n margin: 0;\n}\n\n.mj-forms-empty-search-message strong {\n color: var(--mj-text-primary);\n font-weight: var(--mj-font-semibold);\n}\n\n.mj-forms-empty-search-link {\n color: var(--mj-brand-primary);\n text-decoration: none;\n font-weight: var(--mj-font-medium);\n}\n\n.mj-forms-empty-search-link:hover {\n text-decoration: underline;\n}\n\n/* ============================================\n RESPONSIVE\n ============================================ */\n@media (max-width: 768px) {\n .mj-forms-panels-container {\n padding: 16px 12px 32px;\n }\n}\n"] }]
539
- }], null, { Record: [{
736
+ args: [{ standalone: false, selector: 'mj-record-form-container', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<!-- ============================================\n BEFORE-TOOLBAR SLOT\n ============================================ -->\n<ng-content select=\"[before-toolbar]\"></ng-content>\n\n<!-- ============================================\n TOOLBAR (bridges FormComponent state \u2192 toolbar inputs)\n ============================================ -->\n<mj-form-toolbar\n [Record]=\"EffectiveRecord\"\n [EditMode]=\"EffectiveEditMode\"\n [UserCanEdit]=\"EffectiveUserCanEdit\"\n [UserCanDelete]=\"EffectiveUserCanDelete\"\n [IsFavorite]=\"EffectiveIsFavorite\"\n [FavoriteInitDone]=\"EffectiveFavoriteInitDone\"\n [IsDirty]=\"EffectiveIsDirty\"\n [DirtyFieldNames]=\"EffectiveDirtyFieldNames\"\n [ListCount]=\"ListCount\"\n [TagCount]=\"TagCount\"\n [VersionCount]=\"VersionCount\"\n [EntityInfo]=\"EffectiveEntityInfo\"\n [Config]=\"ToolbarConfig\"\n [IsSaving]=\"EffectiveIsSaving\"\n [VisibleSectionCount]=\"VisibleSectionCount\"\n [TotalSectionCount]=\"TotalSectionCount\"\n [ExpandedSectionCount]=\"ExpandedSectionCount\"\n [SearchFilter]=\"EffectiveSearchFilter\"\n [ShowEmptyFields]=\"EffectiveShowEmptyFields\"\n [WidthMode]=\"EffectiveWidthMode\"\n [HasCustomSectionOrder]=\"EffectiveHasCustomSectionOrder\"\n (Navigate)=\"OnNavigate($event)\"\n (EditModeChange)=\"OnEditModeChange($event)\"\n (BeforeSave)=\"BeforeSave.emit($event)\"\n (SaveRequested)=\"OnSaveRequested()\"\n (BeforeCancel)=\"BeforeCancel.emit($event)\"\n (CancelRequested)=\"OnCancelRequested()\"\n (BeforeDelete)=\"BeforeDelete.emit($event)\"\n (DeleteRequested)=\"OnDeleteRequested()\"\n (FavoriteToggled)=\"OnFavoriteToggled()\"\n (BeforeHistoryView)=\"BeforeHistoryView.emit($event)\"\n (HistoryRequested)=\"OnHistoryRequested()\"\n (BeforeListManagement)=\"BeforeListManagement.emit($event)\"\n (ListManagementRequested)=\"OnListManagementRequested()\"\n (ShowChangesRequested)=\"OnShowChangesRequested()\"\n (CustomButtonClick)=\"CustomButtonClick.emit($event)\"\n (FilterChange)=\"OnFilterChange($event)\"\n (ExpandAllRequested)=\"OnExpandAll()\"\n (CollapseAllRequested)=\"OnCollapseAll()\"\n (ShowEmptyFieldsChange)=\"OnShowEmptyFieldsChange($event)\"\n (WidthModeChange)=\"OnWidthModeChange($event)\"\n (ResetSectionOrderRequested)=\"OnResetSectionOrder()\"\n (ManageSectionsRequested)=\"OnManageSections()\"\n (TagsPanelToggled)=\"OnTagsPanelToggled()\">\n</mj-form-toolbar>\n\n<!-- ============================================\n SCROLL AREA (full-width so mouse wheel works anywhere)\n ============================================ -->\n<div class=\"mj-forms-scroll-area\">\n <div class=\"mj-forms-panels-container\"\n [class.mj-forms-panels--full-width]=\"EffectiveWidthMode === 'full-width'\"\n [class.mj-forms-panels--edit-mode]=\"EffectiveEditMode\"\n [class.mj-forms-panels--has-isa-panel]=\"HasIsaRelatedItems\">\n <!-- Flex row: form panels on left, ISA side panel on right -->\n <div class=\"mj-forms-layout-row\">\n <!-- All panels in a single flex container \u2014 CSS order drives sequencing -->\n <div class=\"mj-forms-all-panels\">\n <ng-content></ng-content>\n\n <!-- Empty state when no sections match search -->\n @if (EffectiveSearchFilter && VisibleSectionCount === 0) {\n <div class=\"mj-forms-empty-search-state\">\n <div class=\"mj-forms-empty-search-icon\">\n <i class=\"fa-solid fa-magnifying-glass\"></i>\n </div>\n <h3 class=\"mj-forms-empty-search-title\">No sections found</h3>\n <p class=\"mj-forms-empty-search-message\">\n No sections match \"<strong>{{ EffectiveSearchFilter }}</strong>\".\n <br>Try a different search term or <a href=\"#\" (click)=\"OnFilterChange(''); $event.preventDefault()\" class=\"mj-forms-empty-search-link\">clear the search</a>.\n </p>\n </div>\n }\n </div>\n\n <!-- IS-A Related Records Side Panel -->\n <mj-isa-related-panel\n [Record]=\"EffectiveRecord\"\n [EditMode]=\"EffectiveEditMode\"\n [Collapsed]=\"EffectiveWidthMode === 'full-width'\"\n (Navigate)=\"OnNavigate($event)\">\n </mj-isa-related-panel>\n </div>\n </div>\n</div>\n\n<!-- ============================================\n RECORD CHANGES DRAWER (shown when history button clicked)\n ============================================ -->\n@if (ShowRecordChanges && EffectiveRecord) {\n <mj-record-changes\n [record]=\"EffectiveRecord\"\n [AllowRestore]=\"EffectiveUserCanEdit\"\n (RestoreRequested)=\"OnRestoreRequested($event)\"\n (dialogClosed)=\"OnRecordChangesClosed()\">\n </mj-record-changes>\n}\n\n<!-- ============================================\n TAGS PANEL (shown when tags button clicked)\n ============================================ -->\n@if (ShowTagsPanel && EffectiveRecord) {\n <mj-record-tags\n [Record]=\"EffectiveRecord\"\n [WidthPx]=\"TagsPanelWidth\"\n (PanelClosed)=\"OnTagsPanelClosed()\"\n (TagCountChanged)=\"OnTagCountChanged($event)\"\n (RecordNavigate)=\"OnTagsRecordNavigate($event)\"\n (WidthChanged)=\"OnTagsPanelWidthChanged($event)\">\n </mj-record-tags>\n}\n\n<!-- ============================================\n LIST MANAGEMENT DIALOG (shown when lists button clicked)\n ============================================ -->\n@if (ShowListManagement && EffectiveRecord) {\n <mj-list-management-dialog\n [visible]=\"ShowListManagement\"\n [config]=\"{\n mode: 'manage',\n entityId: EffectiveRecord.EntityInfo.ID,\n entityName: EffectiveRecord.EntityInfo.Name,\n recordIds: [EffectiveRecord.PrimaryKey.Values()[0]],\n allowCreate: true\n }\"\n (complete)=\"OnListManagementClosed()\"\n (cancel)=\"OnListManagementClosed()\">\n </mj-list-management-dialog>\n}\n\n<!-- ============================================\n SECTION MANAGER DRAWER (shown when manage-sections button clicked)\n ============================================ -->\n<mj-section-manager\n [Sections]=\"SectionManagerItems\"\n [SectionOrder]=\"SectionManagerOrder\"\n [Visible]=\"ShowSectionManager\"\n (SectionOrderChange)=\"OnSectionOrderChange($event)\"\n (ResetRequested)=\"OnSectionManagerReset()\"\n (Closed)=\"OnSectionManagerClosed()\">\n</mj-section-manager>\n", styles: ["/* ============================================\n RECORD FORM CONTAINER \u2014 uses global --mj-* design tokens\n Top-level wrapper: toolbar + scrollable content\n ============================================ */\nmj-record-form-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n position: relative;\n overflow: hidden;\n}\n\n/* ViewEncapsulation.None fallback \u2014 ensure the element itself constrains overflow */\nmj-record-form-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n position: relative;\n overflow: hidden;\n}\n\n/* ============================================\n SCROLL AREA (full-width so mouse wheel works anywhere)\n ============================================ */\n.mj-forms-scroll-area {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n background: var(--mj-bg-page);\n}\n\n/* ============================================\n PANELS CONTAINER (centered content within scroll area)\n ============================================ */\n.mj-forms-panels-container {\n padding: 24px 32px 48px;\n max-width: 920px;\n margin: 0 auto;\n width: 100%;\n box-sizing: border-box;\n}\n\n/* Widen max-width when ISA side panel is present */\n.mj-forms-panels--has-isa-panel {\n max-width: 1240px;\n}\n\n.mj-forms-panels--full-width {\n max-width: none;\n padding-left: 24px;\n padding-right: 24px;\n}\n\n/* Flex row layout: form panels + optional ISA side panel */\n.mj-forms-layout-row {\n display: flex;\n gap: 20px;\n align-items: flex-start;\n}\n\n/* All panels in a single flex container \u2014 CSS order drives sequencing */\n.mj-forms-all-panels {\n display: flex;\n flex-direction: column;\n gap: 16px;\n flex: 1;\n min-width: 0;\n}\n\n/* Hide related entity panels in edit mode (variant host class on mj-collapsible-panel) */\n.mj-forms-panels--edit-mode .mj-panel--related-entity {\n display: none;\n}\n\n/* ============================================\n EMPTY SEARCH STATE\n ============================================ */\n.mj-forms-empty-search-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 80px 24px;\n text-align: center;\n min-height: 400px;\n}\n\n.mj-forms-empty-search-icon {\n width: 80px;\n height: 80px;\n border-radius: var(--mj-radius-full);\n background: var(--mj-bg-surface-sunken);\n display: flex;\n align-items: center;\n justify-content: center;\n margin-bottom: 24px;\n}\n\n.mj-forms-empty-search-icon i {\n font-size: 32px;\n color: var(--mj-text-muted);\n}\n\n.mj-forms-empty-search-title {\n font-size: var(--mj-text-xl);\n font-weight: var(--mj-font-semibold);\n color: var(--mj-text-primary);\n margin: 0 0 12px 0;\n}\n\n.mj-forms-empty-search-message {\n font-size: var(--mj-text-sm);\n color: var(--mj-text-secondary);\n line-height: 1.6;\n max-width: 400px;\n margin: 0;\n}\n\n.mj-forms-empty-search-message strong {\n color: var(--mj-text-primary);\n font-weight: var(--mj-font-semibold);\n}\n\n.mj-forms-empty-search-link {\n color: var(--mj-brand-primary);\n text-decoration: none;\n font-weight: var(--mj-font-medium);\n}\n\n.mj-forms-empty-search-link:hover {\n text-decoration: underline;\n}\n\n/* ============================================\n RESPONSIVE\n ============================================ */\n@media (max-width: 768px) {\n .mj-forms-panels-container {\n padding: 16px 12px 32px;\n }\n}\n"] }]
737
+ }], null, { recordChangesDrawer: [{
738
+ type: ViewChild,
739
+ args: [RecordChangesComponent]
740
+ }], Record: [{
540
741
  type: Input
541
742
  }], FormComponent: [{
542
743
  type: Input
@@ -598,5 +799,5 @@ export class MjRecordFormContainerComponent {
598
799
  type: ContentChildren,
599
800
  args: [MjCollapsiblePanelComponent, { descendants: true }]
600
801
  }] }); })();
601
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MjRecordFormContainerComponent, { className: "MjRecordFormContainerComponent", filePath: "src/lib/container/record-form-container.component.ts", lineNumber: 63 }); })();
802
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MjRecordFormContainerComponent, { className: "MjRecordFormContainerComponent", filePath: "src/lib/container/record-form-container.component.ts", lineNumber: 66 }); })();
602
803
  //# sourceMappingURL=record-form-container.component.js.map