import { ChangeDetectorRef, EventEmitter, OnInit } from '@angular/core';
import { BaseEntity } from '@memberjunction/core';
import { MJRecordChangeEntity } from '@memberjunction/core-entities';
import { BaseAngularComponent } from '@memberjunction/ng-base-types';
import * as i0 from "@angular/core";
/**
* Mode controls how the preview is rendered and how the restore is interpreted.
*
* - `'live'`: target record exists; the preview shows a current-vs-restore
* diff per field. Confirming applies the snapshot to the live record and
* triggers an UPDATE.
* - `'undelete'`: target record was hard-deleted. The preview shows the
* snapshot fields that will be inserted; confirming triggers an INSERT.
*/
export type RestorePreviewMode = 'live' | 'undelete';
/**
* One row in the restore preview table.
*
* Renders as a checkbox + field name + (current / restore) values. The
* `IsChanged` flag drives the default-checked state and the row's visual
* treatment. `IsMissingInSchema` and `IsFKMissing` surface drift warnings.
*/
export interface RestoreFieldRow {
/** Raw field name (matches EntityField.Name). */
FieldName: string;
/** Friendly label (EntityField.DisplayNameOrName). */
DisplayName: string;
/** Formatted current value of the live record (empty in undelete mode). */
CurrentValue: string;
/** Formatted snapshot value that would be applied. */
RestoreValue: string;
/** Raw snapshot value (the value passed to BaseEntity.Set). */
RawRestoreValue: unknown;
/** True when CurrentValue and RestoreValue differ. Drives default checked. */
IsChanged: boolean;
/** User's selection — when true, this field will be applied on restore. */
Selected: boolean;
/** True when the snapshot references a field that no longer exists on the entity. */
IsMissingInSchema: boolean;
/** True when the field is a FK whose target row no longer exists (best-effort). */
IsFKMissing: boolean;
/** True when the field is read-only / system / PK and cannot be restored. */
IsImmutable: boolean;
}
/**
* Cancelable event fired immediately after the user clicks Restore but
* before {@link RestorePreviewPanelComponent.RestoreConfirmed} emits.
*
* Consumers can set `cancel = true` (and optionally `cancelReason`) to abort
* the restore — useful for custom approval workflows, audit logging hooks,
* or for a consumer that wants to take over the actual save itself.
*/
export interface BeforeRestoreCommitEvent {
/** Set to true to abort. RestoreConfirmed will not fire. */
cancel: boolean;
/** Optional explanation surfaced by the consumer. */
cancelReason?: string;
/** Selected field names (only fields the user kept checked). */
SelectedFieldNames: string[];
/** The full set of rows in the preview, including unselected. */
AllRows: RestoreFieldRow[];
/** ID of the source RecordChange row whose state is being restored. */
SourceChangeID: string;
/** Optional reason text the user entered. */
Reason: string | null;
/** The mode — 'live' (UPDATE) or 'undelete' (INSERT). */
Mode: RestorePreviewMode;
}
/**
* Event payload emitted after the user has confirmed a restore.
*
* The host component is responsible for applying the snapshot to a
* BaseEntity instance, calling {@link BaseEntity.SetRestoreContext}, and
* invoking Save(). This component never touches the database directly so
* it remains usable in any consumer context.
*/
export interface RestoreCommitEvent {
/** ID of the source RecordChange row whose state is being restored. */
SourceChangeID: string;
/** Optional user-entered reason; persisted to RecordChange.RestoreReason. */
Reason: string | null;
/** Selected fields with their snapshot values, ready for BaseEntity.Set. */
FieldValues: Array<{
FieldName: string;
Value: unknown;
}>;
/** The full preview rows (including unselected) for audit/logging. */
AllRows: RestoreFieldRow[];
/** Mode indicates UPDATE (live) vs INSERT (undelete). */
Mode: RestorePreviewMode;
}
/**
* Reusable slide-in panel that previews a restore operation against a
* historical {@link MJRecordChangeEntity} and lets the user confirm with
* field-level granularity.
*
* This component is rendered by both:
* - The Record Changes timeline (for restoring a live record from any past
* change row)
* - The Recycle Bin (for re-creating a hard-deleted record from its delete
* snapshot)
*
* It does NOT perform the save itself — the host component receives a
* {@link RestoreCommitEvent} with the selected field values and is
* responsible for applying them to a BaseEntity, setting the restore
* context, and calling Save(). This keeps the component purely
* presentational and reusable in any context.
*
* ### Semantic correctness
*
* The preview compares the **full snapshot** captured in the source
* change's `FullRecordJSON` to the current live record (or to nothing in
* un-delete mode). It does NOT roll back a single delta — restoring `v2`
* means "make the record look like it did at v2", not "undo v3's changes".
*
* @example Live restore from the timeline
*
*
*
* @example Un-delete from the Recycle Bin
*
*
*/
export declare class RestorePreviewPanelComponent extends BaseAngularComponent implements OnInit {
private cdr;
/**
* Controls panel visibility. Setting to true opens the slide-in;
* setting to false closes it. On every closed→open transition the
* panel auto-resets its transient state (`IsRestoring`, `Reason`,
* `ShowUnchanged`, row checks) so the host doesn't have to remember
* to call `Reset()` after a restore completes.
*/
private _visible;
set Visible(value: boolean);
get Visible(): boolean;
/**
* Operating mode — `'live'` for restoring an existing record from a
* snapshot, `'undelete'` for re-creating a hard-deleted record.
*/
Mode: RestorePreviewMode;
/**
* The historical RecordChange row whose state will be restored. Required.
* The component reads `FullRecordJSON` from this entity to determine the
* target state. The change's `Type` does not matter — `Create`,
* `Update`, `Snapshot`, and `Delete` are all valid restore sources.
*/
private _recordChange;
set RecordChange(value: MJRecordChangeEntity | null);
get RecordChange(): MJRecordChangeEntity | null;
/**
* The current live record to diff against. Required in `'live'` mode,
* ignored in `'undelete'` mode (since the live record no longer exists).
*/
private _liveRecord;
set LiveRecord(value: BaseEntity | null);
get LiveRecord(): BaseEntity | null;
/**
* The entity name. Required in `'undelete'` mode (since there's no live
* record to read it from). In `'live'` mode it can be omitted and is
* inferred from the LiveRecord.
*/
EntityName: string | null;
/**
* When true, the Restore button is disabled until the user enters a
* non-empty reason. Useful for regulated environments where every
* reversal needs justification. Default: false.
*/
RequireReason: boolean;
/**
* When true, hides the optional reason text area entirely. Default: false.
*/
HideReason: boolean;
/**
* Cancelable event fired when the user clicks Restore but before
* {@link RestoreConfirmed} emits. Consumers can set `cancel = true` on
* the event arg to abort the operation — useful for custom approval
* workflows or for taking over the save themselves.
*/
BeforeRestoreCommit: EventEmitter;
/**
* Emitted after the user confirms the restore (and BeforeRestoreCommit
* was not cancelled). The host is responsible for applying the field
* values to a BaseEntity, calling SetRestoreContext, and invoking Save().
*/
RestoreConfirmed: EventEmitter;
/**
* Emitted when the user cancels the preview without restoring.
*/
RestoreCancelled: EventEmitter;
Rows: RestoreFieldRow[];
Reason: string;
IsRestoring: boolean;
ShowUnchanged: boolean;
/** Number of rows where the current value differs from the snapshot. */
ChangedCount: number;
/** Number of rows that are checked (will be applied on restore). */
SelectedCount: number;
/** Number of rows the schema has dropped or renamed since the snapshot. */
DriftCount: number;
private isInitialized;
private resolvedEntityInfo;
constructor(cdr: ChangeDetectorRef);
ngOnInit(): void;
/**
* Toggles whether unchanged rows are visible in the table. When false
* (default), only rows where current ≠ snapshot are shown.
*/
ToggleUnchanged(): void;
/**
* Toggles whether a single row is selected for restore. Updates the
* SelectedCount in real time so the primary button label reflects it.
*/
ToggleRow(row: RestoreFieldRow): void;
/**
* Selects every row that can be selected (skips immutable / drifted).
*/
SelectAll(): void;
/**
* Deselects every row in the preview.
*/
DeselectAll(): void;
/**
* User clicked Restore — fire BeforeRestoreCommit (cancelable), then
* RestoreConfirmed if not cancelled.
*/
ConfirmRestore(): void;
/**
* User cancelled the preview. Resets state and emits RestoreCancelled.
*/
Cancel(): void;
/**
* Resets internal state — useful after a save completes so the panel
* can be reopened cleanly. Called by the host component when needed.
*/
Reset(): void;
get IsRestoreDisabled(): boolean;
get RestoreButtonLabel(): string;
get HeaderTitle(): string;
get VersionTimestamp(): Date | null;
get VersionUser(): string;
get UnchangedCount(): number;
/**
* Rebuilds the Rows array from the current RecordChange + LiveRecord.
* Idempotent and cheap — safe to call from input setters.
*/
private rebuildRows;
private buildRowFromSnapshot;
private getCurrentFieldValue;
private parseSnapshot;
/**
* Resolves the entity metadata. Prefers LiveRecord.EntityInfo (always
* accurate). Falls back to looking up by EntityName. Memoized.
*/
private resolveEntityInfo;
private formatValue;
private recountSelected;
formatTimestamp(date: Date | null): string;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
//# sourceMappingURL=restore-preview-panel.component.d.ts.map