@memberjunction/ng-record-changes 6.2.0-edge.2 → 6.2.0-edge.3
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.
|
@@ -1 +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;
|
|
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;AAgB7G;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,eAAe,GAAG,SAAS,GAAG,MAAM,CAyB5F;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,eAAe,GAAG,SAAS,GAAG,OAAO,CAerG"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { EntityFieldTSType, FormatDateOnly, IsDateOnlySQLType } from '@memberjunction/core';
|
|
2
|
+
import { FormatBinaryChangeValue, IsBinaryChangeValue } from '@memberjunction/global';
|
|
2
3
|
/** An instant: the moment it happened, in the reader's zone. */
|
|
3
4
|
const TIMESTAMP_FORMAT = {
|
|
4
5
|
month: 'short',
|
|
@@ -27,6 +28,11 @@ const DATE_ONLY_FORMAT = { month: 'short', day: 'numeric', year: 'numeric' };
|
|
|
27
28
|
export function FormatChangeValue(value, field) {
|
|
28
29
|
if (value == null)
|
|
29
30
|
return '';
|
|
31
|
+
// A binary field holds base64 (an embedding, a file). Show its size, never the text: a snapshot
|
|
32
|
+
// value is formatted here; a diff value already arrives as the size text and is shown as-is.
|
|
33
|
+
if (field?.IsBinaryFieldType && typeof value === 'string') {
|
|
34
|
+
return IsBinaryChangeValue(value) ? value : FormatBinaryChangeValue(value);
|
|
35
|
+
}
|
|
30
36
|
if (field?.TSType === EntityFieldTSType.Date && (value instanceof Date || typeof value === 'string')) {
|
|
31
37
|
const date = value instanceof Date ? value : new Date(value);
|
|
32
38
|
if (!isNaN(date.getTime())) {
|
|
@@ -58,6 +64,10 @@ export function FormatChangeValue(value, field) {
|
|
|
58
64
|
* @param field The field's metadata, when known
|
|
59
65
|
*/
|
|
60
66
|
export function ChangeValuesMatch(a, b, field) {
|
|
67
|
+
// Two binary values of the same size format identically, so compare the base64 itself.
|
|
68
|
+
if (field?.IsBinaryFieldType) {
|
|
69
|
+
return (a ?? '') === (b ?? '');
|
|
70
|
+
}
|
|
61
71
|
if (field?.TSType === EntityFieldTSType.Date) {
|
|
62
72
|
const left = asValidDate(a);
|
|
63
73
|
const right = asValidDate(b);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format-change-value.js","sourceRoot":"","sources":["../../src/lib/format-change-value.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,iBAAiB,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;
|
|
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';\nimport { FormatBinaryChangeValue, IsBinaryChangeValue } from '@memberjunction/global';\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 // A binary field holds base64 (an embedding, a file). Show its size, never the text: a snapshot\n // value is formatted here; a diff value already arrives as the size text and is shown as-is.\n if (field?.IsBinaryFieldType && typeof value === 'string') {\n return IsBinaryChangeValue(value) ? value : FormatBinaryChangeValue(value);\n }\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 // Two binary values of the same size format identically, so compare the base64 itself.\n if (field?.IsBinaryFieldType) {\n return (a ?? '') === (b ?? '');\n }\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"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memberjunction/ng-record-changes",
|
|
3
|
-
"version": "6.2.0-edge.
|
|
3
|
+
"version": "6.2.0-edge.3",
|
|
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.2.0-edge.
|
|
16
|
+
"@memberjunction/ng-test-utils": "6.2.0-edge.3",
|
|
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.2.0-edge.
|
|
28
|
-
"@memberjunction/core-entities": "6.2.0-edge.
|
|
29
|
-
"@memberjunction/global": "6.2.0-edge.
|
|
30
|
-
"@memberjunction/ng-base-types": "6.2.0-edge.
|
|
31
|
-
"@memberjunction/ng-notifications": "6.2.0-edge.
|
|
32
|
-
"@memberjunction/ng-shared-generic": "6.2.0-edge.
|
|
33
|
-
"@memberjunction/ng-ui-components": "6.2.0-edge.
|
|
34
|
-
"@memberjunction/ng-versions": "6.2.0-edge.
|
|
27
|
+
"@memberjunction/core": "6.2.0-edge.3",
|
|
28
|
+
"@memberjunction/core-entities": "6.2.0-edge.3",
|
|
29
|
+
"@memberjunction/global": "6.2.0-edge.3",
|
|
30
|
+
"@memberjunction/ng-base-types": "6.2.0-edge.3",
|
|
31
|
+
"@memberjunction/ng-notifications": "6.2.0-edge.3",
|
|
32
|
+
"@memberjunction/ng-shared-generic": "6.2.0-edge.3",
|
|
33
|
+
"@memberjunction/ng-ui-components": "6.2.0-edge.3",
|
|
34
|
+
"@memberjunction/ng-versions": "6.2.0-edge.3",
|
|
35
35
|
"diff": "8.0.3",
|
|
36
36
|
"rxjs": "^7.8.2",
|
|
37
37
|
"tslib": "^2.8.1"
|