@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.
- package/dist/__tests__/tag-count-badge.test.d.ts +2 -0
- package/dist/__tests__/tag-count-badge.test.d.ts.map +1 -0
- package/dist/__tests__/tag-count-badge.test.js +70 -0
- package/dist/__tests__/tag-count-badge.test.js.map +1 -0
- package/dist/lib/base-form-component.d.ts +11 -2
- package/dist/lib/base-form-component.d.ts.map +1 -1
- package/dist/lib/base-form-component.js +18 -1
- package/dist/lib/base-form-component.js.map +1 -1
- package/dist/lib/container/record-form-container.component.d.ts +51 -0
- package/dist/lib/container/record-form-container.component.d.ts.map +1 -1
- package/dist/lib/container/record-form-container.component.js +227 -26
- package/dist/lib/container/record-form-container.component.js.map +1 -1
- package/dist/lib/isa-related-panel/isa-related-card.component.js +1 -1
- package/dist/lib/isa-related-panel/isa-related-card.component.js.map +1 -1
- package/dist/lib/toolbar/form-toolbar.component.d.ts +10 -1
- package/dist/lib/toolbar/form-toolbar.component.d.ts.map +1 -1
- package/dist/lib/toolbar/form-toolbar.component.js +208 -147
- package/dist/lib/toolbar/form-toolbar.component.js.map +1 -1
- package/dist/lib/types/toolbar-config.d.ts +2 -0
- package/dist/lib/types/toolbar-config.d.ts.map +1 -1
- package/dist/lib/types/toolbar-config.js +2 -0
- package/dist/lib/types/toolbar-config.js.map +1 -1
- package/dist/module.d.ts +2 -1
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +7 -3
- package/dist/module.js.map +1 -1
- package/package.json +10 -8
|
@@ -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 "
|
|
11
|
-
import * as i4 from "../
|
|
12
|
-
import * as i5 from "../
|
|
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",
|
|
20
|
-
i0.ɵɵelement(2, "i",
|
|
24
|
+
i0.ɵɵelementStart(0, "div", 5)(1, "div", 11);
|
|
25
|
+
i0.ɵɵelement(2, "i", 12);
|
|
21
26
|
i0.ɵɵelementEnd();
|
|
22
|
-
i0.ɵɵelementStart(3, "h3",
|
|
27
|
+
i0.ɵɵelementStart(3, "h3", 13);
|
|
23
28
|
i0.ɵɵtext(4, "No sections found");
|
|
24
29
|
i0.ɵɵelementEnd();
|
|
25
|
-
i0.ɵɵelementStart(5, "p",
|
|
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",
|
|
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",
|
|
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-
|
|
56
|
-
i0.ɵɵlistener("
|
|
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
|
-
} },
|
|
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,
|
|
515
|
-
i0.ɵɵconditionalCreate(10, MjRecordFormContainerComponent_Conditional_10_Template, 1,
|
|
516
|
-
i0.ɵɵ
|
|
517
|
-
i0.ɵɵ
|
|
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.
|
|
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.
|
|
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, {
|
|
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:
|
|
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
|