@memberjunction/ng-archive-manager 5.51.0 → 6.1.0-edge.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2023 MemberJunction
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
@@ -1,4 +1,5 @@
1
1
  import { EventEmitter, OnDestroy } from '@angular/core';
2
+ import { BaseAngularComponent } from '@memberjunction/ng-base-types';
2
3
  import * as i0 from "@angular/core";
3
4
  /** Represents a single archived version of a record */
4
5
  export interface ArchiveVersion {
@@ -17,7 +18,7 @@ export interface ArchiveVersion {
17
18
  }
18
19
  /** Result status after a restore attempt */
19
20
  export type RestoreStatus = 'idle' | 'loading' | 'restoring' | 'success' | 'error';
20
- export declare class ArchiveRestoreDialogComponent implements OnDestroy {
21
+ export declare class ArchiveRestoreDialogComponent extends BaseAngularComponent implements OnDestroy {
21
22
  private cdr;
22
23
  /** All available versions for this record */
23
24
  Versions: ArchiveVersion[];
@@ -1 +1 @@
1
- {"version":3,"file":"archive-restore-dialog.component.d.ts","sourceRoot":"","sources":["../../../src/lib/archive-restore/archive-restore-dialog.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,YAAY,EACZ,SAAS,EAEV,MAAM,eAAe,CAAC;;AAIvB,uDAAuD;AACvD,MAAM,WAAW,cAAc;IAC7B,4BAA4B;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,mCAAmC;IACnC,UAAU,EAAE,IAAI,CAAC;IACjB,uCAAuC;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,oBAAoB;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,WAAW,EAAE,MAAM,CAAC;IACpB,+CAA+C;IAC/C,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,4CAA4C;AAC5C,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,OAAO,CAAC;AAEnF,qBAOa,6BAA8B,YAAW,SAAS;IAC7D,OAAO,CAAC,GAAG,CAA6B;IAExC,6CAA6C;IAC7C,QAAQ,EAAE,cAAc,EAAE,CAAM;IAEhC,6CAA6C;IAC7C,eAAe,EAAE,cAAc,GAAG,IAAI,CAAQ;IAE9C,kDAAkD;IAClD,WAAW,SAAM;IAEjB,+BAA+B;IAC/B,MAAM,EAAE,aAAa,CAAU;IAE/B,qCAAqC;IACrC,YAAY,SAAM;IAElB,oCAAoC;IACpC,cAAc,SAAM;IAEpB,OAAO,CAAC,SAAS,CAAS;IAG1B,OAAO,CAAC,WAAW,CAAM;IAEzB,IACI,UAAU,CAAC,KAAK,EAAE,MAAM,EAE3B;IACD,IAAI,UAAU,IAAI,MAAM,CAEvB;IAGD,OAAO,CAAC,SAAS,CAAM;IAEvB,IACI,QAAQ,CAAC,KAAK,EAAE,MAAM,EAEzB;IACD,IAAI,QAAQ,IAAI,MAAM,CAErB;IAGD,OAAO,CAAC,QAAQ,CAAS;IAEzB,IACI,OAAO,CAAC,KAAK,EAAE,OAAO,EASzB;IACD,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,0CAA0C;IAChC,aAAa,wBAA+B;IAEtD,yCAAyC;IAC/B,gBAAgB,qBAA4B;IAEtD,WAAW,IAAI,IAAI;IAInB,yCAAyC;IACzC,aAAa,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAM5C,uDAAuD;IACvD,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO;IAI5C,+CAA+C;IACzC,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC;IAyB7C,uBAAuB;IACvB,KAAK,IAAI,IAAI;IAKb,gDAAgD;IAChD,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IASlC,gCAAgC;IAChC,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM;IAU9B,6CAA6C;YAC/B,cAAc;IAK5B,uCAAuC;IACvC,OAAO,CAAC,cAAc;IAItB,iDAAiD;YACnC,YAAY;IAuB1B,4CAA4C;YAC9B,mBAAmB;IAcjC,gDAAgD;IAChD,OAAO,CAAC,iBAAiB;IAczB,0DAA0D;IAC1D,OAAO,CAAC,sBAAsB;IAM9B,2CAA2C;YAC7B,cAAc;IAM5B,8CAA8C;IAC9C,OAAO,CAAC,UAAU;IASlB,6BAA6B;IAC7B,OAAO,CAAC,UAAU;yCApOP,6BAA6B;2CAA7B,6BAA6B;CA4OzC"}
1
+ {"version":3,"file":"archive-restore-dialog.component.d.ts","sourceRoot":"","sources":["../../../src/lib/archive-restore/archive-restore-dialog.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,YAAY,EACZ,SAAS,EAEV,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;;AAGrE,uDAAuD;AACvD,MAAM,WAAW,cAAc;IAC7B,4BAA4B;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,mCAAmC;IACnC,UAAU,EAAE,IAAI,CAAC;IACjB,uCAAuC;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,oBAAoB;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,WAAW,EAAE,MAAM,CAAC;IACpB,+CAA+C;IAC/C,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,4CAA4C;AAC5C,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,OAAO,CAAC;AAEnF,qBAOa,6BAA8B,SAAQ,oBAAqB,YAAW,SAAS;IAC1F,OAAO,CAAC,GAAG,CAA6B;IAExC,6CAA6C;IAC7C,QAAQ,EAAE,cAAc,EAAE,CAAM;IAEhC,6CAA6C;IAC7C,eAAe,EAAE,cAAc,GAAG,IAAI,CAAQ;IAE9C,kDAAkD;IAClD,WAAW,SAAM;IAEjB,+BAA+B;IAC/B,MAAM,EAAE,aAAa,CAAU;IAE/B,qCAAqC;IACrC,YAAY,SAAM;IAElB,oCAAoC;IACpC,cAAc,SAAM;IAEpB,OAAO,CAAC,SAAS,CAAS;IAG1B,OAAO,CAAC,WAAW,CAAM;IAEzB,IACI,UAAU,CAAC,KAAK,EAAE,MAAM,EAE3B;IACD,IAAI,UAAU,IAAI,MAAM,CAEvB;IAGD,OAAO,CAAC,SAAS,CAAM;IAEvB,IACI,QAAQ,CAAC,KAAK,EAAE,MAAM,EAEzB;IACD,IAAI,QAAQ,IAAI,MAAM,CAErB;IAGD,OAAO,CAAC,QAAQ,CAAS;IAEzB,IACI,OAAO,CAAC,KAAK,EAAE,OAAO,EASzB;IACD,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,0CAA0C;IAChC,aAAa,wBAA+B;IAEtD,yCAAyC;IAC/B,gBAAgB,qBAA4B;IAEtD,WAAW,IAAI,IAAI;IAInB,yCAAyC;IACzC,aAAa,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAM5C,uDAAuD;IACvD,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO;IAI5C,+CAA+C;IACzC,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC;IAyB7C,uBAAuB;IACvB,KAAK,IAAI,IAAI;IAKb,gDAAgD;IAChD,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IASlC,gCAAgC;IAChC,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM;IAU9B,6CAA6C;YAC/B,cAAc;IAK5B,uCAAuC;IACvC,OAAO,CAAC,cAAc;IAItB,iDAAiD;YACnC,YAAY;IAuB1B,4CAA4C;YAC9B,mBAAmB;IAcjC,gDAAgD;IAChD,OAAO,CAAC,iBAAiB;IAczB,0DAA0D;IAC1D,OAAO,CAAC,sBAAsB;IAM9B,2CAA2C;YAC7B,cAAc;IAM5B,8CAA8C;IAC9C,OAAO,CAAC,UAAU;IASlB,6BAA6B;IAC7B,OAAO,CAAC,UAAU;yCApOP,6BAA6B;2CAA7B,6BAA6B;CA4OzC"}
@@ -1,5 +1,6 @@
1
1
  import { Component, ChangeDetectionStrategy, ChangeDetectorRef, Input, Output, EventEmitter, inject, } from '@angular/core';
2
2
  import { RunView } from '@memberjunction/core';
3
+ import { BaseAngularComponent } from '@memberjunction/ng-base-types';
3
4
  import { UUIDsEqual } from '@memberjunction/global';
4
5
  import * as i0 from "@angular/core";
5
6
  import * as i1 from "@memberjunction/ng-shared-generic";
@@ -151,7 +152,7 @@ function ArchiveRestoreDialogComponent_Conditional_0_Template(rf, ctx) { if (rf
151
152
  i0.ɵɵadvance();
152
153
  i0.ɵɵconditional(ctx_r1.Status === "restoring" ? 14 : 15);
153
154
  } }
154
- export class ArchiveRestoreDialogComponent {
155
+ export class ArchiveRestoreDialogComponent extends BaseAngularComponent {
155
156
  cdr = inject(ChangeDetectorRef);
156
157
  /** All available versions for this record */
157
158
  Versions = [];
@@ -298,7 +299,7 @@ export class ArchiveRestoreDialogComponent {
298
299
  }
299
300
  /** Fetch version records from the server */
300
301
  async fetchVersionRecords() {
301
- const rv = new RunView();
302
+ const rv = RunView.FromMetadataProvider(this.ProviderToUse);
302
303
  const escapedEntity = this._entityName.replace(/'/g, "''");
303
304
  const escapedRecord = this._recordID.replace(/'/g, "''");
304
305
  return rv.RunView({
@@ -354,8 +355,8 @@ export class ArchiveRestoreDialogComponent {
354
355
  this.ErrorMessage = '';
355
356
  this.SuccessMessage = '';
356
357
  }
357
- static ɵfac = function ArchiveRestoreDialogComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ArchiveRestoreDialogComponent)(); };
358
- 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"], ["Size", "compact", "Icon", "fa-solid fa-inbox", "Title", "No archived versions found.", 1, "restore-empty"], [1, "timeline"], [1, "restore-preview-panel"], ["Icon", "fa-solid fa-hand-pointer", "Title", "No version selected", "Message", "Select a version to preview", 1, "preview-placeholder"], ["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-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) {
358
+ static ɵfac = /*@__PURE__*/ (() => { let ɵArchiveRestoreDialogComponent_BaseFactory; return function ArchiveRestoreDialogComponent_Factory(__ngFactoryType__) { return (ɵArchiveRestoreDialogComponent_BaseFactory || (ɵArchiveRestoreDialogComponent_BaseFactory = i0.ɵɵgetInheritedFactory(ArchiveRestoreDialogComponent)))(__ngFactoryType__ || ArchiveRestoreDialogComponent); }; })();
359
+ 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, features: [i0.ɵɵInheritDefinitionFeature], 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"], ["Size", "compact", "Icon", "fa-solid fa-inbox", "Title", "No archived versions found.", 1, "restore-empty"], [1, "timeline"], [1, "restore-preview-panel"], ["Icon", "fa-solid fa-hand-pointer", "Title", "No version selected", "Message", "Select a version to preview", 1, "preview-placeholder"], ["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-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) {
359
360
  i0.ɵɵconditionalCreate(0, ArchiveRestoreDialogComponent_Conditional_0_Template, 18, 6);
360
361
  } if (rf & 2) {
361
362
  i0.ɵɵconditional(ctx.Visible ? 0 : -1);
@@ -375,5 +376,5 @@ export class ArchiveRestoreDialogComponent {
375
376
  }], RestoreCompleted: [{
376
377
  type: Output
377
378
  }] }); })();
378
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ArchiveRestoreDialogComponent, { className: "ArchiveRestoreDialogComponent", filePath: "src/lib/archive-restore/archive-restore-dialog.component.ts", lineNumber: 40 }); })();
379
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ArchiveRestoreDialogComponent, { className: "ArchiveRestoreDialogComponent", filePath: "src/lib/archive-restore/archive-restore-dialog.component.ts", lineNumber: 41 }); })();
379
380
  //# sourceMappingURL=archive-restore-dialog.component.js.map
@@ -1 +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 <mj-empty-state class=\"restore-empty\" Size=\"compact\"\n Icon=\"fa-solid fa-inbox\"\n Title=\"No archived versions found.\" />\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 <mj-empty-state class=\"preview-placeholder\"\n Icon=\"fa-solid fa-hand-pointer\"\n Title=\"No version selected\"\n Message=\"Select a version to preview\" />\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"]}
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 { BaseAngularComponent } from '@memberjunction/ng-base-types';\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 extends BaseAngularComponent 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 = RunView.FromMetadataProvider(this.ProviderToUse);\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 <mj-empty-state class=\"restore-empty\" Size=\"compact\"\n Icon=\"fa-solid fa-inbox\"\n Title=\"No archived versions found.\" />\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 <mj-empty-state class=\"preview-placeholder\"\n Icon=\"fa-solid fa-hand-pointer\"\n Title=\"No version selected\"\n Message=\"Select a version to preview\" />\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"]}
@@ -1,4 +1,5 @@
1
1
  import { OnInit, OnDestroy } from '@angular/core';
2
+ import { BaseAngularComponent } from '@memberjunction/ng-base-types';
2
3
  import * as i0 from "@angular/core";
3
4
  /** Summary metrics for the dashboard cards */
4
5
  export interface ArchiveRunMetrics {
@@ -30,7 +31,7 @@ export interface ArchiveRunDetailRow {
30
31
  Bytes: number;
31
32
  ArchivedAt: string;
32
33
  }
33
- export declare class ArchiveRunViewerComponent implements OnInit, OnDestroy {
34
+ export declare class ArchiveRunViewerComponent extends BaseAngularComponent implements OnInit, OnDestroy {
34
35
  private cdr;
35
36
  /** Summary metrics */
36
37
  Metrics: ArchiveRunMetrics;
@@ -1 +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"}
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;AAEvB,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;;AAErE,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,SAAQ,oBAAqB,YAAW,MAAM,EAAE,SAAS;IAC9F,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"}
@@ -1,5 +1,6 @@
1
1
  import { Component, ChangeDetectionStrategy, ChangeDetectorRef, inject, } from '@angular/core';
2
2
  import { RunView } from '@memberjunction/core';
3
+ import { BaseAngularComponent } from '@memberjunction/ng-base-types';
3
4
  import * as i0 from "@angular/core";
4
5
  import * as i1 from "@angular/common";
5
6
  import * as i2 from "@memberjunction/ng-shared-generic";
@@ -287,7 +288,7 @@ function ArchiveRunViewerComponent_Conditional_5_Template(rf, ctx) { if (rf & 1)
287
288
  i0.ɵɵadvance();
288
289
  i0.ɵɵconditional(!ctx_r2.IsDrawerLoading && ctx_r2.RunDetails.length > 0 ? 47 : -1);
289
290
  } }
290
- export class ArchiveRunViewerComponent {
291
+ export class ArchiveRunViewerComponent extends BaseAngularComponent {
291
292
  cdr = inject(ChangeDetectorRef);
292
293
  /** Summary metrics */
293
294
  Metrics = {
@@ -395,7 +396,7 @@ export class ArchiveRunViewerComponent {
395
396
  }
396
397
  /** Fetch run records from the server */
397
398
  async fetchRuns() {
398
- const rv = new RunView();
399
+ const rv = RunView.FromMetadataProvider(this.ProviderToUse);
399
400
  const result = await rv.RunView({
400
401
  EntityName: 'MJ: Archive Runs',
401
402
  ExtraFilter: '',
@@ -441,7 +442,7 @@ export class ArchiveRunViewerComponent {
441
442
  this.RunDetails = [];
442
443
  this.cdr.markForCheck();
443
444
  try {
444
- const rv = new RunView();
445
+ const rv = RunView.FromMetadataProvider(this.ProviderToUse);
445
446
  const escapedId = runId.replace(/'/g, "''");
446
447
  const result = await rv.RunView({
447
448
  EntityName: 'MJ: Archive Run Details',
@@ -480,8 +481,8 @@ export class ArchiveRunViewerComponent {
480
481
  this.cdr.markForCheck();
481
482
  }
482
483
  }
483
- static ɵfac = function ArchiveRunViewerComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ArchiveRunViewerComponent)(); };
484
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ArchiveRunViewerComponent, selectors: [["mj-archive-run-viewer"]], standalone: false, decls: 6, vars: 6, consts: [[1, "run-viewer"], [1, "run-viewer-loading"], [1, "archive-drawer-backdrop"], [1, "archive-drawer"], ["text", "Loading archive runs..."], [1, "metrics-row"], [1, "metric-card"], [1, "metric-icon"], [1, "fa-solid", "fa-play-circle"], [1, "metric-content"], [1, "metric-value"], [1, "metric-label"], [1, "metric-icon", "metric-icon-archive"], [1, "fa-solid", "fa-box-archive"], [1, "metric-icon", "metric-icon-storage"], [1, "fa-solid", "fa-database"], [1, "metric-icon", "metric-icon-time"], [1, "fa-solid", "fa-clock"], [1, "run-list"], [1, "run-list-title"], ["Size", "compact", "Icon", "fa-solid fa-inbox", "Title", "No archive runs found.", 1, "run-empty"], ["tabindex", "0", "role", "button", 1, "run-card"], ["tabindex", "0", "role", "button", 1, "run-card", 3, "click", "keydown.enter"], [1, "run-card-header"], [1, "run-card-name"], [1, "status-badge", 3, "ngClass"], [1, "run-card-date"], [1, "fa-solid", "fa-calendar"], [1, "run-card-stats"], [1, "run-stat"], [1, "run-stat", "run-stat-error"], [1, "run-stat", "run-stat-muted"], [1, "fa-solid", "fa-stopwatch"], [1, "fa-solid", "fa-hard-drive"], [1, "fa-solid", "fa-circle-xmark"], [1, "fa-solid", "fa-forward"], [1, "archive-drawer-backdrop", 3, "click"], [1, "drawer-header"], ["aria-label", "Close drawer", 1, "drawer-close-btn", 3, "click"], [1, "fa-solid", "fa-xmark"], [1, "drawer-summary"], [1, "drawer-summary-row"], [1, "drawer-label"], [1, "drawer-value"], [1, "drawer-stats"], [1, "drawer-stat"], [1, "drawer-stat-value"], [1, "drawer-stat-label"], [1, "drawer-stat", "drawer-stat-error"], [1, "drawer-stat", "drawer-stat-muted"], [1, "drawer-details"], ["text", "Loading details...", "size", "small"], ["Size", "compact", "Icon", "", "Title", "No detail records found.", 1, "drawer-details-empty"], [1, "drawer-table-wrapper"], [1, "drawer-table"], [1, "cell-entity"], [1, "cell-id", 3, "title"], [1, "status-badge", "status-badge-sm", 3, "ngClass"], [1, "cell-bytes"]], template: function ArchiveRunViewerComponent_Template(rf, ctx) { if (rf & 1) {
484
+ static ɵfac = /*@__PURE__*/ (() => { let ɵArchiveRunViewerComponent_BaseFactory; return function ArchiveRunViewerComponent_Factory(__ngFactoryType__) { return (ɵArchiveRunViewerComponent_BaseFactory || (ɵArchiveRunViewerComponent_BaseFactory = i0.ɵɵgetInheritedFactory(ArchiveRunViewerComponent)))(__ngFactoryType__ || ArchiveRunViewerComponent); }; })();
485
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ArchiveRunViewerComponent, selectors: [["mj-archive-run-viewer"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 6, vars: 6, consts: [[1, "run-viewer"], [1, "run-viewer-loading"], [1, "archive-drawer-backdrop"], [1, "archive-drawer"], ["text", "Loading archive runs..."], [1, "metrics-row"], [1, "metric-card"], [1, "metric-icon"], [1, "fa-solid", "fa-play-circle"], [1, "metric-content"], [1, "metric-value"], [1, "metric-label"], [1, "metric-icon", "metric-icon-archive"], [1, "fa-solid", "fa-box-archive"], [1, "metric-icon", "metric-icon-storage"], [1, "fa-solid", "fa-database"], [1, "metric-icon", "metric-icon-time"], [1, "fa-solid", "fa-clock"], [1, "run-list"], [1, "run-list-title"], ["Size", "compact", "Icon", "fa-solid fa-inbox", "Title", "No archive runs found.", 1, "run-empty"], ["tabindex", "0", "role", "button", 1, "run-card"], ["tabindex", "0", "role", "button", 1, "run-card", 3, "click", "keydown.enter"], [1, "run-card-header"], [1, "run-card-name"], [1, "status-badge", 3, "ngClass"], [1, "run-card-date"], [1, "fa-solid", "fa-calendar"], [1, "run-card-stats"], [1, "run-stat"], [1, "run-stat", "run-stat-error"], [1, "run-stat", "run-stat-muted"], [1, "fa-solid", "fa-stopwatch"], [1, "fa-solid", "fa-hard-drive"], [1, "fa-solid", "fa-circle-xmark"], [1, "fa-solid", "fa-forward"], [1, "archive-drawer-backdrop", 3, "click"], [1, "drawer-header"], ["aria-label", "Close drawer", 1, "drawer-close-btn", 3, "click"], [1, "fa-solid", "fa-xmark"], [1, "drawer-summary"], [1, "drawer-summary-row"], [1, "drawer-label"], [1, "drawer-value"], [1, "drawer-stats"], [1, "drawer-stat"], [1, "drawer-stat-value"], [1, "drawer-stat-label"], [1, "drawer-stat", "drawer-stat-error"], [1, "drawer-stat", "drawer-stat-muted"], [1, "drawer-details"], ["text", "Loading details...", "size", "small"], ["Size", "compact", "Icon", "", "Title", "No detail records found.", 1, "drawer-details-empty"], [1, "drawer-table-wrapper"], [1, "drawer-table"], [1, "cell-entity"], [1, "cell-id", 3, "title"], [1, "status-badge", "status-badge-sm", 3, "ngClass"], [1, "cell-bytes"]], template: function ArchiveRunViewerComponent_Template(rf, ctx) { if (rf & 1) {
485
486
  i0.ɵɵelementStart(0, "div", 0);
486
487
  i0.ɵɵconditionalCreate(1, ArchiveRunViewerComponent_Conditional_1_Template, 2, 0, "div", 1);
487
488
  i0.ɵɵconditionalCreate(2, ArchiveRunViewerComponent_Conditional_2_Template, 39, 5);
@@ -506,5 +507,5 @@ export class ArchiveRunViewerComponent {
506
507
  type: Component,
507
508
  args: [{ standalone: false, selector: 'mj-archive-run-viewer', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"run-viewer\">\n <!-- Loading state -->\n @if (IsLoading) {\n <div class=\"run-viewer-loading\">\n <mj-loading text=\"Loading archive runs...\"></mj-loading>\n </div>\n }\n\n @if (!IsLoading) {\n <!-- Summary metric cards -->\n <div class=\"metrics-row\">\n <div class=\"metric-card\">\n <div class=\"metric-icon\">\n <i class=\"fa-solid fa-play-circle\"></i>\n </div>\n <div class=\"metric-content\">\n <span class=\"metric-value\">{{ Metrics.TotalRuns }}</span>\n <span class=\"metric-label\">Total Runs</span>\n </div>\n </div>\n\n <div class=\"metric-card\">\n <div class=\"metric-icon metric-icon-archive\">\n <i class=\"fa-solid fa-box-archive\"></i>\n </div>\n <div class=\"metric-content\">\n <span class=\"metric-value\">{{ Metrics.TotalRecordsArchived }}</span>\n <span class=\"metric-label\">Records Archived</span>\n </div>\n </div>\n\n <div class=\"metric-card\">\n <div class=\"metric-icon metric-icon-storage\">\n <i class=\"fa-solid fa-database\"></i>\n </div>\n <div class=\"metric-content\">\n <span class=\"metric-value\">{{ FormatBytes(Metrics.TotalStorageBytes) }}</span>\n <span class=\"metric-label\">Storage Used</span>\n </div>\n </div>\n\n <div class=\"metric-card\">\n <div class=\"metric-icon metric-icon-time\">\n <i class=\"fa-solid fa-clock\"></i>\n </div>\n <div class=\"metric-content\">\n <span class=\"metric-value\">{{ FormatDate(Metrics.LastRunDate) }}</span>\n <span class=\"metric-label\">Last Run</span>\n </div>\n </div>\n </div>\n\n <!-- Run list -->\n <div class=\"run-list\">\n <h3 class=\"run-list-title\">Run History</h3>\n\n @if (Runs.length === 0) {\n <mj-empty-state class=\"run-empty\" Size=\"compact\"\n Icon=\"fa-solid fa-inbox\"\n Title=\"No archive runs found.\" />\n }\n\n @for (run of Runs; track run.ID) {\n <div\n class=\"run-card\"\n (click)=\"OpenRunDrawer(run)\"\n (keydown.enter)=\"OpenRunDrawer(run)\"\n tabindex=\"0\"\n role=\"button\"\n [attr.aria-label]=\"'View details for run on ' + FormatDate(run.StartedAt)\">\n <div class=\"run-card-header\">\n <span class=\"run-card-name\">{{ run.ConfigurationName }}</span>\n <span class=\"status-badge\" [ngClass]=\"GetStatusClass(run.Status)\">{{ run.Status }}</span>\n </div>\n <div class=\"run-card-date\">\n <i class=\"fa-solid fa-calendar\"></i>\n {{ FormatDate(run.StartedAt) }}\n </div>\n <div class=\"run-card-stats\">\n <span class=\"run-stat\">\n <i class=\"fa-solid fa-box-archive\"></i>\n {{ run.RecordsArchived }} archived\n </span>\n @if (run.RecordsFailed > 0) {\n <span class=\"run-stat run-stat-error\">\n <i class=\"fa-solid fa-circle-xmark\"></i>\n {{ run.RecordsFailed }} failed\n </span>\n }\n @if (run.RecordsSkipped > 0) {\n <span class=\"run-stat run-stat-muted\">\n <i class=\"fa-solid fa-forward\"></i>\n {{ run.RecordsSkipped }} skipped\n </span>\n }\n <span class=\"run-stat\">\n <i class=\"fa-solid fa-stopwatch\"></i>\n {{ FormatDuration(run.DurationSeconds) }}\n </span>\n <span class=\"run-stat\">\n <i class=\"fa-solid fa-hard-drive\"></i>\n {{ FormatBytes(run.TotalBytes) }}\n </span>\n </div>\n </div>\n }\n </div>\n }\n\n <!-- Drawer backdrop -->\n @if (DrawerOpen) {\n <div class=\"archive-drawer-backdrop\" (click)=\"CloseDrawer()\"></div>\n }\n\n <!-- Slide-in drawer -->\n <div class=\"archive-drawer\" [class.open]=\"DrawerOpen\">\n @if (SelectedRun) {\n <!-- Drawer header -->\n <div class=\"drawer-header\">\n <h3>Run Details</h3>\n <button class=\"drawer-close-btn\" (click)=\"CloseDrawer()\" aria-label=\"Close drawer\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n\n <!-- Run summary -->\n <div class=\"drawer-summary\">\n <div class=\"drawer-summary-row\">\n <span class=\"drawer-label\">Configuration</span>\n <span class=\"drawer-value\">{{ SelectedRun.ConfigurationName }}</span>\n </div>\n <div class=\"drawer-summary-row\">\n <span class=\"drawer-label\">Status</span>\n <span class=\"status-badge\" [ngClass]=\"GetStatusClass(SelectedRun.Status)\">{{ SelectedRun.Status }}</span>\n </div>\n <div class=\"drawer-summary-row\">\n <span class=\"drawer-label\">Started</span>\n <span class=\"drawer-value\">{{ FormatDate(SelectedRun.StartedAt) }}</span>\n </div>\n <div class=\"drawer-summary-row\">\n <span class=\"drawer-label\">Duration</span>\n <span class=\"drawer-value\">{{ FormatDuration(SelectedRun.DurationSeconds) }}</span>\n </div>\n </div>\n\n <!-- Stats row -->\n <div class=\"drawer-stats\">\n <div class=\"drawer-stat\">\n <span class=\"drawer-stat-value\">{{ SelectedRun.RecordsArchived }}</span>\n <span class=\"drawer-stat-label\">Archived</span>\n </div>\n <div class=\"drawer-stat drawer-stat-error\">\n <span class=\"drawer-stat-value\">{{ SelectedRun.RecordsFailed }}</span>\n <span class=\"drawer-stat-label\">Failed</span>\n </div>\n <div class=\"drawer-stat drawer-stat-muted\">\n <span class=\"drawer-stat-value\">{{ SelectedRun.RecordsSkipped }}</span>\n <span class=\"drawer-stat-label\">Skipped</span>\n </div>\n </div>\n\n <!-- Detail table -->\n <div class=\"drawer-details\">\n <h4>Per-Record Results</h4>\n\n @if (IsDrawerLoading) {\n <mj-loading text=\"Loading details...\" size=\"small\"></mj-loading>\n }\n\n @if (!IsDrawerLoading && RunDetails.length === 0) {\n <mj-empty-state class=\"drawer-details-empty\" Size=\"compact\" Icon=\"\" Title=\"No detail records found.\" />\n }\n\n @if (!IsDrawerLoading && RunDetails.length > 0) {\n <div class=\"drawer-table-wrapper\">\n <table class=\"drawer-table\">\n <thead>\n <tr>\n <th>Entity</th>\n <th>Record ID</th>\n <th>Status</th>\n <th>Bytes</th>\n </tr>\n </thead>\n <tbody>\n @for (detail of RunDetails; track detail.ID) {\n <tr>\n <td class=\"cell-entity\">{{ detail.EntityName }}</td>\n <td class=\"cell-id\" [title]=\"detail.RecordID\">{{ detail.RecordID }}</td>\n <td>\n <span class=\"status-badge status-badge-sm\" [ngClass]=\"GetStatusClass(detail.Status)\">\n {{ detail.Status }}\n </span>\n </td>\n <td class=\"cell-bytes\">{{ FormatBytes(detail.Bytes) }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </div>\n }\n </div>\n</div>\n", styles: [".run-viewer {\n padding: 20px;\n position: relative;\n}\n\n/* Loading */\n.run-viewer-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 60px;\n}\n\n/* Metric cards row */\n.metrics-row {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: 16px;\n margin-bottom: 24px;\n}\n\n.metric-card {\n display: flex;\n align-items: center;\n gap: 14px;\n padding: 18px 20px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 8px;\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n\n &:hover {\n border-color: var(--mj-border-default);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-text-primary) 6%, transparent);\n }\n}\n\n.metric-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 42px;\n height: 42px;\n border-radius: 10px;\n font-size: 1.1rem;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.metric-icon-archive {\n background: color-mix(in srgb, var(--mj-status-success) 10%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n.metric-icon-storage {\n background: color-mix(in srgb, var(--mj-status-warning) 10%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n}\n\n.metric-icon-time {\n background: color-mix(in srgb, var(--mj-status-info) 10%, var(--mj-bg-surface));\n color: var(--mj-status-info);\n}\n\n.metric-content {\n display: flex;\n flex-direction: column;\n}\n\n.metric-value {\n font-size: 1.25rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1.2;\n}\n\n.metric-label {\n font-size: 0.78rem;\n color: var(--mj-text-muted);\n margin-top: 2px;\n}\n\n/* Run list */\n.run-list-title {\n margin: 0 0 14px;\n font-size: 1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.run-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 40px;\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/* Run card */\n.run-card {\n padding: 14px 18px;\n margin-bottom: 10px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 6px;\n cursor: pointer;\n transition: border-color 0.15s ease, background 0.15s ease;\n\n &:hover {\n border-color: var(--mj-border-default);\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\n.run-card-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 6px;\n}\n\n.run-card-name {\n font-weight: 600;\n font-size: 0.9rem;\n color: var(--mj-text-primary);\n}\n\n.run-card-date {\n font-size: 0.78rem;\n color: var(--mj-text-muted);\n margin-bottom: 8px;\n\n i {\n margin-right: 4px;\n }\n}\n\n.run-card-stats {\n display: flex;\n flex-wrap: wrap;\n gap: 14px;\n}\n\n.run-stat {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 0.78rem;\n color: var(--mj-text-secondary);\n\n i {\n font-size: 0.72rem;\n }\n}\n\n.run-stat-error {\n color: var(--mj-status-error-text);\n}\n\n.run-stat-muted {\n color: var(--mj-text-muted);\n}\n\n/* Status badges */\n.status-badge {\n display: inline-flex;\n align-items: center;\n padding: 2px 10px;\n font-size: 0.72rem;\n font-weight: 600;\n border-radius: 10px;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n}\n\n.status-badge-sm {\n padding: 1px 7px;\n font-size: 0.68rem;\n}\n\n.status-badge-success {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n.status-badge-error {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n}\n\n.status-badge-info {\n background: var(--mj-status-info-bg);\n color: var(--mj-status-info-text);\n}\n\n.status-badge-default {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n}\n\n/* Drawer backdrop */\n.archive-drawer-backdrop {\n position: fixed;\n inset: 0;\n background: var(--mj-bg-overlay);\n z-index: 999;\n}\n\n/* Slide-in drawer */\n.archive-drawer {\n position: fixed;\n top: 0;\n right: 0;\n width: 400px;\n height: 100vh;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n box-shadow: -4px 0 24px color-mix(in srgb, var(--mj-text-primary) 10%, transparent);\n z-index: 1000;\n transform: translateX(100%);\n transition: transform 0.3s ease;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n\n &.open {\n transform: translateX(0);\n }\n}\n\n/* Drawer header */\n.drawer-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 14px 18px;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n\n h3 {\n margin: 0;\n font-size: 1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n }\n}\n\n.drawer-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: 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/* Drawer summary */\n.drawer-summary {\n padding: 14px 18px;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.drawer-summary-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 4px 0;\n}\n\n.drawer-label {\n font-size: 0.78rem;\n font-weight: 600;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.03em;\n}\n\n.drawer-value {\n font-size: 0.85rem;\n color: var(--mj-text-primary);\n}\n\n/* Drawer stats */\n.drawer-stats {\n display: flex;\n gap: 0;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.drawer-stat {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 14px 10px;\n border-right: 1px solid var(--mj-border-subtle);\n\n &:last-child {\n border-right: none;\n }\n}\n\n.drawer-stat-value {\n font-size: 1.2rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.drawer-stat-error .drawer-stat-value {\n color: var(--mj-status-error);\n}\n\n.drawer-stat-muted .drawer-stat-value {\n color: var(--mj-text-muted);\n}\n\n.drawer-stat-label {\n font-size: 0.72rem;\n color: var(--mj-text-muted);\n margin-top: 2px;\n}\n\n/* Drawer detail table */\n.drawer-details {\n flex: 1;\n padding: 14px 18px;\n overflow-y: auto;\n\n h4 {\n margin: 0 0 12px;\n font-size: 0.88rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n }\n}\n\n.drawer-details-empty {\n color: var(--mj-text-muted);\n font-size: 0.85rem;\n text-align: center;\n padding: 20px;\n}\n\n.drawer-table-wrapper {\n overflow-x: auto;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n}\n\n.drawer-table {\n width: 100%;\n border-collapse: collapse;\n font-size: 0.78rem;\n\n th {\n padding: 7px 10px;\n text-align: left;\n font-weight: 600;\n font-size: 0.72rem;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n }\n\n td {\n padding: 6px 10px;\n border-bottom: 1px solid var(--mj-border-subtle);\n color: var(--mj-text-primary);\n }\n\n tr:last-child td {\n border-bottom: none;\n }\n}\n\n.cell-entity {\n font-weight: 500;\n}\n\n.cell-id {\n max-width: 100px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-family: monospace;\n font-size: 0.72rem;\n color: var(--mj-text-secondary);\n}\n\n.cell-bytes {\n white-space: nowrap;\n}\n\n/* Responsive: stack metric cards on small screens */\n@media (max-width: 900px) {\n .metrics-row {\n grid-template-columns: repeat(2, 1fr);\n }\n}\n\n@media (max-width: 600px) {\n .metrics-row {\n grid-template-columns: 1fr;\n }\n}\n"] }]
508
509
  }], null, null); })();
509
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ArchiveRunViewerComponent, { className: "ArchiveRunViewerComponent", filePath: "src/lib/archive-run-viewer/archive-run-viewer.component.ts", lineNumber: 51 }); })();
510
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ArchiveRunViewerComponent, { className: "ArchiveRunViewerComponent", filePath: "src/lib/archive-run-viewer/archive-run-viewer.component.ts", lineNumber: 52 }); })();
510
511
  //# sourceMappingURL=archive-run-viewer.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"archive-run-viewer.component.js","sourceRoot":"","sources":["../../../src/lib/archive-run-viewer/archive-run-viewer.component.ts","../../../src/lib/archive-run-viewer/archive-run-viewer.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n OnInit,\n OnDestroy,\n inject,\n} from '@angular/core';\nimport { RunView } from '@memberjunction/core';\n\n/** Summary metrics for the dashboard cards */\nexport interface ArchiveRunMetrics {\n TotalRuns: number;\n TotalRecordsArchived: number;\n TotalStorageBytes: number;\n LastRunDate: Date | null;\n}\n\n/** Represents a single archive run */\nexport interface ArchiveRunSummary {\n ID: string;\n ConfigurationName: string;\n StartedAt: Date;\n CompletedAt: Date | null;\n Status: string;\n RecordsArchived: number;\n RecordsFailed: number;\n RecordsSkipped: number;\n TotalBytes: number;\n DurationSeconds: number;\n}\n\n/** Detail record for a single archived item within a run */\nexport interface ArchiveRunDetailRow {\n ID: string;\n EntityName: string;\n RecordID: string;\n Status: string;\n StoragePath: string;\n Bytes: number;\n ArchivedAt: string;\n}\n\n@Component({\n standalone: false,\n selector: 'mj-archive-run-viewer',\n templateUrl: './archive-run-viewer.component.html',\n styleUrls: ['./archive-run-viewer.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ArchiveRunViewerComponent implements OnInit, OnDestroy {\n private cdr = inject(ChangeDetectorRef);\n\n /** Summary metrics */\n Metrics: ArchiveRunMetrics = {\n TotalRuns: 0,\n TotalRecordsArchived: 0,\n TotalStorageBytes: 0,\n LastRunDate: null,\n };\n\n /** All archive runs */\n Runs: ArchiveRunSummary[] = [];\n\n /** Currently selected run for the drawer */\n SelectedRun: ArchiveRunSummary | null = null;\n\n /** Detail records for the selected run */\n RunDetails: ArchiveRunDetailRow[] = [];\n\n /** Whether the drawer is open */\n DrawerOpen = false;\n\n /** Whether the main data is loading */\n IsLoading = true;\n\n /** Whether drawer details are loading */\n IsDrawerLoading = false;\n\n private destroyed = false;\n\n ngOnInit(): void {\n this.loadRunData();\n }\n\n ngOnDestroy(): void {\n this.destroyed = true;\n }\n\n /** Open the drawer for a specific run */\n async OpenRunDrawer(run: ArchiveRunSummary): Promise<void> {\n this.SelectedRun = run;\n this.DrawerOpen = true;\n this.cdr.markForCheck();\n await this.loadRunDetails(run.ID);\n }\n\n /** Close the drawer */\n CloseDrawer(): void {\n this.DrawerOpen = false;\n this.SelectedRun = null;\n this.RunDetails = [];\n this.cdr.markForCheck();\n }\n\n /** Format bytes into a readable string */\n FormatBytes(bytes: number | string | null | undefined): string {\n const numBytes = Number(bytes);\n if (!numBytes || numBytes <= 0) return '0 B';\n const units = ['B', 'KB', 'MB', 'GB', 'TB'];\n const k = 1024;\n const i = Math.floor(Math.log(numBytes) / Math.log(k));\n const value = numBytes / 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 | null): string {\n if (!date) return 'N/A';\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 /** Format duration in seconds to a readable string */\n FormatDuration(seconds: number): string {\n if (seconds < 60) return `${seconds}s`;\n const mins = Math.floor(seconds / 60);\n const secs = seconds % 60;\n return secs > 0 ? `${mins}m ${secs}s` : `${mins}m`;\n }\n\n /** Get CSS class for a status badge */\n GetStatusClass(status: string): string {\n switch (status.toLowerCase()) {\n case 'success':\n case 'completed':\n return 'status-badge-success';\n case 'failed':\n case 'error':\n return 'status-badge-error';\n case 'running':\n case 'in progress':\n return 'status-badge-info';\n default:\n return 'status-badge-default';\n }\n }\n\n /** Load all run data and compute metrics */\n private async loadRunData(): Promise<void> {\n this.IsLoading = true;\n this.cdr.markForCheck();\n\n try {\n const runs = await this.fetchRuns();\n this.Runs = runs;\n this.Metrics = this.computeMetrics(runs);\n } catch {\n this.Runs = [];\n } finally {\n this.IsLoading = false;\n this.markForCheckIfAlive();\n }\n }\n\n /** Fetch run records from the server */\n private async fetchRuns(): Promise<ArchiveRunSummary[]> {\n const rv = new RunView();\n const result = await rv.RunView<RunRecord>({\n EntityName: 'MJ: Archive Runs',\n ExtraFilter: '',\n OrderBy: 'StartedAt DESC',\n ResultType: 'simple',\n });\n\n if (!result.Success) return [];\n return result.Results.map((r) => this.mapRunRecord(r));\n }\n\n /** Map a raw run record to a typed summary */\n private mapRunRecord(r: RunRecord): ArchiveRunSummary {\n const startedAt = new Date(r.StartedAt);\n const completedAt = r.CompletedAt ? new Date(r.CompletedAt) : null;\n const durationSeconds = completedAt\n ? Math.round((completedAt.getTime() - startedAt.getTime()) / 1000)\n : 0;\n\n return {\n ID: r.ID,\n ConfigurationName: r.ArchiveConfiguration ?? '',\n StartedAt: startedAt,\n CompletedAt: completedAt,\n Status: r.Status ?? 'Unknown',\n RecordsArchived: Number(r.ArchivedRecords) || 0,\n RecordsFailed: Number(r.FailedRecords) || 0,\n RecordsSkipped: Number(r.SkippedRecords) || 0,\n TotalBytes: Number(r.TotalBytesArchived) || 0,\n DurationSeconds: durationSeconds,\n };\n }\n\n /** Compute summary metrics from all runs */\n private computeMetrics(runs: ArchiveRunSummary[]): ArchiveRunMetrics {\n return {\n TotalRuns: runs.length,\n TotalRecordsArchived: runs.reduce((sum, r) => sum + r.RecordsArchived, 0),\n TotalStorageBytes: runs.reduce((sum, r) => sum + r.TotalBytes, 0),\n LastRunDate: runs.length > 0 ? runs[0].StartedAt : null,\n };\n }\n\n /** Load detail records for a specific run */\n private async loadRunDetails(runId: string): Promise<void> {\n this.IsDrawerLoading = true;\n this.RunDetails = [];\n this.cdr.markForCheck();\n\n try {\n const rv = new RunView();\n const escapedId = runId.replace(/'/g, \"''\");\n const result = await rv.RunView<DetailRecord>({\n EntityName: 'MJ: Archive Run Details',\n ExtraFilter: `ArchiveRunID='${escapedId}'`,\n OrderBy: '__mj_CreatedAt DESC',\n ResultType: 'simple',\n Fields: ['ID', 'Entity', 'RecordID', 'Status', 'StoragePath', 'BytesArchived', '__mj_CreatedAt'],\n });\n\n if (result.Success) {\n this.RunDetails = result.Results.map((r) => this.mapDetailRecord(r));\n }\n } catch {\n this.RunDetails = [];\n } finally {\n this.IsDrawerLoading = false;\n this.markForCheckIfAlive();\n }\n }\n\n /** Map a raw detail record to a typed row */\n private mapDetailRecord(r: DetailRecord): ArchiveRunDetailRow {\n return {\n ID: r.ID,\n EntityName: r.Entity ?? '',\n RecordID: r.RecordID ?? '',\n Status: r.Status ?? 'Unknown',\n StoragePath: r.StoragePath ?? '',\n Bytes: Number(r.BytesArchived) || 0,\n ArchivedAt: r.__mj_CreatedAt ?? '',\n };\n }\n\n /** Mark for check only if not destroyed */\n private markForCheckIfAlive(): void {\n if (!this.destroyed) {\n this.cdr.markForCheck();\n }\n }\n}\n\n/** Shape of a run record from the simple RunView query */\ninterface RunRecord {\n ID: string;\n ArchiveConfiguration: string;\n StartedAt: string;\n CompletedAt: string;\n Status: string;\n ArchivedRecords: number;\n FailedRecords: number;\n SkippedRecords: number;\n TotalBytesArchived: number;\n}\n\n/** Shape of a detail record from the simple RunView query */\ninterface DetailRecord {\n ID: string;\n Entity: string;\n RecordID: string;\n Status: string;\n StoragePath: string;\n BytesArchived: number;\n __mj_CreatedAt: string;\n}\n","<div class=\"run-viewer\">\n <!-- Loading state -->\n @if (IsLoading) {\n <div class=\"run-viewer-loading\">\n <mj-loading text=\"Loading archive runs...\"></mj-loading>\n </div>\n }\n\n @if (!IsLoading) {\n <!-- Summary metric cards -->\n <div class=\"metrics-row\">\n <div class=\"metric-card\">\n <div class=\"metric-icon\">\n <i class=\"fa-solid fa-play-circle\"></i>\n </div>\n <div class=\"metric-content\">\n <span class=\"metric-value\">{{ Metrics.TotalRuns }}</span>\n <span class=\"metric-label\">Total Runs</span>\n </div>\n </div>\n\n <div class=\"metric-card\">\n <div class=\"metric-icon metric-icon-archive\">\n <i class=\"fa-solid fa-box-archive\"></i>\n </div>\n <div class=\"metric-content\">\n <span class=\"metric-value\">{{ Metrics.TotalRecordsArchived }}</span>\n <span class=\"metric-label\">Records Archived</span>\n </div>\n </div>\n\n <div class=\"metric-card\">\n <div class=\"metric-icon metric-icon-storage\">\n <i class=\"fa-solid fa-database\"></i>\n </div>\n <div class=\"metric-content\">\n <span class=\"metric-value\">{{ FormatBytes(Metrics.TotalStorageBytes) }}</span>\n <span class=\"metric-label\">Storage Used</span>\n </div>\n </div>\n\n <div class=\"metric-card\">\n <div class=\"metric-icon metric-icon-time\">\n <i class=\"fa-solid fa-clock\"></i>\n </div>\n <div class=\"metric-content\">\n <span class=\"metric-value\">{{ FormatDate(Metrics.LastRunDate) }}</span>\n <span class=\"metric-label\">Last Run</span>\n </div>\n </div>\n </div>\n\n <!-- Run list -->\n <div class=\"run-list\">\n <h3 class=\"run-list-title\">Run History</h3>\n\n @if (Runs.length === 0) {\n <mj-empty-state class=\"run-empty\" Size=\"compact\"\n Icon=\"fa-solid fa-inbox\"\n Title=\"No archive runs found.\" />\n }\n\n @for (run of Runs; track run.ID) {\n <div\n class=\"run-card\"\n (click)=\"OpenRunDrawer(run)\"\n (keydown.enter)=\"OpenRunDrawer(run)\"\n tabindex=\"0\"\n role=\"button\"\n [attr.aria-label]=\"'View details for run on ' + FormatDate(run.StartedAt)\">\n <div class=\"run-card-header\">\n <span class=\"run-card-name\">{{ run.ConfigurationName }}</span>\n <span class=\"status-badge\" [ngClass]=\"GetStatusClass(run.Status)\">{{ run.Status }}</span>\n </div>\n <div class=\"run-card-date\">\n <i class=\"fa-solid fa-calendar\"></i>\n {{ FormatDate(run.StartedAt) }}\n </div>\n <div class=\"run-card-stats\">\n <span class=\"run-stat\">\n <i class=\"fa-solid fa-box-archive\"></i>\n {{ run.RecordsArchived }} archived\n </span>\n @if (run.RecordsFailed > 0) {\n <span class=\"run-stat run-stat-error\">\n <i class=\"fa-solid fa-circle-xmark\"></i>\n {{ run.RecordsFailed }} failed\n </span>\n }\n @if (run.RecordsSkipped > 0) {\n <span class=\"run-stat run-stat-muted\">\n <i class=\"fa-solid fa-forward\"></i>\n {{ run.RecordsSkipped }} skipped\n </span>\n }\n <span class=\"run-stat\">\n <i class=\"fa-solid fa-stopwatch\"></i>\n {{ FormatDuration(run.DurationSeconds) }}\n </span>\n <span class=\"run-stat\">\n <i class=\"fa-solid fa-hard-drive\"></i>\n {{ FormatBytes(run.TotalBytes) }}\n </span>\n </div>\n </div>\n }\n </div>\n }\n\n <!-- Drawer backdrop -->\n @if (DrawerOpen) {\n <div class=\"archive-drawer-backdrop\" (click)=\"CloseDrawer()\"></div>\n }\n\n <!-- Slide-in drawer -->\n <div class=\"archive-drawer\" [class.open]=\"DrawerOpen\">\n @if (SelectedRun) {\n <!-- Drawer header -->\n <div class=\"drawer-header\">\n <h3>Run Details</h3>\n <button class=\"drawer-close-btn\" (click)=\"CloseDrawer()\" aria-label=\"Close drawer\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n\n <!-- Run summary -->\n <div class=\"drawer-summary\">\n <div class=\"drawer-summary-row\">\n <span class=\"drawer-label\">Configuration</span>\n <span class=\"drawer-value\">{{ SelectedRun.ConfigurationName }}</span>\n </div>\n <div class=\"drawer-summary-row\">\n <span class=\"drawer-label\">Status</span>\n <span class=\"status-badge\" [ngClass]=\"GetStatusClass(SelectedRun.Status)\">{{ SelectedRun.Status }}</span>\n </div>\n <div class=\"drawer-summary-row\">\n <span class=\"drawer-label\">Started</span>\n <span class=\"drawer-value\">{{ FormatDate(SelectedRun.StartedAt) }}</span>\n </div>\n <div class=\"drawer-summary-row\">\n <span class=\"drawer-label\">Duration</span>\n <span class=\"drawer-value\">{{ FormatDuration(SelectedRun.DurationSeconds) }}</span>\n </div>\n </div>\n\n <!-- Stats row -->\n <div class=\"drawer-stats\">\n <div class=\"drawer-stat\">\n <span class=\"drawer-stat-value\">{{ SelectedRun.RecordsArchived }}</span>\n <span class=\"drawer-stat-label\">Archived</span>\n </div>\n <div class=\"drawer-stat drawer-stat-error\">\n <span class=\"drawer-stat-value\">{{ SelectedRun.RecordsFailed }}</span>\n <span class=\"drawer-stat-label\">Failed</span>\n </div>\n <div class=\"drawer-stat drawer-stat-muted\">\n <span class=\"drawer-stat-value\">{{ SelectedRun.RecordsSkipped }}</span>\n <span class=\"drawer-stat-label\">Skipped</span>\n </div>\n </div>\n\n <!-- Detail table -->\n <div class=\"drawer-details\">\n <h4>Per-Record Results</h4>\n\n @if (IsDrawerLoading) {\n <mj-loading text=\"Loading details...\" size=\"small\"></mj-loading>\n }\n\n @if (!IsDrawerLoading && RunDetails.length === 0) {\n <mj-empty-state class=\"drawer-details-empty\" Size=\"compact\" Icon=\"\" Title=\"No detail records found.\" />\n }\n\n @if (!IsDrawerLoading && RunDetails.length > 0) {\n <div class=\"drawer-table-wrapper\">\n <table class=\"drawer-table\">\n <thead>\n <tr>\n <th>Entity</th>\n <th>Record ID</th>\n <th>Status</th>\n <th>Bytes</th>\n </tr>\n </thead>\n <tbody>\n @for (detail of RunDetails; track detail.ID) {\n <tr>\n <td class=\"cell-entity\">{{ detail.EntityName }}</td>\n <td class=\"cell-id\" [title]=\"detail.RecordID\">{{ detail.RecordID }}</td>\n <td>\n <span class=\"status-badge status-badge-sm\" [ngClass]=\"GetStatusClass(detail.Status)\">\n {{ detail.Status }}\n </span>\n </td>\n <td class=\"cell-bytes\">{{ FormatBytes(detail.Bytes) }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </div>\n }\n </div>\n</div>\n"]}
1
+ {"version":3,"file":"archive-run-viewer.component.js","sourceRoot":"","sources":["../../../src/lib/archive-run-viewer/archive-run-viewer.component.ts","../../../src/lib/archive-run-viewer/archive-run-viewer.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n OnInit,\n OnDestroy,\n inject,\n} from '@angular/core';\nimport { RunView } from '@memberjunction/core';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\n\n/** Summary metrics for the dashboard cards */\nexport interface ArchiveRunMetrics {\n TotalRuns: number;\n TotalRecordsArchived: number;\n TotalStorageBytes: number;\n LastRunDate: Date | null;\n}\n\n/** Represents a single archive run */\nexport interface ArchiveRunSummary {\n ID: string;\n ConfigurationName: string;\n StartedAt: Date;\n CompletedAt: Date | null;\n Status: string;\n RecordsArchived: number;\n RecordsFailed: number;\n RecordsSkipped: number;\n TotalBytes: number;\n DurationSeconds: number;\n}\n\n/** Detail record for a single archived item within a run */\nexport interface ArchiveRunDetailRow {\n ID: string;\n EntityName: string;\n RecordID: string;\n Status: string;\n StoragePath: string;\n Bytes: number;\n ArchivedAt: string;\n}\n\n@Component({\n standalone: false,\n selector: 'mj-archive-run-viewer',\n templateUrl: './archive-run-viewer.component.html',\n styleUrls: ['./archive-run-viewer.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ArchiveRunViewerComponent extends BaseAngularComponent implements OnInit, OnDestroy {\n private cdr = inject(ChangeDetectorRef);\n\n /** Summary metrics */\n Metrics: ArchiveRunMetrics = {\n TotalRuns: 0,\n TotalRecordsArchived: 0,\n TotalStorageBytes: 0,\n LastRunDate: null,\n };\n\n /** All archive runs */\n Runs: ArchiveRunSummary[] = [];\n\n /** Currently selected run for the drawer */\n SelectedRun: ArchiveRunSummary | null = null;\n\n /** Detail records for the selected run */\n RunDetails: ArchiveRunDetailRow[] = [];\n\n /** Whether the drawer is open */\n DrawerOpen = false;\n\n /** Whether the main data is loading */\n IsLoading = true;\n\n /** Whether drawer details are loading */\n IsDrawerLoading = false;\n\n private destroyed = false;\n\n ngOnInit(): void {\n this.loadRunData();\n }\n\n ngOnDestroy(): void {\n this.destroyed = true;\n }\n\n /** Open the drawer for a specific run */\n async OpenRunDrawer(run: ArchiveRunSummary): Promise<void> {\n this.SelectedRun = run;\n this.DrawerOpen = true;\n this.cdr.markForCheck();\n await this.loadRunDetails(run.ID);\n }\n\n /** Close the drawer */\n CloseDrawer(): void {\n this.DrawerOpen = false;\n this.SelectedRun = null;\n this.RunDetails = [];\n this.cdr.markForCheck();\n }\n\n /** Format bytes into a readable string */\n FormatBytes(bytes: number | string | null | undefined): string {\n const numBytes = Number(bytes);\n if (!numBytes || numBytes <= 0) return '0 B';\n const units = ['B', 'KB', 'MB', 'GB', 'TB'];\n const k = 1024;\n const i = Math.floor(Math.log(numBytes) / Math.log(k));\n const value = numBytes / 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 | null): string {\n if (!date) return 'N/A';\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 /** Format duration in seconds to a readable string */\n FormatDuration(seconds: number): string {\n if (seconds < 60) return `${seconds}s`;\n const mins = Math.floor(seconds / 60);\n const secs = seconds % 60;\n return secs > 0 ? `${mins}m ${secs}s` : `${mins}m`;\n }\n\n /** Get CSS class for a status badge */\n GetStatusClass(status: string): string {\n switch (status.toLowerCase()) {\n case 'success':\n case 'completed':\n return 'status-badge-success';\n case 'failed':\n case 'error':\n return 'status-badge-error';\n case 'running':\n case 'in progress':\n return 'status-badge-info';\n default:\n return 'status-badge-default';\n }\n }\n\n /** Load all run data and compute metrics */\n private async loadRunData(): Promise<void> {\n this.IsLoading = true;\n this.cdr.markForCheck();\n\n try {\n const runs = await this.fetchRuns();\n this.Runs = runs;\n this.Metrics = this.computeMetrics(runs);\n } catch {\n this.Runs = [];\n } finally {\n this.IsLoading = false;\n this.markForCheckIfAlive();\n }\n }\n\n /** Fetch run records from the server */\n private async fetchRuns(): Promise<ArchiveRunSummary[]> {\n const rv = RunView.FromMetadataProvider(this.ProviderToUse);\n const result = await rv.RunView<RunRecord>({\n EntityName: 'MJ: Archive Runs',\n ExtraFilter: '',\n OrderBy: 'StartedAt DESC',\n ResultType: 'simple',\n });\n\n if (!result.Success) return [];\n return result.Results.map((r) => this.mapRunRecord(r));\n }\n\n /** Map a raw run record to a typed summary */\n private mapRunRecord(r: RunRecord): ArchiveRunSummary {\n const startedAt = new Date(r.StartedAt);\n const completedAt = r.CompletedAt ? new Date(r.CompletedAt) : null;\n const durationSeconds = completedAt\n ? Math.round((completedAt.getTime() - startedAt.getTime()) / 1000)\n : 0;\n\n return {\n ID: r.ID,\n ConfigurationName: r.ArchiveConfiguration ?? '',\n StartedAt: startedAt,\n CompletedAt: completedAt,\n Status: r.Status ?? 'Unknown',\n RecordsArchived: Number(r.ArchivedRecords) || 0,\n RecordsFailed: Number(r.FailedRecords) || 0,\n RecordsSkipped: Number(r.SkippedRecords) || 0,\n TotalBytes: Number(r.TotalBytesArchived) || 0,\n DurationSeconds: durationSeconds,\n };\n }\n\n /** Compute summary metrics from all runs */\n private computeMetrics(runs: ArchiveRunSummary[]): ArchiveRunMetrics {\n return {\n TotalRuns: runs.length,\n TotalRecordsArchived: runs.reduce((sum, r) => sum + r.RecordsArchived, 0),\n TotalStorageBytes: runs.reduce((sum, r) => sum + r.TotalBytes, 0),\n LastRunDate: runs.length > 0 ? runs[0].StartedAt : null,\n };\n }\n\n /** Load detail records for a specific run */\n private async loadRunDetails(runId: string): Promise<void> {\n this.IsDrawerLoading = true;\n this.RunDetails = [];\n this.cdr.markForCheck();\n\n try {\n const rv = RunView.FromMetadataProvider(this.ProviderToUse);\n const escapedId = runId.replace(/'/g, \"''\");\n const result = await rv.RunView<DetailRecord>({\n EntityName: 'MJ: Archive Run Details',\n ExtraFilter: `ArchiveRunID='${escapedId}'`,\n OrderBy: '__mj_CreatedAt DESC',\n ResultType: 'simple',\n Fields: ['ID', 'Entity', 'RecordID', 'Status', 'StoragePath', 'BytesArchived', '__mj_CreatedAt'],\n });\n\n if (result.Success) {\n this.RunDetails = result.Results.map((r) => this.mapDetailRecord(r));\n }\n } catch {\n this.RunDetails = [];\n } finally {\n this.IsDrawerLoading = false;\n this.markForCheckIfAlive();\n }\n }\n\n /** Map a raw detail record to a typed row */\n private mapDetailRecord(r: DetailRecord): ArchiveRunDetailRow {\n return {\n ID: r.ID,\n EntityName: r.Entity ?? '',\n RecordID: r.RecordID ?? '',\n Status: r.Status ?? 'Unknown',\n StoragePath: r.StoragePath ?? '',\n Bytes: Number(r.BytesArchived) || 0,\n ArchivedAt: r.__mj_CreatedAt ?? '',\n };\n }\n\n /** Mark for check only if not destroyed */\n private markForCheckIfAlive(): void {\n if (!this.destroyed) {\n this.cdr.markForCheck();\n }\n }\n}\n\n/** Shape of a run record from the simple RunView query */\ninterface RunRecord {\n ID: string;\n ArchiveConfiguration: string;\n StartedAt: string;\n CompletedAt: string;\n Status: string;\n ArchivedRecords: number;\n FailedRecords: number;\n SkippedRecords: number;\n TotalBytesArchived: number;\n}\n\n/** Shape of a detail record from the simple RunView query */\ninterface DetailRecord {\n ID: string;\n Entity: string;\n RecordID: string;\n Status: string;\n StoragePath: string;\n BytesArchived: number;\n __mj_CreatedAt: string;\n}\n","<div class=\"run-viewer\">\n <!-- Loading state -->\n @if (IsLoading) {\n <div class=\"run-viewer-loading\">\n <mj-loading text=\"Loading archive runs...\"></mj-loading>\n </div>\n }\n\n @if (!IsLoading) {\n <!-- Summary metric cards -->\n <div class=\"metrics-row\">\n <div class=\"metric-card\">\n <div class=\"metric-icon\">\n <i class=\"fa-solid fa-play-circle\"></i>\n </div>\n <div class=\"metric-content\">\n <span class=\"metric-value\">{{ Metrics.TotalRuns }}</span>\n <span class=\"metric-label\">Total Runs</span>\n </div>\n </div>\n\n <div class=\"metric-card\">\n <div class=\"metric-icon metric-icon-archive\">\n <i class=\"fa-solid fa-box-archive\"></i>\n </div>\n <div class=\"metric-content\">\n <span class=\"metric-value\">{{ Metrics.TotalRecordsArchived }}</span>\n <span class=\"metric-label\">Records Archived</span>\n </div>\n </div>\n\n <div class=\"metric-card\">\n <div class=\"metric-icon metric-icon-storage\">\n <i class=\"fa-solid fa-database\"></i>\n </div>\n <div class=\"metric-content\">\n <span class=\"metric-value\">{{ FormatBytes(Metrics.TotalStorageBytes) }}</span>\n <span class=\"metric-label\">Storage Used</span>\n </div>\n </div>\n\n <div class=\"metric-card\">\n <div class=\"metric-icon metric-icon-time\">\n <i class=\"fa-solid fa-clock\"></i>\n </div>\n <div class=\"metric-content\">\n <span class=\"metric-value\">{{ FormatDate(Metrics.LastRunDate) }}</span>\n <span class=\"metric-label\">Last Run</span>\n </div>\n </div>\n </div>\n\n <!-- Run list -->\n <div class=\"run-list\">\n <h3 class=\"run-list-title\">Run History</h3>\n\n @if (Runs.length === 0) {\n <mj-empty-state class=\"run-empty\" Size=\"compact\"\n Icon=\"fa-solid fa-inbox\"\n Title=\"No archive runs found.\" />\n }\n\n @for (run of Runs; track run.ID) {\n <div\n class=\"run-card\"\n (click)=\"OpenRunDrawer(run)\"\n (keydown.enter)=\"OpenRunDrawer(run)\"\n tabindex=\"0\"\n role=\"button\"\n [attr.aria-label]=\"'View details for run on ' + FormatDate(run.StartedAt)\">\n <div class=\"run-card-header\">\n <span class=\"run-card-name\">{{ run.ConfigurationName }}</span>\n <span class=\"status-badge\" [ngClass]=\"GetStatusClass(run.Status)\">{{ run.Status }}</span>\n </div>\n <div class=\"run-card-date\">\n <i class=\"fa-solid fa-calendar\"></i>\n {{ FormatDate(run.StartedAt) }}\n </div>\n <div class=\"run-card-stats\">\n <span class=\"run-stat\">\n <i class=\"fa-solid fa-box-archive\"></i>\n {{ run.RecordsArchived }} archived\n </span>\n @if (run.RecordsFailed > 0) {\n <span class=\"run-stat run-stat-error\">\n <i class=\"fa-solid fa-circle-xmark\"></i>\n {{ run.RecordsFailed }} failed\n </span>\n }\n @if (run.RecordsSkipped > 0) {\n <span class=\"run-stat run-stat-muted\">\n <i class=\"fa-solid fa-forward\"></i>\n {{ run.RecordsSkipped }} skipped\n </span>\n }\n <span class=\"run-stat\">\n <i class=\"fa-solid fa-stopwatch\"></i>\n {{ FormatDuration(run.DurationSeconds) }}\n </span>\n <span class=\"run-stat\">\n <i class=\"fa-solid fa-hard-drive\"></i>\n {{ FormatBytes(run.TotalBytes) }}\n </span>\n </div>\n </div>\n }\n </div>\n }\n\n <!-- Drawer backdrop -->\n @if (DrawerOpen) {\n <div class=\"archive-drawer-backdrop\" (click)=\"CloseDrawer()\"></div>\n }\n\n <!-- Slide-in drawer -->\n <div class=\"archive-drawer\" [class.open]=\"DrawerOpen\">\n @if (SelectedRun) {\n <!-- Drawer header -->\n <div class=\"drawer-header\">\n <h3>Run Details</h3>\n <button class=\"drawer-close-btn\" (click)=\"CloseDrawer()\" aria-label=\"Close drawer\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n\n <!-- Run summary -->\n <div class=\"drawer-summary\">\n <div class=\"drawer-summary-row\">\n <span class=\"drawer-label\">Configuration</span>\n <span class=\"drawer-value\">{{ SelectedRun.ConfigurationName }}</span>\n </div>\n <div class=\"drawer-summary-row\">\n <span class=\"drawer-label\">Status</span>\n <span class=\"status-badge\" [ngClass]=\"GetStatusClass(SelectedRun.Status)\">{{ SelectedRun.Status }}</span>\n </div>\n <div class=\"drawer-summary-row\">\n <span class=\"drawer-label\">Started</span>\n <span class=\"drawer-value\">{{ FormatDate(SelectedRun.StartedAt) }}</span>\n </div>\n <div class=\"drawer-summary-row\">\n <span class=\"drawer-label\">Duration</span>\n <span class=\"drawer-value\">{{ FormatDuration(SelectedRun.DurationSeconds) }}</span>\n </div>\n </div>\n\n <!-- Stats row -->\n <div class=\"drawer-stats\">\n <div class=\"drawer-stat\">\n <span class=\"drawer-stat-value\">{{ SelectedRun.RecordsArchived }}</span>\n <span class=\"drawer-stat-label\">Archived</span>\n </div>\n <div class=\"drawer-stat drawer-stat-error\">\n <span class=\"drawer-stat-value\">{{ SelectedRun.RecordsFailed }}</span>\n <span class=\"drawer-stat-label\">Failed</span>\n </div>\n <div class=\"drawer-stat drawer-stat-muted\">\n <span class=\"drawer-stat-value\">{{ SelectedRun.RecordsSkipped }}</span>\n <span class=\"drawer-stat-label\">Skipped</span>\n </div>\n </div>\n\n <!-- Detail table -->\n <div class=\"drawer-details\">\n <h4>Per-Record Results</h4>\n\n @if (IsDrawerLoading) {\n <mj-loading text=\"Loading details...\" size=\"small\"></mj-loading>\n }\n\n @if (!IsDrawerLoading && RunDetails.length === 0) {\n <mj-empty-state class=\"drawer-details-empty\" Size=\"compact\" Icon=\"\" Title=\"No detail records found.\" />\n }\n\n @if (!IsDrawerLoading && RunDetails.length > 0) {\n <div class=\"drawer-table-wrapper\">\n <table class=\"drawer-table\">\n <thead>\n <tr>\n <th>Entity</th>\n <th>Record ID</th>\n <th>Status</th>\n <th>Bytes</th>\n </tr>\n </thead>\n <tbody>\n @for (detail of RunDetails; track detail.ID) {\n <tr>\n <td class=\"cell-entity\">{{ detail.EntityName }}</td>\n <td class=\"cell-id\" [title]=\"detail.RecordID\">{{ detail.RecordID }}</td>\n <td>\n <span class=\"status-badge status-badge-sm\" [ngClass]=\"GetStatusClass(detail.Status)\">\n {{ detail.Status }}\n </span>\n </td>\n <td class=\"cell-bytes\">{{ FormatBytes(detail.Bytes) }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </div>\n }\n </div>\n</div>\n"]}
@@ -1,4 +1,5 @@
1
1
  import { EventEmitter, OnDestroy } from '@angular/core';
2
+ import { BaseAngularComponent } from '@memberjunction/ng-base-types';
2
3
  import * as i0 from "@angular/core";
3
4
  /**
4
5
  * Summary information about an archived version of a record.
@@ -17,7 +18,7 @@ export interface ArchiveVersionInfo {
17
18
  /** Size of the archived data in bytes */
18
19
  Bytes: number;
19
20
  }
20
- export declare class ArchiveStatusBadgeComponent implements OnDestroy {
21
+ export declare class ArchiveStatusBadgeComponent extends BaseAngularComponent implements OnDestroy {
21
22
  private cdr;
22
23
  /** Whether the badge is visible (record has archived fields) */
23
24
  HasArchivedFields: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"archive-status-badge.component.d.ts","sourceRoot":"","sources":["../../../src/lib/archive-status/archive-status-badge.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,YAAY,EACZ,SAAS,EAEV,MAAM,eAAe,CAAC;;AAGvB;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,uCAAuC;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,yCAAyC;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,yCAAyC;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,0CAA0C;IAC1C,UAAU,EAAE,MAAM,CAAC;IACnB,qCAAqC;IACrC,UAAU,EAAE,IAAI,CAAC;IACjB,yCAAyC;IACzC,KAAK,EAAE,MAAM,CAAC;CACf;AAED,qBAOa,2BAA4B,YAAW,SAAS;IAC3D,OAAO,CAAC,GAAG,CAA6B;IAExC,gEAAgE;IAChE,iBAAiB,UAAS;IAE1B,gCAAgC;IAChC,kBAAkB,SAAK;IAEvB,sCAAsC;IACtC,gBAAgB,EAAE,IAAI,GAAG,IAAI,CAAQ;IAErC,wCAAwC;IACxC,SAAS,UAAS;IAElB,kCAAkC;IAClC,WAAW,SAAM;IAEjB,qDAAqD;IACrD,OAAO,CAAC,aAAa,CAAmC;IAExD,sDAAsD;IACtD,OAAO,CAAC,SAAS,CAAS;IAG1B,OAAO,CAAC,WAAW,CAAM;IAEzB,IACI,UAAU,CAAC,KAAK,EAAE,MAAM,EAM3B;IACD,IAAI,UAAU,IAAI,MAAM,CAEvB;IAGD,OAAO,CAAC,SAAS,CAAM;IAEvB,IACI,QAAQ,CAAC,KAAK,EAAE,MAAM,EAMzB;IACD,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,kEAAkE;IACxD,gBAAgB,mCAA0C;IAEpE,WAAW,IAAI,IAAI;IAInB,gEAAgE;IAChE,YAAY,IAAI,IAAI;IAMpB;;;OAGG;YACW,iBAAiB;IAqB/B,uDAAuD;YACzC,mBAAmB;IAcjC,2DAA2D;IAC3D,OAAO,CAAC,qBAAqB;IAc7B,gDAAgD;IAChD,OAAO,CAAC,gBAAgB;IAQxB,uDAAuD;IACvD,OAAO,CAAC,gBAAgB;IAWxB,0CAA0C;IAC1C,OAAO,CAAC,UAAU;yCAjJP,2BAA2B;2CAA3B,2BAA2B;CAwJvC"}
1
+ {"version":3,"file":"archive-status-badge.component.d.ts","sourceRoot":"","sources":["../../../src/lib/archive-status/archive-status-badge.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,YAAY,EACZ,SAAS,EAEV,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;;AAErE;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,uCAAuC;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,yCAAyC;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,yCAAyC;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,0CAA0C;IAC1C,UAAU,EAAE,MAAM,CAAC;IACnB,qCAAqC;IACrC,UAAU,EAAE,IAAI,CAAC;IACjB,yCAAyC;IACzC,KAAK,EAAE,MAAM,CAAC;CACf;AAED,qBAOa,2BAA4B,SAAQ,oBAAqB,YAAW,SAAS;IACxF,OAAO,CAAC,GAAG,CAA6B;IAExC,gEAAgE;IAChE,iBAAiB,UAAS;IAE1B,gCAAgC;IAChC,kBAAkB,SAAK;IAEvB,sCAAsC;IACtC,gBAAgB,EAAE,IAAI,GAAG,IAAI,CAAQ;IAErC,wCAAwC;IACxC,SAAS,UAAS;IAElB,kCAAkC;IAClC,WAAW,SAAM;IAEjB,qDAAqD;IACrD,OAAO,CAAC,aAAa,CAAmC;IAExD,sDAAsD;IACtD,OAAO,CAAC,SAAS,CAAS;IAG1B,OAAO,CAAC,WAAW,CAAM;IAEzB,IACI,UAAU,CAAC,KAAK,EAAE,MAAM,EAM3B;IACD,IAAI,UAAU,IAAI,MAAM,CAEvB;IAGD,OAAO,CAAC,SAAS,CAAM;IAEvB,IACI,QAAQ,CAAC,KAAK,EAAE,MAAM,EAMzB;IACD,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,kEAAkE;IACxD,gBAAgB,mCAA0C;IAEpE,WAAW,IAAI,IAAI;IAInB,gEAAgE;IAChE,YAAY,IAAI,IAAI;IAMpB;;;OAGG;YACW,iBAAiB;IAqB/B,uDAAuD;YACzC,mBAAmB;IAcjC,2DAA2D;IAC3D,OAAO,CAAC,qBAAqB;IAc7B,gDAAgD;IAChD,OAAO,CAAC,gBAAgB;IAQxB,uDAAuD;IACvD,OAAO,CAAC,gBAAgB;IAWxB,0CAA0C;IAC1C,OAAO,CAAC,UAAU;yCAjJP,2BAA2B;2CAA3B,2BAA2B;CAwJvC"}
@@ -1,5 +1,6 @@
1
1
  import { Component, ChangeDetectionStrategy, ChangeDetectorRef, Input, Output, EventEmitter, inject, } from '@angular/core';
2
2
  import { RunView } from '@memberjunction/core';
3
+ import { BaseAngularComponent } from '@memberjunction/ng-base-types';
3
4
  import * as i0 from "@angular/core";
4
5
  import * as i1 from "@memberjunction/ng-shared-generic";
5
6
  function ArchiveStatusBadgeComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
@@ -20,7 +21,7 @@ function ArchiveStatusBadgeComponent_Conditional_1_Template(rf, ctx) { if (rf &
20
21
  } if (rf & 2) {
21
22
  i0.ɵɵproperty("showText", false);
22
23
  } }
23
- export class ArchiveStatusBadgeComponent {
24
+ export class ArchiveStatusBadgeComponent extends BaseAngularComponent {
24
25
  cdr = inject(ChangeDetectorRef);
25
26
  /** Whether the badge is visible (record has archived fields) */
26
27
  HasArchivedFields = false;
@@ -97,7 +98,7 @@ export class ArchiveStatusBadgeComponent {
97
98
  }
98
99
  /** Fetch archive run detail records from the server */
99
100
  async fetchArchiveDetails() {
100
- const rv = new RunView();
101
+ const rv = RunView.FromMetadataProvider(this.ProviderToUse);
101
102
  const escapedEntity = this._entityName.replace(/'/g, "''");
102
103
  const escapedRecord = this._recordID.replace(/'/g, "''");
103
104
  return rv.RunView({
@@ -148,8 +149,8 @@ export class ArchiveStatusBadgeComponent {
148
149
  this.TooltipText = '';
149
150
  this.latestVersion = null;
150
151
  }
151
- static ɵfac = function ArchiveStatusBadgeComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ArchiveStatusBadgeComponent)(); };
152
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ArchiveStatusBadgeComponent, selectors: [["mj-archive-status-badge"]], inputs: { EntityName: "EntityName", RecordID: "RecordID" }, outputs: { RestoreRequested: "RestoreRequested" }, standalone: false, decls: 2, vars: 2, consts: [["tabindex", "0", "role", "button", 1, "badge", "badge-warning", "badge-pill", "badge-icon", "badge-clickable", 3, "title"], ["size", "small", 3, "showText"], ["tabindex", "0", "role", "button", 1, "badge", "badge-warning", "badge-pill", "badge-icon", "badge-clickable", 3, "click", "keydown.enter", "title"], [1, "fa-solid", "fa-box-archive"], [1, "badge-text"]], template: function ArchiveStatusBadgeComponent_Template(rf, ctx) { if (rf & 1) {
152
+ static ɵfac = /*@__PURE__*/ (() => { let ɵArchiveStatusBadgeComponent_BaseFactory; return function ArchiveStatusBadgeComponent_Factory(__ngFactoryType__) { return (ɵArchiveStatusBadgeComponent_BaseFactory || (ɵArchiveStatusBadgeComponent_BaseFactory = i0.ɵɵgetInheritedFactory(ArchiveStatusBadgeComponent)))(__ngFactoryType__ || ArchiveStatusBadgeComponent); }; })();
153
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ArchiveStatusBadgeComponent, selectors: [["mj-archive-status-badge"]], inputs: { EntityName: "EntityName", RecordID: "RecordID" }, outputs: { RestoreRequested: "RestoreRequested" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 2, vars: 2, consts: [["tabindex", "0", "role", "button", 1, "badge", "badge-warning", "badge-pill", "badge-icon", "badge-clickable", 3, "title"], ["size", "small", 3, "showText"], ["tabindex", "0", "role", "button", 1, "badge", "badge-warning", "badge-pill", "badge-icon", "badge-clickable", 3, "click", "keydown.enter", "title"], [1, "fa-solid", "fa-box-archive"], [1, "badge-text"]], template: function ArchiveStatusBadgeComponent_Template(rf, ctx) { if (rf & 1) {
153
154
  i0.ɵɵconditionalCreate(0, ArchiveStatusBadgeComponent_Conditional_0_Template, 4, 2, "span", 0);
154
155
  i0.ɵɵconditionalCreate(1, ArchiveStatusBadgeComponent_Conditional_1_Template, 1, 1, "mj-loading", 1);
155
156
  } if (rf & 2) {
@@ -168,5 +169,5 @@ export class ArchiveStatusBadgeComponent {
168
169
  }], RestoreRequested: [{
169
170
  type: Output
170
171
  }] }); })();
171
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ArchiveStatusBadgeComponent, { className: "ArchiveStatusBadgeComponent", filePath: "src/lib/archive-status/archive-status-badge.component.ts", lineNumber: 38 }); })();
172
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ArchiveStatusBadgeComponent, { className: "ArchiveStatusBadgeComponent", filePath: "src/lib/archive-status/archive-status-badge.component.ts", lineNumber: 39 }); })();
172
173
  //# sourceMappingURL=archive-status-badge.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"archive-status-badge.component.js","sourceRoot":"","sources":["../../../src/lib/archive-status/archive-status-badge.component.ts","../../../src/lib/archive-status/archive-status-badge.component.html"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,uBAAuB,EACvB,iBAAiB,EACjB,KAAK,EACL,MAAM,EACN,YAAY,EAEZ,MAAM,GACP,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;;;;;ICT7C,+BAOiD;IAH/C,AADA,6LAAS,qBAAc,KAAC,gMACP,qBAAc,KAAC;IAIhC,uBAAuC;IACvC,+BAAyB;IAAA,wBAAQ;IACnC,AADmC,iBAAO,EACnC;;;IARL,0CAAqB;;;;IAYvB,gCAAyD;;IAA7C,gCAAkB;;ADsBhC,MAAM,OAAO,2BAA2B;IAC9B,GAAG,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAC;IAExC,gEAAgE;IAChE,iBAAiB,GAAG,KAAK,CAAC;IAE1B,gCAAgC;IAChC,kBAAkB,GAAG,CAAC,CAAC;IAEvB,sCAAsC;IACtC,gBAAgB,GAAgB,IAAI,CAAC;IAErC,wCAAwC;IACxC,SAAS,GAAG,KAAK,CAAC;IAElB,kCAAkC;IAClC,WAAW,GAAG,EAAE,CAAC;IAEjB,qDAAqD;IAC7C,aAAa,GAA8B,IAAI,CAAC;IAExD,sDAAsD;IAC9C,SAAS,GAAG,KAAK,CAAC;IAE1B,8CAA8C;IACtC,WAAW,GAAG,EAAE,CAAC;IAEzB,IACI,UAAU,CAAC,KAAa;QAC1B,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC;QAClC,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QACzB,IAAI,KAAK,IAAI,KAAK,KAAK,QAAQ,EAAE,CAAC;YAChC,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC3B,CAAC;IACH,CAAC;IACD,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;IAED,4CAA4C;IACpC,SAAS,GAAG,EAAE,CAAC;IAEvB,IACI,QAAQ,CAAC,KAAa;QACxB,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC;QAChC,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;QACvB,IAAI,KAAK,IAAI,KAAK,KAAK,QAAQ,EAAE,CAAC;YAChC,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC3B,CAAC;IACH,CAAC;IACD,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED,kEAAkE;IACxD,gBAAgB,GAAG,IAAI,YAAY,EAAsB,CAAC;IAEpE,WAAW;QACT,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;IACxB,CAAC;IAED,gEAAgE;IAChE,YAAY;QACV,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACvB,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,iBAAiB;QAC7B,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YACzC,OAAO;QACT,CAAC;QAED,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;QAExB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,mBAAmB,EAAE,CAAC;YAChD,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC,CAAC;QACrC,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC,UAAU,EAAE,CAAC;QACpB,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;YACvB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;gBACpB,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;YAC1B,CAAC;QACH,CAAC;IACH,CAAC;IAED,uDAAuD;IAC/C,KAAK,CAAC,mBAAmB;QAC/B,MAAM,EAAE,GAAG,IAAI,OAAO,EAAE,CAAC;QACzB,MAAM,aAAa,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC3D,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAEzD,OAAO,EAAE,CAAC,OAAO,CAAsB;YACrC,UAAU,EAAE,yBAAyB;YACrC,WAAW,EAAE,WAAW,aAAa,mBAAmB,aAAa,wBAAwB;YAC7F,OAAO,EAAE,qBAAqB;YAC9B,UAAU,EAAE,QAAQ;YACpB,MAAM,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,eAAe,EAAE,gBAAgB,CAAC;SACxE,CAAC,CAAC;IACL,CAAC;IAED,2DAA2D;IACnD,qBAAqB,CAAC,MAA4D;QACxF,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACnD,IAAI,CAAC,UAAU,EAAE,CAAC;YAClB,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACjC,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC;QAC9B,IAAI,CAAC,kBAAkB,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;QAChD,IAAI,CAAC,gBAAgB,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACvF,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAC3C,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACrD,CAAC;IAED,gDAAgD;IACxC,gBAAgB;QACtB,MAAM,SAAS,GAAG,GAAG,IAAI,CAAC,kBAAkB,SAAS,IAAI,CAAC,kBAAkB,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC;QACzG,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC1B,OAAO,GAAG,SAAS,OAAO,IAAI,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,EAAE,CAAC;QACzE,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,uDAAuD;IAC/C,gBAAgB,CAAC,MAA2B;QAClD,OAAO;YACL,QAAQ,EAAE,MAAM,CAAC,EAAE;YACnB,UAAU,EAAE,IAAI,CAAC,WAAW;YAC5B,QAAQ,EAAE,IAAI,CAAC,SAAS;YACxB,UAAU,EAAE,CAAC;YACb,UAAU,EAAE,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE;YAChF,KAAK,EAAE,MAAM,CAAC,aAAa,IAAI,CAAC;SACjC,CAAC;IACJ,CAAC;IAED,0CAA0C;IAClC,UAAU;QAChB,IAAI,CAAC,iBAAiB,GAAG,KAAK,CAAC;QAC/B,IAAI,CAAC,kBAAkB,GAAG,CAAC,CAAC;QAC5B,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAC7B,IAAI,CAAC,WAAW,GAAG,EAAE,CAAC;QACtB,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;IAC5B,CAAC;qHAvJU,2BAA2B;6DAA3B,2BAA2B;YCrCxC,8FAAyB;YAczB,oGAAiB;;YAdjB,gDAYC;YAED,cAEC;YAFD,wCAEC;;;iFDqBY,2BAA2B;cAPvC,SAAS;6BACI,KAAK,YACP,yBAAyB,mBAGlB,uBAAuB,CAAC,MAAM;;kBA6B9C,KAAK;;kBAeL,KAAK;;kBAaL,MAAM;;kFAvDI,2BAA2B","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';\n\n/**\n * Summary information about an archived version of a record.\n */\nexport interface ArchiveVersionInfo {\n /** The archive run detail record ID */\n DetailID: string;\n /** Entity name of the archived record */\n EntityName: string;\n /** Primary key of the archived record */\n RecordID: string;\n /** Number of fields that were archived */\n FieldCount: number;\n /** Date the archive was performed */\n ArchivedAt: Date;\n /** Size of the archived data in bytes */\n Bytes: number;\n}\n\n@Component({\n standalone: false,\n selector: 'mj-archive-status-badge',\n templateUrl: './archive-status-badge.component.html',\n styleUrls: ['./archive-status-badge.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ArchiveStatusBadgeComponent implements OnDestroy {\n private cdr = inject(ChangeDetectorRef);\n\n /** Whether the badge is visible (record has archived fields) */\n HasArchivedFields = false;\n\n /** Number of archived fields */\n ArchivedFieldCount = 0;\n\n /** Date of the most recent archive */\n LastArchivedDate: Date | null = null;\n\n /** Whether data is currently loading */\n IsLoading = false;\n\n /** Tooltip text shown on hover */\n TooltipText = '';\n\n /** Latest archive version info for event emission */\n private latestVersion: ArchiveVersionInfo | null = null;\n\n /** Tracks whether the component has been destroyed */\n private destroyed = false;\n\n // --- EntityName input with getter/setter ---\n private _entityName = '';\n\n @Input()\n set EntityName(value: string) {\n const previous = this._entityName;\n this._entityName = value;\n if (value && value !== previous) {\n this.loadArchiveStatus();\n }\n }\n get EntityName(): string {\n return this._entityName;\n }\n\n // --- RecordID input with getter/setter ---\n private _recordID = '';\n\n @Input()\n set RecordID(value: string) {\n const previous = this._recordID;\n this._recordID = value;\n if (value && value !== previous) {\n this.loadArchiveStatus();\n }\n }\n get RecordID(): string {\n return this._recordID;\n }\n\n /** Emitted when the user clicks the badge to request a restore */\n @Output() RestoreRequested = new EventEmitter<ArchiveVersionInfo>();\n\n ngOnDestroy(): void {\n this.destroyed = true;\n }\n\n /** Handle badge click — emit the latest archive version info */\n OnBadgeClick(): void {\n if (this.latestVersion) {\n this.RestoreRequested.emit(this.latestVersion);\n }\n }\n\n /**\n * Load archive status for the current entity/record combination.\n * Queries MJ: Archive Run Details for successful archives.\n */\n private async loadArchiveStatus(): Promise<void> {\n if (!this._entityName || !this._recordID) {\n return;\n }\n\n this.IsLoading = true;\n this.cdr.markForCheck();\n\n try {\n const result = await this.fetchArchiveDetails();\n this.processArchiveResults(result);\n } catch {\n this.resetState();\n } finally {\n this.IsLoading = false;\n if (!this.destroyed) {\n this.cdr.markForCheck();\n }\n }\n }\n\n /** Fetch archive run detail records from the server */\n private async fetchArchiveDetails(): Promise<{ Success: boolean; Results: ArchiveDetailRecord[] }> {\n const rv = new RunView();\n const escapedEntity = this._entityName.replace(/'/g, \"''\");\n const escapedRecord = this._recordID.replace(/'/g, \"''\");\n\n return rv.RunView<ArchiveDetailRecord>({\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', 'Entity', 'RecordID', 'BytesArchived', '__mj_CreatedAt'],\n });\n }\n\n /** Process the query results and update component state */\n private processArchiveResults(result: { Success: boolean; Results: ArchiveDetailRecord[] }): void {\n if (!result.Success || result.Results.length === 0) {\n this.resetState();\n return;\n }\n\n const latest = result.Results[0];\n this.HasArchivedFields = true;\n this.ArchivedFieldCount = result.Results.length;\n this.LastArchivedDate = latest.__mj_CreatedAt ? new Date(latest.__mj_CreatedAt) : null;\n this.TooltipText = this.buildTooltipText();\n this.latestVersion = this.buildVersionInfo(latest);\n }\n\n /** Build the tooltip text from current state */\n private buildTooltipText(): string {\n const countText = `${this.ArchivedFieldCount} field${this.ArchivedFieldCount !== 1 ? 's' : ''} archived`;\n if (this.LastArchivedDate) {\n return `${countText} on ${this.LastArchivedDate.toLocaleDateString()}`;\n }\n return countText;\n }\n\n /** Build an ArchiveVersionInfo from a detail record */\n private buildVersionInfo(record: ArchiveDetailRecord): ArchiveVersionInfo {\n return {\n DetailID: record.ID,\n EntityName: this._entityName,\n RecordID: this._recordID,\n FieldCount: 0,\n ArchivedAt: record.__mj_CreatedAt ? new Date(record.__mj_CreatedAt) : new Date(),\n Bytes: record.BytesArchived ?? 0,\n };\n }\n\n /** Reset all display state to defaults */\n private resetState(): void {\n this.HasArchivedFields = false;\n this.ArchivedFieldCount = 0;\n this.LastArchivedDate = null;\n this.TooltipText = '';\n this.latestVersion = null;\n }\n}\n\n/** Shape of the simple result from the archive run details query */\ninterface ArchiveDetailRecord {\n ID: string;\n Entity: string;\n RecordID: string;\n BytesArchived: number;\n __mj_CreatedAt: string;\n}\n","@if (HasArchivedFields) {\n <span\n class=\"badge badge-warning badge-pill badge-icon badge-clickable\"\n [title]=\"TooltipText\"\n (click)=\"OnBadgeClick()\"\n (keydown.enter)=\"OnBadgeClick()\"\n tabindex=\"0\"\n role=\"button\"\n [attr.aria-label]=\"'Archived: ' + TooltipText\">\n <i class=\"fa-solid fa-box-archive\"></i>\n <span class=\"badge-text\">Archived</span>\n </span>\n}\n\n@if (IsLoading) {\n <mj-loading [showText]=\"false\" size=\"small\"></mj-loading>\n}\n"]}
1
+ {"version":3,"file":"archive-status-badge.component.js","sourceRoot":"","sources":["../../../src/lib/archive-status/archive-status-badge.component.ts","../../../src/lib/archive-status/archive-status-badge.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 { BaseAngularComponent } from '@memberjunction/ng-base-types';\n\n/**\n * Summary information about an archived version of a record.\n */\nexport interface ArchiveVersionInfo {\n /** The archive run detail record ID */\n DetailID: string;\n /** Entity name of the archived record */\n EntityName: string;\n /** Primary key of the archived record */\n RecordID: string;\n /** Number of fields that were archived */\n FieldCount: number;\n /** Date the archive was performed */\n ArchivedAt: Date;\n /** Size of the archived data in bytes */\n Bytes: number;\n}\n\n@Component({\n standalone: false,\n selector: 'mj-archive-status-badge',\n templateUrl: './archive-status-badge.component.html',\n styleUrls: ['./archive-status-badge.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ArchiveStatusBadgeComponent extends BaseAngularComponent implements OnDestroy {\n private cdr = inject(ChangeDetectorRef);\n\n /** Whether the badge is visible (record has archived fields) */\n HasArchivedFields = false;\n\n /** Number of archived fields */\n ArchivedFieldCount = 0;\n\n /** Date of the most recent archive */\n LastArchivedDate: Date | null = null;\n\n /** Whether data is currently loading */\n IsLoading = false;\n\n /** Tooltip text shown on hover */\n TooltipText = '';\n\n /** Latest archive version info for event emission */\n private latestVersion: ArchiveVersionInfo | null = null;\n\n /** Tracks whether the component has been destroyed */\n private destroyed = false;\n\n // --- EntityName input with getter/setter ---\n private _entityName = '';\n\n @Input()\n set EntityName(value: string) {\n const previous = this._entityName;\n this._entityName = value;\n if (value && value !== previous) {\n this.loadArchiveStatus();\n }\n }\n get EntityName(): string {\n return this._entityName;\n }\n\n // --- RecordID input with getter/setter ---\n private _recordID = '';\n\n @Input()\n set RecordID(value: string) {\n const previous = this._recordID;\n this._recordID = value;\n if (value && value !== previous) {\n this.loadArchiveStatus();\n }\n }\n get RecordID(): string {\n return this._recordID;\n }\n\n /** Emitted when the user clicks the badge to request a restore */\n @Output() RestoreRequested = new EventEmitter<ArchiveVersionInfo>();\n\n ngOnDestroy(): void {\n this.destroyed = true;\n }\n\n /** Handle badge click — emit the latest archive version info */\n OnBadgeClick(): void {\n if (this.latestVersion) {\n this.RestoreRequested.emit(this.latestVersion);\n }\n }\n\n /**\n * Load archive status for the current entity/record combination.\n * Queries MJ: Archive Run Details for successful archives.\n */\n private async loadArchiveStatus(): Promise<void> {\n if (!this._entityName || !this._recordID) {\n return;\n }\n\n this.IsLoading = true;\n this.cdr.markForCheck();\n\n try {\n const result = await this.fetchArchiveDetails();\n this.processArchiveResults(result);\n } catch {\n this.resetState();\n } finally {\n this.IsLoading = false;\n if (!this.destroyed) {\n this.cdr.markForCheck();\n }\n }\n }\n\n /** Fetch archive run detail records from the server */\n private async fetchArchiveDetails(): Promise<{ Success: boolean; Results: ArchiveDetailRecord[] }> {\n const rv = RunView.FromMetadataProvider(this.ProviderToUse);\n const escapedEntity = this._entityName.replace(/'/g, \"''\");\n const escapedRecord = this._recordID.replace(/'/g, \"''\");\n\n return rv.RunView<ArchiveDetailRecord>({\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', 'Entity', 'RecordID', 'BytesArchived', '__mj_CreatedAt'],\n });\n }\n\n /** Process the query results and update component state */\n private processArchiveResults(result: { Success: boolean; Results: ArchiveDetailRecord[] }): void {\n if (!result.Success || result.Results.length === 0) {\n this.resetState();\n return;\n }\n\n const latest = result.Results[0];\n this.HasArchivedFields = true;\n this.ArchivedFieldCount = result.Results.length;\n this.LastArchivedDate = latest.__mj_CreatedAt ? new Date(latest.__mj_CreatedAt) : null;\n this.TooltipText = this.buildTooltipText();\n this.latestVersion = this.buildVersionInfo(latest);\n }\n\n /** Build the tooltip text from current state */\n private buildTooltipText(): string {\n const countText = `${this.ArchivedFieldCount} field${this.ArchivedFieldCount !== 1 ? 's' : ''} archived`;\n if (this.LastArchivedDate) {\n return `${countText} on ${this.LastArchivedDate.toLocaleDateString()}`;\n }\n return countText;\n }\n\n /** Build an ArchiveVersionInfo from a detail record */\n private buildVersionInfo(record: ArchiveDetailRecord): ArchiveVersionInfo {\n return {\n DetailID: record.ID,\n EntityName: this._entityName,\n RecordID: this._recordID,\n FieldCount: 0,\n ArchivedAt: record.__mj_CreatedAt ? new Date(record.__mj_CreatedAt) : new Date(),\n Bytes: record.BytesArchived ?? 0,\n };\n }\n\n /** Reset all display state to defaults */\n private resetState(): void {\n this.HasArchivedFields = false;\n this.ArchivedFieldCount = 0;\n this.LastArchivedDate = null;\n this.TooltipText = '';\n this.latestVersion = null;\n }\n}\n\n/** Shape of the simple result from the archive run details query */\ninterface ArchiveDetailRecord {\n ID: string;\n Entity: string;\n RecordID: string;\n BytesArchived: number;\n __mj_CreatedAt: string;\n}\n","@if (HasArchivedFields) {\n <span\n class=\"badge badge-warning badge-pill badge-icon badge-clickable\"\n [title]=\"TooltipText\"\n (click)=\"OnBadgeClick()\"\n (keydown.enter)=\"OnBadgeClick()\"\n tabindex=\"0\"\n role=\"button\"\n [attr.aria-label]=\"'Archived: ' + TooltipText\">\n <i class=\"fa-solid fa-box-archive\"></i>\n <span class=\"badge-text\">Archived</span>\n </span>\n}\n\n@if (IsLoading) {\n <mj-loading [showText]=\"false\" size=\"small\"></mj-loading>\n}\n"]}
package/package.json CHANGED
@@ -1,18 +1,12 @@
1
1
  {
2
2
  "name": "@memberjunction/ng-archive-manager",
3
- "version": "5.51.0",
3
+ "version": "6.1.0-edge.0",
4
4
  "description": "MemberJunction: Angular Archive Manager - UI components for managing entity field archiving, restoration, and configuration.",
5
5
  "main": "./dist/public-api.js",
6
6
  "typings": "./dist/public-api.d.ts",
7
7
  "files": [
8
8
  "/dist"
9
9
  ],
10
- "scripts": {
11
- "test": "vitest run",
12
- "build": "npm run clean && ngc",
13
- "clean": "rimraf dist",
14
- "test:watch": "vitest"
15
- },
16
10
  "keywords": [
17
11
  "MemberJunction",
18
12
  "Angular",
@@ -23,7 +17,7 @@
23
17
  "devDependencies": {
24
18
  "@angular/compiler": "21.1.3",
25
19
  "@angular/compiler-cli": "21.1.3",
26
- "@memberjunction/ng-test-utils": "5.51.0",
20
+ "@memberjunction/ng-test-utils": "6.1.0-edge.0",
27
21
  "vitest": "^4.0.18"
28
22
  },
29
23
  "peerDependencies": {
@@ -33,17 +27,25 @@
33
27
  "rxjs": "^7.8.2"
34
28
  },
35
29
  "dependencies": {
36
- "@memberjunction/ng-ui-components": "5.51.0",
37
- "@memberjunction/core": "5.51.0",
38
- "@memberjunction/ng-base-types": "5.51.0",
39
- "@memberjunction/core-entities": "5.51.0",
40
- "@memberjunction/global": "5.51.0",
41
- "@memberjunction/ng-shared-generic": "5.51.0",
30
+ "@memberjunction/ng-ui-components": "6.1.0-edge.0",
31
+ "@memberjunction/core": "6.1.0-edge.0",
32
+ "@memberjunction/ng-base-types": "6.1.0-edge.0",
33
+ "@memberjunction/core-entities": "6.1.0-edge.0",
34
+ "@memberjunction/global": "6.1.0-edge.0",
35
+ "@memberjunction/ng-shared-generic": "6.1.0-edge.0",
42
36
  "tslib": "^2.8.1"
43
37
  },
44
38
  "sideEffects": false,
45
39
  "repository": {
46
40
  "type": "git",
47
41
  "url": "https://github.com/MemberJunction/MJ"
42
+ },
43
+ "mjUILayer": "widgets",
44
+ "scripts": {
45
+ "test": "vitest run",
46
+ "test:types": "tsc --noEmit -p tsconfig.spec.json",
47
+ "build": "npm run clean && ngc",
48
+ "clean": "rimraf dist",
49
+ "test:watch": "vitest"
48
50
  }
49
- }
51
+ }