@memberjunction/ng-archive-manager 0.0.1 → 5.29.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.
Files changed (30) hide show
  1. package/dist/lib/archive-config/archive-config-admin.component.d.ts +113 -0
  2. package/dist/lib/archive-config/archive-config-admin.component.d.ts.map +1 -0
  3. package/dist/lib/archive-config/archive-config-admin.component.js +735 -0
  4. package/dist/lib/archive-config/archive-config-admin.component.js.map +1 -0
  5. package/dist/lib/archive-manager.module.d.ts +14 -0
  6. package/dist/lib/archive-manager.module.d.ts.map +1 -0
  7. package/dist/lib/archive-manager.module.js +48 -0
  8. package/dist/lib/archive-manager.module.js.map +1 -0
  9. package/dist/lib/archive-restore/archive-restore-dialog.component.d.ts +82 -0
  10. package/dist/lib/archive-restore/archive-restore-dialog.component.d.ts.map +1 -0
  11. package/dist/lib/archive-restore/archive-restore-dialog.component.js +386 -0
  12. package/dist/lib/archive-restore/archive-restore-dialog.component.js.map +1 -0
  13. package/dist/lib/archive-run-viewer/archive-run-viewer.component.d.ts +81 -0
  14. package/dist/lib/archive-run-viewer/archive-run-viewer.component.d.ts.map +1 -0
  15. package/dist/lib/archive-run-viewer/archive-run-viewer.component.js +515 -0
  16. package/dist/lib/archive-run-viewer/archive-run-viewer.component.js.map +1 -0
  17. package/dist/lib/archive-status/archive-status-badge.component.d.ts +65 -0
  18. package/dist/lib/archive-status/archive-status-badge.component.d.ts.map +1 -0
  19. package/dist/lib/archive-status/archive-status-badge.component.js +172 -0
  20. package/dist/lib/archive-status/archive-status-badge.component.js.map +1 -0
  21. package/dist/lib/archive-types.d.ts +81 -0
  22. package/dist/lib/archive-types.d.ts.map +1 -0
  23. package/dist/lib/archive-types.js +8 -0
  24. package/dist/lib/archive-types.js.map +1 -0
  25. package/dist/public-api.d.ts +6 -0
  26. package/dist/public-api.d.ts.map +1 -0
  27. package/dist/public-api.js +11 -0
  28. package/dist/public-api.js.map +1 -0
  29. package/package.json +42 -6
  30. package/README.md +0 -45
@@ -0,0 +1,386 @@
1
+ import { Component, ChangeDetectionStrategy, ChangeDetectorRef, Input, Output, EventEmitter, inject, } from '@angular/core';
2
+ import { RunView } from '@memberjunction/core';
3
+ import { UUIDsEqual } from '@memberjunction/global';
4
+ import * as i0 from "@angular/core";
5
+ import * as i1 from "@memberjunction/ng-shared-generic";
6
+ const _forTrack0 = ($index, $item) => $item.ID;
7
+ function ArchiveRestoreDialogComponent_Conditional_0_Conditional_8_Template(rf, ctx) { if (rf & 1) {
8
+ i0.ɵɵelementStart(0, "div", 7);
9
+ i0.ɵɵelement(1, "mj-loading", 14);
10
+ i0.ɵɵelementEnd();
11
+ } }
12
+ function ArchiveRestoreDialogComponent_Conditional_0_Conditional_9_Conditional_2_Template(rf, ctx) { if (rf & 1) {
13
+ i0.ɵɵelementStart(0, "div", 16);
14
+ i0.ɵɵelement(1, "i", 20);
15
+ i0.ɵɵelementStart(2, "p");
16
+ i0.ɵɵtext(3, "No archived versions found.");
17
+ i0.ɵɵelementEnd()();
18
+ } }
19
+ function ArchiveRestoreDialogComponent_Conditional_0_Conditional_9_Conditional_3_For_2_Template(rf, ctx) { if (rf & 1) {
20
+ const _r3 = i0.ɵɵgetCurrentView();
21
+ i0.ɵɵelementStart(0, "div", 22);
22
+ i0.ɵɵlistener("click", function ArchiveRestoreDialogComponent_Conditional_0_Conditional_9_Conditional_3_For_2_Template_div_click_0_listener() { const version_r4 = i0.ɵɵrestoreView(_r3).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.SelectVersion(version_r4)); })("keydown.enter", function ArchiveRestoreDialogComponent_Conditional_0_Conditional_9_Conditional_3_For_2_Template_div_keydown_enter_0_listener() { const version_r4 = i0.ɵɵrestoreView(_r3).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.SelectVersion(version_r4)); });
23
+ i0.ɵɵelement(1, "div", 23);
24
+ i0.ɵɵelementStart(2, "div", 24)(3, "span", 25);
25
+ i0.ɵɵtext(4);
26
+ i0.ɵɵelementEnd();
27
+ i0.ɵɵelementStart(5, "span", 26);
28
+ i0.ɵɵtext(6);
29
+ i0.ɵɵelementEnd()()();
30
+ } if (rf & 2) {
31
+ const version_r4 = ctx.$implicit;
32
+ const ctx_r1 = i0.ɵɵnextContext(4);
33
+ i0.ɵɵclassProp("active", ctx_r1.IsSelected(version_r4));
34
+ i0.ɵɵattribute("aria-label", "Version from " + ctx_r1.FormatDate(version_r4.ArchivedAt));
35
+ i0.ɵɵadvance(4);
36
+ i0.ɵɵtextInterpolate(ctx_r1.FormatDate(version_r4.ArchivedAt));
37
+ i0.ɵɵadvance(2);
38
+ i0.ɵɵtextInterpolate3(" ", version_r4.FieldCount, " field", version_r4.FieldCount !== 1 ? "s" : "", " \u00B7 ", ctx_r1.FormatBytes(version_r4.Bytes), " ");
39
+ } }
40
+ function ArchiveRestoreDialogComponent_Conditional_0_Conditional_9_Conditional_3_Template(rf, ctx) { if (rf & 1) {
41
+ i0.ɵɵelementStart(0, "div", 17);
42
+ i0.ɵɵrepeaterCreate(1, ArchiveRestoreDialogComponent_Conditional_0_Conditional_9_Conditional_3_For_2_Template, 7, 7, "div", 21, _forTrack0);
43
+ i0.ɵɵelementEnd();
44
+ } if (rf & 2) {
45
+ const ctx_r1 = i0.ɵɵnextContext(3);
46
+ i0.ɵɵadvance();
47
+ i0.ɵɵrepeater(ctx_r1.Versions);
48
+ } }
49
+ function ArchiveRestoreDialogComponent_Conditional_0_Conditional_9_Conditional_5_Template(rf, ctx) { if (rf & 1) {
50
+ i0.ɵɵelementStart(0, "div", 27)(1, "h3");
51
+ i0.ɵɵtext(2, "Archived Fields Preview");
52
+ i0.ɵɵelementEnd();
53
+ i0.ɵɵelementStart(3, "span", 28);
54
+ i0.ɵɵtext(4);
55
+ i0.ɵɵelementEnd()();
56
+ i0.ɵɵelementStart(5, "pre", 29);
57
+ i0.ɵɵtext(6);
58
+ i0.ɵɵelementEnd();
59
+ } if (rf & 2) {
60
+ const ctx_r1 = i0.ɵɵnextContext(3);
61
+ i0.ɵɵadvance(4);
62
+ i0.ɵɵtextInterpolate(ctx_r1.FormatDate(ctx_r1.SelectedVersion.ArchivedAt));
63
+ i0.ɵɵadvance(2);
64
+ i0.ɵɵtextInterpolate(ctx_r1.PreviewJson);
65
+ } }
66
+ function ArchiveRestoreDialogComponent_Conditional_0_Conditional_9_Conditional_6_Template(rf, ctx) { if (rf & 1) {
67
+ i0.ɵɵelementStart(0, "div", 19);
68
+ i0.ɵɵelement(1, "i", 30);
69
+ i0.ɵɵelementStart(2, "p");
70
+ i0.ɵɵtext(3, "Select a version to preview");
71
+ i0.ɵɵelementEnd()();
72
+ } }
73
+ function ArchiveRestoreDialogComponent_Conditional_0_Conditional_9_Template(rf, ctx) { if (rf & 1) {
74
+ i0.ɵɵelementStart(0, "div", 8)(1, "div", 15);
75
+ i0.ɵɵconditionalCreate(2, ArchiveRestoreDialogComponent_Conditional_0_Conditional_9_Conditional_2_Template, 4, 0, "div", 16);
76
+ i0.ɵɵconditionalCreate(3, ArchiveRestoreDialogComponent_Conditional_0_Conditional_9_Conditional_3_Template, 3, 0, "div", 17);
77
+ i0.ɵɵelementEnd();
78
+ i0.ɵɵelementStart(4, "div", 18);
79
+ i0.ɵɵconditionalCreate(5, ArchiveRestoreDialogComponent_Conditional_0_Conditional_9_Conditional_5_Template, 7, 2);
80
+ i0.ɵɵconditionalCreate(6, ArchiveRestoreDialogComponent_Conditional_0_Conditional_9_Conditional_6_Template, 4, 0, "div", 19);
81
+ i0.ɵɵelementEnd()();
82
+ } if (rf & 2) {
83
+ const ctx_r1 = i0.ɵɵnextContext(2);
84
+ i0.ɵɵadvance(2);
85
+ i0.ɵɵconditional(ctx_r1.Versions.length === 0 ? 2 : -1);
86
+ i0.ɵɵadvance();
87
+ i0.ɵɵconditional(ctx_r1.Versions.length > 0 ? 3 : -1);
88
+ i0.ɵɵadvance(2);
89
+ i0.ɵɵconditional(ctx_r1.SelectedVersion ? 5 : -1);
90
+ i0.ɵɵadvance();
91
+ i0.ɵɵconditional(!ctx_r1.SelectedVersion && ctx_r1.Versions.length > 0 ? 6 : -1);
92
+ } }
93
+ function ArchiveRestoreDialogComponent_Conditional_0_Conditional_10_Template(rf, ctx) { if (rf & 1) {
94
+ i0.ɵɵelementStart(0, "div", 9);
95
+ i0.ɵɵelement(1, "i", 31);
96
+ i0.ɵɵtext(2);
97
+ i0.ɵɵelementEnd();
98
+ } if (rf & 2) {
99
+ const ctx_r1 = i0.ɵɵnextContext(2);
100
+ i0.ɵɵadvance(2);
101
+ i0.ɵɵtextInterpolate1(" ", ctx_r1.SuccessMessage, " ");
102
+ } }
103
+ function ArchiveRestoreDialogComponent_Conditional_0_Conditional_11_Template(rf, ctx) { if (rf & 1) {
104
+ i0.ɵɵelementStart(0, "div", 10);
105
+ i0.ɵɵelement(1, "i", 32);
106
+ i0.ɵɵtext(2);
107
+ i0.ɵɵelementEnd();
108
+ } if (rf & 2) {
109
+ const ctx_r1 = i0.ɵɵnextContext(2);
110
+ i0.ɵɵadvance(2);
111
+ i0.ɵɵtextInterpolate1(" ", ctx_r1.ErrorMessage, " ");
112
+ } }
113
+ function ArchiveRestoreDialogComponent_Conditional_0_Conditional_14_Template(rf, ctx) { if (rf & 1) {
114
+ i0.ɵɵelement(0, "i", 33);
115
+ i0.ɵɵtext(1, " Restoring... ");
116
+ } }
117
+ function ArchiveRestoreDialogComponent_Conditional_0_Conditional_15_Template(rf, ctx) { if (rf & 1) {
118
+ i0.ɵɵelement(0, "i", 34);
119
+ i0.ɵɵtext(1, " Restore to this Version ");
120
+ } }
121
+ function ArchiveRestoreDialogComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
122
+ const _r1 = i0.ɵɵgetCurrentView();
123
+ i0.ɵɵelementStart(0, "div", 0);
124
+ i0.ɵɵlistener("click", function ArchiveRestoreDialogComponent_Conditional_0_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.Close()); });
125
+ i0.ɵɵelementEnd();
126
+ i0.ɵɵelementStart(1, "div", 1)(2, "div", 2)(3, "h2", 3);
127
+ i0.ɵɵelement(4, "i", 4);
128
+ i0.ɵɵtext(5, " Archive History ");
129
+ i0.ɵɵelementEnd();
130
+ i0.ɵɵelementStart(6, "button", 5);
131
+ i0.ɵɵlistener("click", function ArchiveRestoreDialogComponent_Conditional_0_Template_button_click_6_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.Close()); });
132
+ i0.ɵɵelement(7, "i", 6);
133
+ i0.ɵɵelementEnd()();
134
+ i0.ɵɵconditionalCreate(8, ArchiveRestoreDialogComponent_Conditional_0_Conditional_8_Template, 2, 0, "div", 7);
135
+ i0.ɵɵconditionalCreate(9, ArchiveRestoreDialogComponent_Conditional_0_Conditional_9_Template, 7, 4, "div", 8);
136
+ i0.ɵɵconditionalCreate(10, ArchiveRestoreDialogComponent_Conditional_0_Conditional_10_Template, 3, 1, "div", 9);
137
+ i0.ɵɵconditionalCreate(11, ArchiveRestoreDialogComponent_Conditional_0_Conditional_11_Template, 3, 1, "div", 10);
138
+ i0.ɵɵelementStart(12, "div", 11)(13, "button", 12);
139
+ i0.ɵɵlistener("click", function ArchiveRestoreDialogComponent_Conditional_0_Template_button_click_13_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.RestoreSelectedVersion()); });
140
+ i0.ɵɵconditionalCreate(14, ArchiveRestoreDialogComponent_Conditional_0_Conditional_14_Template, 2, 0)(15, ArchiveRestoreDialogComponent_Conditional_0_Conditional_15_Template, 2, 0);
141
+ i0.ɵɵelementEnd();
142
+ i0.ɵɵelementStart(16, "button", 13);
143
+ i0.ɵɵlistener("click", function ArchiveRestoreDialogComponent_Conditional_0_Template_button_click_16_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.Close()); });
144
+ i0.ɵɵtext(17, " Close ");
145
+ i0.ɵɵelementEnd()()();
146
+ } if (rf & 2) {
147
+ const ctx_r1 = i0.ɵɵnextContext();
148
+ i0.ɵɵadvance(8);
149
+ i0.ɵɵconditional(ctx_r1.Status === "loading" ? 8 : -1);
150
+ i0.ɵɵadvance();
151
+ i0.ɵɵconditional(ctx_r1.Status !== "loading" ? 9 : -1);
152
+ i0.ɵɵadvance();
153
+ i0.ɵɵconditional(ctx_r1.Status === "success" ? 10 : -1);
154
+ i0.ɵɵadvance();
155
+ i0.ɵɵconditional(ctx_r1.Status === "error" && ctx_r1.ErrorMessage ? 11 : -1);
156
+ i0.ɵɵadvance(2);
157
+ i0.ɵɵproperty("disabled", !ctx_r1.SelectedVersion || ctx_r1.Status === "restoring");
158
+ i0.ɵɵadvance();
159
+ i0.ɵɵconditional(ctx_r1.Status === "restoring" ? 14 : 15);
160
+ } }
161
+ export class ArchiveRestoreDialogComponent {
162
+ cdr = inject(ChangeDetectorRef);
163
+ /** All available versions for this record */
164
+ Versions = [];
165
+ /** Currently selected version for preview */
166
+ SelectedVersion = null;
167
+ /** Parsed JSON preview of the selected version */
168
+ PreviewJson = '';
169
+ /** Current operation status */
170
+ Status = 'idle';
171
+ /** Error message if restore fails */
172
+ ErrorMessage = '';
173
+ /** Success message after restore */
174
+ SuccessMessage = '';
175
+ destroyed = false;
176
+ // --- EntityName input ---
177
+ _entityName = '';
178
+ set EntityName(value) {
179
+ this._entityName = value;
180
+ }
181
+ get EntityName() {
182
+ return this._entityName;
183
+ }
184
+ // --- RecordID input ---
185
+ _recordID = '';
186
+ set RecordID(value) {
187
+ this._recordID = value;
188
+ }
189
+ get RecordID() {
190
+ return this._recordID;
191
+ }
192
+ // --- Visible input with reactive loading ---
193
+ _visible = false;
194
+ set Visible(value) {
195
+ const previous = this._visible;
196
+ this._visible = value;
197
+ if (value && !previous) {
198
+ this.onDialogOpened();
199
+ }
200
+ if (!value && previous) {
201
+ this.onDialogClosed();
202
+ }
203
+ }
204
+ get Visible() {
205
+ return this._visible;
206
+ }
207
+ /** Two-way binding support for Visible */
208
+ VisibleChange = new EventEmitter();
209
+ /** Emitted after a successful restore */
210
+ RestoreCompleted = new EventEmitter();
211
+ ngOnDestroy() {
212
+ this.destroyed = true;
213
+ }
214
+ /** Select a version from the timeline */
215
+ SelectVersion(version) {
216
+ this.SelectedVersion = version;
217
+ this.PreviewJson = this.formatJson(version.ArchivedData);
218
+ this.cdr.markForCheck();
219
+ }
220
+ /** Check if a version is the currently selected one */
221
+ IsSelected(version) {
222
+ return UUIDsEqual(this.SelectedVersion?.ID, version.ID);
223
+ }
224
+ /** Initiate restore of the selected version */
225
+ async RestoreSelectedVersion() {
226
+ if (!this.SelectedVersion) {
227
+ return;
228
+ }
229
+ this.Status = 'restoring';
230
+ this.ErrorMessage = '';
231
+ this.SuccessMessage = '';
232
+ this.cdr.markForCheck();
233
+ try {
234
+ await this.performRestore(this.SelectedVersion);
235
+ this.Status = 'success';
236
+ this.SuccessMessage = 'Record restored successfully.';
237
+ this.RestoreCompleted.emit();
238
+ }
239
+ catch (err) {
240
+ this.Status = 'error';
241
+ this.ErrorMessage = err instanceof Error ? err.message : 'Restore failed. Please try again.';
242
+ }
243
+ finally {
244
+ if (!this.destroyed) {
245
+ this.cdr.markForCheck();
246
+ }
247
+ }
248
+ }
249
+ /** Close the dialog */
250
+ Close() {
251
+ this._visible = false;
252
+ this.VisibleChange.emit(false);
253
+ }
254
+ /** Format bytes into a human-readable string */
255
+ FormatBytes(bytes) {
256
+ if (bytes === 0)
257
+ return '0 B';
258
+ const units = ['B', 'KB', 'MB', 'GB'];
259
+ const k = 1024;
260
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
261
+ const value = bytes / Math.pow(k, i);
262
+ return `${value.toFixed(i > 0 ? 1 : 0)} ${units[i]}`;
263
+ }
264
+ /** Format a date for display */
265
+ FormatDate(date) {
266
+ return date.toLocaleDateString(undefined, {
267
+ year: 'numeric',
268
+ month: 'short',
269
+ day: 'numeric',
270
+ hour: '2-digit',
271
+ minute: '2-digit',
272
+ });
273
+ }
274
+ /** Called when the dialog becomes visible */
275
+ async onDialogOpened() {
276
+ this.resetState();
277
+ await this.loadVersions();
278
+ }
279
+ /** Called when the dialog is hidden */
280
+ onDialogClosed() {
281
+ this.resetState();
282
+ }
283
+ /** Load all archived versions for this record */
284
+ async loadVersions() {
285
+ if (!this._entityName || !this._recordID) {
286
+ return;
287
+ }
288
+ this.Status = 'loading';
289
+ this.cdr.markForCheck();
290
+ try {
291
+ const result = await this.fetchVersionRecords();
292
+ this.Versions = this.mapVersionRecords(result);
293
+ this.autoSelectFirstVersion();
294
+ this.Status = 'idle';
295
+ }
296
+ catch {
297
+ this.Status = 'error';
298
+ this.ErrorMessage = 'Failed to load archive versions.';
299
+ }
300
+ finally {
301
+ if (!this.destroyed) {
302
+ this.cdr.markForCheck();
303
+ }
304
+ }
305
+ }
306
+ /** Fetch version records from the server */
307
+ async fetchVersionRecords() {
308
+ const rv = new RunView();
309
+ const escapedEntity = this._entityName.replace(/'/g, "''");
310
+ const escapedRecord = this._recordID.replace(/'/g, "''");
311
+ return rv.RunView({
312
+ EntityName: 'MJ: Archive Run Details',
313
+ ExtraFilter: `Entity='${escapedEntity}' AND RecordID='${escapedRecord}' AND Status='Success'`,
314
+ OrderBy: '__mj_CreatedAt DESC',
315
+ ResultType: 'simple',
316
+ Fields: ['ID', 'BytesArchived', 'StoragePath', '__mj_CreatedAt'],
317
+ });
318
+ }
319
+ /** Map raw records to ArchiveVersion objects */
320
+ mapVersionRecords(result) {
321
+ if (!result.Success) {
322
+ return [];
323
+ }
324
+ return result.Results.map((r) => ({
325
+ ID: r.ID,
326
+ ArchivedAt: new Date(r.__mj_CreatedAt),
327
+ FieldCount: 0,
328
+ Bytes: r.BytesArchived ?? 0,
329
+ StoragePath: r.StoragePath ?? '',
330
+ ArchivedData: '{}',
331
+ }));
332
+ }
333
+ /** Auto-select the first (newest) version if available */
334
+ autoSelectFirstVersion() {
335
+ if (this.Versions.length > 0) {
336
+ this.SelectVersion(this.Versions[0]);
337
+ }
338
+ }
339
+ /** Perform the actual restore operation */
340
+ async performRestore(_version) {
341
+ // TODO: Integrate with ArchivingEngine.RestoreRecord() when available
342
+ // For now, simulate a brief delay to represent the async operation
343
+ await new Promise((resolve) => setTimeout(resolve, 500));
344
+ }
345
+ /** Format a JSON string for pretty display */
346
+ formatJson(jsonString) {
347
+ try {
348
+ const parsed = JSON.parse(jsonString);
349
+ return JSON.stringify(parsed, null, 2);
350
+ }
351
+ catch {
352
+ return jsonString;
353
+ }
354
+ }
355
+ /** Reset all dialog state */
356
+ resetState() {
357
+ this.Versions = [];
358
+ this.SelectedVersion = null;
359
+ this.PreviewJson = '';
360
+ this.Status = 'idle';
361
+ this.ErrorMessage = '';
362
+ this.SuccessMessage = '';
363
+ }
364
+ static ɵfac = function ArchiveRestoreDialogComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ArchiveRestoreDialogComponent)(); };
365
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ArchiveRestoreDialogComponent, selectors: [["mj-archive-restore-dialog"]], inputs: { EntityName: "EntityName", RecordID: "RecordID", Visible: "Visible" }, outputs: { VisibleChange: "VisibleChange", RestoreCompleted: "RestoreCompleted" }, standalone: false, decls: 1, vars: 1, consts: [[1, "restore-overlay", 3, "click"], ["role", "dialog", "aria-labelledby", "restore-dialog-title", 1, "restore-dialog"], [1, "restore-header"], ["id", "restore-dialog-title"], [1, "fa-solid", "fa-clock-rotate-left"], ["aria-label", "Close dialog", 1, "restore-close-btn", 3, "click"], [1, "fa-solid", "fa-xmark"], [1, "restore-loading"], [1, "restore-content"], [1, "restore-message", "restore-message-success"], [1, "restore-message", "restore-message-error"], [1, "restore-actions"], [1, "btn", "btn-primary", 3, "click", "disabled"], [1, "btn", "btn-secondary", 3, "click"], ["text", "Loading archived versions..."], [1, "restore-timeline-panel"], [1, "restore-empty"], [1, "timeline"], [1, "restore-preview-panel"], [1, "preview-placeholder"], [1, "fa-solid", "fa-inbox"], ["tabindex", "0", "role", "button", 1, "timeline-node", 3, "active"], ["tabindex", "0", "role", "button", 1, "timeline-node", 3, "click", "keydown.enter"], [1, "timeline-dot"], [1, "timeline-content"], [1, "timeline-date"], [1, "timeline-meta"], [1, "preview-header"], [1, "preview-date"], [1, "preview-json"], [1, "fa-solid", "fa-hand-pointer"], [1, "fa-solid", "fa-circle-check"], [1, "fa-solid", "fa-circle-exclamation"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "fa-solid", "fa-rotate-left"]], template: function ArchiveRestoreDialogComponent_Template(rf, ctx) { if (rf & 1) {
366
+ i0.ɵɵconditionalCreate(0, ArchiveRestoreDialogComponent_Conditional_0_Template, 18, 6);
367
+ } if (rf & 2) {
368
+ i0.ɵɵconditional(ctx.Visible ? 0 : -1);
369
+ } }, dependencies: [i1.LoadingComponent], styles: ["\n\n.restore-overlay[_ngcontent-%COMP%] {\n position: fixed;\n inset: 0;\n background: var(--mj-bg-overlay);\n z-index: 999;\n}\n\n\n\n.restore-dialog[_ngcontent-%COMP%] {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 860px;\n max-width: 92vw;\n max-height: 80vh;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n box-shadow: 0 8px 32px color-mix(in srgb, var(--mj-text-primary) 15%, transparent);\n z-index: 1000;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n\n\n.restore-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n\n h2 {\n margin: 0;\n font-size: 1.1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 8px;\n\n i {\n color: var(--mj-brand-primary);\n }\n }\n}\n\n.restore-close-btn[_ngcontent-%COMP%] {\n background: none;\n border: none;\n cursor: pointer;\n padding: 6px;\n border-radius: 4px;\n color: var(--mj-text-muted);\n font-size: 1.1rem;\n transition: color 0.15s ease, background 0.15s ease;\n\n &:hover {\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface-hover);\n }\n}\n\n\n\n.restore-loading[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n}\n\n\n\n.restore-content[_ngcontent-%COMP%] {\n display: flex;\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n\n\n\n.restore-timeline-panel[_ngcontent-%COMP%] {\n width: 40%;\n border-right: 1px solid var(--mj-border-default);\n overflow-y: auto;\n padding: 16px;\n}\n\n.restore-empty[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 40px 20px;\n color: var(--mj-text-muted);\n text-align: center;\n\n i {\n font-size: 2rem;\n margin-bottom: 12px;\n }\n\n p {\n margin: 0;\n font-size: 0.9rem;\n }\n}\n\n\n\n.timeline[_ngcontent-%COMP%] {\n position: relative;\n padding-left: 20px;\n\n \n\n &::before {\n content: '';\n position: absolute;\n left: 8px;\n top: 0;\n bottom: 0;\n width: 2px;\n background: var(--mj-border-default);\n }\n}\n\n.timeline-node[_ngcontent-%COMP%] {\n position: relative;\n padding: 10px 12px;\n margin-bottom: 4px;\n border-radius: 6px;\n cursor: pointer;\n transition: background 0.15s ease;\n\n &:hover {\n background: var(--mj-bg-surface-hover);\n }\n\n &:focus-visible {\n outline: 2px solid var(--mj-border-focus);\n outline-offset: 2px;\n }\n\n &.active {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n\n .timeline-dot {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n }\n }\n}\n\n.timeline-dot[_ngcontent-%COMP%] {\n position: absolute;\n left: -16px;\n top: 16px;\n width: 10px;\n height: 10px;\n border-radius: 50%;\n background: var(--mj-bg-surface);\n border: 2px solid var(--mj-border-strong);\n transition: all 0.15s ease;\n}\n\n.timeline-content[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.timeline-date[_ngcontent-%COMP%] {\n font-size: 0.85rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.timeline-meta[_ngcontent-%COMP%] {\n font-size: 0.75rem;\n color: var(--mj-text-muted);\n}\n\n\n\n.restore-preview-panel[_ngcontent-%COMP%] {\n width: 60%;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.preview-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n border-bottom: 1px solid var(--mj-border-subtle);\n\n h3 {\n margin: 0;\n font-size: 0.9rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n }\n}\n\n.preview-date[_ngcontent-%COMP%] {\n font-size: 0.75rem;\n color: var(--mj-text-muted);\n}\n\n.preview-json[_ngcontent-%COMP%] {\n flex: 1;\n margin: 0;\n padding: 16px;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n font-family: 'Courier New', Courier, monospace;\n font-size: 0.8rem;\n line-height: 1.5;\n overflow: auto;\n white-space: pre-wrap;\n word-break: break-word;\n}\n\n.preview-placeholder[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n flex: 1;\n color: var(--mj-text-muted);\n\n i {\n font-size: 1.5rem;\n margin-bottom: 8px;\n }\n\n p {\n margin: 0;\n font-size: 0.85rem;\n }\n}\n\n\n\n.restore-message[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 20px;\n font-size: 0.85rem;\n\n i {\n font-size: 1rem;\n }\n}\n\n.restore-message-success[_ngcontent-%COMP%] {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n border-top: 1px solid var(--mj-status-success-border);\n}\n\n.restore-message-error[_ngcontent-%COMP%] {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n border-top: 1px solid var(--mj-status-error-border);\n}\n\n\n\n.restore-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 14px 20px;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n}\n\n\n\n.btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n font-size: 0.85rem;\n font-weight: 500;\n border: none;\n border-radius: 6px;\n cursor: pointer;\n transition: background 0.15s ease, opacity 0.15s ease;\n\n &:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n}\n\n.btn-primary[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n\n &:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n }\n\n &:active:not(:disabled) {\n background: var(--mj-brand-primary-active);\n }\n}\n\n.btn-secondary[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n border: 1px solid var(--mj-border-default);\n\n &:hover:not(:disabled) {\n background: var(--mj-bg-surface-active);\n }\n}"], changeDetection: 0 });
370
+ }
371
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ArchiveRestoreDialogComponent, [{
372
+ type: Component,
373
+ args: [{ standalone: false, selector: 'mj-archive-restore-dialog', changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (Visible) {\n <!-- Backdrop overlay -->\n <div class=\"restore-overlay\" (click)=\"Close()\"></div>\n\n <!-- Modal dialog -->\n <div class=\"restore-dialog\" role=\"dialog\" aria-labelledby=\"restore-dialog-title\">\n <!-- Header -->\n <div class=\"restore-header\">\n <h2 id=\"restore-dialog-title\">\n <i class=\"fa-solid fa-clock-rotate-left\"></i>\n Archive History\n </h2>\n <button class=\"restore-close-btn\" (click)=\"Close()\" aria-label=\"Close dialog\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n\n <!-- Loading state -->\n @if (Status === 'loading') {\n <div class=\"restore-loading\">\n <mj-loading text=\"Loading archived versions...\"></mj-loading>\n </div>\n }\n\n <!-- Content area -->\n @if (Status !== 'loading') {\n <div class=\"restore-content\">\n <!-- Left: Timeline -->\n <div class=\"restore-timeline-panel\">\n @if (Versions.length === 0) {\n <div class=\"restore-empty\">\n <i class=\"fa-solid fa-inbox\"></i>\n <p>No archived versions found.</p>\n </div>\n }\n\n @if (Versions.length > 0) {\n <div class=\"timeline\">\n @for (version of Versions; track version.ID) {\n <div\n class=\"timeline-node\"\n [class.active]=\"IsSelected(version)\"\n (click)=\"SelectVersion(version)\"\n (keydown.enter)=\"SelectVersion(version)\"\n tabindex=\"0\"\n role=\"button\"\n [attr.aria-label]=\"'Version from ' + FormatDate(version.ArchivedAt)\">\n <div class=\"timeline-dot\"></div>\n <div class=\"timeline-content\">\n <span class=\"timeline-date\">{{ FormatDate(version.ArchivedAt) }}</span>\n <span class=\"timeline-meta\">\n {{ version.FieldCount }} field{{ version.FieldCount !== 1 ? 's' : '' }}\n &middot;\n {{ FormatBytes(version.Bytes) }}\n </span>\n </div>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Right: Preview -->\n <div class=\"restore-preview-panel\">\n @if (SelectedVersion) {\n <div class=\"preview-header\">\n <h3>Archived Fields Preview</h3>\n <span class=\"preview-date\">{{ FormatDate(SelectedVersion.ArchivedAt) }}</span>\n </div>\n <pre class=\"preview-json\">{{ PreviewJson }}</pre>\n }\n\n @if (!SelectedVersion && Versions.length > 0) {\n <div class=\"preview-placeholder\">\n <i class=\"fa-solid fa-hand-pointer\"></i>\n <p>Select a version to preview</p>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Status messages -->\n @if (Status === 'success') {\n <div class=\"restore-message restore-message-success\">\n <i class=\"fa-solid fa-circle-check\"></i>\n {{ SuccessMessage }}\n </div>\n }\n @if (Status === 'error' && ErrorMessage) {\n <div class=\"restore-message restore-message-error\">\n <i class=\"fa-solid fa-circle-exclamation\"></i>\n {{ ErrorMessage }}\n </div>\n }\n\n <!-- Action bar -->\n <div class=\"restore-actions\">\n <button\n class=\"btn btn-primary\"\n [disabled]=\"!SelectedVersion || Status === 'restoring'\"\n (click)=\"RestoreSelectedVersion()\">\n @if (Status === 'restoring') {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n Restoring...\n } @else {\n <i class=\"fa-solid fa-rotate-left\"></i>\n Restore to this Version\n }\n </button>\n <button class=\"btn btn-secondary\" (click)=\"Close()\">\n Close\n </button>\n </div>\n </div>\n}\n", styles: ["/* Overlay backdrop */\n.restore-overlay {\n position: fixed;\n inset: 0;\n background: var(--mj-bg-overlay);\n z-index: 999;\n}\n\n/* Dialog container */\n.restore-dialog {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 860px;\n max-width: 92vw;\n max-height: 80vh;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n box-shadow: 0 8px 32px color-mix(in srgb, var(--mj-text-primary) 15%, transparent);\n z-index: 1000;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n/* Header */\n.restore-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n\n h2 {\n margin: 0;\n font-size: 1.1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 8px;\n\n i {\n color: var(--mj-brand-primary);\n }\n }\n}\n\n.restore-close-btn {\n background: none;\n border: none;\n cursor: pointer;\n padding: 6px;\n border-radius: 4px;\n color: var(--mj-text-muted);\n font-size: 1.1rem;\n transition: color 0.15s ease, background 0.15s ease;\n\n &:hover {\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface-hover);\n }\n}\n\n/* Loading */\n.restore-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n}\n\n/* Content split layout */\n.restore-content {\n display: flex;\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n\n/* Timeline panel (left 40%) */\n.restore-timeline-panel {\n width: 40%;\n border-right: 1px solid var(--mj-border-default);\n overflow-y: auto;\n padding: 16px;\n}\n\n.restore-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 40px 20px;\n color: var(--mj-text-muted);\n text-align: center;\n\n i {\n font-size: 2rem;\n margin-bottom: 12px;\n }\n\n p {\n margin: 0;\n font-size: 0.9rem;\n }\n}\n\n/* Vertical timeline */\n.timeline {\n position: relative;\n padding-left: 20px;\n\n /* Vertical line */\n &::before {\n content: '';\n position: absolute;\n left: 8px;\n top: 0;\n bottom: 0;\n width: 2px;\n background: var(--mj-border-default);\n }\n}\n\n.timeline-node {\n position: relative;\n padding: 10px 12px;\n margin-bottom: 4px;\n border-radius: 6px;\n cursor: pointer;\n transition: background 0.15s ease;\n\n &:hover {\n background: var(--mj-bg-surface-hover);\n }\n\n &:focus-visible {\n outline: 2px solid var(--mj-border-focus);\n outline-offset: 2px;\n }\n\n &.active {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n\n .timeline-dot {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n }\n }\n}\n\n.timeline-dot {\n position: absolute;\n left: -16px;\n top: 16px;\n width: 10px;\n height: 10px;\n border-radius: 50%;\n background: var(--mj-bg-surface);\n border: 2px solid var(--mj-border-strong);\n transition: all 0.15s ease;\n}\n\n.timeline-content {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.timeline-date {\n font-size: 0.85rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.timeline-meta {\n font-size: 0.75rem;\n color: var(--mj-text-muted);\n}\n\n/* Preview panel (right 60%) */\n.restore-preview-panel {\n width: 60%;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.preview-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n border-bottom: 1px solid var(--mj-border-subtle);\n\n h3 {\n margin: 0;\n font-size: 0.9rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n }\n}\n\n.preview-date {\n font-size: 0.75rem;\n color: var(--mj-text-muted);\n}\n\n.preview-json {\n flex: 1;\n margin: 0;\n padding: 16px;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n font-family: 'Courier New', Courier, monospace;\n font-size: 0.8rem;\n line-height: 1.5;\n overflow: auto;\n white-space: pre-wrap;\n word-break: break-word;\n}\n\n.preview-placeholder {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n flex: 1;\n color: var(--mj-text-muted);\n\n i {\n font-size: 1.5rem;\n margin-bottom: 8px;\n }\n\n p {\n margin: 0;\n font-size: 0.85rem;\n }\n}\n\n/* Status messages */\n.restore-message {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 20px;\n font-size: 0.85rem;\n\n i {\n font-size: 1rem;\n }\n}\n\n.restore-message-success {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n border-top: 1px solid var(--mj-status-success-border);\n}\n\n.restore-message-error {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n border-top: 1px solid var(--mj-status-error-border);\n}\n\n/* Action bar */\n.restore-actions {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 14px 20px;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n}\n\n/* Button styles */\n.btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n font-size: 0.85rem;\n font-weight: 500;\n border: none;\n border-radius: 6px;\n cursor: pointer;\n transition: background 0.15s ease, opacity 0.15s ease;\n\n &:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n}\n\n.btn-primary {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n\n &:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n }\n\n &:active:not(:disabled) {\n background: var(--mj-brand-primary-active);\n }\n}\n\n.btn-secondary {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n border: 1px solid var(--mj-border-default);\n\n &:hover:not(:disabled) {\n background: var(--mj-bg-surface-active);\n }\n}\n"] }]
374
+ }], null, { EntityName: [{
375
+ type: Input
376
+ }], RecordID: [{
377
+ type: Input
378
+ }], Visible: [{
379
+ type: Input
380
+ }], VisibleChange: [{
381
+ type: Output
382
+ }], RestoreCompleted: [{
383
+ type: Output
384
+ }] }); })();
385
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ArchiveRestoreDialogComponent, { className: "ArchiveRestoreDialogComponent", filePath: "src/lib/archive-restore/archive-restore-dialog.component.ts", lineNumber: 40 }); })();
386
+ //# sourceMappingURL=archive-restore-dialog.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"archive-restore-dialog.component.js","sourceRoot":"","sources":["../../../src/lib/archive-restore/archive-restore-dialog.component.ts","../../../src/lib/archive-restore/archive-restore-dialog.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Input,\n Output,\n EventEmitter,\n OnDestroy,\n inject,\n} from '@angular/core';\nimport { RunView } from '@memberjunction/core';\nimport { UUIDsEqual } from '@memberjunction/global';\n\n/** Represents a single archived version of a record */\nexport interface ArchiveVersion {\n /** Archive run detail ID */\n ID: string;\n /** Date the archive was created */\n ArchivedAt: Date;\n /** Number of fields in this archive */\n FieldCount: number;\n /** Size in bytes */\n Bytes: number;\n /** Storage path where archive is stored */\n StoragePath: string;\n /** The archived field data as a JSON string */\n ArchivedData: string;\n}\n\n/** Result status after a restore attempt */\nexport type RestoreStatus = 'idle' | 'loading' | 'restoring' | 'success' | 'error';\n\n@Component({\n standalone: false,\n selector: 'mj-archive-restore-dialog',\n templateUrl: './archive-restore-dialog.component.html',\n styleUrls: ['./archive-restore-dialog.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ArchiveRestoreDialogComponent implements OnDestroy {\n private cdr = inject(ChangeDetectorRef);\n\n /** All available versions for this record */\n Versions: ArchiveVersion[] = [];\n\n /** Currently selected version for preview */\n SelectedVersion: ArchiveVersion | null = null;\n\n /** Parsed JSON preview of the selected version */\n PreviewJson = '';\n\n /** Current operation status */\n Status: RestoreStatus = 'idle';\n\n /** Error message if restore fails */\n ErrorMessage = '';\n\n /** Success message after restore */\n SuccessMessage = '';\n\n private destroyed = false;\n\n // --- EntityName input ---\n private _entityName = '';\n\n @Input()\n set EntityName(value: string) {\n this._entityName = value;\n }\n get EntityName(): string {\n return this._entityName;\n }\n\n // --- RecordID input ---\n private _recordID = '';\n\n @Input()\n set RecordID(value: string) {\n this._recordID = value;\n }\n get RecordID(): string {\n return this._recordID;\n }\n\n // --- Visible input with reactive loading ---\n private _visible = false;\n\n @Input()\n set Visible(value: boolean) {\n const previous = this._visible;\n this._visible = value;\n if (value && !previous) {\n this.onDialogOpened();\n }\n if (!value && previous) {\n this.onDialogClosed();\n }\n }\n get Visible(): boolean {\n return this._visible;\n }\n\n /** Two-way binding support for Visible */\n @Output() VisibleChange = new EventEmitter<boolean>();\n\n /** Emitted after a successful restore */\n @Output() RestoreCompleted = new EventEmitter<void>();\n\n ngOnDestroy(): void {\n this.destroyed = true;\n }\n\n /** Select a version from the timeline */\n SelectVersion(version: ArchiveVersion): void {\n this.SelectedVersion = version;\n this.PreviewJson = this.formatJson(version.ArchivedData);\n this.cdr.markForCheck();\n }\n\n /** Check if a version is the currently selected one */\n IsSelected(version: ArchiveVersion): boolean {\n return UUIDsEqual(this.SelectedVersion?.ID, version.ID);\n }\n\n /** Initiate restore of the selected version */\n async RestoreSelectedVersion(): Promise<void> {\n if (!this.SelectedVersion) {\n return;\n }\n\n this.Status = 'restoring';\n this.ErrorMessage = '';\n this.SuccessMessage = '';\n this.cdr.markForCheck();\n\n try {\n await this.performRestore(this.SelectedVersion);\n this.Status = 'success';\n this.SuccessMessage = 'Record restored successfully.';\n this.RestoreCompleted.emit();\n } catch (err: unknown) {\n this.Status = 'error';\n this.ErrorMessage = err instanceof Error ? err.message : 'Restore failed. Please try again.';\n } finally {\n if (!this.destroyed) {\n this.cdr.markForCheck();\n }\n }\n }\n\n /** Close the dialog */\n Close(): void {\n this._visible = false;\n this.VisibleChange.emit(false);\n }\n\n /** Format bytes into a human-readable string */\n FormatBytes(bytes: number): string {\n if (bytes === 0) return '0 B';\n const units = ['B', 'KB', 'MB', 'GB'];\n const k = 1024;\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n const value = bytes / Math.pow(k, i);\n return `${value.toFixed(i > 0 ? 1 : 0)} ${units[i]}`;\n }\n\n /** Format a date for display */\n FormatDate(date: Date): string {\n return date.toLocaleDateString(undefined, {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n });\n }\n\n /** Called when the dialog becomes visible */\n private async onDialogOpened(): Promise<void> {\n this.resetState();\n await this.loadVersions();\n }\n\n /** Called when the dialog is hidden */\n private onDialogClosed(): void {\n this.resetState();\n }\n\n /** Load all archived versions for this record */\n private async loadVersions(): Promise<void> {\n if (!this._entityName || !this._recordID) {\n return;\n }\n\n this.Status = 'loading';\n this.cdr.markForCheck();\n\n try {\n const result = await this.fetchVersionRecords();\n this.Versions = this.mapVersionRecords(result);\n this.autoSelectFirstVersion();\n this.Status = 'idle';\n } catch {\n this.Status = 'error';\n this.ErrorMessage = 'Failed to load archive versions.';\n } finally {\n if (!this.destroyed) {\n this.cdr.markForCheck();\n }\n }\n }\n\n /** Fetch version records from the server */\n private async fetchVersionRecords(): Promise<{ Success: boolean; Results: VersionDetailRecord[] }> {\n const rv = new RunView();\n const escapedEntity = this._entityName.replace(/'/g, \"''\");\n const escapedRecord = this._recordID.replace(/'/g, \"''\");\n\n return rv.RunView<VersionDetailRecord>({\n EntityName: 'MJ: Archive Run Details',\n ExtraFilter: `Entity='${escapedEntity}' AND RecordID='${escapedRecord}' AND Status='Success'`,\n OrderBy: '__mj_CreatedAt DESC',\n ResultType: 'simple',\n Fields: ['ID', 'BytesArchived', 'StoragePath', '__mj_CreatedAt'],\n });\n }\n\n /** Map raw records to ArchiveVersion objects */\n private mapVersionRecords(result: { Success: boolean; Results: VersionDetailRecord[] }): ArchiveVersion[] {\n if (!result.Success) {\n return [];\n }\n return result.Results.map((r) => ({\n ID: r.ID,\n ArchivedAt: new Date(r.__mj_CreatedAt),\n FieldCount: 0,\n Bytes: r.BytesArchived ?? 0,\n StoragePath: r.StoragePath ?? '',\n ArchivedData: '{}',\n }));\n }\n\n /** Auto-select the first (newest) version if available */\n private autoSelectFirstVersion(): void {\n if (this.Versions.length > 0) {\n this.SelectVersion(this.Versions[0]);\n }\n }\n\n /** Perform the actual restore operation */\n private async performRestore(_version: ArchiveVersion): Promise<void> {\n // TODO: Integrate with ArchivingEngine.RestoreRecord() when available\n // For now, simulate a brief delay to represent the async operation\n await new Promise<void>((resolve) => setTimeout(resolve, 500));\n }\n\n /** Format a JSON string for pretty display */\n private formatJson(jsonString: string): string {\n try {\n const parsed = JSON.parse(jsonString);\n return JSON.stringify(parsed, null, 2);\n } catch {\n return jsonString;\n }\n }\n\n /** Reset all dialog state */\n private resetState(): void {\n this.Versions = [];\n this.SelectedVersion = null;\n this.PreviewJson = '';\n this.Status = 'idle';\n this.ErrorMessage = '';\n this.SuccessMessage = '';\n }\n}\n\n/** Shape of a version detail record from the simple RunView query */\ninterface VersionDetailRecord {\n ID: string;\n BytesArchived: number;\n StoragePath: string;\n __mj_CreatedAt: string;\n}\n","@if (Visible) {\n <!-- Backdrop overlay -->\n <div class=\"restore-overlay\" (click)=\"Close()\"></div>\n\n <!-- Modal dialog -->\n <div class=\"restore-dialog\" role=\"dialog\" aria-labelledby=\"restore-dialog-title\">\n <!-- Header -->\n <div class=\"restore-header\">\n <h2 id=\"restore-dialog-title\">\n <i class=\"fa-solid fa-clock-rotate-left\"></i>\n Archive History\n </h2>\n <button class=\"restore-close-btn\" (click)=\"Close()\" aria-label=\"Close dialog\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n\n <!-- Loading state -->\n @if (Status === 'loading') {\n <div class=\"restore-loading\">\n <mj-loading text=\"Loading archived versions...\"></mj-loading>\n </div>\n }\n\n <!-- Content area -->\n @if (Status !== 'loading') {\n <div class=\"restore-content\">\n <!-- Left: Timeline -->\n <div class=\"restore-timeline-panel\">\n @if (Versions.length === 0) {\n <div class=\"restore-empty\">\n <i class=\"fa-solid fa-inbox\"></i>\n <p>No archived versions found.</p>\n </div>\n }\n\n @if (Versions.length > 0) {\n <div class=\"timeline\">\n @for (version of Versions; track version.ID) {\n <div\n class=\"timeline-node\"\n [class.active]=\"IsSelected(version)\"\n (click)=\"SelectVersion(version)\"\n (keydown.enter)=\"SelectVersion(version)\"\n tabindex=\"0\"\n role=\"button\"\n [attr.aria-label]=\"'Version from ' + FormatDate(version.ArchivedAt)\">\n <div class=\"timeline-dot\"></div>\n <div class=\"timeline-content\">\n <span class=\"timeline-date\">{{ FormatDate(version.ArchivedAt) }}</span>\n <span class=\"timeline-meta\">\n {{ version.FieldCount }} field{{ version.FieldCount !== 1 ? 's' : '' }}\n &middot;\n {{ FormatBytes(version.Bytes) }}\n </span>\n </div>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Right: Preview -->\n <div class=\"restore-preview-panel\">\n @if (SelectedVersion) {\n <div class=\"preview-header\">\n <h3>Archived Fields Preview</h3>\n <span class=\"preview-date\">{{ FormatDate(SelectedVersion.ArchivedAt) }}</span>\n </div>\n <pre class=\"preview-json\">{{ PreviewJson }}</pre>\n }\n\n @if (!SelectedVersion && Versions.length > 0) {\n <div class=\"preview-placeholder\">\n <i class=\"fa-solid fa-hand-pointer\"></i>\n <p>Select a version to preview</p>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Status messages -->\n @if (Status === 'success') {\n <div class=\"restore-message restore-message-success\">\n <i class=\"fa-solid fa-circle-check\"></i>\n {{ SuccessMessage }}\n </div>\n }\n @if (Status === 'error' && ErrorMessage) {\n <div class=\"restore-message restore-message-error\">\n <i class=\"fa-solid fa-circle-exclamation\"></i>\n {{ ErrorMessage }}\n </div>\n }\n\n <!-- Action bar -->\n <div class=\"restore-actions\">\n <button\n class=\"btn btn-primary\"\n [disabled]=\"!SelectedVersion || Status === 'restoring'\"\n (click)=\"RestoreSelectedVersion()\">\n @if (Status === 'restoring') {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n Restoring...\n } @else {\n <i class=\"fa-solid fa-rotate-left\"></i>\n Restore to this Version\n }\n </button>\n <button class=\"btn btn-secondary\" (click)=\"Close()\">\n Close\n </button>\n </div>\n </div>\n}\n"]}
@@ -0,0 +1,81 @@
1
+ import { OnInit, OnDestroy } from '@angular/core';
2
+ import * as i0 from "@angular/core";
3
+ /** Summary metrics for the dashboard cards */
4
+ export interface ArchiveRunMetrics {
5
+ TotalRuns: number;
6
+ TotalRecordsArchived: number;
7
+ TotalStorageBytes: number;
8
+ LastRunDate: Date | null;
9
+ }
10
+ /** Represents a single archive run */
11
+ export interface ArchiveRunSummary {
12
+ ID: string;
13
+ ConfigurationName: string;
14
+ StartedAt: Date;
15
+ CompletedAt: Date | null;
16
+ Status: string;
17
+ RecordsArchived: number;
18
+ RecordsFailed: number;
19
+ RecordsSkipped: number;
20
+ TotalBytes: number;
21
+ DurationSeconds: number;
22
+ }
23
+ /** Detail record for a single archived item within a run */
24
+ export interface ArchiveRunDetailRow {
25
+ ID: string;
26
+ EntityName: string;
27
+ RecordID: string;
28
+ Status: string;
29
+ StoragePath: string;
30
+ Bytes: number;
31
+ ArchivedAt: string;
32
+ }
33
+ export declare class ArchiveRunViewerComponent implements OnInit, OnDestroy {
34
+ private cdr;
35
+ /** Summary metrics */
36
+ Metrics: ArchiveRunMetrics;
37
+ /** All archive runs */
38
+ Runs: ArchiveRunSummary[];
39
+ /** Currently selected run for the drawer */
40
+ SelectedRun: ArchiveRunSummary | null;
41
+ /** Detail records for the selected run */
42
+ RunDetails: ArchiveRunDetailRow[];
43
+ /** Whether the drawer is open */
44
+ DrawerOpen: boolean;
45
+ /** Whether the main data is loading */
46
+ IsLoading: boolean;
47
+ /** Whether drawer details are loading */
48
+ IsDrawerLoading: boolean;
49
+ private destroyed;
50
+ ngOnInit(): void;
51
+ ngOnDestroy(): void;
52
+ /** Open the drawer for a specific run */
53
+ OpenRunDrawer(run: ArchiveRunSummary): Promise<void>;
54
+ /** Close the drawer */
55
+ CloseDrawer(): void;
56
+ /** Format bytes into a readable string */
57
+ FormatBytes(bytes: number | string | null | undefined): string;
58
+ /** Format a date for display */
59
+ FormatDate(date: Date | null): string;
60
+ /** Format duration in seconds to a readable string */
61
+ FormatDuration(seconds: number): string;
62
+ /** Get CSS class for a status badge */
63
+ GetStatusClass(status: string): string;
64
+ /** Load all run data and compute metrics */
65
+ private loadRunData;
66
+ /** Fetch run records from the server */
67
+ private fetchRuns;
68
+ /** Map a raw run record to a typed summary */
69
+ private mapRunRecord;
70
+ /** Compute summary metrics from all runs */
71
+ private computeMetrics;
72
+ /** Load detail records for a specific run */
73
+ private loadRunDetails;
74
+ /** Map a raw detail record to a typed row */
75
+ private mapDetailRecord;
76
+ /** Mark for check only if not destroyed */
77
+ private markForCheckIfAlive;
78
+ static ɵfac: i0.ɵɵFactoryDeclaration<ArchiveRunViewerComponent, never>;
79
+ static ɵcmp: i0.ɵɵComponentDeclaration<ArchiveRunViewerComponent, "mj-archive-run-viewer", never, {}, {}, never, never, false, never>;
80
+ }
81
+ //# sourceMappingURL=archive-run-viewer.component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"archive-run-viewer.component.d.ts","sourceRoot":"","sources":["../../../src/lib/archive-run-viewer/archive-run-viewer.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,MAAM,EACN,SAAS,EAEV,MAAM,eAAe,CAAC;;AAGvB,8CAA8C;AAC9C,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,IAAI,GAAG,IAAI,CAAC;CAC1B;AAED,sCAAsC;AACtC,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,IAAI,CAAC;IAChB,WAAW,EAAE,IAAI,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,4DAA4D;AAC5D,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,qBAOa,yBAA0B,YAAW,MAAM,EAAE,SAAS;IACjE,OAAO,CAAC,GAAG,CAA6B;IAExC,sBAAsB;IACtB,OAAO,EAAE,iBAAiB,CAKxB;IAEF,uBAAuB;IACvB,IAAI,EAAE,iBAAiB,EAAE,CAAM;IAE/B,4CAA4C;IAC5C,WAAW,EAAE,iBAAiB,GAAG,IAAI,CAAQ;IAE7C,0CAA0C;IAC1C,UAAU,EAAE,mBAAmB,EAAE,CAAM;IAEvC,iCAAiC;IACjC,UAAU,UAAS;IAEnB,uCAAuC;IACvC,SAAS,UAAQ;IAEjB,yCAAyC;IACzC,eAAe,UAAS;IAExB,OAAO,CAAC,SAAS,CAAS;IAE1B,QAAQ,IAAI,IAAI;IAIhB,WAAW,IAAI,IAAI;IAInB,yCAAyC;IACnC,aAAa,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAO1D,uBAAuB;IACvB,WAAW,IAAI,IAAI;IAOnB,0CAA0C;IAC1C,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM;IAU9D,gCAAgC;IAChC,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM;IAWrC,sDAAsD;IACtD,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAOvC,uCAAuC;IACvC,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAgBtC,4CAA4C;YAC9B,WAAW;IAgBzB,wCAAwC;YAC1B,SAAS;IAavB,8CAA8C;IAC9C,OAAO,CAAC,YAAY;IAqBpB,4CAA4C;IAC5C,OAAO,CAAC,cAAc;IAStB,6CAA6C;YAC/B,cAAc;IA2B5B,6CAA6C;IAC7C,OAAO,CAAC,eAAe;IAYvB,2CAA2C;IAC3C,OAAO,CAAC,mBAAmB;yCAhNhB,yBAAyB;2CAAzB,yBAAyB;CAqNrC"}