@memberjunction/ng-record-changes 6.1.3 → 6.1.5

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.
@@ -0,0 +1,32 @@
1
+ import { EntityFieldInfo } from '@memberjunction/core';
2
+ /**
3
+ * Formats a field value from a change record, a snapshot, or a live record for display.
4
+ *
5
+ * Shared by the change history and the restore preview so the two cannot disagree about the same
6
+ * value. A SQL `date` column is a calendar day that arrives as UTC midnight: it is formatted as that
7
+ * day, with no time. Run through the timestamp format, a stored 2026-10-01 read "Sep 30, 2026,
8
+ * 7:00 PM" for a reader in US Central — the wrong day, and a time the value never had.
9
+ *
10
+ * A live record's date field is a `Date` object, not a string, and is formatted the same way rather
11
+ * than falling into the generic object branch, which rendered it as an empty string.
12
+ *
13
+ * @param value The raw value: a string or Date for date fields, any JSON value otherwise
14
+ * @param field The field's metadata, when known; without it the value is treated as text
15
+ */
16
+ export declare function FormatChangeValue(value: unknown, field: EntityFieldInfo | undefined): string;
17
+ /**
18
+ * Whether two values of the same field hold the same data, for deciding whether a restore would
19
+ * change anything.
20
+ *
21
+ * Comparing the display strings is not enough for a date: the display drops seconds, so a timestamp
22
+ * that moved by 30 seconds formats identically and would read as unchanged. A timestamp is compared
23
+ * as the instant it names, and a SQL `date` column as the calendar day it stores, so a snapshot's
24
+ * `'2026-10-01'` matches a live `Date` at UTC midnight of that day. Anything else, and a date that
25
+ * does not parse, falls back to the display strings, as before.
26
+ *
27
+ * @param a One value: a string or Date for date fields, any JSON value otherwise
28
+ * @param b The other value
29
+ * @param field The field's metadata, when known
30
+ */
31
+ export declare function ChangeValuesMatch(a: unknown, b: unknown, field: EntityFieldInfo | undefined): boolean;
32
+ //# sourceMappingURL=format-change-value.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-change-value.d.ts","sourceRoot":"","sources":["../../src/lib/format-change-value.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAwD,MAAM,sBAAsB,CAAC;AAe7G;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,eAAe,GAAG,SAAS,GAAG,MAAM,CAmB5F;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,eAAe,GAAG,SAAS,GAAG,OAAO,CAWrG"}
@@ -0,0 +1,81 @@
1
+ import { EntityFieldTSType, FormatDateOnly, IsDateOnlySQLType } from '@memberjunction/core';
2
+ /** An instant: the moment it happened, in the reader's zone. */
3
+ const TIMESTAMP_FORMAT = {
4
+ month: 'short',
5
+ day: 'numeric',
6
+ year: 'numeric',
7
+ hour: 'numeric',
8
+ minute: '2-digit',
9
+ hour12: true,
10
+ };
11
+ /** A calendar day: no time, and no zone to shift it. */
12
+ const DATE_ONLY_FORMAT = { month: 'short', day: 'numeric', year: 'numeric' };
13
+ /**
14
+ * Formats a field value from a change record, a snapshot, or a live record for display.
15
+ *
16
+ * Shared by the change history and the restore preview so the two cannot disagree about the same
17
+ * value. A SQL `date` column is a calendar day that arrives as UTC midnight: it is formatted as that
18
+ * day, with no time. Run through the timestamp format, a stored 2026-10-01 read "Sep 30, 2026,
19
+ * 7:00 PM" for a reader in US Central — the wrong day, and a time the value never had.
20
+ *
21
+ * A live record's date field is a `Date` object, not a string, and is formatted the same way rather
22
+ * than falling into the generic object branch, which rendered it as an empty string.
23
+ *
24
+ * @param value The raw value: a string or Date for date fields, any JSON value otherwise
25
+ * @param field The field's metadata, when known; without it the value is treated as text
26
+ */
27
+ export function FormatChangeValue(value, field) {
28
+ if (value == null)
29
+ return '';
30
+ if (field?.TSType === EntityFieldTSType.Date && (value instanceof Date || typeof value === 'string')) {
31
+ const date = value instanceof Date ? value : new Date(value);
32
+ if (!isNaN(date.getTime())) {
33
+ return IsDateOnlySQLType(field.Type)
34
+ ? FormatDateOnly(date, DATE_ONLY_FORMAT, 'en-US')
35
+ : new Intl.DateTimeFormat('en-US', TIMESTAMP_FORMAT).format(date);
36
+ }
37
+ }
38
+ if (typeof value === 'object') {
39
+ const keys = Object.keys(value);
40
+ if (keys.length === 0)
41
+ return '';
42
+ return JSON.stringify(value);
43
+ }
44
+ return String(value);
45
+ }
46
+ /**
47
+ * Whether two values of the same field hold the same data, for deciding whether a restore would
48
+ * change anything.
49
+ *
50
+ * Comparing the display strings is not enough for a date: the display drops seconds, so a timestamp
51
+ * that moved by 30 seconds formats identically and would read as unchanged. A timestamp is compared
52
+ * as the instant it names, and a SQL `date` column as the calendar day it stores, so a snapshot's
53
+ * `'2026-10-01'` matches a live `Date` at UTC midnight of that day. Anything else, and a date that
54
+ * does not parse, falls back to the display strings, as before.
55
+ *
56
+ * @param a One value: a string or Date for date fields, any JSON value otherwise
57
+ * @param b The other value
58
+ * @param field The field's metadata, when known
59
+ */
60
+ export function ChangeValuesMatch(a, b, field) {
61
+ if (field?.TSType === EntityFieldTSType.Date) {
62
+ const left = asValidDate(a);
63
+ const right = asValidDate(b);
64
+ if (left && right) {
65
+ return IsDateOnlySQLType(field.Type)
66
+ ? left.toISOString().slice(0, 10) === right.toISOString().slice(0, 10)
67
+ : left.getTime() === right.getTime();
68
+ }
69
+ }
70
+ return FormatChangeValue(a, field) === FormatChangeValue(b, field);
71
+ }
72
+ /** A date or date string as a valid Date, or `null`. */
73
+ function asValidDate(value) {
74
+ if (!(value instanceof Date) && typeof value !== 'string')
75
+ return null;
76
+ if (typeof value === 'string' && value.trim() === '')
77
+ return null;
78
+ const date = value instanceof Date ? value : new Date(value);
79
+ return isNaN(date.getTime()) ? null : date;
80
+ }
81
+ //# sourceMappingURL=format-change-value.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-change-value.js","sourceRoot":"","sources":["../../src/lib/format-change-value.ts"],"names":[],"mappings":"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","sourcesContent":["import { EntityFieldInfo, EntityFieldTSType, FormatDateOnly, IsDateOnlySQLType } from '@memberjunction/core';\n\n/** An instant: the moment it happened, in the reader's zone. */\nconst TIMESTAMP_FORMAT: Intl.DateTimeFormatOptions = {\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n hour: 'numeric',\n minute: '2-digit',\n hour12: true,\n};\n\n/** A calendar day: no time, and no zone to shift it. */\nconst DATE_ONLY_FORMAT: Intl.DateTimeFormatOptions = { month: 'short', day: 'numeric', year: 'numeric' };\n\n/**\n * Formats a field value from a change record, a snapshot, or a live record for display.\n *\n * Shared by the change history and the restore preview so the two cannot disagree about the same\n * value. A SQL `date` column is a calendar day that arrives as UTC midnight: it is formatted as that\n * day, with no time. Run through the timestamp format, a stored 2026-10-01 read \"Sep 30, 2026,\n * 7:00 PM\" for a reader in US Central — the wrong day, and a time the value never had.\n *\n * A live record's date field is a `Date` object, not a string, and is formatted the same way rather\n * than falling into the generic object branch, which rendered it as an empty string.\n *\n * @param value The raw value: a string or Date for date fields, any JSON value otherwise\n * @param field The field's metadata, when known; without it the value is treated as text\n */\nexport function FormatChangeValue(value: unknown, field: EntityFieldInfo | undefined): string {\n if (value == null) return '';\n\n if (field?.TSType === EntityFieldTSType.Date && (value instanceof Date || typeof value === 'string')) {\n const date = value instanceof Date ? value : new Date(value);\n if (!isNaN(date.getTime())) {\n return IsDateOnlySQLType(field.Type)\n ? FormatDateOnly(date, DATE_ONLY_FORMAT, 'en-US')\n : new Intl.DateTimeFormat('en-US', TIMESTAMP_FORMAT).format(date);\n }\n }\n\n if (typeof value === 'object') {\n const keys = Object.keys(value as Record<string, unknown>);\n if (keys.length === 0) return '';\n return JSON.stringify(value);\n }\n\n return String(value);\n}\n\n/**\n * Whether two values of the same field hold the same data, for deciding whether a restore would\n * change anything.\n *\n * Comparing the display strings is not enough for a date: the display drops seconds, so a timestamp\n * that moved by 30 seconds formats identically and would read as unchanged. A timestamp is compared\n * as the instant it names, and a SQL `date` column as the calendar day it stores, so a snapshot's\n * `'2026-10-01'` matches a live `Date` at UTC midnight of that day. Anything else, and a date that\n * does not parse, falls back to the display strings, as before.\n *\n * @param a One value: a string or Date for date fields, any JSON value otherwise\n * @param b The other value\n * @param field The field's metadata, when known\n */\nexport function ChangeValuesMatch(a: unknown, b: unknown, field: EntityFieldInfo | undefined): boolean {\n if (field?.TSType === EntityFieldTSType.Date) {\n const left = asValidDate(a);\n const right = asValidDate(b);\n if (left && right) {\n return IsDateOnlySQLType(field.Type)\n ? left.toISOString().slice(0, 10) === right.toISOString().slice(0, 10)\n : left.getTime() === right.getTime();\n }\n }\n return FormatChangeValue(a, field) === FormatChangeValue(b, field);\n}\n\n/** A date or date string as a valid Date, or `null`. */\nfunction asValidDate(value: unknown): Date | null {\n if (!(value instanceof Date) && typeof value !== 'string') return null;\n if (typeof value === 'string' && value.trim() === '') return null;\n const date = value instanceof Date ? value : new Date(value);\n return isNaN(date.getTime()) ? null : date;\n}\n"]}
@@ -296,7 +296,6 @@ export declare class RecordChangesComponent extends BaseAngularComponent impleme
296
296
  displayName: string;
297
297
  value: string;
298
298
  }>;
299
- private formatChangeValue;
300
299
  private generateDiffHtml;
301
300
  private shouldUseWordDiff;
302
301
  private escapeHtml;
@@ -1 +1 @@
1
- {"version":3,"file":"ng-record-changes.component.d.ts","sourceRoot":"","sources":["../../src/lib/ng-record-changes.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,YAAY,EAEZ,SAAS,EACT,MAAM,EAEN,iBAAiB,EAGjB,MAAM,EACP,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAEnE,OAAO,EACL,UAAU,EAEV,YAAY,EAIb,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAErE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yDAAyD,CAAC;;AAE7F,mFAAmF;AACnF,UAAU,WAAW;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,mBAAmB;IAClC,2EAA2E;IAC3E,cAAc,EAAE,MAAM,CAAC;IACvB,2CAA2C;IAC3C,SAAS,EAAE,IAAI,CAAC;IAChB,8DAA8D;IAC9D,aAAa,EAAE,MAAM,CAAC;IACtB,oDAAoD;IACpD,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,gEAAgE;IAChE,WAAW,EAAE,KAAK,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CAC3D;AAED,oFAAoF;AACpF,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAC;IAClD,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED,mDAAmD;AACnD,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,oBAAoB,EAAE,CAAC;CACjC;AAED,uFAAuF;AACvF,MAAM,WAAW,UAAU;IACzB,4FAA4F;IAC5F,GAAG,EAAE,MAAM,CAAC;IACZ,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAC;IACd,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAC;IACd,kEAAkE;IAClE,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B;AAED;;;;;;;;;;;;;GAaG;AACH,qBAQa,sBAAuB,SAAQ,oBAAqB,YAAW,MAAM,EAAE,SAAS;IAyEzF,OAAO,CAAC,GAAG;IACX,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,qBAAqB;IAC7B,OAAO,CAAC,SAAS;IA3EZ,SAAS,UAAS;IAClB,SAAS,UAAS;IACf,YAAY,oBAAsB;IACnC,MAAM,EAAG,UAAU,CAAC;IAE7B,wFAAwF;IAC/E,YAAY,UAAS;IAE9B;;;;OAIG;IACO,gBAAgB,oCAA2C;IAErE,QAAQ,EAAE,oBAAoB,EAAE,CAAM;IACtC,YAAY,EAAE,oBAAoB,EAAE,CAAM;IAE1C;;;;;;OAMG;IACH,OAAO,CAAC,YAAY,CAA2C;IAC/D,UAAU,EAAE,SAAS,EAAE,CAAM;IAC7B,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,CAAa;IAEvC,yEAAyE;IACzE,oBAAoB,EAAE,oBAAoB,GAAG,IAAI,CAAQ;IACzD,2DAA2D;IAC3D,qBAAqB,UAAS;IAC9B,0FAA0F;IAC1F,WAAW,UAAS;IAGpB,YAAY,EAAE,WAAW,EAAE,CAAM;IACjC,eAAe,UAAS;IACxB,gBAAgB,UAAS;IAGzB,UAAU,SAAM;IAChB,uEAAuE;IACvE,YAAY,SAAM;IAClB,cAAc,SAAM;IACpB,kEAAkE;IAClE,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAM;IAC7C,4CAA4C;IAC5C,kBAAkB,UAAS;IAC3B,wEAAwE;IACxE,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE1C;;;;OAIG;IACH,gBAAgB,EAAE,UAAU,EAAE,CAAM;IAEpC,kFAAkF;IAClF,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAK;IAExC;;;;;OAKG;IACH,OAAO,CAAC,cAAc,CAA6B;gBAGzC,GAAG,EAAE,iBAAiB,EACtB,MAAM,EAAE,MAAM,EACd,qBAAqB,EAAE,qBAAqB,EAC5C,SAAS,EAAE,YAAY;IAGjC,QAAQ,IAAI,IAAI;IAWhB,WAAW,IAAI,IAAI;IAKnB;;;;;;OAMG;IACH,OAAO,CAAC,sBAAsB;IAU9B;;;OAGG;IACI,OAAO,IAAI,IAAI;IAQf,OAAO,IAAI,IAAI;IAOT,iBAAiB,CAAC,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqCtG,cAAc,IAAI,IAAI;IAItB,cAAc,IAAI,IAAI;IAItB;;OAEG;IACI,aAAa,IAAI,IAAI;IAK5B;;OAEG;IACI,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAKpC;;OAEG;IACH,IAAW,aAAa,IAAI,OAAO,CAElC;IAED;;OAEG;IACH,IAAW,mBAAmB,IAAI,OAAO,CAExC;IAED;;;OAGG;IACH,IAAW,kBAAkB,IAAI,OAAO,CAEvC;IAED,sFAAsF;IACtF,IAAW,wBAAwB,IAAI,MAAM,CAE5C;IAEM,oBAAoB,IAAI,IAAI;IAK5B,mBAAmB,IAAI,IAAI;IAK3B,YAAY,IAAI,IAAI;IAM3B;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IAuC/B,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,YAAY;IAmCP,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IAoEvC,gBAAgB,IAAI,IAAI;IAKxB,cAAc,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAWtE,sBAAsB,IAAI,IAAI;IAK9B,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAWlD,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IASvC,qBAAqB,CAAC,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAOnE;;;;;;OAMG;IACH,gBAAgB,CAAC,MAAM,EAAE,oBAAoB,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI;IAOvE;;;;OAIG;IACH,uBAAuB,CAAC,MAAM,EAAE,kBAAkB,GAAG,IAAI;IAwBzD;;OAEG;IACH,uBAAuB,IAAI,IAAI;IAQ/B;;;;OAIG;IACI,2BAA2B,CAAC,MAAM,EAAE,oBAAoB,GAAG,oBAAoB,GAAG,IAAI;IAM7F;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAO5B;;;OAGG;IACI,YAAY,CAAC,MAAM,EAAE,oBAAoB,GAAG,OAAO;IAI1D;;;;;OAKG;IACI,kBAAkB,CAAC,MAAM,EAAE,oBAAoB,GAAG,OAAO;IAIhE;;;OAGG;IACI,kBAAkB,CAAC,YAAY,EAAE,oBAAoB,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI;IAuBtF,OAAO,CAAC,eAAe;IAcvB,OAAO,CAAC,oBAAoB;IAe5B,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAU5C,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAS5C;;;;;OAKG;IACH,qBAAqB,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM;IAK3D;;;;OAIG;IACH,gBAAgB,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,GAAG,IAAI;IAM7D,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAMtC,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAStC,oBAAoB,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM;IAI1D,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM;IAa5C,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM;IAM/C,yBAAyB,IAAI,MAAM;IAKnC,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM;IAQ9B,kBAAkB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM;IAmBtC,kBAAkB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM;IActC,gBAAgB,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM;IAyBtD,oBAAoB,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM;IAY1D,OAAO,CAAC,wBAAwB;IAUhC,OAAO,CAAC,qBAAqB;IAa7B,eAAe,CAAC,MAAM,EAAE,oBAAoB,GAAG,eAAe,EAAE;IAShE,OAAO,CAAC,oBAAoB;IAyB5B,OAAO,CAAC,iBAAiB;IAQzB,gBAAgB,CAAC,MAAM,EAAE,oBAAoB,GAAG,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAqB3G,OAAO,CAAC,iBAAiB;IA4BzB,OAAO,CAAC,gBAAgB;IA4BxB,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,UAAU;yCA93BP,sBAAsB;2CAAtB,sBAAsB;CAm4BlC"}
1
+ {"version":3,"file":"ng-record-changes.component.d.ts","sourceRoot":"","sources":["../../src/lib/ng-record-changes.component.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import { Component, EventEmitter, Input, Output, ChangeDetectionStrategy, ViewEncapsulation, } from '@angular/core';
2
2
  import { EntityFieldTSType, RunView, } from '@memberjunction/core';
3
3
  import { UUIDsEqual, NormalizeUUID } from '@memberjunction/global';
4
+ import { FormatChangeValue } from './format-change-value';
4
5
  import { BaseAngularComponent } from '@memberjunction/ng-base-types';
5
6
  import { diffChars, diffWords } from 'diff';
6
7
  import * as i0 from "@angular/core";
@@ -1314,9 +1315,8 @@ export class RecordChangesComponent extends BaseAngularComponent {
1314
1315
  buildFieldChangeInfo(changeInfo) {
1315
1316
  const field = this.record.EntityInfo.Fields.find((f) => f.Name.trim().toLowerCase() === changeInfo.field?.trim().toLowerCase());
1316
1317
  const fieldType = this.classifyFieldType(field);
1317
- const isDateField = fieldType === 'date';
1318
- const formattedOld = this.formatChangeValue(changeInfo.oldValue, isDateField);
1319
- const formattedNew = this.formatChangeValue(changeInfo.newValue, isDateField);
1318
+ const formattedOld = FormatChangeValue(changeInfo.oldValue, field);
1319
+ const formattedNew = FormatChangeValue(changeInfo.newValue, field);
1320
1320
  let diffHtml;
1321
1321
  if (fieldType === 'text' && formattedOld !== formattedNew) {
1322
1322
  diffHtml = this.generateDiffHtml(formattedOld, formattedNew);
@@ -1352,7 +1352,7 @@ export class RecordChangesComponent extends BaseAngularComponent {
1352
1352
  .map((field) => ({
1353
1353
  name: field.Name,
1354
1354
  displayName: field.DisplayNameOrName,
1355
- value: this.formatChangeValue(record[field.Name], field.TSType === EntityFieldTSType.Date),
1355
+ value: FormatChangeValue(record[field.Name], field),
1356
1356
  }));
1357
1357
  }
1358
1358
  catch {
@@ -1360,30 +1360,6 @@ export class RecordChangesComponent extends BaseAngularComponent {
1360
1360
  }
1361
1361
  }
1362
1362
  // ─── Value Formatting ───────────────────────────────────────────
1363
- formatChangeValue(value, isDateField) {
1364
- if (value == null)
1365
- return '';
1366
- if (typeof value === 'object') {
1367
- const keys = Object.keys(value);
1368
- if (keys.length === 0)
1369
- return '';
1370
- return JSON.stringify(value);
1371
- }
1372
- if (isDateField && typeof value === 'string') {
1373
- const date = new Date(value);
1374
- if (!isNaN(date.getTime())) {
1375
- return new Intl.DateTimeFormat('en-US', {
1376
- month: 'short',
1377
- day: 'numeric',
1378
- year: 'numeric',
1379
- hour: 'numeric',
1380
- minute: '2-digit',
1381
- hour12: true,
1382
- }).format(date);
1383
- }
1384
- }
1385
- return String(value);
1386
- }
1387
1363
  // ─── Diff Generation (text fields only) ─────────────────────────
1388
1364
  generateDiffHtml(oldValue, newValue) {
1389
1365
  if (!oldValue && !newValue) {
@@ -1454,5 +1430,5 @@ export class RecordChangesComponent extends BaseAngularComponent {
1454
1430
  }], RestoreRequested: [{
1455
1431
  type: Output
1456
1432
  }] }); })();
1457
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(RecordChangesComponent, { className: "RecordChangesComponent", filePath: "src/lib/ng-record-changes.component.ts", lineNumber: 120 }); })();
1433
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(RecordChangesComponent, { className: "RecordChangesComponent", filePath: "src/lib/ng-record-changes.component.ts", lineNumber: 121 }); })();
1458
1434
  //# sourceMappingURL=ng-record-changes.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ng-record-changes.component.js","sourceRoot":"","sources":["../../src/lib/ng-record-changes.component.ts","../../src/lib/ng-record-changes.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n EventEmitter,\n Input,\n OnDestroy,\n OnInit,\n Output,\n ChangeDetectorRef,\n ChangeDetectionStrategy,\n ViewEncapsulation,\n NgZone,\n} from '@angular/core';\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\nimport { Subscription } from 'rxjs';\nimport {\n BaseEntity,\n BaseEntityEvent,\n CompositeKey,\n EntityFieldInfo,\n EntityFieldTSType,\n RunView,\n} from '@memberjunction/core';\nimport { UUIDsEqual, NormalizeUUID } from '@memberjunction/global';\nimport { MJRecordChangeEntity } from '@memberjunction/core-entities';\nimport { MJNotificationService } from '@memberjunction/ng-notifications';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nimport { diffChars, diffWords, Change } from 'diff';\nimport { RestoreCommitEvent } from './restore-preview-panel/restore-preview-panel.component';\n\n/** Lightweight shape for displaying a version label associated with this record */\ninterface RecordLabel {\n ID: string;\n Name: string;\n Description: string | null;\n Scope: string;\n Status: string;\n CreatedAt: Date;\n ItemCount: number;\n}\n\n/**\n * Event payload emitted when the user confirms a restore.\n *\n * The host component (typically `record-form-container`) is responsible for:\n * 1. Reloading the live record (concurrency safety),\n * 2. Calling `record.SetRestoreContext(SourceChangeID, Reason)`,\n * 3. Calling `record.Set(FieldName, Value)` for each entry in `FieldValues`,\n * 4. Calling `record.Save()`,\n * 5. Calling `record.ClearRestoreContext()` after the save returns.\n *\n * The provider will write a new RecordChange row with `Source='Restore'`,\n * `RestoredFromID = SourceChangeID`, and `RestoreReason = Reason` —\n * producing the auditable lineage chain.\n */\nexport interface RestoreVersionEvent {\n /** ID of the historical RecordChange row whose state is being restored. */\n SourceChangeID: string;\n /** When the historical change was made. */\n ChangedAt: Date;\n /** Display name / email of who made the historical change. */\n ChangedByUser: string;\n /** Optional user-entered reason for the restore. */\n Reason: string | null;\n /** Selected field values, ready to pass to BaseEntity.Set(). */\n FieldValues: Array<{ FieldName: string; Value: unknown }>;\n}\n\n/** A single field change with type-aware rendering info (timeline display only). */\nexport interface FieldChangeInfo {\n field: string;\n displayName: string;\n oldValue: string;\n newValue: string;\n fieldType: 'boolean' | 'date' | 'number' | 'text';\n diffHtml?: SafeHtml;\n}\n\n/** A group of changes that share the same date. */\nexport interface DateGroup {\n label: string;\n changes: MJRecordChangeEntity[];\n}\n\n/** A conditional filter pill (one per type/source actually present in loaded data). */\nexport interface FilterPill {\n /** Unique key for selection state ('Update', 'Create', 'Delete', 'Snapshot', 'Restore'). */\n Key: string;\n /** User-facing label (pluralized: 'Updates', 'Restored', etc.). */\n Label: string;\n /** Font Awesome icon class. */\n Icon: string;\n /** Number of changes of this kind in the loaded data. */\n Count: number;\n /** Selection style — neutral type pill or violet restore pill. */\n Variant: 'type' | 'restore';\n}\n\n/**\n * Slide-out timeline of all changes to a single record. Hosts the reusable\n * {@link RestorePreviewPanelComponent} for the actual restore confirmation\n * flow, and exposes a `RestoreRequested` event the host can act on to\n * persist the restore.\n *\n * @example\n * <mj-record-changes\n * [record]=\"myEntity\"\n * [AllowRestore]=\"true\"\n * (dialogClosed)=\"showHistory = false\"\n * (RestoreRequested)=\"onRestoreRequested($event)\">\n * </mj-record-changes>\n */\n@Component({\n standalone: false,\n selector: 'mj-record-changes',\n templateUrl: './ng-record-changes.component.html',\n styleUrls: ['./ng-record-changes.component.css'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n})\nexport class RecordChangesComponent extends BaseAngularComponent implements OnInit, OnDestroy {\n public IsLoading = false;\n public IsVisible = false;\n @Output() dialogClosed = new EventEmitter();\n @Input() record!: BaseEntity;\n\n /** Whether to show a \"Restore\" button on each historical version row. Default false. */\n @Input() AllowRestore = false;\n\n /**\n * Emitted when the user confirms a restore in the preview panel.\n * The host is responsible for applying the snapshot to the record and\n * saving with `record.SetRestoreContext()` set first.\n */\n @Output() RestoreRequested = new EventEmitter<RestoreVersionEvent>();\n\n viewData: MJRecordChangeEntity[] = [];\n filteredData: MJRecordChangeEntity[] = [];\n\n /**\n * Change lookup keyed by NormalizeUUID(ID), rebuilt whenever {@link viewData}\n * loads. Lets {@link getRestoredFromSourceChange} resolve a restore row's\n * source change in O(1) instead of an O(rows) `UUIDsEqual` scan — which was\n * previously executed twice per restore row per CD cycle (once in the\n * template `@if` and once inside `getChangeSummary`), giving O(rows^2)/CD.\n */\n private viewDataById = new Map<string, MJRecordChangeEntity>();\n dateGroups: DateGroup[] = [];\n expandedItems: Set<string> = new Set();\n\n /** The change record currently selected for restore preview, or null. */\n RestorePreviewChange: MJRecordChangeEntity | null = null;\n /** Visibility of the embedded restore preview slide-in. */\n RestorePreviewVisible = false;\n /** Whether the restore commit is in progress (between confirmation and host response). */\n IsRestoring = false;\n\n // Version label state\n RecordLabels: RecordLabel[] = [];\n IsLoadingLabels = false;\n ShowCreateWizard = false;\n\n // Filter properties\n searchTerm = '';\n /** Single selected type filter (legacy, kept for backwards compat). */\n selectedType = '';\n selectedSource = '';\n /** Map of Key → selected, used by the conditional chip system. */\n ChipSelections: Record<string, boolean> = {};\n /** Whether the overflow popover is open. */\n ShowFilterOverflow = false;\n /** Highlighted change ID for the lineage-jump indicator (transient). */\n HighlightedChangeID: string | null = null;\n\n /**\n * Conditional filter pills derived from loaded data. Always includes 'All'\n * implicitly. Other pills only render when at least one matching change\n * exists. Overflows into a popover when the count exceeds 2.\n */\n ConditionalPills: FilterPill[] = [];\n\n /** Threshold above which conditional chips collapse into the overflow popover. */\n private readonly OVERFLOW_THRESHOLD = 2;\n\n /**\n * Subscription to the record's BaseEntity event stream. We listen for\n * 'save' events and auto-refresh the timeline so the user immediately\n * sees the new RecordChange row produced by either a normal save or a\n * restore. Cleaned up in ngOnDestroy.\n */\n private _entitySaveSub: Subscription | null = null;\n\n constructor(\n private cdr: ChangeDetectorRef,\n private ngZone: NgZone,\n private mjNotificationService: MJNotificationService,\n private sanitizer: DomSanitizer,\n ) { super(); }\n\n ngOnInit(): void {\n if (this.record) {\n this.IsLoading = true;\n this.IsVisible = true;\n this.cdr.markForCheck();\n this.LoadRecordChanges(this.record.PrimaryKey, '', this.record.EntityInfo.Name);\n this.LoadRecordLabels();\n this.subscribeToRecordSaves();\n }\n }\n\n ngOnDestroy(): void {\n this._entitySaveSub?.unsubscribe();\n this._entitySaveSub = null;\n }\n\n /**\n * Wires up an event handler on the live record so the timeline auto-\n * refreshes immediately after any save lands — including the one\n * produced by the restore flow. Without this the user sees their record\n * update in the form but the panel above still shows the pre-restore\n * change list, which is confusing.\n */\n private subscribeToRecordSaves(): void {\n if (!this.record) return;\n this._entitySaveSub?.unsubscribe();\n this._entitySaveSub = this.record.RegisterEventHandler((event: BaseEntityEvent) => {\n if (event?.type === 'save') {\n this.ngZone.run(() => this.Refresh());\n }\n });\n }\n\n /**\n * Reloads the record changes list from the database.\n * Called by the parent container after a save completes while the drawer is open.\n */\n public Refresh(): void {\n if (this.record) {\n this.IsLoading = true;\n this.cdr.markForCheck();\n this.LoadRecordChanges(this.record.PrimaryKey, '', this.record.EntityInfo.Name);\n }\n }\n\n public OnClose(): void {\n this.IsVisible = false;\n this.cdr.markForCheck();\n // Allow the slide-out animation to complete before emitting\n setTimeout(() => this.dialogClosed.emit(), 300);\n }\n\n public async LoadRecordChanges(pkey: CompositeKey, appName: string, entityName: string): Promise<void> {\n if (pkey && entityName) {\n const md = this.ProviderToUse;\n const entityInfo = md.EntityByName(entityName);\n let changes: MJRecordChangeEntity[] = [];\n if (entityInfo?.TrackRecordChanges) {\n const rvResult = await RunView.FromMetadataProvider(md).RunView<MJRecordChangeEntity>({\n EntityName: 'MJ: Record Changes',\n ExtraFilter: `Entity='${entityName}' AND RecordID='${pkey.ToConcatenatedString()}'`,\n OrderBy: 'ChangedAt DESC',\n ResultType: 'entity_object',\n });\n if (rvResult.Success) changes = rvResult.Results;\n }\n this.ngZone.run(() => {\n if (changes) {\n this.viewData = changes.sort(\n (a: MJRecordChangeEntity, b: MJRecordChangeEntity) => new Date(b.ChangedAt).getTime() - new Date(a.ChangedAt).getTime(),\n );\n this.rebuildViewDataIndex();\n this.rebuildConditionalPills();\n this.applyFilters();\n this.IsLoading = false;\n } else {\n this.mjNotificationService.CreateSimpleNotification(\n `Error loading record changes for ${entityName} with primary key ${pkey.ToString()}.`,\n 'error',\n );\n this.IsLoading = false;\n }\n this.cdr.markForCheck();\n });\n }\n }\n\n // ─── Filter & Search ────────────────────────────────────────────\n\n onSearchChange(): void {\n this.applyFilters();\n }\n\n onFilterChange(): void {\n this.applyFilters();\n }\n\n /**\n * Toggles the \"All\" pill — clears every conditional selection.\n */\n public SelectAllPill(): void {\n for (const k of Object.keys(this.ChipSelections)) this.ChipSelections[k] = false;\n this.applyFilters();\n }\n\n /**\n * Toggles a conditional pill on/off.\n */\n public TogglePill(key: string): void {\n this.ChipSelections[key] = !this.ChipSelections[key];\n this.applyFilters();\n }\n\n /**\n * Returns true when no conditional pills are selected (i.e. \"All\" mode).\n */\n public get IsAllSelected(): boolean {\n return !Object.values(this.ChipSelections).some(v => v);\n }\n\n /**\n * Whether any conditional pills are actually visible at all.\n */\n public get HasConditionalPills(): boolean {\n return this.ConditionalPills.length > 0;\n }\n\n /**\n * True when the conditional chips should collapse into an overflow popover\n * because there are more than the threshold.\n */\n public get UseOverflowPopover(): boolean {\n return this.ConditionalPills.length > this.OVERFLOW_THRESHOLD;\n }\n\n /** Number of currently selected conditional pills (for the popover trigger label). */\n public get SelectedConditionalCount(): number {\n return Object.values(this.ChipSelections).filter(v => v).length;\n }\n\n public ToggleFilterOverflow(): void {\n this.ShowFilterOverflow = !this.ShowFilterOverflow;\n this.cdr.markForCheck();\n }\n\n public CloseFilterOverflow(): void {\n this.ShowFilterOverflow = false;\n this.cdr.markForCheck();\n }\n\n public ClearFilters(): void {\n this.searchTerm = '';\n for (const k of Object.keys(this.ChipSelections)) this.ChipSelections[k] = false;\n this.applyFilters();\n }\n\n /**\n * Builds the list of conditional pills from currently loaded data —\n * a pill only appears for change types/sources that actually exist.\n */\n private rebuildConditionalPills(): void {\n const counts: Record<string, number> = {};\n let restoreCount = 0;\n\n for (const c of this.viewData) {\n const type = c.Type ?? 'Update';\n counts[type] = (counts[type] ?? 0) + 1;\n if (this.isRestoreChange(c)) restoreCount++;\n }\n\n const pills: FilterPill[] = [];\n if ((counts['Update'] ?? 0) > 0) {\n pills.push({ Key: 'Update', Label: 'Updates', Icon: 'fa-pen', Count: counts['Update'], Variant: 'type' });\n }\n if ((counts['Create'] ?? 0) > 0) {\n pills.push({ Key: 'Create', Label: 'Creates', Icon: 'fa-plus', Count: counts['Create'], Variant: 'type' });\n }\n if ((counts['Delete'] ?? 0) > 0) {\n pills.push({ Key: 'Delete', Label: 'Deletes', Icon: 'fa-trash', Count: counts['Delete'], Variant: 'type' });\n }\n if ((counts['Snapshot'] ?? 0) > 0) {\n pills.push({ Key: 'Snapshot', Label: 'Snapshots', Icon: 'fa-camera', Count: counts['Snapshot'], Variant: 'type' });\n }\n if (restoreCount > 0) {\n pills.push({ Key: 'Restore', Label: 'Restored', Icon: 'fa-clock-rotate-left', Count: restoreCount, Variant: 'restore' });\n }\n\n // Initialize/prune selection state\n const validKeys = new Set(pills.map(p => p.Key));\n for (const k of Object.keys(this.ChipSelections)) {\n if (!validKeys.has(k)) delete this.ChipSelections[k];\n }\n for (const p of pills) {\n if (this.ChipSelections[p.Key] === undefined) this.ChipSelections[p.Key] = false;\n }\n\n this.ConditionalPills = pills;\n }\n\n private isRestoreChange(c: MJRecordChangeEntity): boolean {\n return c.Source === 'Restore' || (c as any).RestoredFromID != null;\n }\n\n private applyFilters(): void {\n let filtered = [...this.viewData];\n\n if (this.searchTerm.trim()) {\n const search = this.searchTerm.toLowerCase();\n filtered = filtered.filter(\n change =>\n change.ChangesDescription?.toLowerCase().includes(search) ||\n change.User?.toLowerCase().includes(search) ||\n change.Comments?.toLowerCase().includes(search),\n );\n }\n\n // Apply conditional pill filters — if any are selected, only show changes matching ANY of them (OR semantics).\n const selectedKeys = Object.keys(this.ChipSelections).filter(k => this.ChipSelections[k]);\n if (selectedKeys.length > 0) {\n filtered = filtered.filter(change => {\n for (const key of selectedKeys) {\n if (key === 'Restore') {\n if (this.isRestoreChange(change)) return true;\n } else {\n if (change.Type === key) return true;\n }\n }\n return false;\n });\n }\n\n this.filteredData = filtered;\n this.dateGroups = this.buildDateGroups(this.filteredData);\n this.cdr.markForCheck();\n }\n\n // ─── Version Labels ─────────────────────────────────────────────\n\n public async LoadRecordLabels(): Promise<void> {\n if (!this.record) return;\n\n this.IsLoadingLabels = true;\n this.cdr.markForCheck();\n\n try {\n const entityId = this.record.EntityInfo.ID;\n const recordId = this.record.PrimaryKey.ToConcatenatedString();\n\n const rv = RunView.FromMetadataProvider(this.ProviderToUse);\n const itemsResult = await rv.RunView<{ VersionLabelID: string }>({\n EntityName: 'MJ: Version Label Items',\n Fields: ['VersionLabelID'],\n ExtraFilter: `EntityID='${entityId}' AND RecordID='${recordId}'`,\n ResultType: 'simple',\n });\n\n if (!itemsResult.Success || itemsResult.Results.length === 0) {\n this.ngZone.run(() => {\n this.RecordLabels = [];\n this.IsLoadingLabels = false;\n this.cdr.markForCheck();\n });\n return;\n }\n\n const labelIds = [...new Set(itemsResult.Results.map(i => i.VersionLabelID))];\n const labelIdFilter = labelIds.map(id => `'${id}'`).join(',');\n\n const labelsResult = await rv.RunView<{\n ID: string;\n Name: string;\n Description: string | null;\n Scope: string;\n Status: string;\n ItemCount: number;\n __mj_CreatedAt: Date;\n }>({\n EntityName: 'MJ: Version Labels',\n Fields: ['ID', 'Name', 'Description', 'Scope', 'Status', 'ItemCount', '__mj_CreatedAt'],\n ExtraFilter: `ID IN (${labelIdFilter})`,\n OrderBy: '__mj_CreatedAt DESC',\n ResultType: 'simple',\n });\n\n if (labelsResult.Success) {\n this.RecordLabels = labelsResult.Results.map(l => ({\n ID: l.ID,\n Name: l.Name,\n Description: l.Description,\n Scope: l.Scope,\n Status: l.Status,\n CreatedAt: l.__mj_CreatedAt,\n ItemCount: l.ItemCount,\n }));\n }\n } catch (error) {\n console.error('Error loading version labels for record:', error);\n this.RecordLabels = [];\n } finally {\n this.ngZone.run(() => {\n this.IsLoadingLabels = false;\n this.cdr.markForCheck();\n });\n }\n }\n\n public OpenCreateWizard(): void {\n this.ShowCreateWizard = true;\n this.cdr.markForCheck();\n }\n\n public OnLabelCreated(event: { LabelCount: number; ItemCount: number }): void {\n this.ShowCreateWizard = false;\n this.cdr.markForCheck();\n this.LoadRecordLabels();\n this.mjNotificationService.CreateSimpleNotification(\n `Version label created with ${event.ItemCount} snapshot${event.ItemCount !== 1 ? 's' : ''}`,\n 'info',\n 2000,\n );\n }\n\n public OnLabelCreateCancelled(): void {\n this.ShowCreateWizard = false;\n this.cdr.markForCheck();\n }\n\n public getLabelStatusClass(status: string): string {\n switch (status) {\n case 'Active': return 'label-status-active';\n case 'Archived': return 'label-status-archived';\n case 'Restored': return 'label-status-restored';\n default: return '';\n }\n }\n\n // ─── Timeline Interaction ───────────────────────────────────────\n\n toggleExpansion(changeId: string): void {\n if (this.expandedItems.has(changeId)) {\n this.expandedItems.delete(changeId);\n } else {\n this.expandedItems.add(changeId);\n }\n this.cdr.markForCheck();\n }\n\n onTimelineItemKeydown(event: KeyboardEvent, changeId: string): void {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n this.toggleExpansion(changeId);\n }\n }\n\n /**\n * Opens the embedded restore preview panel for a given change record.\n * The panel computes a full-record diff (current vs the change's\n * FullRecordJSON snapshot) — this is the semantic-correctness fix:\n * we restore TO the state at that point in time, not just undo the\n * one delta the user clicked.\n */\n OnRestoreVersion(change: MJRecordChangeEntity, event: MouseEvent): void {\n event.stopPropagation();\n this.RestorePreviewChange = change;\n this.RestorePreviewVisible = true;\n this.cdr.markForCheck();\n }\n\n /**\n * Called when the user confirms the restore in the embedded panel.\n * Translates the panel's RestoreCommitEvent into the broader-shape\n * RestoreVersionEvent the host is wired to handle.\n */\n OnRestorePanelConfirmed(commit: RestoreCommitEvent): void {\n if (!this.RestorePreviewChange) return;\n\n const change = this.RestorePreviewChange;\n this.IsRestoring = true;\n this.cdr.markForCheck();\n\n this.RestoreRequested.emit({\n SourceChangeID: commit.SourceChangeID,\n ChangedAt: change.ChangedAt,\n ChangedByUser: change.User || '',\n Reason: commit.Reason,\n FieldValues: commit.FieldValues,\n });\n\n // Close the panel after a brief delay so the host has a moment to react.\n setTimeout(() => {\n this.RestorePreviewVisible = false;\n this.RestorePreviewChange = null;\n this.IsRestoring = false;\n this.cdr.markForCheck();\n }, 500);\n }\n\n /**\n * Called when the user dismisses the restore preview without confirming.\n */\n OnRestorePanelCancelled(): void {\n this.RestorePreviewVisible = false;\n this.RestorePreviewChange = null;\n this.cdr.markForCheck();\n }\n\n // ─── Lineage chip ───────────────────────────────────────────────\n\n /**\n * Returns the source change for a given restored row, if found in the\n * currently loaded changes. Returns null when the source isn't loaded\n * (e.g., it's been pruned from history) or when this row isn't a restore.\n */\n public getRestoredFromSourceChange(change: MJRecordChangeEntity): MJRecordChangeEntity | null {\n const sourceId = (change as any).RestoredFromID;\n if (!sourceId) return null;\n return this.viewDataById.get(NormalizeUUID(sourceId)) ?? null;\n }\n\n /**\n * Rebuilds {@link viewDataById} from the current {@link viewData}. Called once\n * per data load so source-change resolution is an O(1) Map read.\n */\n private rebuildViewDataIndex(): void {\n this.viewDataById.clear();\n for (const c of this.viewData) {\n this.viewDataById.set(NormalizeUUID(c.ID), c);\n }\n }\n\n /**\n * True when the row was produced by a restore operation (either the\n * `Source` is `'Restore'` OR `RestoredFromID` is populated).\n */\n public isRestoreRow(change: MJRecordChangeEntity): boolean {\n return this.isRestoreChange(change);\n }\n\n /**\n * True when this change is the most recent in the loaded history.\n * `viewData` is sorted DESC by `ChangedAt`, so the most recent is index 0.\n * Restoring to the most recent version is a no-op, so the timeline hides\n * the Restore button on this row.\n */\n public isMostRecentChange(change: MJRecordChangeEntity): boolean {\n return this.viewData.length > 0 && this.viewData[0] === change;\n }\n\n /**\n * Click handler for the lineage chip — scrolls/highlights the source\n * change row in the timeline. Auto-clears after a few seconds.\n */\n public JumpToSourceChange(sourceChange: MJRecordChangeEntity, event: MouseEvent): void {\n event.stopPropagation();\n this.HighlightedChangeID = sourceChange.ID;\n this.expandedItems.add(sourceChange.ID);\n this.cdr.markForCheck();\n\n // Auto-clear the highlight after 3s\n setTimeout(() => {\n if (this.HighlightedChangeID && UUIDsEqual(this.HighlightedChangeID, sourceChange.ID)) {\n this.HighlightedChangeID = null;\n this.cdr.markForCheck();\n }\n }, 3000);\n\n // Scroll into view\n setTimeout(() => {\n const el = document.querySelector(`[data-change-id=\"${sourceChange.ID}\"]`);\n el?.scrollIntoView({ behavior: 'smooth', block: 'center' });\n }, 50);\n }\n\n // ─── Date Grouping ─────────────────────────────────────────────\n\n private buildDateGroups(changes: MJRecordChangeEntity[]): DateGroup[] {\n const groups = new Map<string, MJRecordChangeEntity[]>();\n\n for (const change of changes) {\n const label = this.formatDateGroupLabel(new Date(change.ChangedAt));\n if (!groups.has(label)) {\n groups.set(label, []);\n }\n groups.get(label)!.push(change);\n }\n\n return Array.from(groups.entries()).map(([label, items]) => ({ label, changes: items }));\n }\n\n private formatDateGroupLabel(date: Date): string {\n const now = new Date();\n const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n const target = new Date(date.getFullYear(), date.getMonth(), date.getDate());\n const diffDays = Math.floor((today.getTime() - target.getTime()) / 86400000);\n\n const formatted = new Intl.DateTimeFormat('en-US', { month: 'short', day: 'numeric', year: 'numeric' }).format(date);\n\n if (diffDays === 0) return `Today \\u2014 ${formatted}`;\n if (diffDays === 1) return `Yesterday \\u2014 ${formatted}`;\n return formatted;\n }\n\n // ─── Display Helpers ────────────────────────────────────────────\n\n getChangeTypeCardClass(type: string): string {\n switch (type) {\n case 'Create': return 'type-create';\n case 'Update': return 'type-update';\n case 'Delete': return 'type-delete';\n case 'Snapshot': return 'type-snapshot';\n default: return 'type-update';\n }\n }\n\n getChangeTypeBadgeText(type: string): string {\n switch (type) {\n case 'Create': return 'Created';\n case 'Delete': return 'Deleted';\n case 'Snapshot': return 'Snapshot';\n default: return type;\n }\n }\n\n /**\n * Badge text for the row's primary type tag. For restore rows we override\n * the underlying `Type='Update'` and show \"Restore\" instead — matches the\n * mockup's intent of treating restore as a first-class operation in the\n * timeline rather than a flavor of update.\n */\n getEffectiveBadgeText(change: MJRecordChangeEntity): string {\n if (this.isRestoreRow(change)) return 'Restore';\n return this.getChangeTypeBadgeText(change.Type);\n }\n\n /**\n * Optional restore reason — pulled from the dynamic `RestoreReason`\n * column added by the lineage migration. Returns null when not present\n * or not a restore row.\n */\n getRestoreReason(change: MJRecordChangeEntity): string | null {\n if (!this.isRestoreRow(change)) return null;\n const reason = (change as unknown as { RestoreReason?: string | null }).RestoreReason;\n return reason && reason.trim().length > 0 ? reason : null;\n }\n\n getSourceClass(source: string): string {\n if (source === 'Restore') return 'source-restore';\n if (source === 'Internal') return 'source-internal';\n return 'source-external';\n }\n\n getStatusClass(status: string): string {\n switch (status) {\n case 'Complete': return 'status-complete';\n case 'Pending': return 'status-pending';\n case 'Error': return 'status-error';\n default: return 'status-unknown';\n }\n }\n\n getTimelineItemLabel(change: MJRecordChangeEntity): string {\n return `${change.Type} by ${change.User || 'Unknown User'} on ${this.formatFullDateTime(change.ChangedAt)}`;\n }\n\n getUserInitials(user: string | null): string {\n if (!user) return '?';\n if (user.includes('@')) {\n const local = user.split('@')[0];\n return local.substring(0, 2).toUpperCase();\n }\n const parts = user.trim().split(/\\s+/);\n if (parts.length >= 2) {\n return (parts[0][0] + parts[1][0]).toUpperCase();\n }\n return user.substring(0, 2).toUpperCase();\n }\n\n getUserDisplayName(user: string | null): string {\n if (!user) return 'Unknown';\n if (user.includes('@')) return user.split('@')[0];\n return user;\n }\n\n getUniqueContributorCount(): number {\n const users = new Set(this.viewData.map(c => c.User).filter(Boolean));\n return users.size;\n }\n\n formatTime(date: Date): string {\n return new Intl.DateTimeFormat('en-US', {\n hour: 'numeric',\n minute: '2-digit',\n hour12: true,\n }).format(new Date(date));\n }\n\n formatRelativeTime(date: Date): string {\n const now = new Date();\n const diffMs = now.getTime() - new Date(date).getTime();\n const diffMins = Math.floor(diffMs / 60000);\n const diffHours = Math.floor(diffMins / 60);\n const diffDays = Math.floor(diffHours / 24);\n\n if (diffMins < 1) return 'Just now';\n if (diffMins < 60) return `${diffMins} min${diffMins > 1 ? 's' : ''} ago`;\n if (diffHours < 24) return `${diffHours} hour${diffHours > 1 ? 's' : ''} ago`;\n if (diffDays < 7) return `${diffDays} day${diffDays > 1 ? 's' : ''} ago`;\n\n return new Intl.DateTimeFormat('en-US', {\n month: 'short',\n day: 'numeric',\n year: diffDays > 365 ? 'numeric' : undefined,\n }).format(new Date(date));\n }\n\n formatFullDateTime(date: Date): string {\n return new Intl.DateTimeFormat('en-US', {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n hour: 'numeric',\n minute: 'numeric',\n hour12: true,\n timeZoneName: 'short',\n }).format(new Date(date));\n }\n\n // ─── Change Summary ─────────────────────────────────────────────\n\n getChangeSummary(change: MJRecordChangeEntity): string {\n // Restore rows get a distinctive summary so the timeline reads like a\n // sentence — \"Restored to 5:56 PM version\" rather than yet another\n // \"Name and Description changed\". The lineage chip carries the full\n // source-version detail.\n if (this.isRestoreRow(change)) {\n const src = this.getRestoredFromSourceChange(change);\n if (src) return `Restored to ${this.formatTime(src.ChangedAt)} version`;\n return 'Restored from earlier version';\n }\n if (change.Type === 'Create') return 'Record created';\n if (change.Type === 'Delete') return 'Record deleted';\n if (change.Type === 'Snapshot') return change.ChangesDescription || 'Snapshot captured';\n\n try {\n const changesJson = JSON.parse(change.ChangesJSON || '{}');\n const fieldNames = this.extractFieldDisplayNames(changesJson);\n if (fieldNames.length === 0) return 'No field changes detected';\n\n return this.buildFieldListSummary(fieldNames);\n } catch {\n return change.ChangesDescription || 'Changes made';\n }\n }\n\n getCreatedFieldCount(change: MJRecordChangeEntity): number {\n try {\n if (!change.FullRecordJSON) return 0;\n const record = JSON.parse(change.FullRecordJSON);\n return this.record.EntityInfo.Fields.filter(\n (f: EntityFieldInfo) => record[f.Name] != null && record[f.Name] !== '',\n ).length;\n } catch {\n return 0;\n }\n }\n\n private extractFieldDisplayNames(changesJson: Record<string, { field?: string }>): string[] {\n return Object.keys(changesJson).map(fieldKey => {\n const changeInfo = changesJson[fieldKey];\n const field = this.record.EntityInfo.Fields.find(\n (f: EntityFieldInfo) => f.Name.trim().toLowerCase() === changeInfo.field?.trim().toLowerCase(),\n );\n return field?.DisplayNameOrName || changeInfo.field || fieldKey;\n });\n }\n\n private buildFieldListSummary(fieldNames: string[]): string {\n if (fieldNames.length === 1) return `${fieldNames[0]} changed`;\n if (fieldNames.length === 2) return `${fieldNames[0]} and ${fieldNames[1]} changed`;\n if (fieldNames.length <= 4) {\n const last = fieldNames[fieldNames.length - 1];\n return `${fieldNames.slice(0, -1).join(', ')}, and ${last} changed`;\n }\n const remaining = fieldNames.length - 3;\n return `${fieldNames.slice(0, 3).join(', ')}, and ${remaining} other field${remaining > 1 ? 's' : ''} changed`;\n }\n\n // ─── Field Changes (type-aware) ────────────────────────────────\n\n getFieldChanges(change: MJRecordChangeEntity): FieldChangeInfo[] {\n try {\n const changesJson = JSON.parse(change.ChangesJSON || '{}');\n return Object.keys(changesJson).map(fieldKey => this.buildFieldChangeInfo(changesJson[fieldKey]));\n } catch {\n return [];\n }\n }\n\n private buildFieldChangeInfo(changeInfo: { field?: string; oldValue?: unknown; newValue?: unknown }): FieldChangeInfo {\n const field = this.record.EntityInfo.Fields.find(\n (f: EntityFieldInfo) => f.Name.trim().toLowerCase() === changeInfo.field?.trim().toLowerCase(),\n );\n\n const fieldType = this.classifyFieldType(field);\n const isDateField = fieldType === 'date';\n const formattedOld = this.formatChangeValue(changeInfo.oldValue, isDateField);\n const formattedNew = this.formatChangeValue(changeInfo.newValue, isDateField);\n\n let diffHtml: SafeHtml | undefined;\n if (fieldType === 'text' && formattedOld !== formattedNew) {\n diffHtml = this.generateDiffHtml(formattedOld, formattedNew);\n }\n\n return {\n field: changeInfo.field || '',\n displayName: field?.DisplayNameOrName || changeInfo.field || '',\n oldValue: formattedOld,\n newValue: formattedNew,\n fieldType,\n diffHtml,\n };\n }\n\n private classifyFieldType(field: EntityFieldInfo | undefined): 'boolean' | 'date' | 'number' | 'text' {\n if (!field) return 'text';\n if (field.TSType === EntityFieldTSType.Boolean) return 'boolean';\n if (field.TSType === EntityFieldTSType.Date) return 'date';\n if (field.TSType === EntityFieldTSType.Number) return 'number';\n return 'text';\n }\n\n getCreatedFields(change: MJRecordChangeEntity): Array<{ name: string; displayName: string; value: string }> {\n try {\n if (!change.FullRecordJSON) return [];\n\n const record = JSON.parse(change.FullRecordJSON);\n const fields = this.record.EntityInfo.Fields;\n\n return fields\n .filter((field: EntityFieldInfo) => record[field.Name] != null && record[field.Name] !== '')\n .map((field: EntityFieldInfo) => ({\n name: field.Name,\n displayName: field.DisplayNameOrName,\n value: this.formatChangeValue(record[field.Name], field.TSType === EntityFieldTSType.Date),\n }));\n } catch {\n return [];\n }\n }\n\n // ─── Value Formatting ───────────────────────────────────────────\n\n private formatChangeValue(value: unknown, isDateField: boolean): string {\n if (value == null) return '';\n\n if (typeof value === 'object') {\n const keys = Object.keys(value as Record<string, unknown>);\n if (keys.length === 0) return '';\n return JSON.stringify(value);\n }\n\n if (isDateField && typeof value === 'string') {\n const date = new Date(value);\n if (!isNaN(date.getTime())) {\n return new Intl.DateTimeFormat('en-US', {\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n hour: 'numeric',\n minute: '2-digit',\n hour12: true,\n }).format(date);\n }\n }\n\n return String(value);\n }\n\n // ─── Diff Generation (text fields only) ─────────────────────────\n\n private generateDiffHtml(oldValue: string, newValue: string): SafeHtml {\n if (!oldValue && !newValue) {\n return this.sanitizer.bypassSecurityTrustHtml('<span class=\"rc-diff-unchanged\">(no change)</span>');\n }\n\n if (!oldValue) {\n return this.sanitizer.bypassSecurityTrustHtml(`<span class=\"rc-diff-added\">${this.escapeHtml(newValue)}</span>`);\n }\n\n if (!newValue) {\n return this.sanitizer.bypassSecurityTrustHtml(`<span class=\"rc-diff-removed\">${this.escapeHtml(oldValue)}</span>`);\n }\n\n const useWordDiff = this.shouldUseWordDiff(oldValue, newValue);\n const diffs = useWordDiff ? diffWords(oldValue, newValue) : diffChars(oldValue, newValue);\n\n const html = diffs\n .map((part: Change) => {\n const escaped = this.escapeHtml(part.value);\n if (part.added) return `<span class=\"rc-diff-added\">${escaped}</span>`;\n if (part.removed) return `<span class=\"rc-diff-removed\">${escaped}</span>`;\n return `<span class=\"rc-diff-unchanged\">${escaped}</span>`;\n })\n .join('');\n\n return this.sanitizer.bypassSecurityTrustHtml(html);\n }\n\n private shouldUseWordDiff(oldValue: string, newValue: string): boolean {\n const hasMultipleWords = (text: string) => text.includes(' ') && text.split(' ').length > 3;\n const isLongText = (text: string) => text.length > 50;\n\n return (hasMultipleWords(oldValue) || hasMultipleWords(newValue)) && (isLongText(oldValue) || isLongText(newValue));\n }\n\n private escapeHtml(text: string): string {\n const div = document.createElement('div');\n div.textContent = text;\n return div.innerHTML;\n }\n}\n","<mj-slide-panel\n [Mode]=\"'slide'\"\n [Title]=\"'Record Changes History'\"\n [Visible]=\"IsVisible\"\n [Resizable]=\"true\"\n [MinWidthPx]=\"400\"\n [MaxWidthRatio]=\"0.6\"\n (Closed)=\"OnClose()\">\n\n @if (IsLoading) {\n <mj-loading text=\"Loading history...\" size=\"medium\"></mj-loading>\n }\n\n @if (!IsLoading) {\n <div class=\"rc-container\">\n <!-- Version Labels Section -->\n <div class=\"rc-labels-section\">\n <div class=\"rc-labels-header\">\n <div class=\"rc-labels-title\">\n <i class=\"fa-solid fa-tags\" aria-hidden=\"true\"></i>\n <span>Version Labels</span>\n @if (RecordLabels.length > 0) {\n <span class=\"rc-labels-count\">{{ RecordLabels.length }}</span>\n }\n </div>\n <button class=\"rc-create-label-btn\" (click)=\"OpenCreateWizard()\" title=\"Create a version label for this record\">\n <i class=\"fa-solid fa-plus\"></i> Create Label\n </button>\n </div>\n @if (IsLoadingLabels) {\n <div class=\"rc-labels-loading\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Loading labels...\n </div>\n } @else if (RecordLabels.length === 0) {\n <mj-empty-state class=\"rc-labels-empty\" Size=\"compact\"\n Icon=\"\" Title=\"No version labels for this record yet.\" />\n } @else {\n <div class=\"rc-labels-list\">\n @for (label of RecordLabels; track label.ID) {\n <div class=\"rc-label-chip\" [title]=\"label.Description || label.Name\">\n <i class=\"fa-solid fa-tag rc-label-chip-icon\"></i>\n <span class=\"rc-label-chip-name\">{{ label.Name }}</span>\n <span class=\"rc-label-chip-meta\">\n <span class=\"rc-label-chip-status\" [class]=\"getLabelStatusClass(label.Status)\">{{ label.Status }}</span>\n <span class=\"rc-label-chip-items\">{{ label.ItemCount }} item{{ label.ItemCount !== 1 ? 's' : '' }}</span>\n </span>\n </div>\n }\n </div>\n }\n </div>\n\n @if (viewData.length === 0) {\n <!-- Empty state -->\n <mj-empty-state\n Icon=\"fa-solid fa-clock-rotate-left\"\n Title=\"No Change History\"\n Message=\"This record doesn't have any tracked changes yet. Changes will appear here automatically as edits are made.\"\n Size=\"large\">\n <div class=\"rc-empty-state-hint\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n <span>Record change tracking is managed at the entity level</span>\n </div>\n </mj-empty-state>\n } @else {\n <!-- Page Header -->\n <div class=\"rc-page-header\">\n <div>\n <h2 class=\"rc-page-title\">Change History</h2>\n <div class=\"rc-page-subtitle\">{{ record.EntityInfo.Name }}</div>\n </div>\n <div class=\"rc-header-meta\">\n <div class=\"rc-entity-badge\">\n <i class=\"fa-solid fa-database\" aria-hidden=\"true\"></i>\n {{ record.EntityInfo.Name }}\n </div>\n <div class=\"rc-change-count\">{{ viewData.length }} change{{ viewData.length !== 1 ? 's' : '' }} &middot; {{ getUniqueContributorCount() }} contributor{{ getUniqueContributorCount() !== 1 ? 's' : '' }}</div>\n </div>\n </div>\n\n <!-- Filter Bar — chips render only for change types/sources actually present in loaded data.\n When more than 2 conditional chips would render, they collapse into a \"More filters\" popover. -->\n <div class=\"rc-filter-bar\">\n <div class=\"rc-search-wrap\">\n <i class=\"fa-solid fa-search\" aria-hidden=\"true\"></i>\n <input\n class=\"rc-search-box\"\n type=\"text\"\n placeholder=\"Search changes...\"\n [(ngModel)]=\"searchTerm\"\n (input)=\"onSearchChange()\"\n aria-label=\"Search record changes\"\n />\n </div>\n\n <button class=\"rc-filter-pill\" [class.active]=\"IsAllSelected\" (click)=\"SelectAllPill()\" type=\"button\">\n <i class=\"fa-solid fa-layer-group\" aria-hidden=\"true\"></i> All\n </button>\n\n @if (HasConditionalPills) {\n @if (!UseOverflowPopover) {\n <!-- 1-2 conditional pills: render inline -->\n @for (pill of ConditionalPills; track pill.Key) {\n <button class=\"rc-filter-pill\"\n [class.active]=\"ChipSelections[pill.Key]\"\n [class.rc-filter-pill-restore]=\"pill.Variant === 'restore'\"\n (click)=\"TogglePill(pill.Key)\"\n type=\"button\">\n <i class=\"fa-solid {{ pill.Icon }}\" aria-hidden=\"true\"></i>\n {{ pill.Label }}\n <span class=\"rc-filter-pill-count\">{{ pill.Count }}</span>\n </button>\n }\n } @else {\n <!-- 3+ conditional pills: overflow popover -->\n <div class=\"rc-filter-overflow-wrap\">\n <button class=\"rc-filter-pill rc-filter-pill-overflow\"\n [class.active]=\"SelectedConditionalCount > 0\"\n (click)=\"ToggleFilterOverflow()\"\n type=\"button\">\n <i class=\"fa-solid fa-sliders\" aria-hidden=\"true\"></i>\n More filters\n @if (SelectedConditionalCount > 0) {\n <span class=\"rc-filter-pill-count\">{{ SelectedConditionalCount }}</span>\n }\n <i class=\"fa-solid fa-chevron-down rc-filter-overflow-caret\" aria-hidden=\"true\"></i>\n </button>\n\n @if (ShowFilterOverflow) {\n <!-- Backdrop: clicks close the popover -->\n <div class=\"rc-filter-overflow-backdrop\" (click)=\"CloseFilterOverflow()\"></div>\n <div class=\"rc-filter-overflow-popover\" role=\"menu\">\n <div class=\"rc-filter-overflow-header\">Filter by</div>\n @for (pill of ConditionalPills; track pill.Key) {\n <label class=\"rc-filter-overflow-row\" [class.rc-filter-overflow-row-restore]=\"pill.Variant === 'restore'\">\n <input type=\"checkbox\"\n [checked]=\"ChipSelections[pill.Key]\"\n (change)=\"TogglePill(pill.Key)\" />\n <i class=\"fa-solid {{ pill.Icon }}\" aria-hidden=\"true\"></i>\n <span class=\"rc-filter-overflow-label\">{{ pill.Label }}</span>\n <span class=\"rc-filter-overflow-count\">{{ pill.Count }}</span>\n </label>\n }\n <div class=\"rc-filter-overflow-actions\">\n <button class=\"rc-filter-overflow-clear\" (click)=\"SelectAllPill(); CloseFilterOverflow()\" type=\"button\">\n Clear all\n </button>\n <button class=\"rc-filter-overflow-done\" (click)=\"CloseFilterOverflow()\" type=\"button\">\n Done\n </button>\n </div>\n </div>\n }\n </div>\n }\n }\n </div>\n\n @if (filteredData.length !== viewData.length) {\n <div class=\"rc-filter-results\">\n Showing {{ filteredData.length }} of {{ viewData.length }} changes\n <button class=\"rc-clear-filters-link\" (click)=\"ClearFilters()\">Clear filters</button>\n </div>\n }\n\n <!-- Timeline -->\n <div class=\"rc-timeline\" [attr.aria-label]=\"'Timeline of changes for ' + record.EntityInfo.Name + ' record'\">\n @if (filteredData.length === 0) {\n <mj-empty-state\n Variant=\"no-results\"\n Icon=\"fa-solid fa-filter\"\n Title=\"No changes match your current filters\"\n ActionText=\"Clear filters\"\n ActionIcon=\"fa-solid fa-rotate-left\"\n (Action)=\"ClearFilters()\" />\n } @else {\n @for (group of dateGroups; track group.label) {\n <div class=\"rc-date-group\">\n <div class=\"rc-date-label\">{{ group.label }}</div>\n\n @for (change of group.changes; track change.ID) {\n <div\n class=\"rc-card\"\n [attr.data-change-id]=\"change.ID\"\n [class]=\"getChangeTypeCardClass(change.Type)\"\n [class.expanded]=\"expandedItems.has(change.ID)\"\n [class.rc-card-restore]=\"isRestoreRow(change)\"\n [class.rc-card-highlight]=\"HighlightedChangeID === change.ID\"\n [attr.tabindex]=\"0\"\n [attr.aria-expanded]=\"expandedItems.has(change.ID)\"\n [attr.aria-label]=\"getTimelineItemLabel(change)\"\n (keydown)=\"onTimelineItemKeydown($event, change.ID)\"\n >\n <!-- Card Header -->\n <div class=\"rc-card-header\" (click)=\"toggleExpansion(change.ID)\">\n <div class=\"rc-card-header-left\">\n <span class=\"rc-card-type-badge\"\n [class.rc-card-type-badge-restore]=\"isRestoreRow(change)\">{{ getEffectiveBadgeText(change) }}</span>\n <span class=\"rc-card-summary\">{{ getChangeSummary(change) }}</span>\n\n <!-- Lineage chip — visible when this row was produced by a restore -->\n @if (isRestoreRow(change)) {\n @if (getRestoredFromSourceChange(change); as srcChange) {\n <a class=\"rc-restored-chip\"\n (click)=\"JumpToSourceChange(srcChange, $event)\"\n [title]=\"'Jump to source version (' + formatFullDateTime(srcChange.ChangedAt) + ')'\">\n <i class=\"fa-solid fa-link\" aria-hidden=\"true\"></i>\n Restored from {{ formatTime(srcChange.ChangedAt) }} {{ srcChange.ChangedAt ? 'on ' + (srcChange.ChangedAt | date:'mediumDate') : '' }}\n @if (srcChange.User) {\n by {{ getUserDisplayName(srcChange.User) }}\n }\n </a>\n } @else {\n <span class=\"rc-restored-chip rc-restored-chip-orphan\"\n title=\"Source version was not loaded into this view\">\n <i class=\"fa-solid fa-clock-rotate-left\" aria-hidden=\"true\"></i>\n Restored from earlier version\n </span>\n }\n }\n </div>\n <div class=\"rc-card-meta\">\n <div class=\"rc-card-user\">\n <div class=\"rc-avatar\">{{ getUserInitials(change.User) }}</div>\n {{ getUserDisplayName(change.User) }}\n </div>\n <span class=\"rc-card-time\" [title]=\"formatFullDateTime(change.ChangedAt)\">{{ formatTime(change.ChangedAt) }}</span>\n <span class=\"rc-card-source\" [class]=\"getSourceClass(change.Source)\">{{ change.Source }}</span>\n <span class=\"rc-card-status\" [class]=\"getStatusClass(change.Status)\">{{ change.Status }}</span>\n <i class=\"fa-solid fa-chevron-down rc-card-chevron\" aria-hidden=\"true\"></i>\n </div>\n </div>\n\n <!-- Card Body (expanded) -->\n @if (expandedItems.has(change.ID)) {\n <div class=\"rc-card-body\">\n <!-- Restore reason (when present) — Notion/Linear-style\n blockquote: a thin violet left bar + italic text,\n with a tiny \"Reason\" prefix. No box, no header,\n no large vertical footprint. Reads as a\n justification note rather than a callout. -->\n @if (getRestoreReason(change); as reason) {\n <blockquote class=\"rc-restore-reason\">\n <span class=\"rc-restore-reason-label\">Reason</span>\n <span class=\"rc-restore-reason-text\">{{ reason }}</span>\n </blockquote>\n }\n\n @if (change.Type === 'Create') {\n @if (change.FullRecordJSON) {\n @for (field of getCreatedFields(change); track field.name) {\n <div class=\"rc-field-row\">\n <div class=\"rc-field-label\">{{ field.displayName }}</div>\n <div class=\"rc-field-values\">\n <span class=\"rc-val-new\">{{ field.value }}</span>\n </div>\n </div>\n }\n }\n } @else if (change.Type === 'Delete') {\n <div class=\"rc-deletion-note\">\n <i class=\"fa-solid fa-trash\" aria-hidden=\"true\"></i>\n This record was permanently removed from the system.\n </div>\n } @else {\n <!-- Update / Snapshot / Restore: type-aware field changes -->\n @for (fc of getFieldChanges(change); track fc.field) {\n <div class=\"rc-field-row\">\n <div class=\"rc-field-label\">{{ fc.displayName }}</div>\n <div class=\"rc-field-values\">\n @if (fc.fieldType === 'boolean') {\n <div class=\"rc-bool-change\">\n <span class=\"rc-bool-dot\" [class.on]=\"fc.oldValue === 'true' || fc.oldValue === '1'\" [class.off]=\"fc.oldValue !== 'true' && fc.oldValue !== '1'\"></span>\n <span class=\"rc-bool-label old\">{{ fc.oldValue === 'true' || fc.oldValue === '1' ? 'Yes' : 'No' }}</span>\n <i class=\"fa-solid fa-arrow-right rc-val-arrow\" aria-hidden=\"true\"></i>\n <span class=\"rc-bool-dot\" [class.on]=\"fc.newValue === 'true' || fc.newValue === '1'\" [class.off]=\"fc.newValue !== 'true' && fc.newValue !== '1'\"></span>\n <span class=\"rc-bool-label new\" [class.active]=\"fc.newValue === 'true' || fc.newValue === '1'\" [class.inactive]=\"fc.newValue !== 'true' && fc.newValue !== '1'\">{{ fc.newValue === 'true' || fc.newValue === '1' ? 'Yes' : 'No' }}</span>\n </div>\n } @else if (fc.fieldType === 'date' || fc.fieldType === 'number') {\n <div class=\"rc-atomic-change\">\n <span class=\"rc-val-old\">{{ fc.oldValue || '(empty)' }}</span>\n <i class=\"fa-solid fa-arrow-right rc-val-arrow\" aria-hidden=\"true\"></i>\n <span class=\"rc-val-new\">{{ fc.newValue || '(empty)' }}</span>\n </div>\n } @else if (fc.diffHtml) {\n <div class=\"rc-text-diff\" [innerHTML]=\"fc.diffHtml\"></div>\n } @else {\n <div class=\"rc-atomic-change\">\n <span class=\"rc-val-old\">{{ fc.oldValue || '(empty)' }}</span>\n <i class=\"fa-solid fa-arrow-right rc-val-arrow\" aria-hidden=\"true\"></i>\n <span class=\"rc-val-new\">{{ fc.newValue || '(empty)' }}</span>\n </div>\n }\n </div>\n </div>\n }\n }\n\n @if (change.Comments) {\n <div class=\"rc-comments\">\n <i class=\"fa-solid fa-comment\" aria-hidden=\"true\"></i>\n {{ change.Comments }}\n </div>\n }\n\n @if (change.ErrorLog) {\n <div class=\"rc-errors\">\n <i class=\"fa-solid fa-exclamation-triangle\" aria-hidden=\"true\"></i>\n <pre class=\"rc-error-log\">{{ change.ErrorLog }}</pre>\n </div>\n }\n\n <!-- Restore action: shown for Update, Create, and Snapshot rows.\n Hidden on Delete rows (handled via the Recycle Bin path)\n and on the most recent change (restoring to current state is a no-op). -->\n @if (AllowRestore && change.Type !== 'Delete' && !isMostRecentChange(change)) {\n <div class=\"rc-restore-action\">\n <button class=\"rc-restore-btn\"\n (click)=\"OnRestoreVersion(change, $event)\"\n title=\"Restore the entire record to its state at this version\">\n <i class=\"fa-solid fa-clock-rotate-left\" aria-hidden=\"true\"></i>\n Restore record to this version\n </button>\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n }\n </div>\n }\n </div>\n }\n\n <!-- Restore preview slide-in (reusable component) -->\n <mj-restore-preview-panel\n [Visible]=\"RestorePreviewVisible\"\n [Mode]=\"'live'\"\n [RecordChange]=\"RestorePreviewChange\"\n [LiveRecord]=\"record\"\n (RestoreConfirmed)=\"OnRestorePanelConfirmed($event)\"\n (RestoreCancelled)=\"OnRestorePanelCancelled()\">\n </mj-restore-preview-panel>\n\n @if (ShowCreateWizard) {\n <div class=\"rc-wizard-overlay\" (click)=\"OnLabelCreateCancelled()\">\n <div class=\"rc-wizard-container\" (click)=\"$event.stopPropagation()\">\n <mj-label-create\n [PreselectedEntity]=\"record.EntityInfo\"\n [PreselectedRecordIds]=\"[record.PrimaryKey.KeyValuePairs[0].Value]\"\n (Created)=\"OnLabelCreated($event)\"\n (Cancel)=\"OnLabelCreateCancelled()\">\n </mj-label-create>\n </div>\n </div>\n }\n</mj-slide-panel>\n"]}
1
+ {"version":3,"file":"ng-record-changes.component.js","sourceRoot":"","sources":["../../src/lib/ng-record-changes.component.ts","../../src/lib/ng-record-changes.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n EventEmitter,\n Input,\n OnDestroy,\n OnInit,\n Output,\n ChangeDetectorRef,\n ChangeDetectionStrategy,\n ViewEncapsulation,\n NgZone,\n} from '@angular/core';\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\nimport { Subscription } from 'rxjs';\nimport {\n BaseEntity,\n BaseEntityEvent,\n CompositeKey,\n EntityFieldInfo,\n EntityFieldTSType,\n RunView,\n} from '@memberjunction/core';\nimport { UUIDsEqual, NormalizeUUID } from '@memberjunction/global';\nimport { MJRecordChangeEntity } from '@memberjunction/core-entities';\nimport { FormatChangeValue } from './format-change-value';\nimport { MJNotificationService } from '@memberjunction/ng-notifications';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nimport { diffChars, diffWords, Change } from 'diff';\nimport { RestoreCommitEvent } from './restore-preview-panel/restore-preview-panel.component';\n\n/** Lightweight shape for displaying a version label associated with this record */\ninterface RecordLabel {\n ID: string;\n Name: string;\n Description: string | null;\n Scope: string;\n Status: string;\n CreatedAt: Date;\n ItemCount: number;\n}\n\n/**\n * Event payload emitted when the user confirms a restore.\n *\n * The host component (typically `record-form-container`) is responsible for:\n * 1. Reloading the live record (concurrency safety),\n * 2. Calling `record.SetRestoreContext(SourceChangeID, Reason)`,\n * 3. Calling `record.Set(FieldName, Value)` for each entry in `FieldValues`,\n * 4. Calling `record.Save()`,\n * 5. Calling `record.ClearRestoreContext()` after the save returns.\n *\n * The provider will write a new RecordChange row with `Source='Restore'`,\n * `RestoredFromID = SourceChangeID`, and `RestoreReason = Reason` —\n * producing the auditable lineage chain.\n */\nexport interface RestoreVersionEvent {\n /** ID of the historical RecordChange row whose state is being restored. */\n SourceChangeID: string;\n /** When the historical change was made. */\n ChangedAt: Date;\n /** Display name / email of who made the historical change. */\n ChangedByUser: string;\n /** Optional user-entered reason for the restore. */\n Reason: string | null;\n /** Selected field values, ready to pass to BaseEntity.Set(). */\n FieldValues: Array<{ FieldName: string; Value: unknown }>;\n}\n\n/** A single field change with type-aware rendering info (timeline display only). */\nexport interface FieldChangeInfo {\n field: string;\n displayName: string;\n oldValue: string;\n newValue: string;\n fieldType: 'boolean' | 'date' | 'number' | 'text';\n diffHtml?: SafeHtml;\n}\n\n/** A group of changes that share the same date. */\nexport interface DateGroup {\n label: string;\n changes: MJRecordChangeEntity[];\n}\n\n/** A conditional filter pill (one per type/source actually present in loaded data). */\nexport interface FilterPill {\n /** Unique key for selection state ('Update', 'Create', 'Delete', 'Snapshot', 'Restore'). */\n Key: string;\n /** User-facing label (pluralized: 'Updates', 'Restored', etc.). */\n Label: string;\n /** Font Awesome icon class. */\n Icon: string;\n /** Number of changes of this kind in the loaded data. */\n Count: number;\n /** Selection style — neutral type pill or violet restore pill. */\n Variant: 'type' | 'restore';\n}\n\n/**\n * Slide-out timeline of all changes to a single record. Hosts the reusable\n * {@link RestorePreviewPanelComponent} for the actual restore confirmation\n * flow, and exposes a `RestoreRequested` event the host can act on to\n * persist the restore.\n *\n * @example\n * <mj-record-changes\n * [record]=\"myEntity\"\n * [AllowRestore]=\"true\"\n * (dialogClosed)=\"showHistory = false\"\n * (RestoreRequested)=\"onRestoreRequested($event)\">\n * </mj-record-changes>\n */\n@Component({\n standalone: false,\n selector: 'mj-record-changes',\n templateUrl: './ng-record-changes.component.html',\n styleUrls: ['./ng-record-changes.component.css'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n})\nexport class RecordChangesComponent extends BaseAngularComponent implements OnInit, OnDestroy {\n public IsLoading = false;\n public IsVisible = false;\n @Output() dialogClosed = new EventEmitter();\n @Input() record!: BaseEntity;\n\n /** Whether to show a \"Restore\" button on each historical version row. Default false. */\n @Input() AllowRestore = false;\n\n /**\n * Emitted when the user confirms a restore in the preview panel.\n * The host is responsible for applying the snapshot to the record and\n * saving with `record.SetRestoreContext()` set first.\n */\n @Output() RestoreRequested = new EventEmitter<RestoreVersionEvent>();\n\n viewData: MJRecordChangeEntity[] = [];\n filteredData: MJRecordChangeEntity[] = [];\n\n /**\n * Change lookup keyed by NormalizeUUID(ID), rebuilt whenever {@link viewData}\n * loads. Lets {@link getRestoredFromSourceChange} resolve a restore row's\n * source change in O(1) instead of an O(rows) `UUIDsEqual` scan — which was\n * previously executed twice per restore row per CD cycle (once in the\n * template `@if` and once inside `getChangeSummary`), giving O(rows^2)/CD.\n */\n private viewDataById = new Map<string, MJRecordChangeEntity>();\n dateGroups: DateGroup[] = [];\n expandedItems: Set<string> = new Set();\n\n /** The change record currently selected for restore preview, or null. */\n RestorePreviewChange: MJRecordChangeEntity | null = null;\n /** Visibility of the embedded restore preview slide-in. */\n RestorePreviewVisible = false;\n /** Whether the restore commit is in progress (between confirmation and host response). */\n IsRestoring = false;\n\n // Version label state\n RecordLabels: RecordLabel[] = [];\n IsLoadingLabels = false;\n ShowCreateWizard = false;\n\n // Filter properties\n searchTerm = '';\n /** Single selected type filter (legacy, kept for backwards compat). */\n selectedType = '';\n selectedSource = '';\n /** Map of Key → selected, used by the conditional chip system. */\n ChipSelections: Record<string, boolean> = {};\n /** Whether the overflow popover is open. */\n ShowFilterOverflow = false;\n /** Highlighted change ID for the lineage-jump indicator (transient). */\n HighlightedChangeID: string | null = null;\n\n /**\n * Conditional filter pills derived from loaded data. Always includes 'All'\n * implicitly. Other pills only render when at least one matching change\n * exists. Overflows into a popover when the count exceeds 2.\n */\n ConditionalPills: FilterPill[] = [];\n\n /** Threshold above which conditional chips collapse into the overflow popover. */\n private readonly OVERFLOW_THRESHOLD = 2;\n\n /**\n * Subscription to the record's BaseEntity event stream. We listen for\n * 'save' events and auto-refresh the timeline so the user immediately\n * sees the new RecordChange row produced by either a normal save or a\n * restore. Cleaned up in ngOnDestroy.\n */\n private _entitySaveSub: Subscription | null = null;\n\n constructor(\n private cdr: ChangeDetectorRef,\n private ngZone: NgZone,\n private mjNotificationService: MJNotificationService,\n private sanitizer: DomSanitizer,\n ) { super(); }\n\n ngOnInit(): void {\n if (this.record) {\n this.IsLoading = true;\n this.IsVisible = true;\n this.cdr.markForCheck();\n this.LoadRecordChanges(this.record.PrimaryKey, '', this.record.EntityInfo.Name);\n this.LoadRecordLabels();\n this.subscribeToRecordSaves();\n }\n }\n\n ngOnDestroy(): void {\n this._entitySaveSub?.unsubscribe();\n this._entitySaveSub = null;\n }\n\n /**\n * Wires up an event handler on the live record so the timeline auto-\n * refreshes immediately after any save lands — including the one\n * produced by the restore flow. Without this the user sees their record\n * update in the form but the panel above still shows the pre-restore\n * change list, which is confusing.\n */\n private subscribeToRecordSaves(): void {\n if (!this.record) return;\n this._entitySaveSub?.unsubscribe();\n this._entitySaveSub = this.record.RegisterEventHandler((event: BaseEntityEvent) => {\n if (event?.type === 'save') {\n this.ngZone.run(() => this.Refresh());\n }\n });\n }\n\n /**\n * Reloads the record changes list from the database.\n * Called by the parent container after a save completes while the drawer is open.\n */\n public Refresh(): void {\n if (this.record) {\n this.IsLoading = true;\n this.cdr.markForCheck();\n this.LoadRecordChanges(this.record.PrimaryKey, '', this.record.EntityInfo.Name);\n }\n }\n\n public OnClose(): void {\n this.IsVisible = false;\n this.cdr.markForCheck();\n // Allow the slide-out animation to complete before emitting\n setTimeout(() => this.dialogClosed.emit(), 300);\n }\n\n public async LoadRecordChanges(pkey: CompositeKey, appName: string, entityName: string): Promise<void> {\n if (pkey && entityName) {\n const md = this.ProviderToUse;\n const entityInfo = md.EntityByName(entityName);\n let changes: MJRecordChangeEntity[] = [];\n if (entityInfo?.TrackRecordChanges) {\n const rvResult = await RunView.FromMetadataProvider(md).RunView<MJRecordChangeEntity>({\n EntityName: 'MJ: Record Changes',\n ExtraFilter: `Entity='${entityName}' AND RecordID='${pkey.ToConcatenatedString()}'`,\n OrderBy: 'ChangedAt DESC',\n ResultType: 'entity_object',\n });\n if (rvResult.Success) changes = rvResult.Results;\n }\n this.ngZone.run(() => {\n if (changes) {\n this.viewData = changes.sort(\n (a: MJRecordChangeEntity, b: MJRecordChangeEntity) => new Date(b.ChangedAt).getTime() - new Date(a.ChangedAt).getTime(),\n );\n this.rebuildViewDataIndex();\n this.rebuildConditionalPills();\n this.applyFilters();\n this.IsLoading = false;\n } else {\n this.mjNotificationService.CreateSimpleNotification(\n `Error loading record changes for ${entityName} with primary key ${pkey.ToString()}.`,\n 'error',\n );\n this.IsLoading = false;\n }\n this.cdr.markForCheck();\n });\n }\n }\n\n // ─── Filter & Search ────────────────────────────────────────────\n\n onSearchChange(): void {\n this.applyFilters();\n }\n\n onFilterChange(): void {\n this.applyFilters();\n }\n\n /**\n * Toggles the \"All\" pill — clears every conditional selection.\n */\n public SelectAllPill(): void {\n for (const k of Object.keys(this.ChipSelections)) this.ChipSelections[k] = false;\n this.applyFilters();\n }\n\n /**\n * Toggles a conditional pill on/off.\n */\n public TogglePill(key: string): void {\n this.ChipSelections[key] = !this.ChipSelections[key];\n this.applyFilters();\n }\n\n /**\n * Returns true when no conditional pills are selected (i.e. \"All\" mode).\n */\n public get IsAllSelected(): boolean {\n return !Object.values(this.ChipSelections).some(v => v);\n }\n\n /**\n * Whether any conditional pills are actually visible at all.\n */\n public get HasConditionalPills(): boolean {\n return this.ConditionalPills.length > 0;\n }\n\n /**\n * True when the conditional chips should collapse into an overflow popover\n * because there are more than the threshold.\n */\n public get UseOverflowPopover(): boolean {\n return this.ConditionalPills.length > this.OVERFLOW_THRESHOLD;\n }\n\n /** Number of currently selected conditional pills (for the popover trigger label). */\n public get SelectedConditionalCount(): number {\n return Object.values(this.ChipSelections).filter(v => v).length;\n }\n\n public ToggleFilterOverflow(): void {\n this.ShowFilterOverflow = !this.ShowFilterOverflow;\n this.cdr.markForCheck();\n }\n\n public CloseFilterOverflow(): void {\n this.ShowFilterOverflow = false;\n this.cdr.markForCheck();\n }\n\n public ClearFilters(): void {\n this.searchTerm = '';\n for (const k of Object.keys(this.ChipSelections)) this.ChipSelections[k] = false;\n this.applyFilters();\n }\n\n /**\n * Builds the list of conditional pills from currently loaded data —\n * a pill only appears for change types/sources that actually exist.\n */\n private rebuildConditionalPills(): void {\n const counts: Record<string, number> = {};\n let restoreCount = 0;\n\n for (const c of this.viewData) {\n const type = c.Type ?? 'Update';\n counts[type] = (counts[type] ?? 0) + 1;\n if (this.isRestoreChange(c)) restoreCount++;\n }\n\n const pills: FilterPill[] = [];\n if ((counts['Update'] ?? 0) > 0) {\n pills.push({ Key: 'Update', Label: 'Updates', Icon: 'fa-pen', Count: counts['Update'], Variant: 'type' });\n }\n if ((counts['Create'] ?? 0) > 0) {\n pills.push({ Key: 'Create', Label: 'Creates', Icon: 'fa-plus', Count: counts['Create'], Variant: 'type' });\n }\n if ((counts['Delete'] ?? 0) > 0) {\n pills.push({ Key: 'Delete', Label: 'Deletes', Icon: 'fa-trash', Count: counts['Delete'], Variant: 'type' });\n }\n if ((counts['Snapshot'] ?? 0) > 0) {\n pills.push({ Key: 'Snapshot', Label: 'Snapshots', Icon: 'fa-camera', Count: counts['Snapshot'], Variant: 'type' });\n }\n if (restoreCount > 0) {\n pills.push({ Key: 'Restore', Label: 'Restored', Icon: 'fa-clock-rotate-left', Count: restoreCount, Variant: 'restore' });\n }\n\n // Initialize/prune selection state\n const validKeys = new Set(pills.map(p => p.Key));\n for (const k of Object.keys(this.ChipSelections)) {\n if (!validKeys.has(k)) delete this.ChipSelections[k];\n }\n for (const p of pills) {\n if (this.ChipSelections[p.Key] === undefined) this.ChipSelections[p.Key] = false;\n }\n\n this.ConditionalPills = pills;\n }\n\n private isRestoreChange(c: MJRecordChangeEntity): boolean {\n return c.Source === 'Restore' || (c as any).RestoredFromID != null;\n }\n\n private applyFilters(): void {\n let filtered = [...this.viewData];\n\n if (this.searchTerm.trim()) {\n const search = this.searchTerm.toLowerCase();\n filtered = filtered.filter(\n change =>\n change.ChangesDescription?.toLowerCase().includes(search) ||\n change.User?.toLowerCase().includes(search) ||\n change.Comments?.toLowerCase().includes(search),\n );\n }\n\n // Apply conditional pill filters — if any are selected, only show changes matching ANY of them (OR semantics).\n const selectedKeys = Object.keys(this.ChipSelections).filter(k => this.ChipSelections[k]);\n if (selectedKeys.length > 0) {\n filtered = filtered.filter(change => {\n for (const key of selectedKeys) {\n if (key === 'Restore') {\n if (this.isRestoreChange(change)) return true;\n } else {\n if (change.Type === key) return true;\n }\n }\n return false;\n });\n }\n\n this.filteredData = filtered;\n this.dateGroups = this.buildDateGroups(this.filteredData);\n this.cdr.markForCheck();\n }\n\n // ─── Version Labels ─────────────────────────────────────────────\n\n public async LoadRecordLabels(): Promise<void> {\n if (!this.record) return;\n\n this.IsLoadingLabels = true;\n this.cdr.markForCheck();\n\n try {\n const entityId = this.record.EntityInfo.ID;\n const recordId = this.record.PrimaryKey.ToConcatenatedString();\n\n const rv = RunView.FromMetadataProvider(this.ProviderToUse);\n const itemsResult = await rv.RunView<{ VersionLabelID: string }>({\n EntityName: 'MJ: Version Label Items',\n Fields: ['VersionLabelID'],\n ExtraFilter: `EntityID='${entityId}' AND RecordID='${recordId}'`,\n ResultType: 'simple',\n });\n\n if (!itemsResult.Success || itemsResult.Results.length === 0) {\n this.ngZone.run(() => {\n this.RecordLabels = [];\n this.IsLoadingLabels = false;\n this.cdr.markForCheck();\n });\n return;\n }\n\n const labelIds = [...new Set(itemsResult.Results.map(i => i.VersionLabelID))];\n const labelIdFilter = labelIds.map(id => `'${id}'`).join(',');\n\n const labelsResult = await rv.RunView<{\n ID: string;\n Name: string;\n Description: string | null;\n Scope: string;\n Status: string;\n ItemCount: number;\n __mj_CreatedAt: Date;\n }>({\n EntityName: 'MJ: Version Labels',\n Fields: ['ID', 'Name', 'Description', 'Scope', 'Status', 'ItemCount', '__mj_CreatedAt'],\n ExtraFilter: `ID IN (${labelIdFilter})`,\n OrderBy: '__mj_CreatedAt DESC',\n ResultType: 'simple',\n });\n\n if (labelsResult.Success) {\n this.RecordLabels = labelsResult.Results.map(l => ({\n ID: l.ID,\n Name: l.Name,\n Description: l.Description,\n Scope: l.Scope,\n Status: l.Status,\n CreatedAt: l.__mj_CreatedAt,\n ItemCount: l.ItemCount,\n }));\n }\n } catch (error) {\n console.error('Error loading version labels for record:', error);\n this.RecordLabels = [];\n } finally {\n this.ngZone.run(() => {\n this.IsLoadingLabels = false;\n this.cdr.markForCheck();\n });\n }\n }\n\n public OpenCreateWizard(): void {\n this.ShowCreateWizard = true;\n this.cdr.markForCheck();\n }\n\n public OnLabelCreated(event: { LabelCount: number; ItemCount: number }): void {\n this.ShowCreateWizard = false;\n this.cdr.markForCheck();\n this.LoadRecordLabels();\n this.mjNotificationService.CreateSimpleNotification(\n `Version label created with ${event.ItemCount} snapshot${event.ItemCount !== 1 ? 's' : ''}`,\n 'info',\n 2000,\n );\n }\n\n public OnLabelCreateCancelled(): void {\n this.ShowCreateWizard = false;\n this.cdr.markForCheck();\n }\n\n public getLabelStatusClass(status: string): string {\n switch (status) {\n case 'Active': return 'label-status-active';\n case 'Archived': return 'label-status-archived';\n case 'Restored': return 'label-status-restored';\n default: return '';\n }\n }\n\n // ─── Timeline Interaction ───────────────────────────────────────\n\n toggleExpansion(changeId: string): void {\n if (this.expandedItems.has(changeId)) {\n this.expandedItems.delete(changeId);\n } else {\n this.expandedItems.add(changeId);\n }\n this.cdr.markForCheck();\n }\n\n onTimelineItemKeydown(event: KeyboardEvent, changeId: string): void {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n this.toggleExpansion(changeId);\n }\n }\n\n /**\n * Opens the embedded restore preview panel for a given change record.\n * The panel computes a full-record diff (current vs the change's\n * FullRecordJSON snapshot) — this is the semantic-correctness fix:\n * we restore TO the state at that point in time, not just undo the\n * one delta the user clicked.\n */\n OnRestoreVersion(change: MJRecordChangeEntity, event: MouseEvent): void {\n event.stopPropagation();\n this.RestorePreviewChange = change;\n this.RestorePreviewVisible = true;\n this.cdr.markForCheck();\n }\n\n /**\n * Called when the user confirms the restore in the embedded panel.\n * Translates the panel's RestoreCommitEvent into the broader-shape\n * RestoreVersionEvent the host is wired to handle.\n */\n OnRestorePanelConfirmed(commit: RestoreCommitEvent): void {\n if (!this.RestorePreviewChange) return;\n\n const change = this.RestorePreviewChange;\n this.IsRestoring = true;\n this.cdr.markForCheck();\n\n this.RestoreRequested.emit({\n SourceChangeID: commit.SourceChangeID,\n ChangedAt: change.ChangedAt,\n ChangedByUser: change.User || '',\n Reason: commit.Reason,\n FieldValues: commit.FieldValues,\n });\n\n // Close the panel after a brief delay so the host has a moment to react.\n setTimeout(() => {\n this.RestorePreviewVisible = false;\n this.RestorePreviewChange = null;\n this.IsRestoring = false;\n this.cdr.markForCheck();\n }, 500);\n }\n\n /**\n * Called when the user dismisses the restore preview without confirming.\n */\n OnRestorePanelCancelled(): void {\n this.RestorePreviewVisible = false;\n this.RestorePreviewChange = null;\n this.cdr.markForCheck();\n }\n\n // ─── Lineage chip ───────────────────────────────────────────────\n\n /**\n * Returns the source change for a given restored row, if found in the\n * currently loaded changes. Returns null when the source isn't loaded\n * (e.g., it's been pruned from history) or when this row isn't a restore.\n */\n public getRestoredFromSourceChange(change: MJRecordChangeEntity): MJRecordChangeEntity | null {\n const sourceId = (change as any).RestoredFromID;\n if (!sourceId) return null;\n return this.viewDataById.get(NormalizeUUID(sourceId)) ?? null;\n }\n\n /**\n * Rebuilds {@link viewDataById} from the current {@link viewData}. Called once\n * per data load so source-change resolution is an O(1) Map read.\n */\n private rebuildViewDataIndex(): void {\n this.viewDataById.clear();\n for (const c of this.viewData) {\n this.viewDataById.set(NormalizeUUID(c.ID), c);\n }\n }\n\n /**\n * True when the row was produced by a restore operation (either the\n * `Source` is `'Restore'` OR `RestoredFromID` is populated).\n */\n public isRestoreRow(change: MJRecordChangeEntity): boolean {\n return this.isRestoreChange(change);\n }\n\n /**\n * True when this change is the most recent in the loaded history.\n * `viewData` is sorted DESC by `ChangedAt`, so the most recent is index 0.\n * Restoring to the most recent version is a no-op, so the timeline hides\n * the Restore button on this row.\n */\n public isMostRecentChange(change: MJRecordChangeEntity): boolean {\n return this.viewData.length > 0 && this.viewData[0] === change;\n }\n\n /**\n * Click handler for the lineage chip — scrolls/highlights the source\n * change row in the timeline. Auto-clears after a few seconds.\n */\n public JumpToSourceChange(sourceChange: MJRecordChangeEntity, event: MouseEvent): void {\n event.stopPropagation();\n this.HighlightedChangeID = sourceChange.ID;\n this.expandedItems.add(sourceChange.ID);\n this.cdr.markForCheck();\n\n // Auto-clear the highlight after 3s\n setTimeout(() => {\n if (this.HighlightedChangeID && UUIDsEqual(this.HighlightedChangeID, sourceChange.ID)) {\n this.HighlightedChangeID = null;\n this.cdr.markForCheck();\n }\n }, 3000);\n\n // Scroll into view\n setTimeout(() => {\n const el = document.querySelector(`[data-change-id=\"${sourceChange.ID}\"]`);\n el?.scrollIntoView({ behavior: 'smooth', block: 'center' });\n }, 50);\n }\n\n // ─── Date Grouping ─────────────────────────────────────────────\n\n private buildDateGroups(changes: MJRecordChangeEntity[]): DateGroup[] {\n const groups = new Map<string, MJRecordChangeEntity[]>();\n\n for (const change of changes) {\n const label = this.formatDateGroupLabel(new Date(change.ChangedAt));\n if (!groups.has(label)) {\n groups.set(label, []);\n }\n groups.get(label)!.push(change);\n }\n\n return Array.from(groups.entries()).map(([label, items]) => ({ label, changes: items }));\n }\n\n private formatDateGroupLabel(date: Date): string {\n const now = new Date();\n const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n const target = new Date(date.getFullYear(), date.getMonth(), date.getDate());\n const diffDays = Math.floor((today.getTime() - target.getTime()) / 86400000);\n\n const formatted = new Intl.DateTimeFormat('en-US', { month: 'short', day: 'numeric', year: 'numeric' }).format(date);\n\n if (diffDays === 0) return `Today \\u2014 ${formatted}`;\n if (diffDays === 1) return `Yesterday \\u2014 ${formatted}`;\n return formatted;\n }\n\n // ─── Display Helpers ────────────────────────────────────────────\n\n getChangeTypeCardClass(type: string): string {\n switch (type) {\n case 'Create': return 'type-create';\n case 'Update': return 'type-update';\n case 'Delete': return 'type-delete';\n case 'Snapshot': return 'type-snapshot';\n default: return 'type-update';\n }\n }\n\n getChangeTypeBadgeText(type: string): string {\n switch (type) {\n case 'Create': return 'Created';\n case 'Delete': return 'Deleted';\n case 'Snapshot': return 'Snapshot';\n default: return type;\n }\n }\n\n /**\n * Badge text for the row's primary type tag. For restore rows we override\n * the underlying `Type='Update'` and show \"Restore\" instead — matches the\n * mockup's intent of treating restore as a first-class operation in the\n * timeline rather than a flavor of update.\n */\n getEffectiveBadgeText(change: MJRecordChangeEntity): string {\n if (this.isRestoreRow(change)) return 'Restore';\n return this.getChangeTypeBadgeText(change.Type);\n }\n\n /**\n * Optional restore reason — pulled from the dynamic `RestoreReason`\n * column added by the lineage migration. Returns null when not present\n * or not a restore row.\n */\n getRestoreReason(change: MJRecordChangeEntity): string | null {\n if (!this.isRestoreRow(change)) return null;\n const reason = (change as unknown as { RestoreReason?: string | null }).RestoreReason;\n return reason && reason.trim().length > 0 ? reason : null;\n }\n\n getSourceClass(source: string): string {\n if (source === 'Restore') return 'source-restore';\n if (source === 'Internal') return 'source-internal';\n return 'source-external';\n }\n\n getStatusClass(status: string): string {\n switch (status) {\n case 'Complete': return 'status-complete';\n case 'Pending': return 'status-pending';\n case 'Error': return 'status-error';\n default: return 'status-unknown';\n }\n }\n\n getTimelineItemLabel(change: MJRecordChangeEntity): string {\n return `${change.Type} by ${change.User || 'Unknown User'} on ${this.formatFullDateTime(change.ChangedAt)}`;\n }\n\n getUserInitials(user: string | null): string {\n if (!user) return '?';\n if (user.includes('@')) {\n const local = user.split('@')[0];\n return local.substring(0, 2).toUpperCase();\n }\n const parts = user.trim().split(/\\s+/);\n if (parts.length >= 2) {\n return (parts[0][0] + parts[1][0]).toUpperCase();\n }\n return user.substring(0, 2).toUpperCase();\n }\n\n getUserDisplayName(user: string | null): string {\n if (!user) return 'Unknown';\n if (user.includes('@')) return user.split('@')[0];\n return user;\n }\n\n getUniqueContributorCount(): number {\n const users = new Set(this.viewData.map(c => c.User).filter(Boolean));\n return users.size;\n }\n\n formatTime(date: Date): string {\n return new Intl.DateTimeFormat('en-US', {\n hour: 'numeric',\n minute: '2-digit',\n hour12: true,\n }).format(new Date(date));\n }\n\n formatRelativeTime(date: Date): string {\n const now = new Date();\n const diffMs = now.getTime() - new Date(date).getTime();\n const diffMins = Math.floor(diffMs / 60000);\n const diffHours = Math.floor(diffMins / 60);\n const diffDays = Math.floor(diffHours / 24);\n\n if (diffMins < 1) return 'Just now';\n if (diffMins < 60) return `${diffMins} min${diffMins > 1 ? 's' : ''} ago`;\n if (diffHours < 24) return `${diffHours} hour${diffHours > 1 ? 's' : ''} ago`;\n if (diffDays < 7) return `${diffDays} day${diffDays > 1 ? 's' : ''} ago`;\n\n return new Intl.DateTimeFormat('en-US', {\n month: 'short',\n day: 'numeric',\n year: diffDays > 365 ? 'numeric' : undefined,\n }).format(new Date(date));\n }\n\n formatFullDateTime(date: Date): string {\n return new Intl.DateTimeFormat('en-US', {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n hour: 'numeric',\n minute: 'numeric',\n hour12: true,\n timeZoneName: 'short',\n }).format(new Date(date));\n }\n\n // ─── Change Summary ─────────────────────────────────────────────\n\n getChangeSummary(change: MJRecordChangeEntity): string {\n // Restore rows get a distinctive summary so the timeline reads like a\n // sentence — \"Restored to 5:56 PM version\" rather than yet another\n // \"Name and Description changed\". The lineage chip carries the full\n // source-version detail.\n if (this.isRestoreRow(change)) {\n const src = this.getRestoredFromSourceChange(change);\n if (src) return `Restored to ${this.formatTime(src.ChangedAt)} version`;\n return 'Restored from earlier version';\n }\n if (change.Type === 'Create') return 'Record created';\n if (change.Type === 'Delete') return 'Record deleted';\n if (change.Type === 'Snapshot') return change.ChangesDescription || 'Snapshot captured';\n\n try {\n const changesJson = JSON.parse(change.ChangesJSON || '{}');\n const fieldNames = this.extractFieldDisplayNames(changesJson);\n if (fieldNames.length === 0) return 'No field changes detected';\n\n return this.buildFieldListSummary(fieldNames);\n } catch {\n return change.ChangesDescription || 'Changes made';\n }\n }\n\n getCreatedFieldCount(change: MJRecordChangeEntity): number {\n try {\n if (!change.FullRecordJSON) return 0;\n const record = JSON.parse(change.FullRecordJSON);\n return this.record.EntityInfo.Fields.filter(\n (f: EntityFieldInfo) => record[f.Name] != null && record[f.Name] !== '',\n ).length;\n } catch {\n return 0;\n }\n }\n\n private extractFieldDisplayNames(changesJson: Record<string, { field?: string }>): string[] {\n return Object.keys(changesJson).map(fieldKey => {\n const changeInfo = changesJson[fieldKey];\n const field = this.record.EntityInfo.Fields.find(\n (f: EntityFieldInfo) => f.Name.trim().toLowerCase() === changeInfo.field?.trim().toLowerCase(),\n );\n return field?.DisplayNameOrName || changeInfo.field || fieldKey;\n });\n }\n\n private buildFieldListSummary(fieldNames: string[]): string {\n if (fieldNames.length === 1) return `${fieldNames[0]} changed`;\n if (fieldNames.length === 2) return `${fieldNames[0]} and ${fieldNames[1]} changed`;\n if (fieldNames.length <= 4) {\n const last = fieldNames[fieldNames.length - 1];\n return `${fieldNames.slice(0, -1).join(', ')}, and ${last} changed`;\n }\n const remaining = fieldNames.length - 3;\n return `${fieldNames.slice(0, 3).join(', ')}, and ${remaining} other field${remaining > 1 ? 's' : ''} changed`;\n }\n\n // ─── Field Changes (type-aware) ────────────────────────────────\n\n getFieldChanges(change: MJRecordChangeEntity): FieldChangeInfo[] {\n try {\n const changesJson = JSON.parse(change.ChangesJSON || '{}');\n return Object.keys(changesJson).map(fieldKey => this.buildFieldChangeInfo(changesJson[fieldKey]));\n } catch {\n return [];\n }\n }\n\n private buildFieldChangeInfo(changeInfo: { field?: string; oldValue?: unknown; newValue?: unknown }): FieldChangeInfo {\n const field = this.record.EntityInfo.Fields.find(\n (f: EntityFieldInfo) => f.Name.trim().toLowerCase() === changeInfo.field?.trim().toLowerCase(),\n );\n\n const fieldType = this.classifyFieldType(field);\n const formattedOld = FormatChangeValue(changeInfo.oldValue, field);\n const formattedNew = FormatChangeValue(changeInfo.newValue, field);\n\n let diffHtml: SafeHtml | undefined;\n if (fieldType === 'text' && formattedOld !== formattedNew) {\n diffHtml = this.generateDiffHtml(formattedOld, formattedNew);\n }\n\n return {\n field: changeInfo.field || '',\n displayName: field?.DisplayNameOrName || changeInfo.field || '',\n oldValue: formattedOld,\n newValue: formattedNew,\n fieldType,\n diffHtml,\n };\n }\n\n private classifyFieldType(field: EntityFieldInfo | undefined): 'boolean' | 'date' | 'number' | 'text' {\n if (!field) return 'text';\n if (field.TSType === EntityFieldTSType.Boolean) return 'boolean';\n if (field.TSType === EntityFieldTSType.Date) return 'date';\n if (field.TSType === EntityFieldTSType.Number) return 'number';\n return 'text';\n }\n\n getCreatedFields(change: MJRecordChangeEntity): Array<{ name: string; displayName: string; value: string }> {\n try {\n if (!change.FullRecordJSON) return [];\n\n const record = JSON.parse(change.FullRecordJSON);\n const fields = this.record.EntityInfo.Fields;\n\n return fields\n .filter((field: EntityFieldInfo) => record[field.Name] != null && record[field.Name] !== '')\n .map((field: EntityFieldInfo) => ({\n name: field.Name,\n displayName: field.DisplayNameOrName,\n value: FormatChangeValue(record[field.Name], field),\n }));\n } catch {\n return [];\n }\n }\n\n // ─── Value Formatting ───────────────────────────────────────────\n\n // ─── Diff Generation (text fields only) ─────────────────────────\n\n private generateDiffHtml(oldValue: string, newValue: string): SafeHtml {\n if (!oldValue && !newValue) {\n return this.sanitizer.bypassSecurityTrustHtml('<span class=\"rc-diff-unchanged\">(no change)</span>');\n }\n\n if (!oldValue) {\n return this.sanitizer.bypassSecurityTrustHtml(`<span class=\"rc-diff-added\">${this.escapeHtml(newValue)}</span>`);\n }\n\n if (!newValue) {\n return this.sanitizer.bypassSecurityTrustHtml(`<span class=\"rc-diff-removed\">${this.escapeHtml(oldValue)}</span>`);\n }\n\n const useWordDiff = this.shouldUseWordDiff(oldValue, newValue);\n const diffs = useWordDiff ? diffWords(oldValue, newValue) : diffChars(oldValue, newValue);\n\n const html = diffs\n .map((part: Change) => {\n const escaped = this.escapeHtml(part.value);\n if (part.added) return `<span class=\"rc-diff-added\">${escaped}</span>`;\n if (part.removed) return `<span class=\"rc-diff-removed\">${escaped}</span>`;\n return `<span class=\"rc-diff-unchanged\">${escaped}</span>`;\n })\n .join('');\n\n return this.sanitizer.bypassSecurityTrustHtml(html);\n }\n\n private shouldUseWordDiff(oldValue: string, newValue: string): boolean {\n const hasMultipleWords = (text: string) => text.includes(' ') && text.split(' ').length > 3;\n const isLongText = (text: string) => text.length > 50;\n\n return (hasMultipleWords(oldValue) || hasMultipleWords(newValue)) && (isLongText(oldValue) || isLongText(newValue));\n }\n\n private escapeHtml(text: string): string {\n const div = document.createElement('div');\n div.textContent = text;\n return div.innerHTML;\n }\n}\n","<mj-slide-panel\n [Mode]=\"'slide'\"\n [Title]=\"'Record Changes History'\"\n [Visible]=\"IsVisible\"\n [Resizable]=\"true\"\n [MinWidthPx]=\"400\"\n [MaxWidthRatio]=\"0.6\"\n (Closed)=\"OnClose()\">\n\n @if (IsLoading) {\n <mj-loading text=\"Loading history...\" size=\"medium\"></mj-loading>\n }\n\n @if (!IsLoading) {\n <div class=\"rc-container\">\n <!-- Version Labels Section -->\n <div class=\"rc-labels-section\">\n <div class=\"rc-labels-header\">\n <div class=\"rc-labels-title\">\n <i class=\"fa-solid fa-tags\" aria-hidden=\"true\"></i>\n <span>Version Labels</span>\n @if (RecordLabels.length > 0) {\n <span class=\"rc-labels-count\">{{ RecordLabels.length }}</span>\n }\n </div>\n <button class=\"rc-create-label-btn\" (click)=\"OpenCreateWizard()\" title=\"Create a version label for this record\">\n <i class=\"fa-solid fa-plus\"></i> Create Label\n </button>\n </div>\n @if (IsLoadingLabels) {\n <div class=\"rc-labels-loading\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Loading labels...\n </div>\n } @else if (RecordLabels.length === 0) {\n <mj-empty-state class=\"rc-labels-empty\" Size=\"compact\"\n Icon=\"\" Title=\"No version labels for this record yet.\" />\n } @else {\n <div class=\"rc-labels-list\">\n @for (label of RecordLabels; track label.ID) {\n <div class=\"rc-label-chip\" [title]=\"label.Description || label.Name\">\n <i class=\"fa-solid fa-tag rc-label-chip-icon\"></i>\n <span class=\"rc-label-chip-name\">{{ label.Name }}</span>\n <span class=\"rc-label-chip-meta\">\n <span class=\"rc-label-chip-status\" [class]=\"getLabelStatusClass(label.Status)\">{{ label.Status }}</span>\n <span class=\"rc-label-chip-items\">{{ label.ItemCount }} item{{ label.ItemCount !== 1 ? 's' : '' }}</span>\n </span>\n </div>\n }\n </div>\n }\n </div>\n\n @if (viewData.length === 0) {\n <!-- Empty state -->\n <mj-empty-state\n Icon=\"fa-solid fa-clock-rotate-left\"\n Title=\"No Change History\"\n Message=\"This record doesn't have any tracked changes yet. Changes will appear here automatically as edits are made.\"\n Size=\"large\">\n <div class=\"rc-empty-state-hint\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n <span>Record change tracking is managed at the entity level</span>\n </div>\n </mj-empty-state>\n } @else {\n <!-- Page Header -->\n <div class=\"rc-page-header\">\n <div>\n <h2 class=\"rc-page-title\">Change History</h2>\n <div class=\"rc-page-subtitle\">{{ record.EntityInfo.Name }}</div>\n </div>\n <div class=\"rc-header-meta\">\n <div class=\"rc-entity-badge\">\n <i class=\"fa-solid fa-database\" aria-hidden=\"true\"></i>\n {{ record.EntityInfo.Name }}\n </div>\n <div class=\"rc-change-count\">{{ viewData.length }} change{{ viewData.length !== 1 ? 's' : '' }} &middot; {{ getUniqueContributorCount() }} contributor{{ getUniqueContributorCount() !== 1 ? 's' : '' }}</div>\n </div>\n </div>\n\n <!-- Filter Bar — chips render only for change types/sources actually present in loaded data.\n When more than 2 conditional chips would render, they collapse into a \"More filters\" popover. -->\n <div class=\"rc-filter-bar\">\n <div class=\"rc-search-wrap\">\n <i class=\"fa-solid fa-search\" aria-hidden=\"true\"></i>\n <input\n class=\"rc-search-box\"\n type=\"text\"\n placeholder=\"Search changes...\"\n [(ngModel)]=\"searchTerm\"\n (input)=\"onSearchChange()\"\n aria-label=\"Search record changes\"\n />\n </div>\n\n <button class=\"rc-filter-pill\" [class.active]=\"IsAllSelected\" (click)=\"SelectAllPill()\" type=\"button\">\n <i class=\"fa-solid fa-layer-group\" aria-hidden=\"true\"></i> All\n </button>\n\n @if (HasConditionalPills) {\n @if (!UseOverflowPopover) {\n <!-- 1-2 conditional pills: render inline -->\n @for (pill of ConditionalPills; track pill.Key) {\n <button class=\"rc-filter-pill\"\n [class.active]=\"ChipSelections[pill.Key]\"\n [class.rc-filter-pill-restore]=\"pill.Variant === 'restore'\"\n (click)=\"TogglePill(pill.Key)\"\n type=\"button\">\n <i class=\"fa-solid {{ pill.Icon }}\" aria-hidden=\"true\"></i>\n {{ pill.Label }}\n <span class=\"rc-filter-pill-count\">{{ pill.Count }}</span>\n </button>\n }\n } @else {\n <!-- 3+ conditional pills: overflow popover -->\n <div class=\"rc-filter-overflow-wrap\">\n <button class=\"rc-filter-pill rc-filter-pill-overflow\"\n [class.active]=\"SelectedConditionalCount > 0\"\n (click)=\"ToggleFilterOverflow()\"\n type=\"button\">\n <i class=\"fa-solid fa-sliders\" aria-hidden=\"true\"></i>\n More filters\n @if (SelectedConditionalCount > 0) {\n <span class=\"rc-filter-pill-count\">{{ SelectedConditionalCount }}</span>\n }\n <i class=\"fa-solid fa-chevron-down rc-filter-overflow-caret\" aria-hidden=\"true\"></i>\n </button>\n\n @if (ShowFilterOverflow) {\n <!-- Backdrop: clicks close the popover -->\n <div class=\"rc-filter-overflow-backdrop\" (click)=\"CloseFilterOverflow()\"></div>\n <div class=\"rc-filter-overflow-popover\" role=\"menu\">\n <div class=\"rc-filter-overflow-header\">Filter by</div>\n @for (pill of ConditionalPills; track pill.Key) {\n <label class=\"rc-filter-overflow-row\" [class.rc-filter-overflow-row-restore]=\"pill.Variant === 'restore'\">\n <input type=\"checkbox\"\n [checked]=\"ChipSelections[pill.Key]\"\n (change)=\"TogglePill(pill.Key)\" />\n <i class=\"fa-solid {{ pill.Icon }}\" aria-hidden=\"true\"></i>\n <span class=\"rc-filter-overflow-label\">{{ pill.Label }}</span>\n <span class=\"rc-filter-overflow-count\">{{ pill.Count }}</span>\n </label>\n }\n <div class=\"rc-filter-overflow-actions\">\n <button class=\"rc-filter-overflow-clear\" (click)=\"SelectAllPill(); CloseFilterOverflow()\" type=\"button\">\n Clear all\n </button>\n <button class=\"rc-filter-overflow-done\" (click)=\"CloseFilterOverflow()\" type=\"button\">\n Done\n </button>\n </div>\n </div>\n }\n </div>\n }\n }\n </div>\n\n @if (filteredData.length !== viewData.length) {\n <div class=\"rc-filter-results\">\n Showing {{ filteredData.length }} of {{ viewData.length }} changes\n <button class=\"rc-clear-filters-link\" (click)=\"ClearFilters()\">Clear filters</button>\n </div>\n }\n\n <!-- Timeline -->\n <div class=\"rc-timeline\" [attr.aria-label]=\"'Timeline of changes for ' + record.EntityInfo.Name + ' record'\">\n @if (filteredData.length === 0) {\n <mj-empty-state\n Variant=\"no-results\"\n Icon=\"fa-solid fa-filter\"\n Title=\"No changes match your current filters\"\n ActionText=\"Clear filters\"\n ActionIcon=\"fa-solid fa-rotate-left\"\n (Action)=\"ClearFilters()\" />\n } @else {\n @for (group of dateGroups; track group.label) {\n <div class=\"rc-date-group\">\n <div class=\"rc-date-label\">{{ group.label }}</div>\n\n @for (change of group.changes; track change.ID) {\n <div\n class=\"rc-card\"\n [attr.data-change-id]=\"change.ID\"\n [class]=\"getChangeTypeCardClass(change.Type)\"\n [class.expanded]=\"expandedItems.has(change.ID)\"\n [class.rc-card-restore]=\"isRestoreRow(change)\"\n [class.rc-card-highlight]=\"HighlightedChangeID === change.ID\"\n [attr.tabindex]=\"0\"\n [attr.aria-expanded]=\"expandedItems.has(change.ID)\"\n [attr.aria-label]=\"getTimelineItemLabel(change)\"\n (keydown)=\"onTimelineItemKeydown($event, change.ID)\"\n >\n <!-- Card Header -->\n <div class=\"rc-card-header\" (click)=\"toggleExpansion(change.ID)\">\n <div class=\"rc-card-header-left\">\n <span class=\"rc-card-type-badge\"\n [class.rc-card-type-badge-restore]=\"isRestoreRow(change)\">{{ getEffectiveBadgeText(change) }}</span>\n <span class=\"rc-card-summary\">{{ getChangeSummary(change) }}</span>\n\n <!-- Lineage chip — visible when this row was produced by a restore -->\n @if (isRestoreRow(change)) {\n @if (getRestoredFromSourceChange(change); as srcChange) {\n <a class=\"rc-restored-chip\"\n (click)=\"JumpToSourceChange(srcChange, $event)\"\n [title]=\"'Jump to source version (' + formatFullDateTime(srcChange.ChangedAt) + ')'\">\n <i class=\"fa-solid fa-link\" aria-hidden=\"true\"></i>\n Restored from {{ formatTime(srcChange.ChangedAt) }} {{ srcChange.ChangedAt ? 'on ' + (srcChange.ChangedAt | date:'mediumDate') : '' }}\n @if (srcChange.User) {\n by {{ getUserDisplayName(srcChange.User) }}\n }\n </a>\n } @else {\n <span class=\"rc-restored-chip rc-restored-chip-orphan\"\n title=\"Source version was not loaded into this view\">\n <i class=\"fa-solid fa-clock-rotate-left\" aria-hidden=\"true\"></i>\n Restored from earlier version\n </span>\n }\n }\n </div>\n <div class=\"rc-card-meta\">\n <div class=\"rc-card-user\">\n <div class=\"rc-avatar\">{{ getUserInitials(change.User) }}</div>\n {{ getUserDisplayName(change.User) }}\n </div>\n <span class=\"rc-card-time\" [title]=\"formatFullDateTime(change.ChangedAt)\">{{ formatTime(change.ChangedAt) }}</span>\n <span class=\"rc-card-source\" [class]=\"getSourceClass(change.Source)\">{{ change.Source }}</span>\n <span class=\"rc-card-status\" [class]=\"getStatusClass(change.Status)\">{{ change.Status }}</span>\n <i class=\"fa-solid fa-chevron-down rc-card-chevron\" aria-hidden=\"true\"></i>\n </div>\n </div>\n\n <!-- Card Body (expanded) -->\n @if (expandedItems.has(change.ID)) {\n <div class=\"rc-card-body\">\n <!-- Restore reason (when present) — Notion/Linear-style\n blockquote: a thin violet left bar + italic text,\n with a tiny \"Reason\" prefix. No box, no header,\n no large vertical footprint. Reads as a\n justification note rather than a callout. -->\n @if (getRestoreReason(change); as reason) {\n <blockquote class=\"rc-restore-reason\">\n <span class=\"rc-restore-reason-label\">Reason</span>\n <span class=\"rc-restore-reason-text\">{{ reason }}</span>\n </blockquote>\n }\n\n @if (change.Type === 'Create') {\n @if (change.FullRecordJSON) {\n @for (field of getCreatedFields(change); track field.name) {\n <div class=\"rc-field-row\">\n <div class=\"rc-field-label\">{{ field.displayName }}</div>\n <div class=\"rc-field-values\">\n <span class=\"rc-val-new\">{{ field.value }}</span>\n </div>\n </div>\n }\n }\n } @else if (change.Type === 'Delete') {\n <div class=\"rc-deletion-note\">\n <i class=\"fa-solid fa-trash\" aria-hidden=\"true\"></i>\n This record was permanently removed from the system.\n </div>\n } @else {\n <!-- Update / Snapshot / Restore: type-aware field changes -->\n @for (fc of getFieldChanges(change); track fc.field) {\n <div class=\"rc-field-row\">\n <div class=\"rc-field-label\">{{ fc.displayName }}</div>\n <div class=\"rc-field-values\">\n @if (fc.fieldType === 'boolean') {\n <div class=\"rc-bool-change\">\n <span class=\"rc-bool-dot\" [class.on]=\"fc.oldValue === 'true' || fc.oldValue === '1'\" [class.off]=\"fc.oldValue !== 'true' && fc.oldValue !== '1'\"></span>\n <span class=\"rc-bool-label old\">{{ fc.oldValue === 'true' || fc.oldValue === '1' ? 'Yes' : 'No' }}</span>\n <i class=\"fa-solid fa-arrow-right rc-val-arrow\" aria-hidden=\"true\"></i>\n <span class=\"rc-bool-dot\" [class.on]=\"fc.newValue === 'true' || fc.newValue === '1'\" [class.off]=\"fc.newValue !== 'true' && fc.newValue !== '1'\"></span>\n <span class=\"rc-bool-label new\" [class.active]=\"fc.newValue === 'true' || fc.newValue === '1'\" [class.inactive]=\"fc.newValue !== 'true' && fc.newValue !== '1'\">{{ fc.newValue === 'true' || fc.newValue === '1' ? 'Yes' : 'No' }}</span>\n </div>\n } @else if (fc.fieldType === 'date' || fc.fieldType === 'number') {\n <div class=\"rc-atomic-change\">\n <span class=\"rc-val-old\">{{ fc.oldValue || '(empty)' }}</span>\n <i class=\"fa-solid fa-arrow-right rc-val-arrow\" aria-hidden=\"true\"></i>\n <span class=\"rc-val-new\">{{ fc.newValue || '(empty)' }}</span>\n </div>\n } @else if (fc.diffHtml) {\n <div class=\"rc-text-diff\" [innerHTML]=\"fc.diffHtml\"></div>\n } @else {\n <div class=\"rc-atomic-change\">\n <span class=\"rc-val-old\">{{ fc.oldValue || '(empty)' }}</span>\n <i class=\"fa-solid fa-arrow-right rc-val-arrow\" aria-hidden=\"true\"></i>\n <span class=\"rc-val-new\">{{ fc.newValue || '(empty)' }}</span>\n </div>\n }\n </div>\n </div>\n }\n }\n\n @if (change.Comments) {\n <div class=\"rc-comments\">\n <i class=\"fa-solid fa-comment\" aria-hidden=\"true\"></i>\n {{ change.Comments }}\n </div>\n }\n\n @if (change.ErrorLog) {\n <div class=\"rc-errors\">\n <i class=\"fa-solid fa-exclamation-triangle\" aria-hidden=\"true\"></i>\n <pre class=\"rc-error-log\">{{ change.ErrorLog }}</pre>\n </div>\n }\n\n <!-- Restore action: shown for Update, Create, and Snapshot rows.\n Hidden on Delete rows (handled via the Recycle Bin path)\n and on the most recent change (restoring to current state is a no-op). -->\n @if (AllowRestore && change.Type !== 'Delete' && !isMostRecentChange(change)) {\n <div class=\"rc-restore-action\">\n <button class=\"rc-restore-btn\"\n (click)=\"OnRestoreVersion(change, $event)\"\n title=\"Restore the entire record to its state at this version\">\n <i class=\"fa-solid fa-clock-rotate-left\" aria-hidden=\"true\"></i>\n Restore record to this version\n </button>\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n }\n </div>\n }\n </div>\n }\n\n <!-- Restore preview slide-in (reusable component) -->\n <mj-restore-preview-panel\n [Visible]=\"RestorePreviewVisible\"\n [Mode]=\"'live'\"\n [RecordChange]=\"RestorePreviewChange\"\n [LiveRecord]=\"record\"\n (RestoreConfirmed)=\"OnRestorePanelConfirmed($event)\"\n (RestoreCancelled)=\"OnRestorePanelCancelled()\">\n </mj-restore-preview-panel>\n\n @if (ShowCreateWizard) {\n <div class=\"rc-wizard-overlay\" (click)=\"OnLabelCreateCancelled()\">\n <div class=\"rc-wizard-container\" (click)=\"$event.stopPropagation()\">\n <mj-label-create\n [PreselectedEntity]=\"record.EntityInfo\"\n [PreselectedRecordIds]=\"[record.PrimaryKey.KeyValuePairs[0].Value]\"\n (Created)=\"OnLabelCreated($event)\"\n (Cancel)=\"OnLabelCreateCancelled()\">\n </mj-label-create>\n </div>\n </div>\n }\n</mj-slide-panel>\n"]}
@@ -258,13 +258,14 @@ export declare class RestorePreviewPanelComponent extends BaseAngularComponent i
258
258
  private rebuildRows;
259
259
  private buildRowFromSnapshot;
260
260
  private getCurrentFieldValue;
261
+ /** The live record's raw value for a field, or `undefined` when there is no live record or field. */
262
+ private getCurrentRawValue;
261
263
  private parseSnapshot;
262
264
  /**
263
265
  * Resolves the entity metadata. Prefers LiveRecord.EntityInfo (always
264
266
  * accurate). Falls back to looking up by EntityName. Memoized.
265
267
  */
266
268
  private resolveEntityInfo;
267
- private formatValue;
268
269
  private recountSelected;
269
270
  formatTimestamp(date: Date | null): string;
270
271
  static ɵfac: i0.ɵɵFactoryDeclaration<RestorePreviewPanelComponent, never>;
@@ -1 +1 @@
1
- {"version":3,"file":"restore-preview-panel.component.d.ts","sourceRoot":"","sources":["../../../src/lib/restore-preview-panel/restore-preview-panel.component.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"restore-preview-panel.component.d.ts","sourceRoot":"","sources":["../../../src/lib/restore-preview-panel/restore-preview-panel.component.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { Component, ChangeDetectionStrategy, EventEmitter, Input, Output, ViewEncapsulation, } from '@angular/core';
2
- import { EntityFieldTSType, } from '@memberjunction/core';
2
+ import { ChangeValuesMatch, FormatChangeValue } from '../format-change-value';
3
3
  import { BaseAngularComponent } from '@memberjunction/ng-base-types';
4
4
  import * as i0 from "@angular/core";
5
5
  import * as i1 from "@angular/forms";
@@ -627,14 +627,15 @@ export class RestorePreviewPanelComponent extends BaseAngularComponent {
627
627
  return null;
628
628
  const isImmutable = !!field && (field.ReadOnly || field.IsPrimaryKey);
629
629
  const isMissingInSchema = !field;
630
- const isDateField = field?.TSType === EntityFieldTSType.Date;
631
- const formattedRestore = this.formatValue(snapshotValue, isDateField);
630
+ const formattedRestore = FormatChangeValue(snapshotValue, field);
632
631
  const formattedCurrent = this.Mode === 'undelete'
633
632
  ? ''
634
- : this.getCurrentFieldValue(fieldName, isDateField);
633
+ : this.getCurrentFieldValue(fieldName, field);
634
+ // Compared by value, not by the display strings: those drop seconds, so a timestamp that moved
635
+ // by under a minute would read as unchanged and be left out of the restore.
635
636
  const isChanged = this.Mode === 'undelete'
636
637
  ? snapshotValue != null && snapshotValue !== ''
637
- : formattedCurrent !== formattedRestore;
638
+ : !ChangeValuesMatch(this.getCurrentRawValue(fieldName), snapshotValue, field);
638
639
  // Default selection: pre-check changed rows that we can actually apply.
639
640
  const selected = isChanged && !isImmutable && !isMissingInSchema;
640
641
  return {
@@ -650,13 +651,15 @@ export class RestorePreviewPanelComponent extends BaseAngularComponent {
650
651
  IsImmutable: isImmutable,
651
652
  };
652
653
  }
653
- getCurrentFieldValue(fieldName, isDateField) {
654
+ getCurrentFieldValue(fieldName, entityField) {
655
+ return FormatChangeValue(this.getCurrentRawValue(fieldName), entityField);
656
+ }
657
+ /** The live record's raw value for a field, or `undefined` when there is no live record or field. */
658
+ getCurrentRawValue(fieldName) {
654
659
  if (!this._liveRecord)
655
- return '';
660
+ return undefined;
656
661
  const field = this._liveRecord.Fields.find(f => f.Name.trim().toLowerCase() === fieldName.trim().toLowerCase());
657
- if (!field)
658
- return '';
659
- return this.formatValue(field.Value, isDateField);
662
+ return field?.Value;
660
663
  }
661
664
  parseSnapshot(json) {
662
665
  if (!json)
@@ -687,30 +690,6 @@ export class RestorePreviewPanelComponent extends BaseAngularComponent {
687
690
  }
688
691
  return null;
689
692
  }
690
- formatValue(value, isDateField) {
691
- if (value == null)
692
- return '';
693
- if (typeof value === 'object') {
694
- const keys = Object.keys(value);
695
- if (keys.length === 0)
696
- return '';
697
- return JSON.stringify(value);
698
- }
699
- if (isDateField && typeof value === 'string') {
700
- const date = new Date(value);
701
- if (!isNaN(date.getTime())) {
702
- return new Intl.DateTimeFormat('en-US', {
703
- month: 'short',
704
- day: 'numeric',
705
- year: 'numeric',
706
- hour: 'numeric',
707
- minute: '2-digit',
708
- hour12: true,
709
- }).format(date);
710
- }
711
- }
712
- return String(value);
713
- }
714
693
  recountSelected() {
715
694
  this.SelectedCount = this.Rows.filter(r => r.Selected).length;
716
695
  }
@@ -1 +1 @@
1
- {"version":3,"file":"restore-preview-panel.component.js","sourceRoot":"","sources":["../../../src/lib/restore-preview-panel/restore-preview-panel.component.ts","../../../src/lib/restore-preview-panel/restore-preview-panel.component.html"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,uBAAuB,EAEvB,YAAY,EACZ,KAAK,EACL,MAAM,EAEN,iBAAiB,GAClB,MAAM,eAAe,CAAC;AACvB,OAAO,EAGL,iBAAiB,GAElB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;;;;;;ICKjD,AAAN,4BAAM,aAAQ;IAAA,mBAAG;IAAA,iBAAS;IAAC,YAAiB;IAAA,iBAAO;;;IAAxB,eAAiB;IAAjB,8CAAiB;;;IAQlD,8BAA2C;IACzC,wBAAmE;IACnE,4BAAM;IAAA,YAA6H;IACrI,AADqI,iBAAO,EACtI;;;IADE,eAA6H;IAA7H,oKAA6H;;;IAMrI,oCAE0D;;;;IAMxD,AADF,+BAA4B,eACS;IAAA,YAA+E;IAAA,iBAAO;IAEvH,AADF,+BAAoC,iBACwD;IAA/C,gNAAS,kBAAW,KAAC;IAA0B,kCAAkB;IAAA,iBAAS;IACrH,gCAAiC;IAAA,sBAAC;IAAA,iBAAO;IACzC,kCAA4F;IAAjD,gNAAS,oBAAa,KAAC;IAA0B,4BAAY;IAE5G,AADE,AAD0G,iBAAS,EAC7G,EACF;;;IAN+B,eAA+E;IAA/E,sHAA+E;IAE/C,eAAwB;IAAxB,6CAAwB;IAEtB,eAAwB;IAAxB,6CAAwB;;;IAcrF,8BAA4B;IAAA,6BAAa;IAAA,iBAAK;IAC9C,8BAA4B;IAAA,0BAAU;IAAA,iBAAK;;;IAE3C,8BAAwC;IAAA,oCAAoB;IAAA,iBAAK;;;IAqBzD,wBAAoD;;;IASxD,8BAAuE;IACrE,YACF;IAAA,iBAAK;IACL,8BAAuE;IACrE,YACF;IAAA,iBAAK;;;IALuB,sDAA0C;IACpE,cACF;IADE,iEACF;IAC4B,cAA0C;IAA1C,sDAA0C;IACpE,cACF;IADE,iEACF;;;IAEA,8BAAmF;IACjF,YACF;IAAA,iBAAK;;;IAFmC,sDAA0C;IAChF,cACF;IADE,iEACF;;;IAIE,wBAE0B;;;IAE1B,wBAE0B;;;IAE1B,wBAE0B;;;IAE1B,wBAE0B;;;;IA5C5B,AADF,AAJF,0BAGkD,aACtB,iBAOG;IAAzB,kRAAS,wBAAc,KAAC;IACxB,+IAAoB;IAIxB,AADE,iBAAS,EACN;IAEH,AADF,8BAA0B,cACO;IAAA,YAAqB;IAAA,iBAAM;IAC1D,+BAA4B;IAAA,YAAmB;IACjD,AADiD,iBAAM,EAClD;IAQH,AAPF,sIAAuB,4HAOd;IAKT,+BAAyB;IAarB,AAJA,AAJA,AAJF,iJAA6B,2HAIC,2HAIF,2HAInB;IAMb,AADE,iBAAK,EACF;;;;IAjDD,AADA,AADA,AADA,mDAAuC,wCACG,yCACC,2CACE;IAI3C,eAA8B;IAC9B,AADA,0CAA8B,4DAC6B;IAC3D,+FAAoE;;IAGpE,cAEC;IAFD,0CAEC;IAI4B,eAAqB;IAArB,wCAAqB;IACxB,eAAmB;IAAnB,sCAAmB;IAEjD,cAWC;IAXD,iDAWC;IAEC,eAgBC;IAhBD,sGAgBC;;;IAnDP,oIAAsC;;;;IAAtC,mEAsDC;;;;IAQP,kCAAyE;IAA5B,+NAAS,wBAAiB,KAAC;IACtE,wBAG0B;IAC1B,4BAAM;IAAA,YAA+G;IACvH,AADuH,iBAAO,EACrH;;;IAJJ,cAAyC;IACzC,AADA,yDAAyC,yCACF;IAEpC,eAA+G;IAA/G,yJAA+G;;;IAjFnH,AADF,AADF,AADF,+BAA4B,gBACD,YAChB,SACD;IACF,yBAA+B;IAC/B,8BAA0B;IAAA,qBAAK;IAAA,iBAAK;IAIlC,AAHF,iHAAuB,qGAGd;IAGT,yBAA8B;IAElC,AADE,iBAAK,EACC;IACR,8BAAO;IACL,gIAwDC;IAGP,AADE,AADE,iBAAQ,EACF,EACJ;IAGN,iIAA6C;;;IAxErC,eAKC;IALD,gDAKC;IAKH,eAwDC;IAxDD,0BAwDC;IAMP,eAQC;IARD,+EAQC;;;IASK,gCAA2B;IAAA,iBAAC;IAAA,iBAAO;;;IAEnC,gCAA2B;IAAA,0BAAU;IAAA,iBAAO;;;;IALhD,AADF,+BAAgC,gBACA;IAC5B,oCACA;IAEE,AAFF,6HAAqB,uGAEZ;IAGX,iBAAQ;IACR,oCAKW;IAJT,mUAAoB;IAKxB,AADa,iBAAW,EAClB;;;IAZF,eAIC;IAJD,8CAIC;IAGD,eAAoB;IAApB,6CAAoB;IACpB,6CAAwB;;;IAa1B,4BAAM;IAAA,0FAA0E;IAAA,iBAAO;;;IAEvF,4BAAM;IAAA,qHAAmG;IAAA,iBAAO;;;IAS9G,wBAA8D;;;IAE9D,wBAA0D;;;;IA3K9D,AADF,AAHF,8BAA2B,aAGD,aACO;IAC3B,uBAAgE;IAClE,iBAAM;IAEJ,AADF,8BAA6B,aACG;IAAA,YAAiB;IAAA,iBAAM;IAE7C,AAAN,AADF,8BAA6B,WACrB,aAAQ;IAAA,yBAAQ;IAAA,iBAAS;IAAC,aAAuC;IAAA,iBAAO;IAC9E,4GAAmB;IAKzB,AADE,AADE,iBAAM,EACF,EACF;IAGN,8GAAsB;IAQtB,yHAAyB;IAOzB,gHAA8C;IAY9C,qGAAuB;IA2FvB,+GAAsC;IAkBxC,iBAAM;IAIJ,AADF,gCAAwB,eACO;IAC3B,yBAA4D;IAG1D,AAFF,4GAAuB,sFAEd;IAGX,iBAAM;IAEJ,AADF,gCAAgC,kBAID;IAA3B,iMAAS,uBAAgB,KAAC;IAGxB,AAFF,6GAAmB,uFAEV;IAGT,aACF;IAAA,iBAAS;IACT,mCAGqB;IAAnB,iMAAS,eAAQ,KAAC;IAAC,uBAAM;IAE/B,AADE,AAD6B,iBAAS,EAChC,EACF;;;IAhL8B,eAAiB;IAAjB,wCAAiB;IAEb,eAAuC;IAAvC,2EAAuC;IACvE,cAEC;IAFD,8CAEC;IAMP,cAKC;IALD,iDAKC;IAGD,cAIC;IAJD,oDAIC;IAGD,cASC;IATD,gFASC;IAGD,cAwFC;IAxFD,kDAwFC;IAGD,cAiBC;IAjBD,wEAiBC;IAOC,eAIC;IAJD,kDAIC;IAKC,eAA8B;IAA9B,mDAA8B;IAE9B,cAIC;IAJD,8CAIC;IACD,eACF;IADE,0DACF;IAGE,cAAwB;IAAxB,6CAAwB;;ADrFlC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AASH,MAAM,OAAO,4BAA6B,SAAQ,oBAAoB;IAqHhD;IApHpB,mEAAmE;IAEnE;;;;;;OAMG;IACK,QAAQ,GAAG,KAAK,CAAC;IACzB,IACI,OAAO,CAAC,KAAc;QACxB,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC3B,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACtB,IAAI,CAAC,IAAI,IAAI,KAAK,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACzC,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,CAAC;IACH,CAAC;IACD,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAED;;;OAGG;IACM,IAAI,GAAuB,MAAM,CAAC;IAE3C;;;;;OAKG;IACK,aAAa,GAAgC,IAAI,CAAC;IAC1D,IACI,YAAY,CAAC,KAAkC;QACjD,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC;QAC3B,IAAI,IAAI,CAAC,aAAa;YAAE,IAAI,CAAC,WAAW,EAAE,CAAC;IAC7C,CAAC;IACD,IAAI,YAAY;QACd,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;IAED;;;OAGG;IACK,WAAW,GAAsB,IAAI,CAAC;IAC9C,IACI,UAAU,CAAC,KAAwB;QACrC,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QACzB,IAAI,IAAI,CAAC,aAAa;YAAE,IAAI,CAAC,WAAW,EAAE,CAAC;IAC7C,CAAC;IACD,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;IAED;;;;OAIG;IACM,UAAU,GAAkB,IAAI,CAAC;IAE1C;;;;OAIG;IACM,aAAa,GAAG,KAAK,CAAC;IAE/B;;OAEG;IACM,UAAU,GAAG,KAAK,CAAC;IAE5B,mEAAmE;IAEnE;;;;;OAKG;IACO,mBAAmB,GAAG,IAAI,YAAY,EAA4B,CAAC;IAE7E;;;;OAIG;IACO,gBAAgB,GAAG,IAAI,YAAY,EAAsB,CAAC;IAEpE;;OAEG;IACO,gBAAgB,GAAG,IAAI,YAAY,EAAQ,CAAC;IAEtD,mEAAmE;IAE5D,IAAI,GAAsB,EAAE,CAAC;IAC7B,MAAM,GAAG,EAAE,CAAC;IACZ,WAAW,GAAG,KAAK,CAAC;IACpB,aAAa,GAAG,KAAK,CAAC;IAE7B,wEAAwE;IACjE,YAAY,GAAG,CAAC,CAAC;IACxB,oEAAoE;IAC7D,aAAa,GAAG,CAAC,CAAC;IACzB,2EAA2E;IACpE,UAAU,GAAG,CAAC,CAAC;IAEd,aAAa,GAAG,KAAK,CAAC;IACtB,kBAAkB,GAAsB,IAAI,CAAC;IAErD,YAAoB,GAAsB;QAAI,KAAK,EAAE,CAAC;QAAlC,QAAG,GAAH,GAAG,CAAmB;IAAa,CAAC;IAExD,QAAQ;QACN,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;QAC1B,mEAAmE;QACnE,qEAAqE;QACrE,iEAAiE;QACjE,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,WAAW,EAAE,CAAC;QACrB,CAAC;IACH,CAAC;IAED,mEAAmE;IAEnE;;;OAGG;IACI,eAAe;QACpB,IAAI,CAAC,aAAa,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC;QACzC,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;IAC1B,CAAC;IAED;;;OAGG;IACI,SAAS,CAAC,GAAoB;QACnC,IAAI,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC,iBAAiB;YAAE,OAAO;QACrD,GAAG,CAAC,QAAQ,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC;QAC7B,IAAI,CAAC,eAAe,EAAE,CAAC;QACvB,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;IAC1B,CAAC;IAED;;OAEG;IACI,SAAS;QACd,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YAC5B,IAAI,CAAC,GAAG,CAAC,WAAW,IAAI,CAAC,GAAG,CAAC,iBAAiB;gBAAE,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC;QACtE,CAAC;QACD,IAAI,CAAC,eAAe,EAAE,CAAC;QACvB,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;IAC1B,CAAC;IAED;;OAEG;IACI,WAAW;QAChB,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI;YAAE,GAAG,CAAC,QAAQ,GAAG,KAAK,CAAC;QAClD,IAAI,CAAC,eAAe,EAAE,CAAC;QACvB,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;IAC1B,CAAC;IAED;;;OAGG;IACI,cAAc;QACnB,IAAI,CAAC,IAAI,CAAC,aAAa;YAAE,OAAO;QAChC,IAAI,IAAI,CAAC,iBAAiB;YAAE,OAAO;QAEnC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC,iBAAiB,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;QAC7F,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QAE9D,MAAM,WAAW,GAA6B;YAC5C,MAAM,EAAE,KAAK;YACb,kBAAkB,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;YAClD,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE;YAC1B,cAAc,EAAE,IAAI,CAAC,aAAa,CAAC,EAAE;YACrC,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,IAAI;SAChB,CAAC;QACF,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC3C,IAAI,WAAW,CAAC,MAAM;YAAE,OAAO;QAE/B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;QAExB,MAAM,WAAW,GAAuB;YACtC,cAAc,EAAE,IAAI,CAAC,aAAa,CAAC,EAAE;YACrC,MAAM,EAAE,MAAM;YACd,WAAW,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,eAAe,EAAE,CAAC,CAAC;YACtF,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE;YAC1B,IAAI,EAAE,IAAI,CAAC,IAAI;SAChB,CAAC;QACF,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC1C,CAAC;IAED;;OAEG;IACI,MAAM;QACX,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE,CAAC;IAC/B,CAAC;IAED;;;OAGG;IACI,KAAK;QACV,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;QACjB,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QACzB,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC;QAC3B,IAAI,CAAC,WAAW,EAAE,CAAC;IACrB,CAAC;IAED,mEAAmE;IAEnE,IAAW,iBAAiB;QAC1B,IAAI,IAAI,CAAC,WAAW;YAAE,OAAO,IAAI,CAAC;QAClC,IAAI,IAAI,CAAC,aAAa,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAC1C,IAAI,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QACvE,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAW,kBAAkB;QAC3B,IAAI,IAAI,CAAC,WAAW;YAAE,OAAO,YAAY,CAAC;QAC1C,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC7B,OAAO,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC,CAAC,cAAc,IAAI,CAAC,aAAa,SAAS,IAAI,CAAC,aAAa,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC;QAChI,CAAC;QACD,OAAO,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,IAAI,CAAC,aAAa,SAAS,IAAI,CAAC,aAAa,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;IAC5H,CAAC;IAED,IAAW,WAAW;QACpB,OAAO,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,gCAAgC,CAAC;IACjG,CAAC;IAED,IAAW,gBAAgB;QACzB,OAAO,IAAI,CAAC,aAAa,EAAE,SAAS,IAAI,IAAI,CAAC;IAC/C,CAAC;IAED,IAAW,WAAW;QACpB,OAAO,IAAI,CAAC,aAAa,EAAE,IAAI,IAAI,EAAE,CAAC;IACxC,CAAC;IAED,IAAW,cAAc;QACvB,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC;IAC9C,CAAC;IAED,mEAAmE;IAEnE;;;OAGG;IACK,WAAW;QACjB,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC;QACf,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC;QACtB,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC;QACvB,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;QAEpB,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YACxB,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;YACxB,OAAO;QACT,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,aAAa,CAAC,cAAc,CAAC,CAAC;QACvE,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;YACxB,OAAO;QACT,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC5C,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;YACxB,OAAO;QACT,CAAC;QAED,uEAAuE;QACvE,sEAAsE;QACtE,kDAAkD;QAClD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;QAC/B,KAAK,MAAM,SAAS,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC9C,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,CAAC;YAClC,MAAM,GAAG,GAAG,IAAI,CAAC,oBAAoB,CAAC,SAAS,EAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,UAAU,CAAC,CAAC;YAClF,IAAI,GAAG;gBAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC/B,CAAC;QAED,gFAAgF;QAChF,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACtB,IAAI,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,SAAS;gBAAE,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC7D,OAAO,CAAC,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;QACpD,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC;QAC9D,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,MAAM,CAAC;QACpE,IAAI,CAAC,eAAe,EAAE,CAAC;QACvB,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;IAC1B,CAAC;IAEO,oBAAoB,CAC1B,SAAiB,EACjB,aAAsB,EACtB,UAAsB;QAEtB,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,CAClC,CAAC,CAAkB,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CACvF,CAAC;QAEF,4DAA4D;QAC5D,IAAI,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC;YAAE,OAAO,IAAI,CAAC;QAE/C,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,YAAY,CAAC,CAAC;QACtE,MAAM,iBAAiB,GAAG,CAAC,KAAK,CAAC;QACjC,MAAM,WAAW,GAAG,KAAK,EAAE,MAAM,KAAK,iBAAiB,CAAC,IAAI,CAAC;QAE7D,MAAM,gBAAgB,GAAG,IAAI,CAAC,WAAW,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;QACtE,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,KAAK,UAAU;YAC/C,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;QAEtD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,KAAK,UAAU;YACxC,CAAC,CAAC,aAAa,IAAI,IAAI,IAAI,aAAa,KAAK,EAAE;YAC/C,CAAC,CAAC,gBAAgB,KAAK,gBAAgB,CAAC;QAE1C,wEAAwE;QACxE,MAAM,QAAQ,GAAG,SAAS,IAAI,CAAC,WAAW,IAAI,CAAC,iBAAiB,CAAC;QAEjE,OAAO;YACL,SAAS,EAAE,SAAS;YACpB,WAAW,EAAE,KAAK,EAAE,iBAAiB,IAAI,SAAS;YAClD,YAAY,EAAE,gBAAgB;YAC9B,YAAY,EAAE,gBAAgB;YAC9B,eAAe,EAAE,aAAa;YAC9B,SAAS,EAAE,SAAS;YACpB,QAAQ,EAAE,QAAQ;YAClB,iBAAiB,EAAE,iBAAiB;YACpC,WAAW,EAAE,KAAK,EAAE,yCAAyC;YAC7D,WAAW,EAAE,WAAW;SACzB,CAAC;IACJ,CAAC;IAEO,oBAAoB,CAAC,SAAiB,EAAE,WAAoB;QAClE,IAAI,CAAC,IAAI,CAAC,WAAW;YAAE,OAAO,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CACxC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CACpE,CAAC;QACF,IAAI,CAAC,KAAK;YAAE,OAAO,EAAE,CAAC;QACtB,OAAO,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;IACpD,CAAC;IAEO,aAAa,CAAC,IAA+B;QACnD,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAC;QACvB,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAA4B,CAAC;QACrD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED;;;OAGG;IACK,iBAAiB;QACvB,IAAI,IAAI,CAAC,kBAAkB;YAAE,OAAO,IAAI,CAAC,kBAAkB,CAAC;QAC5D,IAAI,IAAI,CAAC,WAAW,EAAE,UAAU,EAAE,CAAC;YACjC,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC;YACtD,OAAO,IAAI,CAAC,kBAAkB,CAAC;QACjC,CAAC;QACD,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,MAAM,EAAE,GAAG,IAAI,CAAC,aAAa,CAAC;YAC9B,MAAM,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CACzB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC,UAAW,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAC3E,CAAC;YACF,IAAI,CAAC,kBAAkB,GAAG,EAAE,IAAI,IAAI,CAAC;YACrC,OAAO,IAAI,CAAC,kBAAkB,CAAC;QACjC,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,WAAW,CAAC,KAAc,EAAE,WAAoB;QACtD,IAAI,KAAK,IAAI,IAAI;YAAE,OAAO,EAAE,CAAC;QAC7B,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC9B,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,KAAgC,CAAC,CAAC;YAC3D,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,EAAE,CAAC;YACjC,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC/B,CAAC;QACD,IAAI,WAAW,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC7C,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC;YAC7B,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;gBAC3B,OAAO,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE;oBACtC,KAAK,EAAE,OAAO;oBACd,GAAG,EAAE,SAAS;oBACd,IAAI,EAAE,SAAS;oBACf,IAAI,EAAE,SAAS;oBACf,MAAM,EAAE,SAAS;oBACjB,MAAM,EAAE,IAAI;iBACb,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAClB,CAAC;QACH,CAAC;QACD,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;IAEO,eAAe;QACrB,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC;IAChE,CAAC;IAED,mEAAmE;IAE5D,eAAe,CAAC,IAAiB;QACtC,IAAI,CAAC,IAAI;YAAE,OAAO,EAAE,CAAC;QACrB,OAAO,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE;YACtC,IAAI,EAAE,SAAS;YACf,KAAK,EAAE,MAAM;YACb,GAAG,EAAE,SAAS;YACd,IAAI,EAAE,SAAS;YACf,MAAM,EAAE,SAAS;YACjB,MAAM,EAAE,IAAI;SACb,CAAC,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5B,CAAC;sHA9aU,4BAA4B;6DAA5B,4BAA4B;YC9JzC,yCAOsB;YAApB,mHAAU,YAAQ,IAAC;YAEnB,sFAAoB;YA2LtB,iBAAiB;;YA9Lf,AADA,AADA,AADA,AADA,AADA,8BAAgB,0BACK,wBACF,mBACD,mBACA,sBACG;YAGrB,cA0LC;YA1LD,2CA0LC;;;iFDrCU,4BAA4B;cARxC,SAAS;6BACI,KAAK,YACP,0BAA0B,mBAGnB,uBAAuB,CAAC,MAAM,iBAChC,iBAAiB,CAAC,IAAI;;kBAapC,KAAK;;kBAgBL,KAAK;;kBASL,KAAK;;kBAcL,KAAK;;kBAcL,KAAK;;kBAOL,KAAK;;kBAKL,KAAK;;kBAUL,MAAM;;kBAON,MAAM;;kBAKN,MAAM;;kFAlGI,4BAA4B","sourcesContent":["import {\n Component,\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n EventEmitter,\n Input,\n Output,\n OnInit,\n ViewEncapsulation,\n} from '@angular/core';\nimport {\n BaseEntity,\n EntityFieldInfo,\n EntityFieldTSType,\n EntityInfo,\n} from '@memberjunction/core';\nimport { MJRecordChangeEntity } from '@memberjunction/core-entities';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\n\n/**\n * Mode controls how the preview is rendered and how the restore is interpreted.\n *\n * - `'live'`: target record exists; the preview shows a current-vs-restore\n * diff per field. Confirming applies the snapshot to the live record and\n * triggers an UPDATE.\n * - `'undelete'`: target record was hard-deleted. The preview shows the\n * snapshot fields that will be inserted; confirming triggers an INSERT.\n */\nexport type RestorePreviewMode = 'live' | 'undelete';\n\n/**\n * One row in the restore preview table.\n *\n * Renders as a checkbox + field name + (current / restore) values. The\n * `IsChanged` flag drives the default-checked state and the row's visual\n * treatment. `IsMissingInSchema` and `IsFKMissing` surface drift warnings.\n */\nexport interface RestoreFieldRow {\n /** Raw field name (matches EntityField.Name). */\n FieldName: string;\n /** Friendly label (EntityField.DisplayNameOrName). */\n DisplayName: string;\n /** Formatted current value of the live record (empty in undelete mode). */\n CurrentValue: string;\n /** Formatted snapshot value that would be applied. */\n RestoreValue: string;\n /** Raw snapshot value (the value passed to BaseEntity.Set). */\n RawRestoreValue: unknown;\n /** True when CurrentValue and RestoreValue differ. Drives default checked. */\n IsChanged: boolean;\n /** User's selection — when true, this field will be applied on restore. */\n Selected: boolean;\n /** True when the snapshot references a field that no longer exists on the entity. */\n IsMissingInSchema: boolean;\n /** True when the field is a FK whose target row no longer exists (best-effort). */\n IsFKMissing: boolean;\n /** True when the field is read-only / system / PK and cannot be restored. */\n IsImmutable: boolean;\n}\n\n/**\n * Cancelable event fired immediately after the user clicks Restore but\n * before {@link RestorePreviewPanelComponent.RestoreConfirmed} emits.\n *\n * Consumers can set `cancel = true` (and optionally `cancelReason`) to abort\n * the restore — useful for custom approval workflows, audit logging hooks,\n * or for a consumer that wants to take over the actual save itself.\n */\nexport interface BeforeRestoreCommitEvent {\n /** Set to true to abort. RestoreConfirmed will not fire. */\n cancel: boolean;\n /** Optional explanation surfaced by the consumer. */\n cancelReason?: string;\n /** Selected field names (only fields the user kept checked). */\n SelectedFieldNames: string[];\n /** The full set of rows in the preview, including unselected. */\n AllRows: RestoreFieldRow[];\n /** ID of the source RecordChange row whose state is being restored. */\n SourceChangeID: string;\n /** Optional reason text the user entered. */\n Reason: string | null;\n /** The mode — 'live' (UPDATE) or 'undelete' (INSERT). */\n Mode: RestorePreviewMode;\n}\n\n/**\n * Event payload emitted after the user has confirmed a restore.\n *\n * The host component is responsible for applying the snapshot to a\n * BaseEntity instance, calling {@link BaseEntity.SetRestoreContext}, and\n * invoking Save(). This component never touches the database directly so\n * it remains usable in any consumer context.\n */\nexport interface RestoreCommitEvent {\n /** ID of the source RecordChange row whose state is being restored. */\n SourceChangeID: string;\n /** Optional user-entered reason; persisted to RecordChange.RestoreReason. */\n Reason: string | null;\n /** Selected fields with their snapshot values, ready for BaseEntity.Set. */\n FieldValues: Array<{ FieldName: string; Value: unknown }>;\n /** The full preview rows (including unselected) for audit/logging. */\n AllRows: RestoreFieldRow[];\n /** Mode indicates UPDATE (live) vs INSERT (undelete). */\n Mode: RestorePreviewMode;\n}\n\n/**\n * Reusable slide-in panel that previews a restore operation against a\n * historical {@link MJRecordChangeEntity} and lets the user confirm with\n * field-level granularity.\n *\n * This component is rendered by both:\n * - The Record Changes timeline (for restoring a live record from any past\n * change row)\n * - The Recycle Bin (for re-creating a hard-deleted record from its delete\n * snapshot)\n *\n * It does NOT perform the save itself — the host component receives a\n * {@link RestoreCommitEvent} with the selected field values and is\n * responsible for applying them to a BaseEntity, setting the restore\n * context, and calling Save(). This keeps the component purely\n * presentational and reusable in any context.\n *\n * ### Semantic correctness\n *\n * The preview compares the **full snapshot** captured in the source\n * change's `FullRecordJSON` to the current live record (or to nothing in\n * un-delete mode). It does NOT roll back a single delta — restoring `v2`\n * means \"make the record look like it did at v2\", not \"undo v3's changes\".\n *\n * @example Live restore from the timeline\n * <mj-restore-preview-panel\n * [Visible]=\"showPreview\"\n * [Mode]=\"'live'\"\n * [RecordChange]=\"selectedChange\"\n * [LiveRecord]=\"record\"\n * (RestoreConfirmed)=\"onRestoreConfirmed($event)\"\n * (RestoreCancelled)=\"showPreview = false\">\n * </mj-restore-preview-panel>\n *\n * @example Un-delete from the Recycle Bin\n * <mj-restore-preview-panel\n * [Visible]=\"showPreview\"\n * [Mode]=\"'undelete'\"\n * [RecordChange]=\"deletedChange\"\n * [EntityName]=\"'Customers'\"\n * (RestoreConfirmed)=\"onRecreate($event)\"\n * (RestoreCancelled)=\"showPreview = false\">\n * </mj-restore-preview-panel>\n */\n@Component({\n standalone: false,\n selector: 'mj-restore-preview-panel',\n templateUrl: './restore-preview-panel.component.html',\n styleUrls: ['./restore-preview-panel.component.css'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n})\nexport class RestorePreviewPanelComponent extends BaseAngularComponent implements OnInit {\n // ─── Inputs ─────────────────────────────────────────────────────\n\n /**\n * Controls panel visibility. Setting to true opens the slide-in;\n * setting to false closes it. On every closed→open transition the\n * panel auto-resets its transient state (`IsRestoring`, `Reason`,\n * `ShowUnchanged`, row checks) so the host doesn't have to remember\n * to call `Reset()` after a restore completes.\n */\n private _visible = false;\n @Input()\n set Visible(value: boolean) {\n const prev = this._visible;\n this._visible = value;\n if (!prev && value && this.isInitialized) {\n this.Reset();\n }\n }\n get Visible(): boolean {\n return this._visible;\n }\n\n /**\n * Operating mode — `'live'` for restoring an existing record from a\n * snapshot, `'undelete'` for re-creating a hard-deleted record.\n */\n @Input() Mode: RestorePreviewMode = 'live';\n\n /**\n * The historical RecordChange row whose state will be restored. Required.\n * The component reads `FullRecordJSON` from this entity to determine the\n * target state. The change's `Type` does not matter — `Create`,\n * `Update`, `Snapshot`, and `Delete` are all valid restore sources.\n */\n private _recordChange: MJRecordChangeEntity | null = null;\n @Input()\n set RecordChange(value: MJRecordChangeEntity | null) {\n this._recordChange = value;\n if (this.isInitialized) this.rebuildRows();\n }\n get RecordChange(): MJRecordChangeEntity | null {\n return this._recordChange;\n }\n\n /**\n * The current live record to diff against. Required in `'live'` mode,\n * ignored in `'undelete'` mode (since the live record no longer exists).\n */\n private _liveRecord: BaseEntity | null = null;\n @Input()\n set LiveRecord(value: BaseEntity | null) {\n this._liveRecord = value;\n if (this.isInitialized) this.rebuildRows();\n }\n get LiveRecord(): BaseEntity | null {\n return this._liveRecord;\n }\n\n /**\n * The entity name. Required in `'undelete'` mode (since there's no live\n * record to read it from). In `'live'` mode it can be omitted and is\n * inferred from the LiveRecord.\n */\n @Input() EntityName: string | null = null;\n\n /**\n * When true, the Restore button is disabled until the user enters a\n * non-empty reason. Useful for regulated environments where every\n * reversal needs justification. Default: false.\n */\n @Input() RequireReason = false;\n\n /**\n * When true, hides the optional reason text area entirely. Default: false.\n */\n @Input() HideReason = false;\n\n // ─── Outputs ────────────────────────────────────────────────────\n\n /**\n * Cancelable event fired when the user clicks Restore but before\n * {@link RestoreConfirmed} emits. Consumers can set `cancel = true` on\n * the event arg to abort the operation — useful for custom approval\n * workflows or for taking over the save themselves.\n */\n @Output() BeforeRestoreCommit = new EventEmitter<BeforeRestoreCommitEvent>();\n\n /**\n * Emitted after the user confirms the restore (and BeforeRestoreCommit\n * was not cancelled). The host is responsible for applying the field\n * values to a BaseEntity, calling SetRestoreContext, and invoking Save().\n */\n @Output() RestoreConfirmed = new EventEmitter<RestoreCommitEvent>();\n\n /**\n * Emitted when the user cancels the preview without restoring.\n */\n @Output() RestoreCancelled = new EventEmitter<void>();\n\n // ─── Public state (read by template) ────────────────────────────\n\n public Rows: RestoreFieldRow[] = [];\n public Reason = '';\n public IsRestoring = false;\n public ShowUnchanged = false;\n\n /** Number of rows where the current value differs from the snapshot. */\n public ChangedCount = 0;\n /** Number of rows that are checked (will be applied on restore). */\n public SelectedCount = 0;\n /** Number of rows the schema has dropped or renamed since the snapshot. */\n public DriftCount = 0;\n\n private isInitialized = false;\n private resolvedEntityInfo: EntityInfo | null = null;\n\n constructor(private cdr: ChangeDetectorRef) { super(); }\n\n ngOnInit(): void {\n this.isInitialized = true;\n // If the panel was opened synchronously during host bootstrap, the\n // Visible setter ran before `isInitialized` was true and skipped the\n // auto-reset. Do it here once so the first open is always clean.\n if (this._visible) {\n this.Reset();\n } else {\n this.rebuildRows();\n }\n }\n\n // ─── Public methods ─────────────────────────────────────────────\n\n /**\n * Toggles whether unchanged rows are visible in the table. When false\n * (default), only rows where current ≠ snapshot are shown.\n */\n public ToggleUnchanged(): void {\n this.ShowUnchanged = !this.ShowUnchanged;\n this.cdr.markForCheck();\n }\n\n /**\n * Toggles whether a single row is selected for restore. Updates the\n * SelectedCount in real time so the primary button label reflects it.\n */\n public ToggleRow(row: RestoreFieldRow): void {\n if (row.IsImmutable || row.IsMissingInSchema) return;\n row.Selected = !row.Selected;\n this.recountSelected();\n this.cdr.markForCheck();\n }\n\n /**\n * Selects every row that can be selected (skips immutable / drifted).\n */\n public SelectAll(): void {\n for (const row of this.Rows) {\n if (!row.IsImmutable && !row.IsMissingInSchema) row.Selected = true;\n }\n this.recountSelected();\n this.cdr.markForCheck();\n }\n\n /**\n * Deselects every row in the preview.\n */\n public DeselectAll(): void {\n for (const row of this.Rows) row.Selected = false;\n this.recountSelected();\n this.cdr.markForCheck();\n }\n\n /**\n * User clicked Restore — fire BeforeRestoreCommit (cancelable), then\n * RestoreConfirmed if not cancelled.\n */\n public ConfirmRestore(): void {\n if (!this._recordChange) return;\n if (this.IsRestoreDisabled) return;\n\n const selected = this.Rows.filter(r => r.Selected && !r.IsMissingInSchema && !r.IsImmutable);\n const reason = this.Reason.trim() ? this.Reason.trim() : null;\n\n const beforeEvent: BeforeRestoreCommitEvent = {\n cancel: false,\n SelectedFieldNames: selected.map(r => r.FieldName),\n AllRows: this.Rows.slice(),\n SourceChangeID: this._recordChange.ID,\n Reason: reason,\n Mode: this.Mode,\n };\n this.BeforeRestoreCommit.emit(beforeEvent);\n if (beforeEvent.cancel) return;\n\n this.IsRestoring = true;\n this.cdr.markForCheck();\n\n const commitEvent: RestoreCommitEvent = {\n SourceChangeID: this._recordChange.ID,\n Reason: reason,\n FieldValues: selected.map(r => ({ FieldName: r.FieldName, Value: r.RawRestoreValue })),\n AllRows: this.Rows.slice(),\n Mode: this.Mode,\n };\n this.RestoreConfirmed.emit(commitEvent);\n }\n\n /**\n * User cancelled the preview. Resets state and emits RestoreCancelled.\n */\n public Cancel(): void {\n this.RestoreCancelled.emit();\n }\n\n /**\n * Resets internal state — useful after a save completes so the panel\n * can be reopened cleanly. Called by the host component when needed.\n */\n public Reset(): void {\n this.Reason = '';\n this.IsRestoring = false;\n this.ShowUnchanged = false;\n this.rebuildRows();\n }\n\n // ─── Computed getters (template) ────────────────────────────────\n\n public get IsRestoreDisabled(): boolean {\n if (this.IsRestoring) return true;\n if (this.SelectedCount === 0) return true;\n if (this.RequireReason && this.Reason.trim().length === 0) return true;\n return false;\n }\n\n public get RestoreButtonLabel(): string {\n if (this.IsRestoring) return 'Restoring…';\n if (this.Mode === 'undelete') {\n return this.SelectedCount > 0 ? `Re-create (${this.SelectedCount} field${this.SelectedCount === 1 ? '' : 's'})` : 'Re-create';\n }\n return this.SelectedCount > 0 ? `Restore (${this.SelectedCount} field${this.SelectedCount === 1 ? '' : 's'})` : 'Restore';\n }\n\n public get HeaderTitle(): string {\n return this.Mode === 'undelete' ? 'Re-create from snapshot' : 'Restore record to this version';\n }\n\n public get VersionTimestamp(): Date | null {\n return this._recordChange?.ChangedAt ?? null;\n }\n\n public get VersionUser(): string {\n return this._recordChange?.User ?? '';\n }\n\n public get UnchangedCount(): number {\n return this.Rows.length - this.ChangedCount;\n }\n\n // ─── Internal: row building ─────────────────────────────────────\n\n /**\n * Rebuilds the Rows array from the current RecordChange + LiveRecord.\n * Idempotent and cheap — safe to call from input setters.\n */\n private rebuildRows(): void {\n this.Rows = [];\n this.ChangedCount = 0;\n this.SelectedCount = 0;\n this.DriftCount = 0;\n\n if (!this._recordChange) {\n this.cdr.markForCheck();\n return;\n }\n\n const snapshot = this.parseSnapshot(this._recordChange.FullRecordJSON);\n if (!snapshot) {\n this.cdr.markForCheck();\n return;\n }\n\n const entityInfo = this.resolveEntityInfo();\n if (!entityInfo) {\n this.cdr.markForCheck();\n return;\n }\n\n // Build a row for every field in the snapshot. We iterate the snapshot\n // (not EntityInfo.Fields) so fields that exist in the snapshot but no\n // longer in the schema surface as drift warnings.\n const seen = new Set<string>();\n for (const fieldName of Object.keys(snapshot)) {\n seen.add(fieldName.toLowerCase());\n const row = this.buildRowFromSnapshot(fieldName, snapshot[fieldName], entityInfo);\n if (row) this.Rows.push(row);\n }\n\n // Sort: changed rows first, then unchanged. Within each group, by display name.\n this.Rows.sort((a, b) => {\n if (a.IsChanged !== b.IsChanged) return a.IsChanged ? -1 : 1;\n return a.DisplayName.localeCompare(b.DisplayName);\n });\n\n this.ChangedCount = this.Rows.filter(r => r.IsChanged).length;\n this.DriftCount = this.Rows.filter(r => r.IsMissingInSchema).length;\n this.recountSelected();\n this.cdr.markForCheck();\n }\n\n private buildRowFromSnapshot(\n fieldName: string,\n snapshotValue: unknown,\n entityInfo: EntityInfo,\n ): RestoreFieldRow | null {\n const field = entityInfo.Fields.find(\n (f: EntityFieldInfo) => f.Name.trim().toLowerCase() === fieldName.trim().toLowerCase(),\n );\n\n // Skip system / timestamp fields that the platform manages.\n if (fieldName.startsWith('__mj_')) return null;\n\n const isImmutable = !!field && (field.ReadOnly || field.IsPrimaryKey);\n const isMissingInSchema = !field;\n const isDateField = field?.TSType === EntityFieldTSType.Date;\n\n const formattedRestore = this.formatValue(snapshotValue, isDateField);\n const formattedCurrent = this.Mode === 'undelete'\n ? ''\n : this.getCurrentFieldValue(fieldName, isDateField);\n\n const isChanged = this.Mode === 'undelete'\n ? snapshotValue != null && snapshotValue !== ''\n : formattedCurrent !== formattedRestore;\n\n // Default selection: pre-check changed rows that we can actually apply.\n const selected = isChanged && !isImmutable && !isMissingInSchema;\n\n return {\n FieldName: fieldName,\n DisplayName: field?.DisplayNameOrName ?? fieldName,\n CurrentValue: formattedCurrent,\n RestoreValue: formattedRestore,\n RawRestoreValue: snapshotValue,\n IsChanged: isChanged,\n Selected: selected,\n IsMissingInSchema: isMissingInSchema,\n IsFKMissing: false, // Reserved for future FK-existence check\n IsImmutable: isImmutable,\n };\n }\n\n private getCurrentFieldValue(fieldName: string, isDateField: boolean): string {\n if (!this._liveRecord) return '';\n const field = this._liveRecord.Fields.find(\n f => f.Name.trim().toLowerCase() === fieldName.trim().toLowerCase(),\n );\n if (!field) return '';\n return this.formatValue(field.Value, isDateField);\n }\n\n private parseSnapshot(json: string | null | undefined): Record<string, unknown> | null {\n if (!json) return null;\n try {\n return JSON.parse(json) as Record<string, unknown>;\n } catch {\n return null;\n }\n }\n\n /**\n * Resolves the entity metadata. Prefers LiveRecord.EntityInfo (always\n * accurate). Falls back to looking up by EntityName. Memoized.\n */\n private resolveEntityInfo(): EntityInfo | null {\n if (this.resolvedEntityInfo) return this.resolvedEntityInfo;\n if (this._liveRecord?.EntityInfo) {\n this.resolvedEntityInfo = this._liveRecord.EntityInfo;\n return this.resolvedEntityInfo;\n }\n if (this.EntityName) {\n const md = this.ProviderToUse;\n const ei = md.Entities.find(\n e => e.Name.trim().toLowerCase() === this.EntityName!.trim().toLowerCase(),\n );\n this.resolvedEntityInfo = ei ?? null;\n return this.resolvedEntityInfo;\n }\n return null;\n }\n\n private formatValue(value: unknown, isDateField: boolean): string {\n if (value == null) return '';\n if (typeof value === 'object') {\n const keys = Object.keys(value as Record<string, unknown>);\n if (keys.length === 0) return '';\n return JSON.stringify(value);\n }\n if (isDateField && typeof value === 'string') {\n const date = new Date(value);\n if (!isNaN(date.getTime())) {\n return new Intl.DateTimeFormat('en-US', {\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n hour: 'numeric',\n minute: '2-digit',\n hour12: true,\n }).format(date);\n }\n }\n return String(value);\n }\n\n private recountSelected(): void {\n this.SelectedCount = this.Rows.filter(r => r.Selected).length;\n }\n\n // ─── Display helpers (template) ─────────────────────────────────\n\n public formatTimestamp(date: Date | null): string {\n if (!date) return '';\n return new Intl.DateTimeFormat('en-US', {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n hour: 'numeric',\n minute: '2-digit',\n hour12: true,\n }).format(new Date(date));\n }\n}\n","<mj-slide-panel\n [Mode]=\"'slide'\"\n [Title]=\"HeaderTitle\"\n [Visible]=\"Visible\"\n [Resizable]=\"true\"\n [MinWidthPx]=\"500\"\n [MaxWidthRatio]=\"0.7\"\n (Closed)=\"Cancel()\">\n\n @if (RecordChange) {\n <div class=\"rpp-container\">\n\n <!-- Header summary block -->\n <div class=\"rpp-header\">\n <div class=\"rpp-header-icon\">\n <i class=\"fa-solid fa-clock-rotate-left\" aria-hidden=\"true\"></i>\n </div>\n <div class=\"rpp-header-text\">\n <div class=\"rpp-header-title\">{{ HeaderTitle }}</div>\n <div class=\"rpp-header-meta\">\n <span><strong>Version:</strong> {{ formatTimestamp(VersionTimestamp) }}</span>\n @if (VersionUser) {\n <span><strong>By:</strong> {{ VersionUser }}</span>\n }\n </div>\n </div>\n </div>\n\n <!-- Drift warning -->\n @if (DriftCount > 0) {\n <div class=\"rpp-banner rpp-banner-warning\">\n <i class=\"fa-solid fa-triangle-exclamation\" aria-hidden=\"true\"></i>\n <span>{{ DriftCount }} field{{ DriftCount === 1 ? '' : 's' }} from this snapshot no longer exist on the entity and will be skipped.</span>\n </div>\n }\n\n <!-- Empty state -->\n @if (Rows.length === 0) {\n <mj-empty-state class=\"rpp-empty\" Size=\"compact\"\n Icon=\"fa-solid fa-circle-info\"\n Title=\"No fields could be parsed from this snapshot.\" />\n }\n\n <!-- Action bar (select all / deselect all) -->\n @if (Rows.length > 0 && Mode !== 'undelete') {\n <div class=\"rpp-action-bar\">\n <span class=\"rpp-action-bar-label\">{{ ChangedCount }} field{{ ChangedCount === 1 ? '' : 's' }} differ from current</span>\n <div class=\"rpp-action-bar-buttons\">\n <button class=\"rpp-link-btn\" type=\"button\" (click)=\"SelectAll()\" [disabled]=\"IsRestoring\">Select all changed</button>\n <span class=\"rpp-action-bar-sep\">·</span>\n <button class=\"rpp-link-btn\" type=\"button\" (click)=\"DeselectAll()\" [disabled]=\"IsRestoring\">Deselect all</button>\n </div>\n </div>\n }\n\n <!-- Diff table -->\n @if (Rows.length > 0) {\n <div class=\"rpp-table-wrap\">\n <table class=\"rpp-table\">\n <thead>\n <tr>\n <th class=\"rpp-col-check\"></th>\n <th class=\"rpp-col-field\">Field</th>\n @if (Mode === 'live') {\n <th class=\"rpp-col-current\">Current Value</th>\n <th class=\"rpp-col-restore\">Restore To</th>\n } @else {\n <th class=\"rpp-col-restore\" colspan=\"2\">Will be created with</th>\n }\n <th class=\"rpp-col-flag\"></th>\n </tr>\n </thead>\n <tbody>\n @for (row of Rows; track row.FieldName) {\n @if (row.IsChanged || ShowUnchanged) {\n <tr [class.rpp-row-changed]=\"row.IsChanged\"\n [class.rpp-row-unchanged]=\"!row.IsChanged\"\n [class.rpp-row-immutable]=\"row.IsImmutable\"\n [class.rpp-row-drift]=\"row.IsMissingInSchema\">\n <td class=\"rpp-col-check\">\n <button type=\"button\"\n class=\"rpp-checkbox\"\n [class.checked]=\"row.Selected\"\n [class.disabled]=\"row.IsImmutable || row.IsMissingInSchema\"\n [disabled]=\"row.IsImmutable || row.IsMissingInSchema || IsRestoring\"\n [attr.aria-label]=\"'Toggle ' + row.DisplayName\"\n (click)=\"ToggleRow(row)\">\n @if (row.Selected) {\n <i class=\"fa-solid fa-check\" aria-hidden=\"true\"></i>\n }\n </button>\n </td>\n <td class=\"rpp-col-field\">\n <div class=\"rpp-field-display\">{{ row.DisplayName }}</div>\n <div class=\"rpp-field-name\">{{ row.FieldName }}</div>\n </td>\n @if (Mode === 'live') {\n <td class=\"rpp-col-current\" [class.rpp-empty-cell]=\"!row.CurrentValue\">\n {{ row.CurrentValue || '(empty)' }}\n </td>\n <td class=\"rpp-col-restore\" [class.rpp-empty-cell]=\"!row.RestoreValue\">\n {{ row.RestoreValue || '(empty)' }}\n </td>\n } @else {\n <td class=\"rpp-col-restore\" colspan=\"2\" [class.rpp-empty-cell]=\"!row.RestoreValue\">\n {{ row.RestoreValue || '(empty)' }}\n </td>\n }\n <td class=\"rpp-col-flag\">\n @if (row.IsMissingInSchema) {\n <i class=\"fa-solid fa-triangle-exclamation rpp-flag-drift\"\n title=\"This field no longer exists on the entity and will be skipped\"\n aria-hidden=\"true\"></i>\n } @else if (row.IsImmutable) {\n <i class=\"fa-solid fa-lock rpp-flag-immutable\"\n title=\"Read-only or system field — cannot be modified\"\n aria-hidden=\"true\"></i>\n } @else if (row.IsChanged) {\n <i class=\"fa-solid fa-circle-exclamation rpp-flag-changed\"\n title=\"Will be changed\"\n aria-hidden=\"true\"></i>\n } @else {\n <i class=\"fa-solid fa-check rpp-flag-ok\"\n title=\"Already matches\"\n aria-hidden=\"true\"></i>\n }\n </td>\n </tr>\n }\n }\n </tbody>\n </table>\n </div>\n\n <!-- Unchanged disclosure -->\n @if (UnchangedCount > 0 && Mode === 'live') {\n <button class=\"rpp-disclosure\" type=\"button\" (click)=\"ToggleUnchanged()\">\n <i class=\"fa-solid\"\n [class.fa-chevron-right]=\"!ShowUnchanged\"\n [class.fa-chevron-down]=\"ShowUnchanged\"\n aria-hidden=\"true\"></i>\n <span>{{ ShowUnchanged ? 'Hide' : 'Show' }} {{ UnchangedCount }} unchanged field{{ UnchangedCount === 1 ? '' : 's' }}</span>\n </button>\n }\n }\n\n <!-- Reason text area -->\n @if (!HideReason && Rows.length > 0) {\n <div class=\"rpp-reason-section\">\n <label for=\"rpp-reason-input\">\n Reason for restore\n @if (RequireReason) {\n <span class=\"rpp-required\">*</span>\n } @else {\n <span class=\"rpp-optional\">(optional)</span>\n }\n </label>\n <textarea id=\"rpp-reason-input\"\n [(ngModel)]=\"Reason\"\n [disabled]=\"IsRestoring\"\n placeholder=\"e.g., Reverting incorrect Q2 entries\"\n class=\"rpp-reason-textarea\"\n rows=\"2\"></textarea>\n </div>\n }\n </div>\n\n <!-- Footer actions -->\n <div class=\"rpp-footer\">\n <div class=\"rpp-footer-info\">\n <i class=\"fa-solid fa-shield-halved\" aria-hidden=\"true\"></i>\n @if (Mode === 'live') {\n <span>A snapshot of the current state is saved automatically before the restore.</span>\n } @else {\n <span>A new \"Created\" entry will be added to this record's history, linked back to the original deletion.</span>\n }\n </div>\n <div class=\"rpp-footer-actions\">\n <button type=\"button\"\n class=\"rpp-btn rpp-btn-primary\"\n [disabled]=\"IsRestoreDisabled\"\n (click)=\"ConfirmRestore()\">\n @if (IsRestoring) {\n <i class=\"fa-solid fa-spinner fa-spin\" aria-hidden=\"true\"></i>\n } @else {\n <i class=\"fa-solid fa-rotate-left\" aria-hidden=\"true\"></i>\n }\n {{ RestoreButtonLabel }}\n </button>\n <button type=\"button\"\n class=\"rpp-btn rpp-btn-secondary\"\n [disabled]=\"IsRestoring\"\n (click)=\"Cancel()\">Cancel</button>\n </div>\n </div>\n }\n</mj-slide-panel>\n"]}
1
+ {"version":3,"file":"restore-preview-panel.component.js","sourceRoot":"","sources":["../../../src/lib/restore-preview-panel/restore-preview-panel.component.ts","../../../src/lib/restore-preview-panel/restore-preview-panel.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n EventEmitter,\n Input,\n Output,\n OnInit,\n ViewEncapsulation,\n} from '@angular/core';\nimport {\n BaseEntity,\n EntityFieldInfo,\n EntityInfo,\n} from '@memberjunction/core';\nimport { MJRecordChangeEntity } from '@memberjunction/core-entities';\nimport { ChangeValuesMatch, FormatChangeValue } from '../format-change-value';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\n\n/**\n * Mode controls how the preview is rendered and how the restore is interpreted.\n *\n * - `'live'`: target record exists; the preview shows a current-vs-restore\n * diff per field. Confirming applies the snapshot to the live record and\n * triggers an UPDATE.\n * - `'undelete'`: target record was hard-deleted. The preview shows the\n * snapshot fields that will be inserted; confirming triggers an INSERT.\n */\nexport type RestorePreviewMode = 'live' | 'undelete';\n\n/**\n * One row in the restore preview table.\n *\n * Renders as a checkbox + field name + (current / restore) values. The\n * `IsChanged` flag drives the default-checked state and the row's visual\n * treatment. `IsMissingInSchema` and `IsFKMissing` surface drift warnings.\n */\nexport interface RestoreFieldRow {\n /** Raw field name (matches EntityField.Name). */\n FieldName: string;\n /** Friendly label (EntityField.DisplayNameOrName). */\n DisplayName: string;\n /** Formatted current value of the live record (empty in undelete mode). */\n CurrentValue: string;\n /** Formatted snapshot value that would be applied. */\n RestoreValue: string;\n /** Raw snapshot value (the value passed to BaseEntity.Set). */\n RawRestoreValue: unknown;\n /** True when CurrentValue and RestoreValue differ. Drives default checked. */\n IsChanged: boolean;\n /** User's selection — when true, this field will be applied on restore. */\n Selected: boolean;\n /** True when the snapshot references a field that no longer exists on the entity. */\n IsMissingInSchema: boolean;\n /** True when the field is a FK whose target row no longer exists (best-effort). */\n IsFKMissing: boolean;\n /** True when the field is read-only / system / PK and cannot be restored. */\n IsImmutable: boolean;\n}\n\n/**\n * Cancelable event fired immediately after the user clicks Restore but\n * before {@link RestorePreviewPanelComponent.RestoreConfirmed} emits.\n *\n * Consumers can set `cancel = true` (and optionally `cancelReason`) to abort\n * the restore — useful for custom approval workflows, audit logging hooks,\n * or for a consumer that wants to take over the actual save itself.\n */\nexport interface BeforeRestoreCommitEvent {\n /** Set to true to abort. RestoreConfirmed will not fire. */\n cancel: boolean;\n /** Optional explanation surfaced by the consumer. */\n cancelReason?: string;\n /** Selected field names (only fields the user kept checked). */\n SelectedFieldNames: string[];\n /** The full set of rows in the preview, including unselected. */\n AllRows: RestoreFieldRow[];\n /** ID of the source RecordChange row whose state is being restored. */\n SourceChangeID: string;\n /** Optional reason text the user entered. */\n Reason: string | null;\n /** The mode — 'live' (UPDATE) or 'undelete' (INSERT). */\n Mode: RestorePreviewMode;\n}\n\n/**\n * Event payload emitted after the user has confirmed a restore.\n *\n * The host component is responsible for applying the snapshot to a\n * BaseEntity instance, calling {@link BaseEntity.SetRestoreContext}, and\n * invoking Save(). This component never touches the database directly so\n * it remains usable in any consumer context.\n */\nexport interface RestoreCommitEvent {\n /** ID of the source RecordChange row whose state is being restored. */\n SourceChangeID: string;\n /** Optional user-entered reason; persisted to RecordChange.RestoreReason. */\n Reason: string | null;\n /** Selected fields with their snapshot values, ready for BaseEntity.Set. */\n FieldValues: Array<{ FieldName: string; Value: unknown }>;\n /** The full preview rows (including unselected) for audit/logging. */\n AllRows: RestoreFieldRow[];\n /** Mode indicates UPDATE (live) vs INSERT (undelete). */\n Mode: RestorePreviewMode;\n}\n\n/**\n * Reusable slide-in panel that previews a restore operation against a\n * historical {@link MJRecordChangeEntity} and lets the user confirm with\n * field-level granularity.\n *\n * This component is rendered by both:\n * - The Record Changes timeline (for restoring a live record from any past\n * change row)\n * - The Recycle Bin (for re-creating a hard-deleted record from its delete\n * snapshot)\n *\n * It does NOT perform the save itself — the host component receives a\n * {@link RestoreCommitEvent} with the selected field values and is\n * responsible for applying them to a BaseEntity, setting the restore\n * context, and calling Save(). This keeps the component purely\n * presentational and reusable in any context.\n *\n * ### Semantic correctness\n *\n * The preview compares the **full snapshot** captured in the source\n * change's `FullRecordJSON` to the current live record (or to nothing in\n * un-delete mode). It does NOT roll back a single delta — restoring `v2`\n * means \"make the record look like it did at v2\", not \"undo v3's changes\".\n *\n * @example Live restore from the timeline\n * <mj-restore-preview-panel\n * [Visible]=\"showPreview\"\n * [Mode]=\"'live'\"\n * [RecordChange]=\"selectedChange\"\n * [LiveRecord]=\"record\"\n * (RestoreConfirmed)=\"onRestoreConfirmed($event)\"\n * (RestoreCancelled)=\"showPreview = false\">\n * </mj-restore-preview-panel>\n *\n * @example Un-delete from the Recycle Bin\n * <mj-restore-preview-panel\n * [Visible]=\"showPreview\"\n * [Mode]=\"'undelete'\"\n * [RecordChange]=\"deletedChange\"\n * [EntityName]=\"'Customers'\"\n * (RestoreConfirmed)=\"onRecreate($event)\"\n * (RestoreCancelled)=\"showPreview = false\">\n * </mj-restore-preview-panel>\n */\n@Component({\n standalone: false,\n selector: 'mj-restore-preview-panel',\n templateUrl: './restore-preview-panel.component.html',\n styleUrls: ['./restore-preview-panel.component.css'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n})\nexport class RestorePreviewPanelComponent extends BaseAngularComponent implements OnInit {\n // ─── Inputs ─────────────────────────────────────────────────────\n\n /**\n * Controls panel visibility. Setting to true opens the slide-in;\n * setting to false closes it. On every closed→open transition the\n * panel auto-resets its transient state (`IsRestoring`, `Reason`,\n * `ShowUnchanged`, row checks) so the host doesn't have to remember\n * to call `Reset()` after a restore completes.\n */\n private _visible = false;\n @Input()\n set Visible(value: boolean) {\n const prev = this._visible;\n this._visible = value;\n if (!prev && value && this.isInitialized) {\n this.Reset();\n }\n }\n get Visible(): boolean {\n return this._visible;\n }\n\n /**\n * Operating mode — `'live'` for restoring an existing record from a\n * snapshot, `'undelete'` for re-creating a hard-deleted record.\n */\n @Input() Mode: RestorePreviewMode = 'live';\n\n /**\n * The historical RecordChange row whose state will be restored. Required.\n * The component reads `FullRecordJSON` from this entity to determine the\n * target state. The change's `Type` does not matter — `Create`,\n * `Update`, `Snapshot`, and `Delete` are all valid restore sources.\n */\n private _recordChange: MJRecordChangeEntity | null = null;\n @Input()\n set RecordChange(value: MJRecordChangeEntity | null) {\n this._recordChange = value;\n if (this.isInitialized) this.rebuildRows();\n }\n get RecordChange(): MJRecordChangeEntity | null {\n return this._recordChange;\n }\n\n /**\n * The current live record to diff against. Required in `'live'` mode,\n * ignored in `'undelete'` mode (since the live record no longer exists).\n */\n private _liveRecord: BaseEntity | null = null;\n @Input()\n set LiveRecord(value: BaseEntity | null) {\n this._liveRecord = value;\n if (this.isInitialized) this.rebuildRows();\n }\n get LiveRecord(): BaseEntity | null {\n return this._liveRecord;\n }\n\n /**\n * The entity name. Required in `'undelete'` mode (since there's no live\n * record to read it from). In `'live'` mode it can be omitted and is\n * inferred from the LiveRecord.\n */\n @Input() EntityName: string | null = null;\n\n /**\n * When true, the Restore button is disabled until the user enters a\n * non-empty reason. Useful for regulated environments where every\n * reversal needs justification. Default: false.\n */\n @Input() RequireReason = false;\n\n /**\n * When true, hides the optional reason text area entirely. Default: false.\n */\n @Input() HideReason = false;\n\n // ─── Outputs ────────────────────────────────────────────────────\n\n /**\n * Cancelable event fired when the user clicks Restore but before\n * {@link RestoreConfirmed} emits. Consumers can set `cancel = true` on\n * the event arg to abort the operation — useful for custom approval\n * workflows or for taking over the save themselves.\n */\n @Output() BeforeRestoreCommit = new EventEmitter<BeforeRestoreCommitEvent>();\n\n /**\n * Emitted after the user confirms the restore (and BeforeRestoreCommit\n * was not cancelled). The host is responsible for applying the field\n * values to a BaseEntity, calling SetRestoreContext, and invoking Save().\n */\n @Output() RestoreConfirmed = new EventEmitter<RestoreCommitEvent>();\n\n /**\n * Emitted when the user cancels the preview without restoring.\n */\n @Output() RestoreCancelled = new EventEmitter<void>();\n\n // ─── Public state (read by template) ────────────────────────────\n\n public Rows: RestoreFieldRow[] = [];\n public Reason = '';\n public IsRestoring = false;\n public ShowUnchanged = false;\n\n /** Number of rows where the current value differs from the snapshot. */\n public ChangedCount = 0;\n /** Number of rows that are checked (will be applied on restore). */\n public SelectedCount = 0;\n /** Number of rows the schema has dropped or renamed since the snapshot. */\n public DriftCount = 0;\n\n private isInitialized = false;\n private resolvedEntityInfo: EntityInfo | null = null;\n\n constructor(private cdr: ChangeDetectorRef) { super(); }\n\n ngOnInit(): void {\n this.isInitialized = true;\n // If the panel was opened synchronously during host bootstrap, the\n // Visible setter ran before `isInitialized` was true and skipped the\n // auto-reset. Do it here once so the first open is always clean.\n if (this._visible) {\n this.Reset();\n } else {\n this.rebuildRows();\n }\n }\n\n // ─── Public methods ─────────────────────────────────────────────\n\n /**\n * Toggles whether unchanged rows are visible in the table. When false\n * (default), only rows where current ≠ snapshot are shown.\n */\n public ToggleUnchanged(): void {\n this.ShowUnchanged = !this.ShowUnchanged;\n this.cdr.markForCheck();\n }\n\n /**\n * Toggles whether a single row is selected for restore. Updates the\n * SelectedCount in real time so the primary button label reflects it.\n */\n public ToggleRow(row: RestoreFieldRow): void {\n if (row.IsImmutable || row.IsMissingInSchema) return;\n row.Selected = !row.Selected;\n this.recountSelected();\n this.cdr.markForCheck();\n }\n\n /**\n * Selects every row that can be selected (skips immutable / drifted).\n */\n public SelectAll(): void {\n for (const row of this.Rows) {\n if (!row.IsImmutable && !row.IsMissingInSchema) row.Selected = true;\n }\n this.recountSelected();\n this.cdr.markForCheck();\n }\n\n /**\n * Deselects every row in the preview.\n */\n public DeselectAll(): void {\n for (const row of this.Rows) row.Selected = false;\n this.recountSelected();\n this.cdr.markForCheck();\n }\n\n /**\n * User clicked Restore — fire BeforeRestoreCommit (cancelable), then\n * RestoreConfirmed if not cancelled.\n */\n public ConfirmRestore(): void {\n if (!this._recordChange) return;\n if (this.IsRestoreDisabled) return;\n\n const selected = this.Rows.filter(r => r.Selected && !r.IsMissingInSchema && !r.IsImmutable);\n const reason = this.Reason.trim() ? this.Reason.trim() : null;\n\n const beforeEvent: BeforeRestoreCommitEvent = {\n cancel: false,\n SelectedFieldNames: selected.map(r => r.FieldName),\n AllRows: this.Rows.slice(),\n SourceChangeID: this._recordChange.ID,\n Reason: reason,\n Mode: this.Mode,\n };\n this.BeforeRestoreCommit.emit(beforeEvent);\n if (beforeEvent.cancel) return;\n\n this.IsRestoring = true;\n this.cdr.markForCheck();\n\n const commitEvent: RestoreCommitEvent = {\n SourceChangeID: this._recordChange.ID,\n Reason: reason,\n FieldValues: selected.map(r => ({ FieldName: r.FieldName, Value: r.RawRestoreValue })),\n AllRows: this.Rows.slice(),\n Mode: this.Mode,\n };\n this.RestoreConfirmed.emit(commitEvent);\n }\n\n /**\n * User cancelled the preview. Resets state and emits RestoreCancelled.\n */\n public Cancel(): void {\n this.RestoreCancelled.emit();\n }\n\n /**\n * Resets internal state — useful after a save completes so the panel\n * can be reopened cleanly. Called by the host component when needed.\n */\n public Reset(): void {\n this.Reason = '';\n this.IsRestoring = false;\n this.ShowUnchanged = false;\n this.rebuildRows();\n }\n\n // ─── Computed getters (template) ────────────────────────────────\n\n public get IsRestoreDisabled(): boolean {\n if (this.IsRestoring) return true;\n if (this.SelectedCount === 0) return true;\n if (this.RequireReason && this.Reason.trim().length === 0) return true;\n return false;\n }\n\n public get RestoreButtonLabel(): string {\n if (this.IsRestoring) return 'Restoring…';\n if (this.Mode === 'undelete') {\n return this.SelectedCount > 0 ? `Re-create (${this.SelectedCount} field${this.SelectedCount === 1 ? '' : 's'})` : 'Re-create';\n }\n return this.SelectedCount > 0 ? `Restore (${this.SelectedCount} field${this.SelectedCount === 1 ? '' : 's'})` : 'Restore';\n }\n\n public get HeaderTitle(): string {\n return this.Mode === 'undelete' ? 'Re-create from snapshot' : 'Restore record to this version';\n }\n\n public get VersionTimestamp(): Date | null {\n return this._recordChange?.ChangedAt ?? null;\n }\n\n public get VersionUser(): string {\n return this._recordChange?.User ?? '';\n }\n\n public get UnchangedCount(): number {\n return this.Rows.length - this.ChangedCount;\n }\n\n // ─── Internal: row building ─────────────────────────────────────\n\n /**\n * Rebuilds the Rows array from the current RecordChange + LiveRecord.\n * Idempotent and cheap — safe to call from input setters.\n */\n private rebuildRows(): void {\n this.Rows = [];\n this.ChangedCount = 0;\n this.SelectedCount = 0;\n this.DriftCount = 0;\n\n if (!this._recordChange) {\n this.cdr.markForCheck();\n return;\n }\n\n const snapshot = this.parseSnapshot(this._recordChange.FullRecordJSON);\n if (!snapshot) {\n this.cdr.markForCheck();\n return;\n }\n\n const entityInfo = this.resolveEntityInfo();\n if (!entityInfo) {\n this.cdr.markForCheck();\n return;\n }\n\n // Build a row for every field in the snapshot. We iterate the snapshot\n // (not EntityInfo.Fields) so fields that exist in the snapshot but no\n // longer in the schema surface as drift warnings.\n const seen = new Set<string>();\n for (const fieldName of Object.keys(snapshot)) {\n seen.add(fieldName.toLowerCase());\n const row = this.buildRowFromSnapshot(fieldName, snapshot[fieldName], entityInfo);\n if (row) this.Rows.push(row);\n }\n\n // Sort: changed rows first, then unchanged. Within each group, by display name.\n this.Rows.sort((a, b) => {\n if (a.IsChanged !== b.IsChanged) return a.IsChanged ? -1 : 1;\n return a.DisplayName.localeCompare(b.DisplayName);\n });\n\n this.ChangedCount = this.Rows.filter(r => r.IsChanged).length;\n this.DriftCount = this.Rows.filter(r => r.IsMissingInSchema).length;\n this.recountSelected();\n this.cdr.markForCheck();\n }\n\n private buildRowFromSnapshot(\n fieldName: string,\n snapshotValue: unknown,\n entityInfo: EntityInfo,\n ): RestoreFieldRow | null {\n const field = entityInfo.Fields.find(\n (f: EntityFieldInfo) => f.Name.trim().toLowerCase() === fieldName.trim().toLowerCase(),\n );\n\n // Skip system / timestamp fields that the platform manages.\n if (fieldName.startsWith('__mj_')) return null;\n\n const isImmutable = !!field && (field.ReadOnly || field.IsPrimaryKey);\n const isMissingInSchema = !field;\n const formattedRestore = FormatChangeValue(snapshotValue, field);\n const formattedCurrent = this.Mode === 'undelete'\n ? ''\n : this.getCurrentFieldValue(fieldName, field);\n\n // Compared by value, not by the display strings: those drop seconds, so a timestamp that moved\n // by under a minute would read as unchanged and be left out of the restore.\n const isChanged = this.Mode === 'undelete'\n ? snapshotValue != null && snapshotValue !== ''\n : !ChangeValuesMatch(this.getCurrentRawValue(fieldName), snapshotValue, field);\n\n // Default selection: pre-check changed rows that we can actually apply.\n const selected = isChanged && !isImmutable && !isMissingInSchema;\n\n return {\n FieldName: fieldName,\n DisplayName: field?.DisplayNameOrName ?? fieldName,\n CurrentValue: formattedCurrent,\n RestoreValue: formattedRestore,\n RawRestoreValue: snapshotValue,\n IsChanged: isChanged,\n Selected: selected,\n IsMissingInSchema: isMissingInSchema,\n IsFKMissing: false, // Reserved for future FK-existence check\n IsImmutable: isImmutable,\n };\n }\n\n private getCurrentFieldValue(fieldName: string, entityField: EntityFieldInfo | undefined): string {\n return FormatChangeValue(this.getCurrentRawValue(fieldName), entityField);\n }\n\n /** The live record's raw value for a field, or `undefined` when there is no live record or field. */\n private getCurrentRawValue(fieldName: string): unknown {\n if (!this._liveRecord) return undefined;\n const field = this._liveRecord.Fields.find(\n f => f.Name.trim().toLowerCase() === fieldName.trim().toLowerCase(),\n );\n return field?.Value;\n }\n\n private parseSnapshot(json: string | null | undefined): Record<string, unknown> | null {\n if (!json) return null;\n try {\n return JSON.parse(json) as Record<string, unknown>;\n } catch {\n return null;\n }\n }\n\n /**\n * Resolves the entity metadata. Prefers LiveRecord.EntityInfo (always\n * accurate). Falls back to looking up by EntityName. Memoized.\n */\n private resolveEntityInfo(): EntityInfo | null {\n if (this.resolvedEntityInfo) return this.resolvedEntityInfo;\n if (this._liveRecord?.EntityInfo) {\n this.resolvedEntityInfo = this._liveRecord.EntityInfo;\n return this.resolvedEntityInfo;\n }\n if (this.EntityName) {\n const md = this.ProviderToUse;\n const ei = md.Entities.find(\n e => e.Name.trim().toLowerCase() === this.EntityName!.trim().toLowerCase(),\n );\n this.resolvedEntityInfo = ei ?? null;\n return this.resolvedEntityInfo;\n }\n return null;\n }\n\n private recountSelected(): void {\n this.SelectedCount = this.Rows.filter(r => r.Selected).length;\n }\n\n // ─── Display helpers (template) ─────────────────────────────────\n\n public formatTimestamp(date: Date | null): string {\n if (!date) return '';\n return new Intl.DateTimeFormat('en-US', {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n hour: 'numeric',\n minute: '2-digit',\n hour12: true,\n }).format(new Date(date));\n }\n}\n","<mj-slide-panel\n [Mode]=\"'slide'\"\n [Title]=\"HeaderTitle\"\n [Visible]=\"Visible\"\n [Resizable]=\"true\"\n [MinWidthPx]=\"500\"\n [MaxWidthRatio]=\"0.7\"\n (Closed)=\"Cancel()\">\n\n @if (RecordChange) {\n <div class=\"rpp-container\">\n\n <!-- Header summary block -->\n <div class=\"rpp-header\">\n <div class=\"rpp-header-icon\">\n <i class=\"fa-solid fa-clock-rotate-left\" aria-hidden=\"true\"></i>\n </div>\n <div class=\"rpp-header-text\">\n <div class=\"rpp-header-title\">{{ HeaderTitle }}</div>\n <div class=\"rpp-header-meta\">\n <span><strong>Version:</strong> {{ formatTimestamp(VersionTimestamp) }}</span>\n @if (VersionUser) {\n <span><strong>By:</strong> {{ VersionUser }}</span>\n }\n </div>\n </div>\n </div>\n\n <!-- Drift warning -->\n @if (DriftCount > 0) {\n <div class=\"rpp-banner rpp-banner-warning\">\n <i class=\"fa-solid fa-triangle-exclamation\" aria-hidden=\"true\"></i>\n <span>{{ DriftCount }} field{{ DriftCount === 1 ? '' : 's' }} from this snapshot no longer exist on the entity and will be skipped.</span>\n </div>\n }\n\n <!-- Empty state -->\n @if (Rows.length === 0) {\n <mj-empty-state class=\"rpp-empty\" Size=\"compact\"\n Icon=\"fa-solid fa-circle-info\"\n Title=\"No fields could be parsed from this snapshot.\" />\n }\n\n <!-- Action bar (select all / deselect all) -->\n @if (Rows.length > 0 && Mode !== 'undelete') {\n <div class=\"rpp-action-bar\">\n <span class=\"rpp-action-bar-label\">{{ ChangedCount }} field{{ ChangedCount === 1 ? '' : 's' }} differ from current</span>\n <div class=\"rpp-action-bar-buttons\">\n <button class=\"rpp-link-btn\" type=\"button\" (click)=\"SelectAll()\" [disabled]=\"IsRestoring\">Select all changed</button>\n <span class=\"rpp-action-bar-sep\">·</span>\n <button class=\"rpp-link-btn\" type=\"button\" (click)=\"DeselectAll()\" [disabled]=\"IsRestoring\">Deselect all</button>\n </div>\n </div>\n }\n\n <!-- Diff table -->\n @if (Rows.length > 0) {\n <div class=\"rpp-table-wrap\">\n <table class=\"rpp-table\">\n <thead>\n <tr>\n <th class=\"rpp-col-check\"></th>\n <th class=\"rpp-col-field\">Field</th>\n @if (Mode === 'live') {\n <th class=\"rpp-col-current\">Current Value</th>\n <th class=\"rpp-col-restore\">Restore To</th>\n } @else {\n <th class=\"rpp-col-restore\" colspan=\"2\">Will be created with</th>\n }\n <th class=\"rpp-col-flag\"></th>\n </tr>\n </thead>\n <tbody>\n @for (row of Rows; track row.FieldName) {\n @if (row.IsChanged || ShowUnchanged) {\n <tr [class.rpp-row-changed]=\"row.IsChanged\"\n [class.rpp-row-unchanged]=\"!row.IsChanged\"\n [class.rpp-row-immutable]=\"row.IsImmutable\"\n [class.rpp-row-drift]=\"row.IsMissingInSchema\">\n <td class=\"rpp-col-check\">\n <button type=\"button\"\n class=\"rpp-checkbox\"\n [class.checked]=\"row.Selected\"\n [class.disabled]=\"row.IsImmutable || row.IsMissingInSchema\"\n [disabled]=\"row.IsImmutable || row.IsMissingInSchema || IsRestoring\"\n [attr.aria-label]=\"'Toggle ' + row.DisplayName\"\n (click)=\"ToggleRow(row)\">\n @if (row.Selected) {\n <i class=\"fa-solid fa-check\" aria-hidden=\"true\"></i>\n }\n </button>\n </td>\n <td class=\"rpp-col-field\">\n <div class=\"rpp-field-display\">{{ row.DisplayName }}</div>\n <div class=\"rpp-field-name\">{{ row.FieldName }}</div>\n </td>\n @if (Mode === 'live') {\n <td class=\"rpp-col-current\" [class.rpp-empty-cell]=\"!row.CurrentValue\">\n {{ row.CurrentValue || '(empty)' }}\n </td>\n <td class=\"rpp-col-restore\" [class.rpp-empty-cell]=\"!row.RestoreValue\">\n {{ row.RestoreValue || '(empty)' }}\n </td>\n } @else {\n <td class=\"rpp-col-restore\" colspan=\"2\" [class.rpp-empty-cell]=\"!row.RestoreValue\">\n {{ row.RestoreValue || '(empty)' }}\n </td>\n }\n <td class=\"rpp-col-flag\">\n @if (row.IsMissingInSchema) {\n <i class=\"fa-solid fa-triangle-exclamation rpp-flag-drift\"\n title=\"This field no longer exists on the entity and will be skipped\"\n aria-hidden=\"true\"></i>\n } @else if (row.IsImmutable) {\n <i class=\"fa-solid fa-lock rpp-flag-immutable\"\n title=\"Read-only or system field — cannot be modified\"\n aria-hidden=\"true\"></i>\n } @else if (row.IsChanged) {\n <i class=\"fa-solid fa-circle-exclamation rpp-flag-changed\"\n title=\"Will be changed\"\n aria-hidden=\"true\"></i>\n } @else {\n <i class=\"fa-solid fa-check rpp-flag-ok\"\n title=\"Already matches\"\n aria-hidden=\"true\"></i>\n }\n </td>\n </tr>\n }\n }\n </tbody>\n </table>\n </div>\n\n <!-- Unchanged disclosure -->\n @if (UnchangedCount > 0 && Mode === 'live') {\n <button class=\"rpp-disclosure\" type=\"button\" (click)=\"ToggleUnchanged()\">\n <i class=\"fa-solid\"\n [class.fa-chevron-right]=\"!ShowUnchanged\"\n [class.fa-chevron-down]=\"ShowUnchanged\"\n aria-hidden=\"true\"></i>\n <span>{{ ShowUnchanged ? 'Hide' : 'Show' }} {{ UnchangedCount }} unchanged field{{ UnchangedCount === 1 ? '' : 's' }}</span>\n </button>\n }\n }\n\n <!-- Reason text area -->\n @if (!HideReason && Rows.length > 0) {\n <div class=\"rpp-reason-section\">\n <label for=\"rpp-reason-input\">\n Reason for restore\n @if (RequireReason) {\n <span class=\"rpp-required\">*</span>\n } @else {\n <span class=\"rpp-optional\">(optional)</span>\n }\n </label>\n <textarea id=\"rpp-reason-input\"\n [(ngModel)]=\"Reason\"\n [disabled]=\"IsRestoring\"\n placeholder=\"e.g., Reverting incorrect Q2 entries\"\n class=\"rpp-reason-textarea\"\n rows=\"2\"></textarea>\n </div>\n }\n </div>\n\n <!-- Footer actions -->\n <div class=\"rpp-footer\">\n <div class=\"rpp-footer-info\">\n <i class=\"fa-solid fa-shield-halved\" aria-hidden=\"true\"></i>\n @if (Mode === 'live') {\n <span>A snapshot of the current state is saved automatically before the restore.</span>\n } @else {\n <span>A new \"Created\" entry will be added to this record's history, linked back to the original deletion.</span>\n }\n </div>\n <div class=\"rpp-footer-actions\">\n <button type=\"button\"\n class=\"rpp-btn rpp-btn-primary\"\n [disabled]=\"IsRestoreDisabled\"\n (click)=\"ConfirmRestore()\">\n @if (IsRestoring) {\n <i class=\"fa-solid fa-spinner fa-spin\" aria-hidden=\"true\"></i>\n } @else {\n <i class=\"fa-solid fa-rotate-left\" aria-hidden=\"true\"></i>\n }\n {{ RestoreButtonLabel }}\n </button>\n <button type=\"button\"\n class=\"rpp-btn rpp-btn-secondary\"\n [disabled]=\"IsRestoring\"\n (click)=\"Cancel()\">Cancel</button>\n </div>\n </div>\n }\n</mj-slide-panel>\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memberjunction/ng-record-changes",
3
- "version": "6.1.3",
3
+ "version": "6.1.5",
4
4
  "description": "MemberJunction: Angular dialog to show changes made to a specific individual record",
5
5
  "main": "./dist/public-api.js",
6
6
  "typings": "./dist/public-api.d.ts",
@@ -13,7 +13,7 @@
13
13
  "devDependencies": {
14
14
  "@angular/compiler": "21.2.22",
15
15
  "@angular/compiler-cli": "21.2.22",
16
- "@memberjunction/ng-test-utils": "6.1.3",
16
+ "@memberjunction/ng-test-utils": "6.1.5",
17
17
  "@types/diff": "^5.2.3",
18
18
  "vitest": "^4.0.18"
19
19
  },
@@ -24,14 +24,14 @@
24
24
  "@angular/platform-browser": "^21.2.22"
25
25
  },
26
26
  "dependencies": {
27
- "@memberjunction/core": "6.1.3",
28
- "@memberjunction/core-entities": "6.1.3",
29
- "@memberjunction/global": "6.1.3",
30
- "@memberjunction/ng-base-types": "6.1.3",
31
- "@memberjunction/ng-notifications": "6.1.3",
32
- "@memberjunction/ng-shared-generic": "6.1.3",
33
- "@memberjunction/ng-ui-components": "6.1.3",
34
- "@memberjunction/ng-versions": "6.1.3",
27
+ "@memberjunction/core": "6.1.5",
28
+ "@memberjunction/core-entities": "6.1.5",
29
+ "@memberjunction/global": "6.1.5",
30
+ "@memberjunction/ng-base-types": "6.1.5",
31
+ "@memberjunction/ng-notifications": "6.1.5",
32
+ "@memberjunction/ng-shared-generic": "6.1.5",
33
+ "@memberjunction/ng-ui-components": "6.1.5",
34
+ "@memberjunction/ng-versions": "6.1.5",
35
35
  "diff": "8.0.3",
36
36
  "rxjs": "^7.8.2",
37
37
  "tslib": "^2.8.1"