@memberjunction/ng-explorer-core 5.33.0 → 5.34.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/resource-wrappers/dashboard-resource.component.js +2 -2
- package/dist/lib/resource-wrappers/dashboard-resource.component.js.map +1 -1
- package/dist/lib/resource-wrappers/search-results-resource.component.d.ts +24 -1
- package/dist/lib/resource-wrappers/search-results-resource.component.d.ts.map +1 -1
- package/dist/lib/resource-wrappers/search-results-resource.component.js +316 -106
- package/dist/lib/resource-wrappers/search-results-resource.component.js.map +1 -1
- package/dist/lib/shell/components/tabs/tab-container.component.d.ts +10 -0
- package/dist/lib/shell/components/tabs/tab-container.component.d.ts.map +1 -1
- package/dist/lib/shell/components/tabs/tab-container.component.js +94 -4
- package/dist/lib/shell/components/tabs/tab-container.component.js.map +1 -1
- package/dist/lib/shell/shell.component.d.ts +1 -0
- package/dist/lib/shell/shell.component.d.ts.map +1 -1
- package/dist/lib/shell/shell.component.js +7 -1
- package/dist/lib/shell/shell.component.js.map +1 -1
- package/dist/lib/single-record/single-record.component.d.ts +8 -0
- package/dist/lib/single-record/single-record.component.d.ts.map +1 -1
- package/dist/lib/single-record/single-record.component.js +128 -40
- package/dist/lib/single-record/single-record.component.js.map +1 -1
- package/dist/lib/system-validation/system-validation-banner.component.js +2 -2
- package/dist/lib/system-validation/system-validation-banner.component.js.map +1 -1
- package/package.json +42 -42
|
@@ -20,6 +20,8 @@ export declare class SingleRecordComponent extends BaseAngularComponent implemen
|
|
|
20
20
|
appDescription: string;
|
|
21
21
|
useGenericForm: boolean;
|
|
22
22
|
loading: boolean;
|
|
23
|
+
errorTitle: string | null;
|
|
24
|
+
errorDetail: string | null;
|
|
23
25
|
private _formComponentRef;
|
|
24
26
|
private _currentRecord;
|
|
25
27
|
private _eventHandlerSubscription;
|
|
@@ -27,6 +29,12 @@ export declare class SingleRecordComponent extends BaseAngularComponent implemen
|
|
|
27
29
|
ngOnInit(): void;
|
|
28
30
|
ngAfterViewInit(): void;
|
|
29
31
|
LoadForm(primaryKey: CompositeKey, entityName: string): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Render a user-visible error state inside the record pane AND log a structured
|
|
34
|
+
* console.error for developers. Always emits `loadComplete` so the Explorer shell
|
|
35
|
+
* does not hang on its first-resource-load gate.
|
|
36
|
+
*/
|
|
37
|
+
private failWithUserError;
|
|
30
38
|
protected SetNewRecordValues(record: BaseEntity): void;
|
|
31
39
|
/**
|
|
32
40
|
* Subscribe to BaseFormComponent @Output events and map them to Explorer services.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"single-record.component.d.ts","sourceRoot":"","sources":["../../../src/lib/single-record/single-record.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAA8C,YAAY,EAAiB,SAAS,EAAE,MAAM,EAAqB,MAAM,eAAe,CAAC;AAC7J,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAChD,OAAO,EAA0B,YAAY,EAAE,UAAU,EAA4D,MAAM,sBAAsB,CAAC;AAGlJ,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;;AACrE,qBAMa,qBAAsB,SAAQ,oBAAqB,YAAW,MAAM,EAAE,aAAa,EAAE,SAAS;IAc5F,OAAO,CAAC,KAAK;IAbY,aAAa,EAAG,SAAS,CAAC;IAChD,UAAU,EAAE,YAAY,CAAsB;IAC9C,UAAU,EAAE,MAAM,GAAG,IAAI,CAAM;IAC/B,eAAe,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAM;IAE7D,YAAY,EAAE,YAAY,CAAC,GAAG,CAAC,CAA2B;IAC1D,WAAW,EAAE,YAAY,CAAC,UAAU,CAAC,CAAkC;IAExF,OAAO,CAAC,mBAAmB,CAAsB;IACjD,OAAO,CAAC,iBAAiB,CAA6B;IACtD,OAAO,CAAC,aAAa,CAAyB;IAC9C,OAAO,CAAC,GAAG,CAA6B;gBAEnB,KAAK,EAAE,cAAc;IAKnC,cAAc,EAAE,MAAM,CAAK;IAC3B,cAAc,EAAE,OAAO,CAAS;IAChC,OAAO,EAAE,OAAO,CAAQ;
|
|
1
|
+
{"version":3,"file":"single-record.component.d.ts","sourceRoot":"","sources":["../../../src/lib/single-record/single-record.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAA8C,YAAY,EAAiB,SAAS,EAAE,MAAM,EAAqB,MAAM,eAAe,CAAC;AAC7J,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAChD,OAAO,EAA0B,YAAY,EAAE,UAAU,EAA4D,MAAM,sBAAsB,CAAC;AAGlJ,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;;AACrE,qBAMa,qBAAsB,SAAQ,oBAAqB,YAAW,MAAM,EAAE,aAAa,EAAE,SAAS;IAc5F,OAAO,CAAC,KAAK;IAbY,aAAa,EAAG,SAAS,CAAC;IAChD,UAAU,EAAE,YAAY,CAAsB;IAC9C,UAAU,EAAE,MAAM,GAAG,IAAI,CAAM;IAC/B,eAAe,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAM;IAE7D,YAAY,EAAE,YAAY,CAAC,GAAG,CAAC,CAA2B;IAC1D,WAAW,EAAE,YAAY,CAAC,UAAU,CAAC,CAAkC;IAExF,OAAO,CAAC,mBAAmB,CAAsB;IACjD,OAAO,CAAC,iBAAiB,CAA6B;IACtD,OAAO,CAAC,aAAa,CAAyB;IAC9C,OAAO,CAAC,GAAG,CAA6B;gBAEnB,KAAK,EAAE,cAAc;IAKnC,cAAc,EAAE,MAAM,CAAK;IAC3B,cAAc,EAAE,OAAO,CAAS;IAChC,OAAO,EAAE,OAAO,CAAQ;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAQ;IACjC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAQ;IAGzC,OAAO,CAAC,iBAAiB,CAAgD;IACzE,OAAO,CAAC,cAAc,CAA2B;IACjD,OAAO,CAAC,yBAAyB,CAA6B;IAC9D,OAAO,CAAC,uBAAuB,CAAsB;IAErD,QAAQ,IAAI,IAAI;IAGhB,eAAe;IAIF,QAAQ,CAAC,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM;IA2GlE;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAyBzB,SAAS,CAAC,kBAAkB,CAAC,MAAM,EAAE,UAAU;IA8E/C;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAW7B,OAAO,CAAC,gBAAgB;IA6BxB,OAAO,CAAC,wBAAwB;IAOhC,WAAW,IAAI,IAAI;yCA/SR,qBAAqB;2CAArB,qBAAqB;CA6UjC"}
|
|
@@ -14,7 +14,34 @@ function SingleRecordComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
|
14
14
|
} if (rf & 2) {
|
|
15
15
|
i0.ɵɵproperty("showText", false);
|
|
16
16
|
} }
|
|
17
|
-
function
|
|
17
|
+
function SingleRecordComponent_Conditional_1_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
18
|
+
i0.ɵɵelementStart(0, "p", 6);
|
|
19
|
+
i0.ɵɵtext(1);
|
|
20
|
+
i0.ɵɵelementEnd();
|
|
21
|
+
} if (rf & 2) {
|
|
22
|
+
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
23
|
+
i0.ɵɵadvance();
|
|
24
|
+
i0.ɵɵtextInterpolate(ctx_r0.errorDetail);
|
|
25
|
+
} }
|
|
26
|
+
function SingleRecordComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
27
|
+
i0.ɵɵelementStart(0, "div", 1)(1, "div", 3);
|
|
28
|
+
i0.ɵɵelement(2, "i", 4);
|
|
29
|
+
i0.ɵɵelementEnd();
|
|
30
|
+
i0.ɵɵelementStart(3, "h2", 5);
|
|
31
|
+
i0.ɵɵtext(4);
|
|
32
|
+
i0.ɵɵelementEnd();
|
|
33
|
+
i0.ɵɵconditionalCreate(5, SingleRecordComponent_Conditional_1_Conditional_5_Template, 2, 1, "p", 6);
|
|
34
|
+
i0.ɵɵelementStart(6, "p", 7);
|
|
35
|
+
i0.ɵɵtext(7, "See browser console for technical details.");
|
|
36
|
+
i0.ɵɵelementEnd()();
|
|
37
|
+
} if (rf & 2) {
|
|
38
|
+
const ctx_r0 = i0.ɵɵnextContext();
|
|
39
|
+
i0.ɵɵadvance(4);
|
|
40
|
+
i0.ɵɵtextInterpolate(ctx_r0.errorTitle);
|
|
41
|
+
i0.ɵɵadvance();
|
|
42
|
+
i0.ɵɵconditional(ctx_r0.errorDetail ? 5 : -1);
|
|
43
|
+
} }
|
|
44
|
+
function SingleRecordComponent_ng_template_2_Template(rf, ctx) { }
|
|
18
45
|
export class SingleRecordComponent extends BaseAngularComponent {
|
|
19
46
|
route;
|
|
20
47
|
formContainer;
|
|
@@ -35,6 +62,8 @@ export class SingleRecordComponent extends BaseAngularComponent {
|
|
|
35
62
|
appDescription = '';
|
|
36
63
|
useGenericForm = false;
|
|
37
64
|
loading = true;
|
|
65
|
+
errorTitle = null;
|
|
66
|
+
errorDetail = null;
|
|
38
67
|
// Track dynamically created components and entities for cleanup
|
|
39
68
|
_formComponentRef = null;
|
|
40
69
|
_currentRecord = null;
|
|
@@ -48,7 +77,10 @@ export class SingleRecordComponent extends BaseAngularComponent {
|
|
|
48
77
|
async LoadForm(primaryKey, entityName) {
|
|
49
78
|
// Perform any necessary actions with the ViewID, such as fetching data
|
|
50
79
|
if (!entityName || entityName.trim().length === 0) {
|
|
51
|
-
|
|
80
|
+
// No entity yet — caller will re-invoke once it has one. Don't emit loadComplete;
|
|
81
|
+
// it would race the real load. The shell's recovery timer will surface the
|
|
82
|
+
// "taking longer than expected" reset if this is the terminal state.
|
|
83
|
+
return;
|
|
52
84
|
}
|
|
53
85
|
this.entityName = entityName;
|
|
54
86
|
if (primaryKey.HasValue) {
|
|
@@ -61,47 +93,91 @@ export class SingleRecordComponent extends BaseAngularComponent {
|
|
|
61
93
|
}
|
|
62
94
|
const formReg = MJGlobal.Instance.ClassFactory.GetRegistration(BaseFormComponent, entityName);
|
|
63
95
|
const md = this.ProviderToUse;
|
|
64
|
-
const entity = md.
|
|
65
|
-
return e.Name === entityName;
|
|
66
|
-
});
|
|
96
|
+
const entity = md.EntityByName(entityName);
|
|
67
97
|
const permissions = entity?.GetUserPermisions(md.CurrentUser);
|
|
68
|
-
|
|
98
|
+
try {
|
|
99
|
+
if (!entity) {
|
|
100
|
+
this.failWithUserError(`Entity not found: "${entityName}"`, `This MemberJunction instance has no metadata for entity "${entityName}". Check that the entity name in the URL matches a row in __mj.Entity, and that the metadata cache is current.`);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
if (!formReg) {
|
|
104
|
+
this.failWithUserError(`No form is registered for "${entityName}".`, `MemberJunction could not find an Angular form component registered against BaseFormComponent for entity "${entityName}". This usually means CodeGen has not generated a form for this entity in the running build (forms live under packages/MJExplorer or your app's entity-form package). Run CodeGen, ensure the generated module is imported, or register a custom form via @RegisterClass(BaseFormComponent, '${entityName}').`, { entityId: entity.ID, recordKey: primaryKey?.ToString?.() ?? '(none)' });
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
69
107
|
const record = await md.GetEntityObject(entityName);
|
|
70
|
-
if (record) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
108
|
+
if (!record) {
|
|
109
|
+
throw new Error(`Unable to instantiate entity ${entityName} with primary key values: ${primaryKey.ToString()}`);
|
|
110
|
+
}
|
|
111
|
+
if (primaryKey.HasValue) {
|
|
112
|
+
const loadOk = await record.InnerLoad(primaryKey);
|
|
113
|
+
if (!loadOk) {
|
|
114
|
+
this.failWithUserError(`Could not load ${entityName} record.`, record.LatestResult?.Message
|
|
115
|
+
? `Server error: ${record.LatestResult.Message}`
|
|
116
|
+
: `InnerLoad returned false for entity "${entityName}" with key ${primaryKey.ToString()}. The record may not exist, you may lack permission to view it, or the load may have been blocked server-side.`, { recordKey: primaryKey.ToString() });
|
|
117
|
+
return;
|
|
79
118
|
}
|
|
80
|
-
//
|
|
81
|
-
this.
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
viewContainerRef.clear();
|
|
87
|
-
const componentRef = viewContainerRef.createComponent(formReg.SubClass);
|
|
88
|
-
// Track component and record for cleanup
|
|
89
|
-
this._formComponentRef = componentRef;
|
|
90
|
-
this._currentRecord = record;
|
|
91
|
-
componentRef.instance.record = record;
|
|
92
|
-
componentRef.instance.userPermissions = permissions;
|
|
93
|
-
componentRef.instance.EditMode = !primaryKey.HasValue; // for new records go direct into edit mode
|
|
94
|
-
// Subscribe to form @Output events and map them to Explorer services
|
|
95
|
-
this.subscribeToFormEvents(componentRef.instance);
|
|
96
|
-
this.useGenericForm = false;
|
|
97
|
-
this.loadComplete.emit();
|
|
119
|
+
// Log access to existing record (fire-and-forget, don't await)
|
|
120
|
+
this.recentAccessService.logAccess(entityName, primaryKey, 'record');
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
record.NewRecord();
|
|
124
|
+
this.SetNewRecordValues(record);
|
|
98
125
|
}
|
|
99
|
-
|
|
100
|
-
|
|
126
|
+
// CRITICAL: Track the event handler subscription for cleanup
|
|
127
|
+
this._eventHandlerSubscription = record.RegisterEventHandler((eventType) => {
|
|
128
|
+
if (eventType.type === 'save')
|
|
129
|
+
this.recordSaved.emit(record);
|
|
130
|
+
});
|
|
131
|
+
const viewContainerRef = this.formContainer.viewContainerRef;
|
|
132
|
+
viewContainerRef.clear();
|
|
133
|
+
const componentRef = viewContainerRef.createComponent(formReg.SubClass);
|
|
134
|
+
// Track component and record for cleanup
|
|
135
|
+
this._formComponentRef = componentRef;
|
|
136
|
+
this._currentRecord = record;
|
|
137
|
+
componentRef.instance.record = record;
|
|
138
|
+
componentRef.instance.userPermissions = permissions;
|
|
139
|
+
componentRef.instance.EditMode = !primaryKey.HasValue; // for new records go direct into edit mode
|
|
140
|
+
// Subscribe to form @Output events and map them to Explorer services
|
|
141
|
+
this.subscribeToFormEvents(componentRef.instance);
|
|
142
|
+
this.useGenericForm = false;
|
|
143
|
+
this.errorTitle = null;
|
|
144
|
+
this.errorDetail = null;
|
|
145
|
+
this.loadComplete.emit();
|
|
146
|
+
}
|
|
147
|
+
catch (err) {
|
|
148
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
149
|
+
this.failWithUserError(`Failed to load ${entityName} record.`, `An unexpected error occurred while loading this record: ${msg}`, { error: err });
|
|
101
150
|
}
|
|
102
151
|
this.loading = false;
|
|
103
152
|
this.cdr.detectChanges();
|
|
104
153
|
}
|
|
154
|
+
/**
|
|
155
|
+
* Render a user-visible error state inside the record pane AND log a structured
|
|
156
|
+
* console.error for developers. Always emits `loadComplete` so the Explorer shell
|
|
157
|
+
* does not hang on its first-resource-load gate.
|
|
158
|
+
*/
|
|
159
|
+
failWithUserError(title, detail, context) {
|
|
160
|
+
this.errorTitle = title;
|
|
161
|
+
this.errorDetail = detail;
|
|
162
|
+
this.loading = false;
|
|
163
|
+
// Single structured console.error for devs — easy to grep, easy to read.
|
|
164
|
+
console.error(`[SingleRecord] ${title}\n${detail}` +
|
|
165
|
+
(context ? `\nContext: ${JSON.stringify(context, null, 2)}` : ''));
|
|
166
|
+
// Clear any prior form/component so the error UI is what shows.
|
|
167
|
+
if (this._formComponentRef) {
|
|
168
|
+
try {
|
|
169
|
+
this._formComponentRef.destroy();
|
|
170
|
+
}
|
|
171
|
+
catch { /* noop */ }
|
|
172
|
+
this._formComponentRef = null;
|
|
173
|
+
}
|
|
174
|
+
if (this.formContainer?.viewContainerRef) {
|
|
175
|
+
this.formContainer.viewContainerRef.clear();
|
|
176
|
+
}
|
|
177
|
+
// Always unblock the shell.
|
|
178
|
+
this.loadComplete.emit();
|
|
179
|
+
this.cdr.detectChanges();
|
|
180
|
+
}
|
|
105
181
|
SetNewRecordValues(record) {
|
|
106
182
|
if (!this.newRecordValues) {
|
|
107
183
|
return;
|
|
@@ -193,7 +269,16 @@ export class SingleRecordComponent extends BaseAngularComponent {
|
|
|
193
269
|
this.navigationService.OpenEntityRecord(event.EntityName, event.PrimaryKey, { forceNewTab: event.OpenInNewTab });
|
|
194
270
|
break;
|
|
195
271
|
case 'new-record':
|
|
196
|
-
|
|
272
|
+
// Creating a new related record from inside an open record form (e.g. + New
|
|
273
|
+
// on a related-entity grid). Force a new tab so the parent record stays
|
|
274
|
+
// intact — otherwise the new-record form silently replaces the parent in
|
|
275
|
+
// single-resource mode and the user loses their context. This is the
|
|
276
|
+
// original intent of dea32401ff, now stated explicitly at the call site
|
|
277
|
+
// instead of as a global navigation heuristic.
|
|
278
|
+
this.navigationService.OpenNewEntityRecord(event.EntityName, {
|
|
279
|
+
newRecordValues: event.DefaultValues,
|
|
280
|
+
forceNewTab: true,
|
|
281
|
+
});
|
|
197
282
|
break;
|
|
198
283
|
case 'entity-hierarchy':
|
|
199
284
|
this.navigationService.OpenEntityRecord(event.EntityName, event.PrimaryKey);
|
|
@@ -243,16 +328,19 @@ export class SingleRecordComponent extends BaseAngularComponent {
|
|
|
243
328
|
} if (rf & 2) {
|
|
244
329
|
let _t;
|
|
245
330
|
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.formContainer = _t.first);
|
|
246
|
-
} }, inputs: { PrimaryKey: "PrimaryKey", entityName: "entityName", newRecordValues: "newRecordValues" }, outputs: { loadComplete: "loadComplete", recordSaved: "recordSaved" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls:
|
|
331
|
+
} }, inputs: { PrimaryKey: "PrimaryKey", entityName: "entityName", newRecordValues: "newRecordValues" }, outputs: { loadComplete: "loadComplete", recordSaved: "recordSaved" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 3, vars: 2, consts: [["size", "large", 3, "showText"], ["role", "alert", 1, "single-record-error"], ["mjContainer", ""], [1, "single-record-error__icon"], [1, "fa-solid", "fa-triangle-exclamation"], [1, "single-record-error__title"], [1, "single-record-error__detail"], [1, "single-record-error__hint"]], template: function SingleRecordComponent_Template(rf, ctx) { if (rf & 1) {
|
|
247
332
|
i0.ɵɵconditionalCreate(0, SingleRecordComponent_Conditional_0_Template, 1, 1, "mj-loading", 0);
|
|
248
|
-
i0.ɵɵ
|
|
333
|
+
i0.ɵɵconditionalCreate(1, SingleRecordComponent_Conditional_1_Template, 8, 2, "div", 1);
|
|
334
|
+
i0.ɵɵtemplate(2, SingleRecordComponent_ng_template_2_Template, 0, 0, "ng-template", 2);
|
|
249
335
|
} if (rf & 2) {
|
|
250
336
|
i0.ɵɵconditional(ctx.loading ? 0 : -1);
|
|
251
|
-
|
|
337
|
+
i0.ɵɵadvance();
|
|
338
|
+
i0.ɵɵconditional(ctx.errorTitle ? 1 : -1);
|
|
339
|
+
} }, dependencies: [i2.Container, i3.LoadingComponent], styles: ["[_nghost-%COMP%] {\n display: block;\n height: 100%;\n width: 100%;\n}\n\n.single-record-error[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n text-align: center;\n padding: 48px 32px;\n max-width: 720px;\n margin: 64px auto;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-status-error-border);\n border-radius: 8px;\n color: var(--mj-text-primary);\n}\n\n.single-record-error__icon[_ngcontent-%COMP%] {\n font-size: 36px;\n color: var(--mj-status-error);\n margin-bottom: 16px;\n}\n\n.single-record-error__title[_ngcontent-%COMP%] {\n font-size: 18px;\n font-weight: 600;\n margin: 0 0 12px 0;\n color: var(--mj-status-error-text);\n}\n\n.single-record-error__detail[_ngcontent-%COMP%] {\n font-size: 14px;\n line-height: 1.5;\n color: var(--mj-text-secondary);\n margin: 0 0 16px 0;\n white-space: pre-wrap;\n}\n\n.single-record-error__hint[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n margin: 0;\n font-style: italic;\n}"] });
|
|
252
340
|
}
|
|
253
341
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(SingleRecordComponent, [{
|
|
254
342
|
type: Component,
|
|
255
|
-
args: [{ standalone: false, selector: 'mj-single-record', template: "@if (loading) {\n <mj-loading [showText]=\"false\" size=\"large\"></mj-loading>\n}\n<ng-template mjContainer></ng-template
|
|
343
|
+
args: [{ standalone: false, selector: 'mj-single-record', template: "@if (loading) {\n <mj-loading [showText]=\"false\" size=\"large\"></mj-loading>\n}\n@if (errorTitle) {\n <div class=\"single-record-error\" role=\"alert\">\n <div class=\"single-record-error__icon\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i>\n </div>\n <h2 class=\"single-record-error__title\">{{ errorTitle }}</h2>\n @if (errorDetail) {\n <p class=\"single-record-error__detail\">{{ errorDetail }}</p>\n }\n <p class=\"single-record-error__hint\">See browser console for technical details.</p>\n </div>\n}\n<ng-template mjContainer></ng-template>\n", styles: [":host {\n display: block;\n height: 100%;\n width: 100%;\n}\n\n.single-record-error {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n text-align: center;\n padding: 48px 32px;\n max-width: 720px;\n margin: 64px auto;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-status-error-border);\n border-radius: 8px;\n color: var(--mj-text-primary);\n}\n\n.single-record-error__icon {\n font-size: 36px;\n color: var(--mj-status-error);\n margin-bottom: 16px;\n}\n\n.single-record-error__title {\n font-size: 18px;\n font-weight: 600;\n margin: 0 0 12px 0;\n color: var(--mj-status-error-text);\n}\n\n.single-record-error__detail {\n font-size: 14px;\n line-height: 1.5;\n color: var(--mj-text-secondary);\n margin: 0 0 16px 0;\n white-space: pre-wrap;\n}\n\n.single-record-error__hint {\n font-size: 12px;\n color: var(--mj-text-muted);\n margin: 0;\n font-style: italic;\n}\n"] }]
|
|
256
344
|
}], () => [{ type: i1.ActivatedRoute }], { formContainer: [{
|
|
257
345
|
type: ViewChild,
|
|
258
346
|
args: [Container, { static: true }]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"single-record.component.js","sourceRoot":"","sources":["../../../src/lib/single-record/single-record.component.ts","../../../src/lib/single-record/single-record.component.html"],"names":[],"mappings":"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","sourcesContent":["import { AfterViewInit, ChangeDetectorRef, Component, ComponentRef, EventEmitter, inject, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core';\nimport { ActivatedRoute } from '@angular/router'\nimport { Metadata, KeyValuePair, CompositeKey, BaseEntity, BaseEntityEvent, FieldValueCollection, EntityFieldTSType } from '@memberjunction/core';\nimport { Subscription } from 'rxjs';\nimport { MJGlobal } from '@memberjunction/global';\nimport { Container } from '@memberjunction/ng-container-directives';\nimport { BaseFormComponent, FormNavigationEvent, FormNotificationEvent } from '@memberjunction/ng-base-forms';\nimport { NavigationService, RecentAccessService, SharedService } from '@memberjunction/ng-shared';\n\n\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\n@Component({\n standalone: false,\n selector: 'mj-single-record',\n templateUrl: './single-record.component.html',\n styleUrls: ['./single-record.component.css']\n})\nexport class SingleRecordComponent extends BaseAngularComponent implements OnInit, AfterViewInit, OnDestroy {\n @ViewChild(Container, {static: true}) formContainer!: Container;\n @Input() public PrimaryKey: CompositeKey = new CompositeKey();\n @Input() public entityName: string | null = '';\n @Input() public newRecordValues: string | Record<string, unknown> | null = '';\n\n @Output() public loadComplete: EventEmitter<any> = new EventEmitter<any>();\n @Output() public recordSaved: EventEmitter<BaseEntity> = new EventEmitter<BaseEntity>();\n\n private recentAccessService: RecentAccessService;\n private navigationService = inject(NavigationService);\n private sharedService = inject(SharedService);\n private cdr = inject(ChangeDetectorRef);\n\n constructor (private route: ActivatedRoute) {\n super();\n this.recentAccessService = new RecentAccessService();\n }\n\n public appDescription: string = ''\n public useGenericForm: boolean = false;\n public loading: boolean = true;\n\n // Track dynamically created components and entities for cleanup\n private _formComponentRef: ComponentRef<BaseFormComponent> | null = null;\n private _currentRecord: BaseEntity | null = null;\n private _eventHandlerSubscription: Subscription | null = null;\n private _formEventSubscriptions: Subscription[] = [];\n\n ngOnInit(): void {\n }\n\n ngAfterViewInit() {\n this.LoadForm(this.PrimaryKey, <string>this.entityName)\n }\n\n public async LoadForm(primaryKey: CompositeKey, entityName: string) {\n \n // Perform any necessary actions with the ViewID, such as fetching data\n if (!entityName || entityName.trim().length === 0) {\n return; // not ready to load\n }\n\n this.entityName = entityName;\n if (primaryKey.HasValue) {\n // we have an existing record to load up\n this.PrimaryKey = primaryKey;\n }\n else {\n // new record, no existing primary key\n this.PrimaryKey = new CompositeKey();\n }\n\n const formReg = MJGlobal.Instance.ClassFactory.GetRegistration(BaseFormComponent, entityName);\n \n const md = this.ProviderToUse;\n const entity = md.Entities.find(e => {\n return e.Name === entityName\n });\n const permissions = entity?.GetUserPermisions(md.CurrentUser);\n\n if (formReg) {\n const record = await md.GetEntityObject<BaseEntity>(entityName);\n if (record) {\n if (primaryKey.HasValue) {\n await record.InnerLoad(primaryKey);\n // Log access to existing record (fire-and-forget, don't await)\n this.recentAccessService.logAccess(entityName, primaryKey, 'record');\n }\n else {\n record.NewRecord();\n this.SetNewRecordValues(record);\n }\n\n // CRITICAL: Track the event handler subscription for cleanup\n this._eventHandlerSubscription = record.RegisterEventHandler((eventType: BaseEntityEvent) => {\n if (eventType.type === 'save')\n this.recordSaved.emit(record);\n });\n \n const viewContainerRef = this.formContainer.viewContainerRef;\n viewContainerRef.clear();\n\n const componentRef = viewContainerRef.createComponent<typeof formReg.SubClass>(formReg.SubClass);\n \n // Track component and record for cleanup\n this._formComponentRef = componentRef;\n this._currentRecord = record;\n \n componentRef.instance.record = record\n componentRef.instance.userPermissions = permissions\n componentRef.instance.EditMode = !primaryKey.HasValue; // for new records go direct into edit mode\n\n // Subscribe to form @Output events and map them to Explorer services\n this.subscribeToFormEvents(componentRef.instance);\n\n this.useGenericForm = false;\n this.loadComplete.emit();\n }\n else\n throw new Error(`Unable to load entity ${entityName} with primary key values: ${primaryKey.ToString()}`);\n }\n\n this.loading = false;\n this.cdr.detectChanges();\n }\n\n protected SetNewRecordValues(record: BaseEntity) {\n if (!this.newRecordValues) {\n return;\n }\n\n // Handle both object and string (URL segment) formats\n if (typeof this.newRecordValues === 'string') {\n if (this.newRecordValues.length === 0) {\n return;\n }\n // we have a URL segment string format: \"field1|value1||field2|value2\"\n const fv = new FieldValueCollection();\n fv.SimpleLoadFromURLSegment(this.newRecordValues);\n // now apply the values to the record\n fv.KeyValuePairs.filter(kvp => kvp.Value !== null && kvp.Value !== undefined).forEach(kvp => {\n const f = record.Fields.find(f => f.Name.trim().toLowerCase() === kvp.FieldName.trim().toLowerCase());\n if (f) {\n // make sure we set the value to the right type based on the f.TSType property\n switch (f.EntityFieldInfo.TSType) {\n case EntityFieldTSType.String:\n record.Set(kvp.FieldName, kvp.Value);\n break;\n case EntityFieldTSType.Number:\n record.Set(kvp.FieldName, parseFloat(kvp.Value));\n break;\n case EntityFieldTSType.Boolean:\n if (kvp.Value === 'false' || kvp.Value === '0' || kvp.Value.toString().trim().length === 0 )\n record.Set(kvp.FieldName, false);\n else\n record.Set(kvp.FieldName, true);\n break;\n case EntityFieldTSType.Date:\n record.Set(kvp.FieldName, new Date(kvp.Value));\n break;\n }\n }\n });\n }\n else {\n // we have a plain object format: { field1: value1, field2: value2 }\n const recordValues = this.newRecordValues as Record<string, unknown>;\n Object.keys(recordValues)\n .filter(key => recordValues[key] !== null && recordValues[key] !== undefined)\n .forEach(key => {\n const f = record.Fields.find(f => f.Name.trim().toLowerCase() === key.trim().toLowerCase());\n if (f) {\n const value = recordValues[key];\n // Set the value with proper type conversion\n switch (f.EntityFieldInfo.TSType) {\n case EntityFieldTSType.String:\n record.Set(key, value?.toString() || '');\n break;\n case EntityFieldTSType.Number:\n record.Set(key, typeof value === 'number' ? value : parseFloat(value?.toString() || '0'));\n break;\n case EntityFieldTSType.Boolean:\n if (typeof value === 'boolean') {\n record.Set(key, value);\n }\n else if (typeof value === 'string') {\n record.Set(key, value !== 'false' && value !== '0' && value.trim().length > 0);\n }\n else {\n record.Set(key, !!value);\n }\n break;\n case EntityFieldTSType.Date:\n record.Set(key, value instanceof Date ? value : new Date(value?.toString() || ''));\n break;\n default:\n record.Set(key, value);\n break;\n }\n }\n });\n }\n }\n\n /**\n * Subscribe to BaseFormComponent @Output events and map them to Explorer services.\n */\n private subscribeToFormEvents(form: BaseFormComponent): void {\n this.cleanupFormSubscriptions();\n\n this._formEventSubscriptions.push(\n form.Navigate.subscribe((event: FormNavigationEvent) => this.handleNavigation(event)),\n form.Notification.subscribe((event: FormNotificationEvent) => {\n this.sharedService.CreateSimpleNotification(event.Message, event.Type, event.Duration);\n })\n );\n }\n\n private handleNavigation(event: FormNavigationEvent): void {\n switch (event.Kind) {\n case 'record':\n this.navigationService.OpenEntityRecord(event.EntityName, event.PrimaryKey, { forceNewTab: event.OpenInNewTab });\n break;\n case 'new-record':\n this.navigationService.OpenNewEntityRecord(event.EntityName, { newRecordValues: event.DefaultValues });\n break;\n case 'entity-hierarchy':\n this.navigationService.OpenEntityRecord(event.EntityName, event.PrimaryKey);\n break;\n case 'external-link':\n window.open(event.Url, '_blank');\n break;\n case 'email':\n window.open(`mailto:${event.EmailAddress}`, '_self');\n break;\n }\n }\n\n private cleanupFormSubscriptions(): void {\n for (const sub of this._formEventSubscriptions) {\n sub.unsubscribe();\n }\n this._formEventSubscriptions = [];\n }\n\n ngOnDestroy(): void {\n // CRITICAL: Clean up form event subscriptions first\n this.cleanupFormSubscriptions();\n\n // CRITICAL: Clean up dynamically created form component to prevent zombie components\n if (this._formComponentRef) {\n this._formComponentRef.destroy();\n this._formComponentRef = null;\n }\n\n // CRITICAL: Unsubscribe from event handler to prevent memory leaks\n if (this._eventHandlerSubscription) {\n this._eventHandlerSubscription.unsubscribe();\n this._eventHandlerSubscription = null;\n }\n \n // Clean up record reference\n if (this._currentRecord) {\n this._currentRecord = null;\n }\n \n // Clear the view container to ensure no lingering references\n if (this.formContainer?.viewContainerRef) {\n this.formContainer.viewContainerRef.clear();\n }\n \n // Reset state\n this.loading = true;\n this.useGenericForm = false;\n }\n}\n","@if (loading) {\n <mj-loading [showText]=\"false\" size=\"large\"></mj-loading>\n}\n<ng-template mjContainer></ng-template>"]}
|
|
1
|
+
{"version":3,"file":"single-record.component.js","sourceRoot":"","sources":["../../../src/lib/single-record/single-record.component.ts","../../../src/lib/single-record/single-record.component.html"],"names":[],"mappings":"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","sourcesContent":["import { AfterViewInit, ChangeDetectorRef, Component, ComponentRef, EventEmitter, inject, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core';\nimport { ActivatedRoute } from '@angular/router'\nimport { Metadata, KeyValuePair, CompositeKey, BaseEntity, BaseEntityEvent, FieldValueCollection, EntityFieldTSType } from '@memberjunction/core';\nimport { Subscription } from 'rxjs';\nimport { MJGlobal } from '@memberjunction/global';\nimport { Container } from '@memberjunction/ng-container-directives';\nimport { BaseFormComponent, FormNavigationEvent, FormNotificationEvent } from '@memberjunction/ng-base-forms';\nimport { NavigationService, RecentAccessService, SharedService } from '@memberjunction/ng-shared';\n\n\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\n@Component({\n standalone: false,\n selector: 'mj-single-record',\n templateUrl: './single-record.component.html',\n styleUrls: ['./single-record.component.css']\n})\nexport class SingleRecordComponent extends BaseAngularComponent implements OnInit, AfterViewInit, OnDestroy {\n @ViewChild(Container, {static: true}) formContainer!: Container;\n @Input() public PrimaryKey: CompositeKey = new CompositeKey();\n @Input() public entityName: string | null = '';\n @Input() public newRecordValues: string | Record<string, unknown> | null = '';\n\n @Output() public loadComplete: EventEmitter<any> = new EventEmitter<any>();\n @Output() public recordSaved: EventEmitter<BaseEntity> = new EventEmitter<BaseEntity>();\n\n private recentAccessService: RecentAccessService;\n private navigationService = inject(NavigationService);\n private sharedService = inject(SharedService);\n private cdr = inject(ChangeDetectorRef);\n\n constructor (private route: ActivatedRoute) {\n super();\n this.recentAccessService = new RecentAccessService();\n }\n\n public appDescription: string = ''\n public useGenericForm: boolean = false;\n public loading: boolean = true;\n public errorTitle: string | null = null;\n public errorDetail: string | null = null;\n\n // Track dynamically created components and entities for cleanup\n private _formComponentRef: ComponentRef<BaseFormComponent> | null = null;\n private _currentRecord: BaseEntity | null = null;\n private _eventHandlerSubscription: Subscription | null = null;\n private _formEventSubscriptions: Subscription[] = [];\n\n ngOnInit(): void {\n }\n\n ngAfterViewInit() {\n this.LoadForm(this.PrimaryKey, <string>this.entityName)\n }\n\n public async LoadForm(primaryKey: CompositeKey, entityName: string) {\n // Perform any necessary actions with the ViewID, such as fetching data\n if (!entityName || entityName.trim().length === 0) {\n // No entity yet — caller will re-invoke once it has one. Don't emit loadComplete;\n // it would race the real load. The shell's recovery timer will surface the\n // \"taking longer than expected\" reset if this is the terminal state.\n return;\n }\n\n this.entityName = entityName;\n if (primaryKey.HasValue) {\n // we have an existing record to load up\n this.PrimaryKey = primaryKey;\n }\n else {\n // new record, no existing primary key\n this.PrimaryKey = new CompositeKey();\n }\n\n const formReg = MJGlobal.Instance.ClassFactory.GetRegistration(BaseFormComponent, entityName);\n\n const md = this.ProviderToUse;\n const entity = md.EntityByName(entityName);\n const permissions = entity?.GetUserPermisions(md.CurrentUser);\n\n try {\n if (!entity) {\n this.failWithUserError(\n `Entity not found: \"${entityName}\"`,\n `This MemberJunction instance has no metadata for entity \"${entityName}\". Check that the entity name in the URL matches a row in __mj.Entity, and that the metadata cache is current.`\n );\n return;\n }\n\n if (!formReg) {\n this.failWithUserError(\n `No form is registered for \"${entityName}\".`,\n `MemberJunction could not find an Angular form component registered against BaseFormComponent for entity \"${entityName}\". This usually means CodeGen has not generated a form for this entity in the running build (forms live under packages/MJExplorer or your app's entity-form package). Run CodeGen, ensure the generated module is imported, or register a custom form via @RegisterClass(BaseFormComponent, '${entityName}').`,\n { entityId: entity.ID, recordKey: primaryKey?.ToString?.() ?? '(none)' }\n );\n return;\n }\n\n const record = await md.GetEntityObject<BaseEntity>(entityName);\n if (!record) {\n throw new Error(`Unable to instantiate entity ${entityName} with primary key values: ${primaryKey.ToString()}`);\n }\n\n if (primaryKey.HasValue) {\n const loadOk = await record.InnerLoad(primaryKey);\n if (!loadOk) {\n this.failWithUserError(\n `Could not load ${entityName} record.`,\n record.LatestResult?.Message\n ? `Server error: ${record.LatestResult.Message}`\n : `InnerLoad returned false for entity \"${entityName}\" with key ${primaryKey.ToString()}. The record may not exist, you may lack permission to view it, or the load may have been blocked server-side.`,\n { recordKey: primaryKey.ToString() }\n );\n return;\n }\n // Log access to existing record (fire-and-forget, don't await)\n this.recentAccessService.logAccess(entityName, primaryKey, 'record');\n }\n else {\n record.NewRecord();\n this.SetNewRecordValues(record);\n }\n\n // CRITICAL: Track the event handler subscription for cleanup\n this._eventHandlerSubscription = record.RegisterEventHandler((eventType: BaseEntityEvent) => {\n if (eventType.type === 'save')\n this.recordSaved.emit(record);\n });\n\n const viewContainerRef = this.formContainer.viewContainerRef;\n viewContainerRef.clear();\n\n const componentRef = viewContainerRef.createComponent<typeof formReg.SubClass>(formReg.SubClass);\n\n // Track component and record for cleanup\n this._formComponentRef = componentRef;\n this._currentRecord = record;\n\n componentRef.instance.record = record\n componentRef.instance.userPermissions = permissions\n componentRef.instance.EditMode = !primaryKey.HasValue; // for new records go direct into edit mode\n\n // Subscribe to form @Output events and map them to Explorer services\n this.subscribeToFormEvents(componentRef.instance);\n\n this.useGenericForm = false;\n this.errorTitle = null;\n this.errorDetail = null;\n this.loadComplete.emit();\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n this.failWithUserError(\n `Failed to load ${entityName} record.`,\n `An unexpected error occurred while loading this record: ${msg}`,\n { error: err }\n );\n }\n\n this.loading = false;\n this.cdr.detectChanges();\n }\n\n /**\n * Render a user-visible error state inside the record pane AND log a structured\n * console.error for developers. Always emits `loadComplete` so the Explorer shell\n * does not hang on its first-resource-load gate.\n */\n private failWithUserError(title: string, detail: string, context?: Record<string, unknown>): void {\n this.errorTitle = title;\n this.errorDetail = detail;\n this.loading = false;\n\n // Single structured console.error for devs — easy to grep, easy to read.\n console.error(\n `[SingleRecord] ${title}\\n${detail}` +\n (context ? `\\nContext: ${JSON.stringify(context, null, 2)}` : '')\n );\n\n // Clear any prior form/component so the error UI is what shows.\n if (this._formComponentRef) {\n try { this._formComponentRef.destroy(); } catch { /* noop */ }\n this._formComponentRef = null;\n }\n if (this.formContainer?.viewContainerRef) {\n this.formContainer.viewContainerRef.clear();\n }\n\n // Always unblock the shell.\n this.loadComplete.emit();\n this.cdr.detectChanges();\n }\n\n protected SetNewRecordValues(record: BaseEntity) {\n if (!this.newRecordValues) {\n return;\n }\n\n // Handle both object and string (URL segment) formats\n if (typeof this.newRecordValues === 'string') {\n if (this.newRecordValues.length === 0) {\n return;\n }\n // we have a URL segment string format: \"field1|value1||field2|value2\"\n const fv = new FieldValueCollection();\n fv.SimpleLoadFromURLSegment(this.newRecordValues);\n // now apply the values to the record\n fv.KeyValuePairs.filter(kvp => kvp.Value !== null && kvp.Value !== undefined).forEach(kvp => {\n const f = record.Fields.find(f => f.Name.trim().toLowerCase() === kvp.FieldName.trim().toLowerCase());\n if (f) {\n // make sure we set the value to the right type based on the f.TSType property\n switch (f.EntityFieldInfo.TSType) {\n case EntityFieldTSType.String:\n record.Set(kvp.FieldName, kvp.Value);\n break;\n case EntityFieldTSType.Number:\n record.Set(kvp.FieldName, parseFloat(kvp.Value));\n break;\n case EntityFieldTSType.Boolean:\n if (kvp.Value === 'false' || kvp.Value === '0' || kvp.Value.toString().trim().length === 0 )\n record.Set(kvp.FieldName, false);\n else\n record.Set(kvp.FieldName, true);\n break;\n case EntityFieldTSType.Date:\n record.Set(kvp.FieldName, new Date(kvp.Value));\n break;\n }\n }\n });\n }\n else {\n // we have a plain object format: { field1: value1, field2: value2 }\n const recordValues = this.newRecordValues as Record<string, unknown>;\n Object.keys(recordValues)\n .filter(key => recordValues[key] !== null && recordValues[key] !== undefined)\n .forEach(key => {\n const f = record.Fields.find(f => f.Name.trim().toLowerCase() === key.trim().toLowerCase());\n if (f) {\n const value = recordValues[key];\n // Set the value with proper type conversion\n switch (f.EntityFieldInfo.TSType) {\n case EntityFieldTSType.String:\n record.Set(key, value?.toString() || '');\n break;\n case EntityFieldTSType.Number:\n record.Set(key, typeof value === 'number' ? value : parseFloat(value?.toString() || '0'));\n break;\n case EntityFieldTSType.Boolean:\n if (typeof value === 'boolean') {\n record.Set(key, value);\n }\n else if (typeof value === 'string') {\n record.Set(key, value !== 'false' && value !== '0' && value.trim().length > 0);\n }\n else {\n record.Set(key, !!value);\n }\n break;\n case EntityFieldTSType.Date:\n record.Set(key, value instanceof Date ? value : new Date(value?.toString() || ''));\n break;\n default:\n record.Set(key, value);\n break;\n }\n }\n });\n }\n }\n\n /**\n * Subscribe to BaseFormComponent @Output events and map them to Explorer services.\n */\n private subscribeToFormEvents(form: BaseFormComponent): void {\n this.cleanupFormSubscriptions();\n\n this._formEventSubscriptions.push(\n form.Navigate.subscribe((event: FormNavigationEvent) => this.handleNavigation(event)),\n form.Notification.subscribe((event: FormNotificationEvent) => {\n this.sharedService.CreateSimpleNotification(event.Message, event.Type, event.Duration);\n })\n );\n }\n\n private handleNavigation(event: FormNavigationEvent): void {\n switch (event.Kind) {\n case 'record':\n this.navigationService.OpenEntityRecord(event.EntityName, event.PrimaryKey, { forceNewTab: event.OpenInNewTab });\n break;\n case 'new-record':\n // Creating a new related record from inside an open record form (e.g. + New\n // on a related-entity grid). Force a new tab so the parent record stays\n // intact — otherwise the new-record form silently replaces the parent in\n // single-resource mode and the user loses their context. This is the\n // original intent of dea32401ff, now stated explicitly at the call site\n // instead of as a global navigation heuristic.\n this.navigationService.OpenNewEntityRecord(event.EntityName, {\n newRecordValues: event.DefaultValues,\n forceNewTab: true,\n });\n break;\n case 'entity-hierarchy':\n this.navigationService.OpenEntityRecord(event.EntityName, event.PrimaryKey);\n break;\n case 'external-link':\n window.open(event.Url, '_blank');\n break;\n case 'email':\n window.open(`mailto:${event.EmailAddress}`, '_self');\n break;\n }\n }\n\n private cleanupFormSubscriptions(): void {\n for (const sub of this._formEventSubscriptions) {\n sub.unsubscribe();\n }\n this._formEventSubscriptions = [];\n }\n\n ngOnDestroy(): void {\n // CRITICAL: Clean up form event subscriptions first\n this.cleanupFormSubscriptions();\n\n // CRITICAL: Clean up dynamically created form component to prevent zombie components\n if (this._formComponentRef) {\n this._formComponentRef.destroy();\n this._formComponentRef = null;\n }\n\n // CRITICAL: Unsubscribe from event handler to prevent memory leaks\n if (this._eventHandlerSubscription) {\n this._eventHandlerSubscription.unsubscribe();\n this._eventHandlerSubscription = null;\n }\n \n // Clean up record reference\n if (this._currentRecord) {\n this._currentRecord = null;\n }\n \n // Clear the view container to ensure no lingering references\n if (this.formContainer?.viewContainerRef) {\n this.formContainer.viewContainerRef.clear();\n }\n \n // Reset state\n this.loading = true;\n this.useGenericForm = false;\n }\n}\n","@if (loading) {\n <mj-loading [showText]=\"false\" size=\"large\"></mj-loading>\n}\n@if (errorTitle) {\n <div class=\"single-record-error\" role=\"alert\">\n <div class=\"single-record-error__icon\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i>\n </div>\n <h2 class=\"single-record-error__title\">{{ errorTitle }}</h2>\n @if (errorDetail) {\n <p class=\"single-record-error__detail\">{{ errorDetail }}</p>\n }\n <p class=\"single-record-error__hint\">See browser console for technical details.</p>\n </div>\n}\n<ng-template mjContainer></ng-template>\n"]}
|
|
@@ -120,7 +120,7 @@ export class SystemValidationBannerComponent {
|
|
|
120
120
|
i0.ɵɵconditionalCreate(0, SystemValidationBannerComponent_Conditional_0_Template, 5, 1, "div", 0);
|
|
121
121
|
} if (rf & 2) {
|
|
122
122
|
i0.ɵɵconditional(ctx.issues.length > 0 ? 0 : -1);
|
|
123
|
-
} }, dependencies: [CommonModule, i2.NgClass], styles: [".system-validation-wrapper[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 10000;\n pointer-events: none;\n }\n \n .system-validation-overlay[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color:
|
|
123
|
+
} }, dependencies: [CommonModule, i2.NgClass], styles: [".system-validation-wrapper[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 10000;\n pointer-events: none;\n }\n \n .system-validation-overlay[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: var(--mj-bg-overlay);\n z-index: 10001;\n pointer-events: auto;\n }\n \n .system-validation-container[_ngcontent-%COMP%] {\n position: fixed;\n top: 60px;\n left: 0;\n right: 0;\n z-index: 10002;\n display: flex;\n flex-direction: column;\n gap: 16px;\n padding: 16px;\n max-height: 80vh;\n overflow-y: auto;\n pointer-events: auto;\n }\n\n .system-validation-banner[_ngcontent-%COMP%] {\n border-radius: 4px;\n box-shadow: var(--mj-shadow-md);\n padding: 16px;\n animation: _ngcontent-%COMP%_slide-down 0.3s ease-out;\n }\n\n .system-validation-error[_ngcontent-%COMP%] {\n background-color: var(--mj-status-error-bg);\n border-left: 4px solid var(--mj-status-error);\n }\n\n .system-validation-warning[_ngcontent-%COMP%] {\n background-color: var(--mj-status-warning-bg);\n border-left: 4px solid var(--mj-status-warning);\n }\n\n .system-validation-info[_ngcontent-%COMP%] {\n background-color: var(--mj-status-info-bg);\n border-left: 4px solid var(--mj-status-info);\n }\n\n .banner-content[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n }\n\n .banner-icon[_ngcontent-%COMP%] {\n margin-right: 16px;\n font-size: 24px;\n }\n\n .severity-icon[_ngcontent-%COMP%] {\n font-size: 18px;\n }\n\n .severity-error[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n }\n\n .severity-warning[_ngcontent-%COMP%] {\n color: var(--mj-status-warning);\n }\n\n .severity-info[_ngcontent-%COMP%] {\n color: var(--mj-status-info);\n }\n\n .banner-message[_ngcontent-%COMP%] {\n flex: 1;\n }\n\n .banner-message[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n }\n\n .banner-message[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 4px 0 0 0;\n font-size: 14px;\n }\n\n .help-text[_ngcontent-%COMP%] {\n font-style: italic;\n }\n\n .dismiss-button[_ngcontent-%COMP%] {\n background: transparent;\n border: none;\n cursor: pointer;\n font-size: 16px;\n color: var(--mj-text-secondary);\n padding: 4px;\n }\n\n .dismiss-button[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-primary);\n }\n\n @keyframes _ngcontent-%COMP%_slide-down {\n 0% {\n transform: translateY(-20px);\n opacity: 0;\n }\n 100% {\n transform: translateY(0);\n opacity: 1;\n }\n }"] });
|
|
124
124
|
}
|
|
125
125
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(SystemValidationBannerComponent, [{
|
|
126
126
|
type: Component,
|
|
@@ -170,7 +170,7 @@ export class SystemValidationBannerComponent {
|
|
|
170
170
|
</div>
|
|
171
171
|
</div>
|
|
172
172
|
}
|
|
173
|
-
`, styles: ["\n .system-validation-wrapper {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 10000;\n pointer-events: none;\n }\n \n .system-validation-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color:
|
|
173
|
+
`, styles: ["\n .system-validation-wrapper {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 10000;\n pointer-events: none;\n }\n \n .system-validation-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: var(--mj-bg-overlay);\n z-index: 10001;\n pointer-events: auto;\n }\n \n .system-validation-container {\n position: fixed;\n top: 60px;\n left: 0;\n right: 0;\n z-index: 10002;\n display: flex;\n flex-direction: column;\n gap: 16px;\n padding: 16px;\n max-height: 80vh;\n overflow-y: auto;\n pointer-events: auto;\n }\n\n .system-validation-banner {\n border-radius: 4px;\n box-shadow: var(--mj-shadow-md);\n padding: 16px;\n animation: slide-down 0.3s ease-out;\n }\n\n .system-validation-error {\n background-color: var(--mj-status-error-bg);\n border-left: 4px solid var(--mj-status-error);\n }\n\n .system-validation-warning {\n background-color: var(--mj-status-warning-bg);\n border-left: 4px solid var(--mj-status-warning);\n }\n\n .system-validation-info {\n background-color: var(--mj-status-info-bg);\n border-left: 4px solid var(--mj-status-info);\n }\n\n .banner-content {\n display: flex;\n align-items: flex-start;\n }\n\n .banner-icon {\n margin-right: 16px;\n font-size: 24px;\n }\n\n .severity-icon {\n font-size: 18px;\n }\n\n .severity-error {\n color: var(--mj-status-error);\n }\n\n .severity-warning {\n color: var(--mj-status-warning);\n }\n\n .severity-info {\n color: var(--mj-status-info);\n }\n\n .banner-message {\n flex: 1;\n }\n\n .banner-message h3 {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n }\n\n .banner-message p {\n margin: 4px 0 0 0;\n font-size: 14px;\n }\n\n .help-text {\n font-style: italic;\n }\n\n .dismiss-button {\n background: transparent;\n border: none;\n cursor: pointer;\n font-size: 16px;\n color: var(--mj-text-secondary);\n padding: 4px;\n }\n\n .dismiss-button:hover {\n color: var(--mj-text-primary);\n }\n\n @keyframes slide-down {\n 0% {\n transform: translateY(-20px);\n opacity: 0;\n }\n 100% {\n transform: translateY(0);\n opacity: 1;\n }\n }\n "] }]
|
|
174
174
|
}], () => [{ type: i1.SystemValidationService }], null); })();
|
|
175
175
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(SystemValidationBannerComponent, { className: "SystemValidationBannerComponent", filePath: "src/lib/system-validation/system-validation-banner.component.ts", lineNumber: 186 }); })();
|
|
176
176
|
//# sourceMappingURL=system-validation-banner.component.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system-validation-banner.component.js","sourceRoot":"","sources":["../../../src/lib/system-validation/system-validation-banner.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAqB,MAAM,eAAe,CAAC;AAG7D,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;;;;;IAWrC,yBAA6C;;;IAUnC,+BAA2C;IAAA,sBAAC;IAAA,iBAAO;;;IAGnD,+BAA6C;IAAA,4BAAE;IAAA,iBAAO;;;IAGtD,+BAA0C;IAAA,4BAAE;IAAA,iBAAO;;;IAMnD,yBAAG;IAAA,YAAmB;IAAA,iBAAI;;;IAAvB,cAAmB;IAAnB,sCAAmB;;;IAGtB,6BAAqB;IAAA,YAAgB;IAAA,iBAAI;;;IAApB,cAAgB;IAAhB,mCAAgB;;;;IAKrC,kCAAqF;IAA7E,wQAAS,gCAAsB,KAAC;IACtC,wBACF;IAAA,iBAAS;;;IAxBb,AADF,AAHF,8BAEoD,aACtB,aACD;IACvB,sHAAkC;IAGlC,sHAAoC;IAGpC,sHAAiC;IAGnC,iBAAM;IAEJ,AADF,8BAA4B,SACtB;IAAA,YAAmB;IAAA,iBAAK;IAC5B,gHAAqB;IAGrB,sHAAkB;IAGpB,iBAAM;IACN,gCAA0B;IACxB,2HAAkC;IAOxC,AADE,AADE,iBAAM,EACF,EACF;;;IA9BJ,kEAAiD;IAG7C,eAEC;IAFD,wDAEC;IACD,cAEC;IAFD,0DAEC;IACD,cAEC;IAFD,uDAEC;IAGG,eAAmB;IAAnB,sCAAmB;IACvB,cAEC;IAFD,2CAEC;IACD,cAEC;IAFD,yCAEC;IAGD,eAIC;IAJD,yDAIC;;;IApCb,8BAAuC;IAErC,+GAAiB;IAGjB,8BAAyC;IACvC,mIAkCC;IAEL,AADE,iBAAM,EACF;;;IAxCJ,cAEC;IAFD,2CAEC;IAEC,eAkCC;IAlCD,4BAkCC;;AAsIX,MAAM,OAAO,+BAA+B;IAKtB;IAJpB,MAAM,GAA4B,EAAE,CAAC;IACrC,SAAS,GAAG,KAAK,CAAC;IACV,YAAY,CAA2B;IAE/C,YAAoB,iBAA0C;QAA1C,sBAAiB,GAAjB,iBAAiB,CAAyB;IAAI,CAAC;IAEnE,QAAQ;QACN,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE;YAC9E,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;YAErB,4CAA4C;YAC5C,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC;QACpE,CAAC,CAAC,CAAC;IACL,CAAC;IAED,WAAW;QACT,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,IAAI,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC;QAClC,CAAC;IACH,CAAC;IAED,YAAY,CAAC,EAAU;QACrB,IAAI,CAAC,iBAAiB,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;IACzC,CAAC;yHAxBU,+BAA+B;6DAA/B,+BAA+B;YA/KxC,iGAAyB;;YAAzB,gDA4CC;4BA9CO,YAAY;;iFAiLX,+BAA+B;cApL3C,SAAS;2BACE,6BAA6B,cAC3B,IAAI,WACP,CAAC,YAAY,CAAC,YACb;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA8CP;;kFAkIQ,+BAA+B","sourcesContent":["import { Component, OnInit, OnDestroy } from '@angular/core';\nimport { SystemValidationService, SystemValidationIssue } from '../services/system-validation.service';\nimport { Subscription } from 'rxjs';\nimport { CommonModule } from '@angular/common';\n\n@Component({\n selector: 'mj-system-validation-banner',\n standalone: true,\n imports: [CommonModule],\n template: `\n @if (issues.length > 0) {\n <div class=\"system-validation-wrapper\">\n <!-- Dark overlay for serious errors -->\n @if (hasErrors) {\n <div class=\"system-validation-overlay\"></div>\n }\n <div class=\"system-validation-container\">\n @for (issue of issues; track issue) {\n <div\n class=\"system-validation-banner\"\n [ngClass]=\"'system-validation-' + issue.severity\">\n <div class=\"banner-content\">\n <div class=\"banner-icon\">\n @if (issue.severity === 'error') {\n <span class=\"severity-icon severity-error\">❌</span>\n }\n @if (issue.severity === 'warning') {\n <span class=\"severity-icon severity-warning\">⚠️</span>\n }\n @if (issue.severity === 'info') {\n <span class=\"severity-icon severity-info\">ℹ️</span>\n }\n </div>\n <div class=\"banner-message\">\n <h3>{{ issue.message }}</h3>\n @if (issue.details) {\n <p>{{ issue.details }}</p>\n }\n @if (issue.help) {\n <p class=\"help-text\">{{ issue.help }}</p>\n }\n </div>\n <div class=\"banner-close\">\n @if (issue.severity !== 'error') {\n <button (click)=\"dismissIssue(issue.id)\" aria-label=\"Dismiss\" class=\"dismiss-button\">\n ✕\n </button>\n }\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n }\n `,\n styles: [`\n .system-validation-wrapper {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 10000;\n pointer-events: none;\n }\n \n .system-validation-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color:
|
|
1
|
+
{"version":3,"file":"system-validation-banner.component.js","sourceRoot":"","sources":["../../../src/lib/system-validation/system-validation-banner.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAqB,MAAM,eAAe,CAAC;AAG7D,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;;;;;IAWrC,yBAA6C;;;IAUnC,+BAA2C;IAAA,sBAAC;IAAA,iBAAO;;;IAGnD,+BAA6C;IAAA,4BAAE;IAAA,iBAAO;;;IAGtD,+BAA0C;IAAA,4BAAE;IAAA,iBAAO;;;IAMnD,yBAAG;IAAA,YAAmB;IAAA,iBAAI;;;IAAvB,cAAmB;IAAnB,sCAAmB;;;IAGtB,6BAAqB;IAAA,YAAgB;IAAA,iBAAI;;;IAApB,cAAgB;IAAhB,mCAAgB;;;;IAKrC,kCAAqF;IAA7E,wQAAS,gCAAsB,KAAC;IACtC,wBACF;IAAA,iBAAS;;;IAxBb,AADF,AAHF,8BAEoD,aACtB,aACD;IACvB,sHAAkC;IAGlC,sHAAoC;IAGpC,sHAAiC;IAGnC,iBAAM;IAEJ,AADF,8BAA4B,SACtB;IAAA,YAAmB;IAAA,iBAAK;IAC5B,gHAAqB;IAGrB,sHAAkB;IAGpB,iBAAM;IACN,gCAA0B;IACxB,2HAAkC;IAOxC,AADE,AADE,iBAAM,EACF,EACF;;;IA9BJ,kEAAiD;IAG7C,eAEC;IAFD,wDAEC;IACD,cAEC;IAFD,0DAEC;IACD,cAEC;IAFD,uDAEC;IAGG,eAAmB;IAAnB,sCAAmB;IACvB,cAEC;IAFD,2CAEC;IACD,cAEC;IAFD,yCAEC;IAGD,eAIC;IAJD,yDAIC;;;IApCb,8BAAuC;IAErC,+GAAiB;IAGjB,8BAAyC;IACvC,mIAkCC;IAEL,AADE,iBAAM,EACF;;;IAxCJ,cAEC;IAFD,2CAEC;IAEC,eAkCC;IAlCD,4BAkCC;;AAsIX,MAAM,OAAO,+BAA+B;IAKtB;IAJpB,MAAM,GAA4B,EAAE,CAAC;IACrC,SAAS,GAAG,KAAK,CAAC;IACV,YAAY,CAA2B;IAE/C,YAAoB,iBAA0C;QAA1C,sBAAiB,GAAjB,iBAAiB,CAAyB;IAAI,CAAC;IAEnE,QAAQ;QACN,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE;YAC9E,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;YAErB,4CAA4C;YAC5C,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC;QACpE,CAAC,CAAC,CAAC;IACL,CAAC;IAED,WAAW;QACT,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,IAAI,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC;QAClC,CAAC;IACH,CAAC;IAED,YAAY,CAAC,EAAU;QACrB,IAAI,CAAC,iBAAiB,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;IACzC,CAAC;yHAxBU,+BAA+B;6DAA/B,+BAA+B;YA/KxC,iGAAyB;;YAAzB,gDA4CC;4BA9CO,YAAY;;iFAiLX,+BAA+B;cApL3C,SAAS;2BACE,6BAA6B,cAC3B,IAAI,WACP,CAAC,YAAY,CAAC,YACb;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA8CP;;kFAkIQ,+BAA+B","sourcesContent":["import { Component, OnInit, OnDestroy } from '@angular/core';\nimport { SystemValidationService, SystemValidationIssue } from '../services/system-validation.service';\nimport { Subscription } from 'rxjs';\nimport { CommonModule } from '@angular/common';\n\n@Component({\n selector: 'mj-system-validation-banner',\n standalone: true,\n imports: [CommonModule],\n template: `\n @if (issues.length > 0) {\n <div class=\"system-validation-wrapper\">\n <!-- Dark overlay for serious errors -->\n @if (hasErrors) {\n <div class=\"system-validation-overlay\"></div>\n }\n <div class=\"system-validation-container\">\n @for (issue of issues; track issue) {\n <div\n class=\"system-validation-banner\"\n [ngClass]=\"'system-validation-' + issue.severity\">\n <div class=\"banner-content\">\n <div class=\"banner-icon\">\n @if (issue.severity === 'error') {\n <span class=\"severity-icon severity-error\">❌</span>\n }\n @if (issue.severity === 'warning') {\n <span class=\"severity-icon severity-warning\">⚠️</span>\n }\n @if (issue.severity === 'info') {\n <span class=\"severity-icon severity-info\">ℹ️</span>\n }\n </div>\n <div class=\"banner-message\">\n <h3>{{ issue.message }}</h3>\n @if (issue.details) {\n <p>{{ issue.details }}</p>\n }\n @if (issue.help) {\n <p class=\"help-text\">{{ issue.help }}</p>\n }\n </div>\n <div class=\"banner-close\">\n @if (issue.severity !== 'error') {\n <button (click)=\"dismissIssue(issue.id)\" aria-label=\"Dismiss\" class=\"dismiss-button\">\n ✕\n </button>\n }\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n }\n `,\n styles: [`\n .system-validation-wrapper {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 10000;\n pointer-events: none;\n }\n \n .system-validation-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: var(--mj-bg-overlay);\n z-index: 10001;\n pointer-events: auto;\n }\n \n .system-validation-container {\n position: fixed;\n top: 60px;\n left: 0;\n right: 0;\n z-index: 10002;\n display: flex;\n flex-direction: column;\n gap: 16px;\n padding: 16px;\n max-height: 80vh;\n overflow-y: auto;\n pointer-events: auto;\n }\n\n .system-validation-banner {\n border-radius: 4px;\n box-shadow: var(--mj-shadow-md);\n padding: 16px;\n animation: slide-down 0.3s ease-out;\n }\n\n .system-validation-error {\n background-color: var(--mj-status-error-bg);\n border-left: 4px solid var(--mj-status-error);\n }\n\n .system-validation-warning {\n background-color: var(--mj-status-warning-bg);\n border-left: 4px solid var(--mj-status-warning);\n }\n\n .system-validation-info {\n background-color: var(--mj-status-info-bg);\n border-left: 4px solid var(--mj-status-info);\n }\n\n .banner-content {\n display: flex;\n align-items: flex-start;\n }\n\n .banner-icon {\n margin-right: 16px;\n font-size: 24px;\n }\n\n .severity-icon {\n font-size: 18px;\n }\n\n .severity-error {\n color: var(--mj-status-error);\n }\n\n .severity-warning {\n color: var(--mj-status-warning);\n }\n\n .severity-info {\n color: var(--mj-status-info);\n }\n\n .banner-message {\n flex: 1;\n }\n\n .banner-message h3 {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n }\n\n .banner-message p {\n margin: 4px 0 0 0;\n font-size: 14px;\n }\n\n .help-text {\n font-style: italic;\n }\n\n .dismiss-button {\n background: transparent;\n border: none;\n cursor: pointer;\n font-size: 16px;\n color: var(--mj-text-secondary);\n padding: 4px;\n }\n\n .dismiss-button:hover {\n color: var(--mj-text-primary);\n }\n\n @keyframes slide-down {\n 0% {\n transform: translateY(-20px);\n opacity: 0;\n }\n 100% {\n transform: translateY(0);\n opacity: 1;\n }\n }\n `]\n})\nexport class SystemValidationBannerComponent implements OnInit, OnDestroy {\n issues: SystemValidationIssue[] = [];\n hasErrors = false;\n private subscription: Subscription | undefined;\n\n constructor(private validationService: SystemValidationService) { }\n\n ngOnInit() {\n this.subscription = this.validationService.validationIssues$.subscribe(issues => {\n this.issues = issues;\n \n // Check if there are any error-level issues\n this.hasErrors = issues.some(issue => issue.severity === 'error');\n });\n }\n\n ngOnDestroy() {\n if (this.subscription) {\n this.subscription.unsubscribe();\n }\n }\n\n dismissIssue(id: string) {\n this.validationService.removeIssue(id);\n }\n}"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memberjunction/ng-explorer-core",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.34.1",
|
|
4
4
|
"description": "MemberJunction Explorer: Core Angular Components",
|
|
5
5
|
"main": "./dist/public-api.js",
|
|
6
6
|
"typings": "./dist/public-api.d.ts",
|
|
@@ -32,47 +32,47 @@
|
|
|
32
32
|
"@angular/cdk": "21.1.3",
|
|
33
33
|
"@angular/platform-browser": "21.1.3",
|
|
34
34
|
"@auth0/auth0-angular": "^2.6.0",
|
|
35
|
-
"@memberjunction/ai-core-plus": "5.
|
|
36
|
-
"@memberjunction/ai-engine-base": "5.
|
|
37
|
-
"@memberjunction/communication-types": "5.
|
|
38
|
-
"@memberjunction/core": "5.
|
|
39
|
-
"@memberjunction/core-entities": "5.
|
|
40
|
-
"@memberjunction/entity-communications-client": "5.
|
|
41
|
-
"@memberjunction/export-engine": "5.
|
|
42
|
-
"@memberjunction/global": "5.
|
|
43
|
-
"@memberjunction/graphql-dataprovider": "5.
|
|
44
|
-
"@memberjunction/ng-ai-test-harness": "5.
|
|
45
|
-
"@memberjunction/ng-artifacts": "5.
|
|
46
|
-
"@memberjunction/ng-auth-services": "5.
|
|
47
|
-
"@memberjunction/ng-base-application": "5.
|
|
48
|
-
"@memberjunction/ng-base-forms": "5.
|
|
49
|
-
"@memberjunction/ng-base-types": "5.
|
|
50
|
-
"@memberjunction/ng-container-directives": "5.
|
|
51
|
-
"@memberjunction/ng-conversations": "5.
|
|
52
|
-
"@memberjunction/ng-dashboard-viewer": "5.
|
|
53
|
-
"@memberjunction/ng-dashboards": "5.
|
|
54
|
-
"@memberjunction/ng-entity-form-dialog": "5.
|
|
55
|
-
"@memberjunction/ng-entity-permissions": "5.
|
|
56
|
-
"@memberjunction/ng-entity-viewer": "5.
|
|
57
|
-
"@memberjunction/ng-explorer-settings": "5.
|
|
58
|
-
"@memberjunction/ng-export-service": "5.
|
|
59
|
-
"@memberjunction/ng-feedback": "5.
|
|
60
|
-
"@memberjunction/ng-file-storage": "5.
|
|
61
|
-
"@memberjunction/ng-generic-dialog": "5.
|
|
62
|
-
"@memberjunction/ng-list-detail-grid": "5.
|
|
63
|
-
"@memberjunction/ng-notifications": "5.
|
|
64
|
-
"@memberjunction/ng-query-viewer": "5.
|
|
65
|
-
"@memberjunction/ng-record-changes": "5.
|
|
66
|
-
"@memberjunction/ng-record-selector": "5.
|
|
67
|
-
"@memberjunction/ng-record-tags": "5.
|
|
68
|
-
"@memberjunction/ng-resource-permissions": "5.
|
|
69
|
-
"@memberjunction/ng-search": "5.
|
|
70
|
-
"@memberjunction/ng-shared": "5.
|
|
71
|
-
"@memberjunction/ng-shared-generic": "5.
|
|
72
|
-
"@memberjunction/ng-ui-components": "5.
|
|
73
|
-
"@memberjunction/ng-user-avatar": "5.
|
|
74
|
-
"@memberjunction/ng-word-cloud": "5.
|
|
75
|
-
"@memberjunction/templates-base-types": "5.
|
|
35
|
+
"@memberjunction/ai-core-plus": "5.34.1",
|
|
36
|
+
"@memberjunction/ai-engine-base": "5.34.1",
|
|
37
|
+
"@memberjunction/communication-types": "5.34.1",
|
|
38
|
+
"@memberjunction/core": "5.34.1",
|
|
39
|
+
"@memberjunction/core-entities": "5.34.1",
|
|
40
|
+
"@memberjunction/entity-communications-client": "5.34.1",
|
|
41
|
+
"@memberjunction/export-engine": "5.34.1",
|
|
42
|
+
"@memberjunction/global": "5.34.1",
|
|
43
|
+
"@memberjunction/graphql-dataprovider": "5.34.1",
|
|
44
|
+
"@memberjunction/ng-ai-test-harness": "5.34.1",
|
|
45
|
+
"@memberjunction/ng-artifacts": "5.34.1",
|
|
46
|
+
"@memberjunction/ng-auth-services": "5.34.1",
|
|
47
|
+
"@memberjunction/ng-base-application": "5.34.1",
|
|
48
|
+
"@memberjunction/ng-base-forms": "5.34.1",
|
|
49
|
+
"@memberjunction/ng-base-types": "5.34.1",
|
|
50
|
+
"@memberjunction/ng-container-directives": "5.34.1",
|
|
51
|
+
"@memberjunction/ng-conversations": "5.34.1",
|
|
52
|
+
"@memberjunction/ng-dashboard-viewer": "5.34.1",
|
|
53
|
+
"@memberjunction/ng-dashboards": "5.34.1",
|
|
54
|
+
"@memberjunction/ng-entity-form-dialog": "5.34.1",
|
|
55
|
+
"@memberjunction/ng-entity-permissions": "5.34.1",
|
|
56
|
+
"@memberjunction/ng-entity-viewer": "5.34.1",
|
|
57
|
+
"@memberjunction/ng-explorer-settings": "5.34.1",
|
|
58
|
+
"@memberjunction/ng-export-service": "5.34.1",
|
|
59
|
+
"@memberjunction/ng-feedback": "5.34.1",
|
|
60
|
+
"@memberjunction/ng-file-storage": "5.34.1",
|
|
61
|
+
"@memberjunction/ng-generic-dialog": "5.34.1",
|
|
62
|
+
"@memberjunction/ng-list-detail-grid": "5.34.1",
|
|
63
|
+
"@memberjunction/ng-notifications": "5.34.1",
|
|
64
|
+
"@memberjunction/ng-query-viewer": "5.34.1",
|
|
65
|
+
"@memberjunction/ng-record-changes": "5.34.1",
|
|
66
|
+
"@memberjunction/ng-record-selector": "5.34.1",
|
|
67
|
+
"@memberjunction/ng-record-tags": "5.34.1",
|
|
68
|
+
"@memberjunction/ng-resource-permissions": "5.34.1",
|
|
69
|
+
"@memberjunction/ng-search": "5.34.1",
|
|
70
|
+
"@memberjunction/ng-shared": "5.34.1",
|
|
71
|
+
"@memberjunction/ng-shared-generic": "5.34.1",
|
|
72
|
+
"@memberjunction/ng-ui-components": "5.34.1",
|
|
73
|
+
"@memberjunction/ng-user-avatar": "5.34.1",
|
|
74
|
+
"@memberjunction/ng-word-cloud": "5.34.1",
|
|
75
|
+
"@memberjunction/templates-base-types": "5.34.1",
|
|
76
76
|
"golden-layout": "^2.6.0",
|
|
77
77
|
"rxjs": "^7.8.2",
|
|
78
78
|
"tslib": "^2.8.1"
|