@memberjunction/ng-record-merge 0.0.1 → 5.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/record-merge-types.test.d.ts +2 -0
- package/dist/__tests__/record-merge-types.test.d.ts.map +1 -0
- package/dist/__tests__/record-merge-types.test.js +132 -0
- package/dist/__tests__/record-merge-types.test.js.map +1 -0
- package/dist/lib/module.d.ts +10 -0
- package/dist/lib/module.d.ts.map +1 -0
- package/dist/lib/module.js +29 -0
- package/dist/lib/module.js.map +1 -0
- package/dist/lib/record-merge-panel.component.d.ts +57 -0
- package/dist/lib/record-merge-panel.component.d.ts.map +1 -0
- package/dist/lib/record-merge-panel.component.js +348 -0
- package/dist/lib/record-merge-panel.component.js.map +1 -0
- package/dist/lib/record-merge-types.d.ts +84 -0
- package/dist/lib/record-merge-types.d.ts.map +1 -0
- package/dist/lib/record-merge-types.js +8 -0
- package/dist/lib/record-merge-types.js.map +1 -0
- package/dist/public-api.d.ts +4 -0
- package/dist/public-api.d.ts.map +1 -0
- package/dist/public-api.js +7 -0
- package/dist/public-api.js.map +1 -0
- package/package.json +36 -7
- package/README.md +0 -45
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record-merge-types.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/record-merge-types.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
describe('Record Merge Types', () => {
|
|
3
|
+
describe('FieldComparison', () => {
|
|
4
|
+
it('should represent a matching field', () => {
|
|
5
|
+
const field = {
|
|
6
|
+
FieldName: 'FirstName',
|
|
7
|
+
DisplayLabel: 'First Name',
|
|
8
|
+
LeftValue: 'John',
|
|
9
|
+
RightValue: 'John',
|
|
10
|
+
HasConflict: false,
|
|
11
|
+
SelectedSide: 'left',
|
|
12
|
+
IsReadOnly: false,
|
|
13
|
+
DataType: 'string'
|
|
14
|
+
};
|
|
15
|
+
expect(field.HasConflict).toBe(false);
|
|
16
|
+
expect(field.LeftValue).toBe(field.RightValue);
|
|
17
|
+
});
|
|
18
|
+
it('should represent a conflicting field', () => {
|
|
19
|
+
const field = {
|
|
20
|
+
FieldName: 'Email',
|
|
21
|
+
DisplayLabel: 'Email',
|
|
22
|
+
LeftValue: 'john@a.com',
|
|
23
|
+
RightValue: 'john@b.com',
|
|
24
|
+
HasConflict: true,
|
|
25
|
+
SelectedSide: 'left',
|
|
26
|
+
IsReadOnly: false,
|
|
27
|
+
DataType: 'string'
|
|
28
|
+
};
|
|
29
|
+
expect(field.HasConflict).toBe(true);
|
|
30
|
+
expect(field.LeftValue).not.toBe(field.RightValue);
|
|
31
|
+
});
|
|
32
|
+
it('should support read-only fields', () => {
|
|
33
|
+
const field = {
|
|
34
|
+
FieldName: 'ID',
|
|
35
|
+
DisplayLabel: 'ID',
|
|
36
|
+
LeftValue: 'abc-123',
|
|
37
|
+
RightValue: 'def-456',
|
|
38
|
+
HasConflict: true,
|
|
39
|
+
SelectedSide: 'left',
|
|
40
|
+
IsReadOnly: true,
|
|
41
|
+
DataType: 'string'
|
|
42
|
+
};
|
|
43
|
+
expect(field.IsReadOnly).toBe(true);
|
|
44
|
+
});
|
|
45
|
+
it('should support custom value selection', () => {
|
|
46
|
+
const field = {
|
|
47
|
+
FieldName: 'Phone',
|
|
48
|
+
DisplayLabel: 'Phone',
|
|
49
|
+
LeftValue: '555-0100',
|
|
50
|
+
RightValue: '555-0200',
|
|
51
|
+
HasConflict: true,
|
|
52
|
+
SelectedSide: 'custom',
|
|
53
|
+
CustomValue: '555-0150',
|
|
54
|
+
IsReadOnly: false,
|
|
55
|
+
DataType: 'string'
|
|
56
|
+
};
|
|
57
|
+
expect(field.SelectedSide).toBe('custom');
|
|
58
|
+
expect(field.CustomValue).toBe('555-0150');
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
describe('MergeConfig', () => {
|
|
62
|
+
it('should define merge parameters', () => {
|
|
63
|
+
const config = {
|
|
64
|
+
EntityName: 'Contacts',
|
|
65
|
+
LeftRecordID: 'rec-1',
|
|
66
|
+
RightRecordID: 'rec-2',
|
|
67
|
+
SurvivorSide: 'left',
|
|
68
|
+
LeftLabel: 'Record A',
|
|
69
|
+
RightLabel: 'Record B'
|
|
70
|
+
};
|
|
71
|
+
expect(config.SurvivorSide).toBe('left');
|
|
72
|
+
expect(config.EntityName).toBe('Contacts');
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
describe('MergeComparisonResult', () => {
|
|
76
|
+
it('should separate conflict and matching fields', () => {
|
|
77
|
+
const result = {
|
|
78
|
+
Fields: [],
|
|
79
|
+
ConflictFields: [
|
|
80
|
+
createField('Email', true),
|
|
81
|
+
createField('Phone', true)
|
|
82
|
+
],
|
|
83
|
+
MatchingFields: [
|
|
84
|
+
createField('FirstName', false),
|
|
85
|
+
createField('LastName', false),
|
|
86
|
+
createField('City', false)
|
|
87
|
+
],
|
|
88
|
+
TotalFieldCount: 5,
|
|
89
|
+
ConflictCount: 2
|
|
90
|
+
};
|
|
91
|
+
expect(result.ConflictCount).toBe(2);
|
|
92
|
+
expect(result.MatchingFields).toHaveLength(3);
|
|
93
|
+
expect(result.TotalFieldCount).toBe(5);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
describe('MergeActionResult', () => {
|
|
97
|
+
it('should represent successful merge', () => {
|
|
98
|
+
const result = {
|
|
99
|
+
Success: true,
|
|
100
|
+
SurvivorRecordID: 'rec-1',
|
|
101
|
+
MergedRecordID: 'rec-2',
|
|
102
|
+
UpdatedFieldCount: 3
|
|
103
|
+
};
|
|
104
|
+
expect(result.Success).toBe(true);
|
|
105
|
+
expect(result.UpdatedFieldCount).toBe(3);
|
|
106
|
+
});
|
|
107
|
+
it('should represent failed merge', () => {
|
|
108
|
+
const result = {
|
|
109
|
+
Success: false,
|
|
110
|
+
SurvivorRecordID: 'rec-1',
|
|
111
|
+
MergedRecordID: 'rec-2',
|
|
112
|
+
UpdatedFieldCount: 0,
|
|
113
|
+
ErrorMessage: 'Record locked by another user'
|
|
114
|
+
};
|
|
115
|
+
expect(result.Success).toBe(false);
|
|
116
|
+
expect(result.ErrorMessage).toBeDefined();
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
function createField(name, hasConflict) {
|
|
121
|
+
return {
|
|
122
|
+
FieldName: name,
|
|
123
|
+
DisplayLabel: name,
|
|
124
|
+
LeftValue: `left-${name}`,
|
|
125
|
+
RightValue: hasConflict ? `right-${name}` : `left-${name}`,
|
|
126
|
+
HasConflict: hasConflict,
|
|
127
|
+
SelectedSide: 'left',
|
|
128
|
+
IsReadOnly: false,
|
|
129
|
+
DataType: 'string'
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=record-merge-types.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record-merge-types.test.js","sourceRoot":"","sources":["../../src/__tests__/record-merge-types.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, it, expect } from 'vitest';\nimport {\n FieldComparison,\n MergeConfig,\n MergeComparisonResult,\n MergeActionResult,\n MergeConfirmedEvent,\n FieldSelectionEvent\n} from '../lib/record-merge-types';\n\ndescribe('Record Merge Types', () => {\n describe('FieldComparison', () => {\n it('should represent a matching field', () => {\n const field: FieldComparison = {\n FieldName: 'FirstName',\n DisplayLabel: 'First Name',\n LeftValue: 'John',\n RightValue: 'John',\n HasConflict: false,\n SelectedSide: 'left',\n IsReadOnly: false,\n DataType: 'string'\n };\n\n expect(field.HasConflict).toBe(false);\n expect(field.LeftValue).toBe(field.RightValue);\n });\n\n it('should represent a conflicting field', () => {\n const field: FieldComparison = {\n FieldName: 'Email',\n DisplayLabel: 'Email',\n LeftValue: 'john@a.com',\n RightValue: 'john@b.com',\n HasConflict: true,\n SelectedSide: 'left',\n IsReadOnly: false,\n DataType: 'string'\n };\n\n expect(field.HasConflict).toBe(true);\n expect(field.LeftValue).not.toBe(field.RightValue);\n });\n\n it('should support read-only fields', () => {\n const field: FieldComparison = {\n FieldName: 'ID',\n DisplayLabel: 'ID',\n LeftValue: 'abc-123',\n RightValue: 'def-456',\n HasConflict: true,\n SelectedSide: 'left',\n IsReadOnly: true,\n DataType: 'string'\n };\n\n expect(field.IsReadOnly).toBe(true);\n });\n\n it('should support custom value selection', () => {\n const field: FieldComparison = {\n FieldName: 'Phone',\n DisplayLabel: 'Phone',\n LeftValue: '555-0100',\n RightValue: '555-0200',\n HasConflict: true,\n SelectedSide: 'custom',\n CustomValue: '555-0150',\n IsReadOnly: false,\n DataType: 'string'\n };\n\n expect(field.SelectedSide).toBe('custom');\n expect(field.CustomValue).toBe('555-0150');\n });\n });\n\n describe('MergeConfig', () => {\n it('should define merge parameters', () => {\n const config: MergeConfig = {\n EntityName: 'Contacts',\n LeftRecordID: 'rec-1',\n RightRecordID: 'rec-2',\n SurvivorSide: 'left',\n LeftLabel: 'Record A',\n RightLabel: 'Record B'\n };\n\n expect(config.SurvivorSide).toBe('left');\n expect(config.EntityName).toBe('Contacts');\n });\n });\n\n describe('MergeComparisonResult', () => {\n it('should separate conflict and matching fields', () => {\n const result: MergeComparisonResult = {\n Fields: [],\n ConflictFields: [\n createField('Email', true),\n createField('Phone', true)\n ],\n MatchingFields: [\n createField('FirstName', false),\n createField('LastName', false),\n createField('City', false)\n ],\n TotalFieldCount: 5,\n ConflictCount: 2\n };\n\n expect(result.ConflictCount).toBe(2);\n expect(result.MatchingFields).toHaveLength(3);\n expect(result.TotalFieldCount).toBe(5);\n });\n });\n\n describe('MergeActionResult', () => {\n it('should represent successful merge', () => {\n const result: MergeActionResult = {\n Success: true,\n SurvivorRecordID: 'rec-1',\n MergedRecordID: 'rec-2',\n UpdatedFieldCount: 3\n };\n\n expect(result.Success).toBe(true);\n expect(result.UpdatedFieldCount).toBe(3);\n });\n\n it('should represent failed merge', () => {\n const result: MergeActionResult = {\n Success: false,\n SurvivorRecordID: 'rec-1',\n MergedRecordID: 'rec-2',\n UpdatedFieldCount: 0,\n ErrorMessage: 'Record locked by another user'\n };\n\n expect(result.Success).toBe(false);\n expect(result.ErrorMessage).toBeDefined();\n });\n });\n});\n\nfunction createField(name: string, hasConflict: boolean): FieldComparison {\n return {\n FieldName: name,\n DisplayLabel: name,\n LeftValue: `left-${name}`,\n RightValue: hasConflict ? `right-${name}` : `left-${name}`,\n HasConflict: hasConflict,\n SelectedSide: 'left',\n IsReadOnly: false,\n DataType: 'string'\n };\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as i0 from "@angular/core";
|
|
2
|
+
import * as i1 from "./record-merge-panel.component";
|
|
3
|
+
import * as i2 from "@angular/common";
|
|
4
|
+
import * as i3 from "@memberjunction/ng-shared-generic";
|
|
5
|
+
export declare class RecordMergeModule {
|
|
6
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<RecordMergeModule, never>;
|
|
7
|
+
static ɵmod: i0.ɵɵNgModuleDeclaration<RecordMergeModule, [typeof i1.RecordMergePanelComponent], [typeof i2.CommonModule, typeof i3.SharedGenericModule], [typeof i1.RecordMergePanelComponent]>;
|
|
8
|
+
static ɵinj: i0.ɵɵInjectorDeclaration<RecordMergeModule>;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=module.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../src/lib/module.ts"],"names":[],"mappings":";;;;AAMA,qBAYa,iBAAiB;yCAAjB,iBAAiB;0CAAjB,iBAAiB;0CAAjB,iBAAiB;CAAI"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { NgModule } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { SharedGenericModule } from '@memberjunction/ng-shared-generic';
|
|
4
|
+
import { RecordMergePanelComponent } from './record-merge-panel.component';
|
|
5
|
+
import * as i0 from "@angular/core";
|
|
6
|
+
export class RecordMergeModule {
|
|
7
|
+
static ɵfac = function RecordMergeModule_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || RecordMergeModule)(); };
|
|
8
|
+
static ɵmod = /*@__PURE__*/ i0.ɵɵdefineNgModule({ type: RecordMergeModule });
|
|
9
|
+
static ɵinj = /*@__PURE__*/ i0.ɵɵdefineInjector({ imports: [CommonModule,
|
|
10
|
+
SharedGenericModule] });
|
|
11
|
+
}
|
|
12
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(RecordMergeModule, [{
|
|
13
|
+
type: NgModule,
|
|
14
|
+
args: [{
|
|
15
|
+
declarations: [
|
|
16
|
+
RecordMergePanelComponent
|
|
17
|
+
],
|
|
18
|
+
imports: [
|
|
19
|
+
CommonModule,
|
|
20
|
+
SharedGenericModule
|
|
21
|
+
],
|
|
22
|
+
exports: [
|
|
23
|
+
RecordMergePanelComponent
|
|
24
|
+
]
|
|
25
|
+
}]
|
|
26
|
+
}], null, null); })();
|
|
27
|
+
(function () { (typeof ngJitMode === "undefined" || ngJitMode) && i0.ɵɵsetNgModuleScope(RecordMergeModule, { declarations: [RecordMergePanelComponent], imports: [CommonModule,
|
|
28
|
+
SharedGenericModule], exports: [RecordMergePanelComponent] }); })();
|
|
29
|
+
//# sourceMappingURL=module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module.js","sourceRoot":"","sources":["../../src/lib/module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAExE,OAAO,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAC;;AAc3E,MAAM,OAAO,iBAAiB;2GAAjB,iBAAiB;4DAAjB,iBAAiB;gEAPtB,YAAY;YACZ,mBAAmB;;iFAMd,iBAAiB;cAZ7B,QAAQ;eAAC;gBACN,YAAY,EAAE;oBACV,yBAAyB;iBAC5B;gBACD,OAAO,EAAE;oBACL,YAAY;oBACZ,mBAAmB;iBACtB;gBACD,OAAO,EAAE;oBACL,yBAAyB;iBAC5B;aACJ;;wFACY,iBAAiB,mBAVtB,yBAAyB,aAGzB,YAAY;QACZ,mBAAmB,aAGnB,yBAAyB","sourcesContent":["import { NgModule } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { SharedGenericModule } from '@memberjunction/ng-shared-generic';\n\nimport { RecordMergePanelComponent } from './record-merge-panel.component';\n\n@NgModule({\n declarations: [\n RecordMergePanelComponent\n ],\n imports: [\n CommonModule,\n SharedGenericModule\n ],\n exports: [\n RecordMergePanelComponent\n ]\n})\nexport class RecordMergeModule { }\n"]}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Record Merge Panel Component
|
|
3
|
+
*
|
|
4
|
+
* Side-by-side field comparison panel for entity records.
|
|
5
|
+
* Highlights conflicting values and allows field-by-field selection
|
|
6
|
+
* of which value to keep in the merge result.
|
|
7
|
+
*/
|
|
8
|
+
import { EventEmitter, OnInit } from '@angular/core';
|
|
9
|
+
import { FieldComparison, MergeConfig, MergeComparisonResult, MergeConfirmedEvent, FieldSelectionEvent } from './record-merge-types';
|
|
10
|
+
import * as i0 from "@angular/core";
|
|
11
|
+
export declare class RecordMergePanelComponent implements OnInit {
|
|
12
|
+
private cdr;
|
|
13
|
+
/** Field comparisons to display */
|
|
14
|
+
Fields: FieldComparison[];
|
|
15
|
+
/** Merge configuration */
|
|
16
|
+
Config: MergeConfig | null;
|
|
17
|
+
/** Whether to show only conflicting fields initially */
|
|
18
|
+
ShowConflictsOnly: boolean;
|
|
19
|
+
/** Whether the merge action is enabled */
|
|
20
|
+
MergeEnabled: boolean;
|
|
21
|
+
/** Whether a merge is in progress */
|
|
22
|
+
IsMerging: boolean;
|
|
23
|
+
MergeConfirmed: EventEmitter<MergeConfirmedEvent>;
|
|
24
|
+
MergeCancelled: EventEmitter<void>;
|
|
25
|
+
FieldSelected: EventEmitter<FieldSelectionEvent>;
|
|
26
|
+
ShowAllFields: boolean;
|
|
27
|
+
Comparison: MergeComparisonResult | null;
|
|
28
|
+
ConfirmDialogVisible: boolean;
|
|
29
|
+
ngOnInit(): void;
|
|
30
|
+
/** Toggle between showing all fields and conflicts only */
|
|
31
|
+
ToggleShowAll(): void;
|
|
32
|
+
/** Select the left value for a field */
|
|
33
|
+
SelectLeft(field: FieldComparison): void;
|
|
34
|
+
/** Select the right value for a field */
|
|
35
|
+
SelectRight(field: FieldComparison): void;
|
|
36
|
+
/** Select all fields from the left side */
|
|
37
|
+
SelectAllLeft(): void;
|
|
38
|
+
/** Select all fields from the right side */
|
|
39
|
+
SelectAllRight(): void;
|
|
40
|
+
/** Get fields to display based on current filter */
|
|
41
|
+
GetVisibleFields(): FieldComparison[];
|
|
42
|
+
/** Show the merge confirmation dialog */
|
|
43
|
+
ShowConfirmDialog(): void;
|
|
44
|
+
/** Confirm the merge */
|
|
45
|
+
ConfirmMerge(): void;
|
|
46
|
+
/** Cancel the merge */
|
|
47
|
+
CancelMerge(): void;
|
|
48
|
+
/** Get the display value for a field value */
|
|
49
|
+
FormatValue(value: unknown): string;
|
|
50
|
+
/** Check if all conflict fields have been resolved */
|
|
51
|
+
AllConflictsResolved(): boolean;
|
|
52
|
+
private buildComparison;
|
|
53
|
+
private emitFieldSelection;
|
|
54
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<RecordMergePanelComponent, never>;
|
|
55
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<RecordMergePanelComponent, "mj-record-merge-panel", never, { "Fields": { "alias": "Fields"; "required": false; }; "Config": { "alias": "Config"; "required": false; }; "ShowConflictsOnly": { "alias": "ShowConflictsOnly"; "required": false; }; "MergeEnabled": { "alias": "MergeEnabled"; "required": false; }; "IsMerging": { "alias": "IsMerging"; "required": false; }; }, { "MergeConfirmed": "MergeConfirmed"; "MergeCancelled": "MergeCancelled"; "FieldSelected": "FieldSelected"; }, never, never, false, never>;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=record-merge-panel.component.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record-merge-panel.component.d.ts","sourceRoot":"","sources":["../../src/lib/record-merge-panel.component.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAEH,YAAY,EAGZ,MAAM,EAGT,MAAM,eAAe,CAAC;AACvB,OAAO,EACH,eAAe,EACf,WAAW,EACX,qBAAqB,EACrB,mBAAmB,EACnB,mBAAmB,EACtB,MAAM,sBAAsB,CAAC;;AAE9B,qBAMa,yBAA0B,YAAW,MAAM;IACpD,OAAO,CAAC,GAAG,CAA6B;IAIxC,mCAAmC;IAC1B,MAAM,EAAE,eAAe,EAAE,CAAM;IAExC,0BAA0B;IACjB,MAAM,EAAE,WAAW,GAAG,IAAI,CAAQ;IAE3C,wDAAwD;IAC/C,iBAAiB,UAAS;IAEnC,0CAA0C;IACjC,YAAY,UAAQ;IAE7B,qCAAqC;IAC5B,SAAS,UAAS;IAIjB,cAAc,oCAA2C;IACzD,cAAc,qBAA4B;IAC1C,aAAa,oCAA2C;IAI3D,aAAa,UAAQ;IACrB,UAAU,EAAE,qBAAqB,GAAG,IAAI,CAAQ;IAChD,oBAAoB,UAAS;IAEpC,QAAQ,IAAI,IAAI;IAKhB,2DAA2D;IACpD,aAAa,IAAI,IAAI;IAK5B,wCAAwC;IACjC,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI;IAM/C,yCAAyC;IAClC,WAAW,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI;IAMhD,2CAA2C;IACpC,aAAa,IAAI,IAAI;IAS5B,4CAA4C;IACrC,cAAc,IAAI,IAAI;IAS7B,oDAAoD;IAC7C,gBAAgB,IAAI,eAAe,EAAE;IAO5C,yCAAyC;IAClC,iBAAiB,IAAI,IAAI;IAKhC,wBAAwB;IACjB,YAAY,IAAI,IAAI;IAS3B,uBAAuB;IAChB,WAAW,IAAI,IAAI;IAK1B,8CAA8C;IACvC,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM;IAa1C,sDAAsD;IAC/C,oBAAoB,IAAI,OAAO;IAOtC,OAAO,CAAC,eAAe;IAYvB,OAAO,CAAC,kBAAkB;yCA7IjB,yBAAyB;2CAAzB,yBAAyB;CAwJrC"}
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Record Merge Panel Component
|
|
3
|
+
*
|
|
4
|
+
* Side-by-side field comparison panel for entity records.
|
|
5
|
+
* Highlights conflicting values and allows field-by-field selection
|
|
6
|
+
* of which value to keep in the merge result.
|
|
7
|
+
*/
|
|
8
|
+
import { Component, EventEmitter, Input, Output, ChangeDetectorRef, inject } from '@angular/core';
|
|
9
|
+
import * as i0 from "@angular/core";
|
|
10
|
+
const _forTrack0 = ($index, $item) => $item.FieldName;
|
|
11
|
+
function RecordMergePanelComponent_Conditional_0_Conditional_11_Template(rf, ctx) { if (rf & 1) {
|
|
12
|
+
i0.ɵɵelement(0, "i", 20);
|
|
13
|
+
i0.ɵɵtext(1, " Show Conflicts Only ");
|
|
14
|
+
} }
|
|
15
|
+
function RecordMergePanelComponent_Conditional_0_Conditional_12_Template(rf, ctx) { if (rf & 1) {
|
|
16
|
+
i0.ɵɵelement(0, "i", 21);
|
|
17
|
+
i0.ɵɵtext(1, " Show All Fields ");
|
|
18
|
+
} }
|
|
19
|
+
function RecordMergePanelComponent_Conditional_0_For_28_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
20
|
+
i0.ɵɵelement(0, "i", 25);
|
|
21
|
+
} }
|
|
22
|
+
function RecordMergePanelComponent_Conditional_0_For_28_Conditional_8_Template(rf, ctx) { if (rf & 1) {
|
|
23
|
+
i0.ɵɵelement(0, "i", 28);
|
|
24
|
+
} }
|
|
25
|
+
function RecordMergePanelComponent_Conditional_0_For_28_Conditional_12_Template(rf, ctx) { if (rf & 1) {
|
|
26
|
+
i0.ɵɵelement(0, "i", 28);
|
|
27
|
+
} }
|
|
28
|
+
function RecordMergePanelComponent_Conditional_0_For_28_Template(rf, ctx) { if (rf & 1) {
|
|
29
|
+
const _r3 = i0.ɵɵgetCurrentView();
|
|
30
|
+
i0.ɵɵelementStart(0, "div", 22)(1, "div", 23)(2, "span", 24);
|
|
31
|
+
i0.ɵɵtext(3);
|
|
32
|
+
i0.ɵɵelementEnd();
|
|
33
|
+
i0.ɵɵconditionalCreate(4, RecordMergePanelComponent_Conditional_0_For_28_Conditional_4_Template, 1, 0, "i", 25);
|
|
34
|
+
i0.ɵɵelementEnd();
|
|
35
|
+
i0.ɵɵelementStart(5, "div", 26);
|
|
36
|
+
i0.ɵɵlistener("click", function RecordMergePanelComponent_Conditional_0_For_28_Template_div_click_5_listener() { const field_r4 = i0.ɵɵrestoreView(_r3).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.SelectLeft(field_r4)); });
|
|
37
|
+
i0.ɵɵelementStart(6, "span", 27);
|
|
38
|
+
i0.ɵɵtext(7);
|
|
39
|
+
i0.ɵɵelementEnd();
|
|
40
|
+
i0.ɵɵconditionalCreate(8, RecordMergePanelComponent_Conditional_0_For_28_Conditional_8_Template, 1, 0, "i", 28);
|
|
41
|
+
i0.ɵɵelementEnd();
|
|
42
|
+
i0.ɵɵelementStart(9, "div", 29);
|
|
43
|
+
i0.ɵɵlistener("click", function RecordMergePanelComponent_Conditional_0_For_28_Template_div_click_9_listener() { const field_r4 = i0.ɵɵrestoreView(_r3).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.SelectRight(field_r4)); });
|
|
44
|
+
i0.ɵɵelementStart(10, "span", 27);
|
|
45
|
+
i0.ɵɵtext(11);
|
|
46
|
+
i0.ɵɵelementEnd();
|
|
47
|
+
i0.ɵɵconditionalCreate(12, RecordMergePanelComponent_Conditional_0_For_28_Conditional_12_Template, 1, 0, "i", 28);
|
|
48
|
+
i0.ɵɵelementEnd()();
|
|
49
|
+
} if (rf & 2) {
|
|
50
|
+
const field_r4 = ctx.$implicit;
|
|
51
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
52
|
+
i0.ɵɵclassProp("merge-row-conflict", field_r4.HasConflict)("merge-row-readonly", field_r4.IsReadOnly);
|
|
53
|
+
i0.ɵɵadvance(3);
|
|
54
|
+
i0.ɵɵtextInterpolate(field_r4.DisplayLabel);
|
|
55
|
+
i0.ɵɵadvance();
|
|
56
|
+
i0.ɵɵconditional(field_r4.IsReadOnly ? 4 : -1);
|
|
57
|
+
i0.ɵɵadvance();
|
|
58
|
+
i0.ɵɵclassProp("merge-cell-selected", field_r4.SelectedSide === "left")("merge-cell-selectable", !field_r4.IsReadOnly);
|
|
59
|
+
i0.ɵɵadvance();
|
|
60
|
+
i0.ɵɵclassProp("merge-value-empty", field_r4.LeftValue === null || field_r4.LeftValue === undefined);
|
|
61
|
+
i0.ɵɵadvance();
|
|
62
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r1.FormatValue(field_r4.LeftValue), " ");
|
|
63
|
+
i0.ɵɵadvance();
|
|
64
|
+
i0.ɵɵconditional(field_r4.SelectedSide === "left" && !field_r4.IsReadOnly ? 8 : -1);
|
|
65
|
+
i0.ɵɵadvance();
|
|
66
|
+
i0.ɵɵclassProp("merge-cell-selected", field_r4.SelectedSide === "right")("merge-cell-selectable", !field_r4.IsReadOnly);
|
|
67
|
+
i0.ɵɵadvance();
|
|
68
|
+
i0.ɵɵclassProp("merge-value-empty", field_r4.RightValue === null || field_r4.RightValue === undefined);
|
|
69
|
+
i0.ɵɵadvance();
|
|
70
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r1.FormatValue(field_r4.RightValue), " ");
|
|
71
|
+
i0.ɵɵadvance();
|
|
72
|
+
i0.ɵɵconditional(field_r4.SelectedSide === "right" && !field_r4.IsReadOnly ? 12 : -1);
|
|
73
|
+
} }
|
|
74
|
+
function RecordMergePanelComponent_Conditional_0_Conditional_29_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
75
|
+
i0.ɵɵelement(0, "i", 32);
|
|
76
|
+
i0.ɵɵtext(1, " Merging... ");
|
|
77
|
+
} }
|
|
78
|
+
function RecordMergePanelComponent_Conditional_0_Conditional_29_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
79
|
+
i0.ɵɵelement(0, "i", 33);
|
|
80
|
+
i0.ɵɵtext(1, " Merge Records ");
|
|
81
|
+
} }
|
|
82
|
+
function RecordMergePanelComponent_Conditional_0_Conditional_29_Template(rf, ctx) { if (rf & 1) {
|
|
83
|
+
const _r5 = i0.ɵɵgetCurrentView();
|
|
84
|
+
i0.ɵɵelementStart(0, "div", 18)(1, "button", 30);
|
|
85
|
+
i0.ɵɵlistener("click", function RecordMergePanelComponent_Conditional_0_Conditional_29_Template_button_click_1_listener() { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.ShowConfirmDialog()); });
|
|
86
|
+
i0.ɵɵconditionalCreate(2, RecordMergePanelComponent_Conditional_0_Conditional_29_Conditional_2_Template, 2, 0)(3, RecordMergePanelComponent_Conditional_0_Conditional_29_Conditional_3_Template, 2, 0);
|
|
87
|
+
i0.ɵɵelementEnd();
|
|
88
|
+
i0.ɵɵelementStart(4, "button", 31);
|
|
89
|
+
i0.ɵɵlistener("click", function RecordMergePanelComponent_Conditional_0_Conditional_29_Template_button_click_4_listener() { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.CancelMerge()); });
|
|
90
|
+
i0.ɵɵtext(5, " Cancel ");
|
|
91
|
+
i0.ɵɵelementEnd()();
|
|
92
|
+
} if (rf & 2) {
|
|
93
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
94
|
+
i0.ɵɵadvance();
|
|
95
|
+
i0.ɵɵproperty("disabled", ctx_r1.IsMerging);
|
|
96
|
+
i0.ɵɵadvance();
|
|
97
|
+
i0.ɵɵconditional(ctx_r1.IsMerging ? 2 : 3);
|
|
98
|
+
i0.ɵɵadvance(2);
|
|
99
|
+
i0.ɵɵproperty("disabled", ctx_r1.IsMerging);
|
|
100
|
+
} }
|
|
101
|
+
function RecordMergePanelComponent_Conditional_0_Conditional_30_Template(rf, ctx) { if (rf & 1) {
|
|
102
|
+
const _r6 = i0.ɵɵgetCurrentView();
|
|
103
|
+
i0.ɵɵelementStart(0, "div", 34);
|
|
104
|
+
i0.ɵɵlistener("click", function RecordMergePanelComponent_Conditional_0_Conditional_30_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.ConfirmDialogVisible = false); });
|
|
105
|
+
i0.ɵɵelementStart(1, "div", 35);
|
|
106
|
+
i0.ɵɵlistener("click", function RecordMergePanelComponent_Conditional_0_Conditional_30_Template_div_click_1_listener($event) { i0.ɵɵrestoreView(_r6); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
107
|
+
i0.ɵɵelementStart(2, "div", 36);
|
|
108
|
+
i0.ɵɵelement(3, "i", 37);
|
|
109
|
+
i0.ɵɵelementStart(4, "h4");
|
|
110
|
+
i0.ɵɵtext(5, "Confirm Merge");
|
|
111
|
+
i0.ɵɵelementEnd()();
|
|
112
|
+
i0.ɵɵelementStart(6, "p", 38);
|
|
113
|
+
i0.ɵɵtext(7, " This will merge the selected field values and create a merge log. This action cannot be undone. Are you sure? ");
|
|
114
|
+
i0.ɵɵelementEnd();
|
|
115
|
+
i0.ɵɵelementStart(8, "div", 39)(9, "button", 40);
|
|
116
|
+
i0.ɵɵlistener("click", function RecordMergePanelComponent_Conditional_0_Conditional_30_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.ConfirmMerge()); });
|
|
117
|
+
i0.ɵɵelement(10, "i", 33);
|
|
118
|
+
i0.ɵɵtext(11, " Confirm Merge ");
|
|
119
|
+
i0.ɵɵelementEnd();
|
|
120
|
+
i0.ɵɵelementStart(12, "button", 41);
|
|
121
|
+
i0.ɵɵlistener("click", function RecordMergePanelComponent_Conditional_0_Conditional_30_Template_button_click_12_listener() { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.ConfirmDialogVisible = false); });
|
|
122
|
+
i0.ɵɵtext(13, " Cancel ");
|
|
123
|
+
i0.ɵɵelementEnd()()()();
|
|
124
|
+
} }
|
|
125
|
+
function RecordMergePanelComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
126
|
+
const _r1 = i0.ɵɵgetCurrentView();
|
|
127
|
+
i0.ɵɵelementStart(0, "div", 1)(1, "div", 2)(2, "div", 3)(3, "h3", 4);
|
|
128
|
+
i0.ɵɵtext(4, "Record Comparison");
|
|
129
|
+
i0.ɵɵelementEnd();
|
|
130
|
+
i0.ɵɵelementStart(5, "span", 5);
|
|
131
|
+
i0.ɵɵtext(6);
|
|
132
|
+
i0.ɵɵelementEnd();
|
|
133
|
+
i0.ɵɵelementStart(7, "span", 6);
|
|
134
|
+
i0.ɵɵtext(8);
|
|
135
|
+
i0.ɵɵelementEnd()();
|
|
136
|
+
i0.ɵɵelementStart(9, "div", 7)(10, "button", 8);
|
|
137
|
+
i0.ɵɵlistener("click", function RecordMergePanelComponent_Conditional_0_Template_button_click_10_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.ToggleShowAll()); });
|
|
138
|
+
i0.ɵɵconditionalCreate(11, RecordMergePanelComponent_Conditional_0_Conditional_11_Template, 2, 0)(12, RecordMergePanelComponent_Conditional_0_Conditional_12_Template, 2, 0);
|
|
139
|
+
i0.ɵɵelementEnd()()();
|
|
140
|
+
i0.ɵɵelementStart(13, "div", 9)(14, "div", 10);
|
|
141
|
+
i0.ɵɵtext(15, "Field");
|
|
142
|
+
i0.ɵɵelementEnd();
|
|
143
|
+
i0.ɵɵelementStart(16, "div", 11)(17, "span");
|
|
144
|
+
i0.ɵɵtext(18);
|
|
145
|
+
i0.ɵɵelementEnd();
|
|
146
|
+
i0.ɵɵelementStart(19, "button", 12);
|
|
147
|
+
i0.ɵɵlistener("click", function RecordMergePanelComponent_Conditional_0_Template_button_click_19_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.SelectAllLeft()); });
|
|
148
|
+
i0.ɵɵelement(20, "i", 13);
|
|
149
|
+
i0.ɵɵelementEnd()();
|
|
150
|
+
i0.ɵɵelementStart(21, "div", 14)(22, "span");
|
|
151
|
+
i0.ɵɵtext(23);
|
|
152
|
+
i0.ɵɵelementEnd();
|
|
153
|
+
i0.ɵɵelementStart(24, "button", 15);
|
|
154
|
+
i0.ɵɵlistener("click", function RecordMergePanelComponent_Conditional_0_Template_button_click_24_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.SelectAllRight()); });
|
|
155
|
+
i0.ɵɵelement(25, "i", 13);
|
|
156
|
+
i0.ɵɵelementEnd()()();
|
|
157
|
+
i0.ɵɵelementStart(26, "div", 16);
|
|
158
|
+
i0.ɵɵrepeaterCreate(27, RecordMergePanelComponent_Conditional_0_For_28_Template, 13, 22, "div", 17, _forTrack0);
|
|
159
|
+
i0.ɵɵelementEnd();
|
|
160
|
+
i0.ɵɵconditionalCreate(29, RecordMergePanelComponent_Conditional_0_Conditional_29_Template, 6, 3, "div", 18);
|
|
161
|
+
i0.ɵɵelementEnd();
|
|
162
|
+
i0.ɵɵconditionalCreate(30, RecordMergePanelComponent_Conditional_0_Conditional_30_Template, 14, 0, "div", 19);
|
|
163
|
+
} if (rf & 2) {
|
|
164
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
165
|
+
i0.ɵɵadvance(6);
|
|
166
|
+
i0.ɵɵtextInterpolate(ctx_r1.Config.EntityName);
|
|
167
|
+
i0.ɵɵadvance(2);
|
|
168
|
+
i0.ɵɵtextInterpolate2(" ", ctx_r1.Comparison.ConflictCount, " conflicts / ", ctx_r1.Comparison.TotalFieldCount, " fields ");
|
|
169
|
+
i0.ɵɵadvance(3);
|
|
170
|
+
i0.ɵɵconditional(ctx_r1.ShowAllFields ? 11 : 12);
|
|
171
|
+
i0.ɵɵadvance(7);
|
|
172
|
+
i0.ɵɵtextInterpolate(ctx_r1.Config.LeftLabel);
|
|
173
|
+
i0.ɵɵadvance(5);
|
|
174
|
+
i0.ɵɵtextInterpolate(ctx_r1.Config.RightLabel);
|
|
175
|
+
i0.ɵɵadvance(4);
|
|
176
|
+
i0.ɵɵrepeater(ctx_r1.GetVisibleFields());
|
|
177
|
+
i0.ɵɵadvance(2);
|
|
178
|
+
i0.ɵɵconditional(ctx_r1.MergeEnabled ? 29 : -1);
|
|
179
|
+
i0.ɵɵadvance();
|
|
180
|
+
i0.ɵɵconditional(ctx_r1.ConfirmDialogVisible ? 30 : -1);
|
|
181
|
+
} }
|
|
182
|
+
function RecordMergePanelComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
183
|
+
i0.ɵɵelementStart(0, "div", 0);
|
|
184
|
+
i0.ɵɵelement(1, "i", 42);
|
|
185
|
+
i0.ɵɵelementStart(2, "p");
|
|
186
|
+
i0.ɵɵtext(3, "Select two records to compare");
|
|
187
|
+
i0.ɵɵelementEnd()();
|
|
188
|
+
} }
|
|
189
|
+
export class RecordMergePanelComponent {
|
|
190
|
+
cdr = inject(ChangeDetectorRef);
|
|
191
|
+
// --- Inputs ---
|
|
192
|
+
/** Field comparisons to display */
|
|
193
|
+
Fields = [];
|
|
194
|
+
/** Merge configuration */
|
|
195
|
+
Config = null;
|
|
196
|
+
/** Whether to show only conflicting fields initially */
|
|
197
|
+
ShowConflictsOnly = false;
|
|
198
|
+
/** Whether the merge action is enabled */
|
|
199
|
+
MergeEnabled = true;
|
|
200
|
+
/** Whether a merge is in progress */
|
|
201
|
+
IsMerging = false;
|
|
202
|
+
// --- Outputs ---
|
|
203
|
+
MergeConfirmed = new EventEmitter();
|
|
204
|
+
MergeCancelled = new EventEmitter();
|
|
205
|
+
FieldSelected = new EventEmitter();
|
|
206
|
+
// --- Component State ---
|
|
207
|
+
ShowAllFields = true;
|
|
208
|
+
Comparison = null;
|
|
209
|
+
ConfirmDialogVisible = false;
|
|
210
|
+
ngOnInit() {
|
|
211
|
+
this.ShowAllFields = !this.ShowConflictsOnly;
|
|
212
|
+
this.buildComparison();
|
|
213
|
+
}
|
|
214
|
+
/** Toggle between showing all fields and conflicts only */
|
|
215
|
+
ToggleShowAll() {
|
|
216
|
+
this.ShowAllFields = !this.ShowAllFields;
|
|
217
|
+
this.cdr.detectChanges();
|
|
218
|
+
}
|
|
219
|
+
/** Select the left value for a field */
|
|
220
|
+
SelectLeft(field) {
|
|
221
|
+
if (field.IsReadOnly)
|
|
222
|
+
return;
|
|
223
|
+
field.SelectedSide = 'left';
|
|
224
|
+
this.emitFieldSelection(field);
|
|
225
|
+
}
|
|
226
|
+
/** Select the right value for a field */
|
|
227
|
+
SelectRight(field) {
|
|
228
|
+
if (field.IsReadOnly)
|
|
229
|
+
return;
|
|
230
|
+
field.SelectedSide = 'right';
|
|
231
|
+
this.emitFieldSelection(field);
|
|
232
|
+
}
|
|
233
|
+
/** Select all fields from the left side */
|
|
234
|
+
SelectAllLeft() {
|
|
235
|
+
for (const field of this.Fields) {
|
|
236
|
+
if (!field.IsReadOnly) {
|
|
237
|
+
field.SelectedSide = 'left';
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
this.cdr.detectChanges();
|
|
241
|
+
}
|
|
242
|
+
/** Select all fields from the right side */
|
|
243
|
+
SelectAllRight() {
|
|
244
|
+
for (const field of this.Fields) {
|
|
245
|
+
if (!field.IsReadOnly) {
|
|
246
|
+
field.SelectedSide = 'right';
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
this.cdr.detectChanges();
|
|
250
|
+
}
|
|
251
|
+
/** Get fields to display based on current filter */
|
|
252
|
+
GetVisibleFields() {
|
|
253
|
+
if (this.ShowAllFields) {
|
|
254
|
+
return this.Fields;
|
|
255
|
+
}
|
|
256
|
+
return this.Fields.filter(f => f.HasConflict);
|
|
257
|
+
}
|
|
258
|
+
/** Show the merge confirmation dialog */
|
|
259
|
+
ShowConfirmDialog() {
|
|
260
|
+
this.ConfirmDialogVisible = true;
|
|
261
|
+
this.cdr.detectChanges();
|
|
262
|
+
}
|
|
263
|
+
/** Confirm the merge */
|
|
264
|
+
ConfirmMerge() {
|
|
265
|
+
if (!this.Config)
|
|
266
|
+
return;
|
|
267
|
+
this.ConfirmDialogVisible = false;
|
|
268
|
+
this.MergeConfirmed.emit({
|
|
269
|
+
Config: this.Config,
|
|
270
|
+
ResolvedFields: this.Fields
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
/** Cancel the merge */
|
|
274
|
+
CancelMerge() {
|
|
275
|
+
this.ConfirmDialogVisible = false;
|
|
276
|
+
this.MergeCancelled.emit();
|
|
277
|
+
}
|
|
278
|
+
/** Get the display value for a field value */
|
|
279
|
+
FormatValue(value) {
|
|
280
|
+
if (value === null || value === undefined) {
|
|
281
|
+
return '(empty)';
|
|
282
|
+
}
|
|
283
|
+
if (value instanceof Date) {
|
|
284
|
+
return value.toLocaleString();
|
|
285
|
+
}
|
|
286
|
+
if (typeof value === 'boolean') {
|
|
287
|
+
return value ? 'Yes' : 'No';
|
|
288
|
+
}
|
|
289
|
+
return String(value);
|
|
290
|
+
}
|
|
291
|
+
/** Check if all conflict fields have been resolved */
|
|
292
|
+
AllConflictsResolved() {
|
|
293
|
+
if (!this.Comparison)
|
|
294
|
+
return true;
|
|
295
|
+
return this.Comparison.ConflictFields.every(f => f.SelectedSide === 'left' || f.SelectedSide === 'right');
|
|
296
|
+
}
|
|
297
|
+
// --- Private Methods ---
|
|
298
|
+
buildComparison() {
|
|
299
|
+
const conflictFields = this.Fields.filter(f => f.HasConflict);
|
|
300
|
+
const matchingFields = this.Fields.filter(f => !f.HasConflict);
|
|
301
|
+
this.Comparison = {
|
|
302
|
+
Fields: this.Fields,
|
|
303
|
+
ConflictFields: conflictFields,
|
|
304
|
+
MatchingFields: matchingFields,
|
|
305
|
+
TotalFieldCount: this.Fields.length,
|
|
306
|
+
ConflictCount: conflictFields.length
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
emitFieldSelection(field) {
|
|
310
|
+
const value = field.SelectedSide === 'left' ? field.LeftValue :
|
|
311
|
+
field.SelectedSide === 'right' ? field.RightValue :
|
|
312
|
+
field.CustomValue;
|
|
313
|
+
this.FieldSelected.emit({
|
|
314
|
+
FieldName: field.FieldName,
|
|
315
|
+
SelectedSide: field.SelectedSide,
|
|
316
|
+
Value: value
|
|
317
|
+
});
|
|
318
|
+
this.cdr.detectChanges();
|
|
319
|
+
}
|
|
320
|
+
static ɵfac = function RecordMergePanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || RecordMergePanelComponent)(); };
|
|
321
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: RecordMergePanelComponent, selectors: [["mj-record-merge-panel"]], inputs: { Fields: "Fields", Config: "Config", ShowConflictsOnly: "ShowConflictsOnly", MergeEnabled: "MergeEnabled", IsMerging: "IsMerging" }, outputs: { MergeConfirmed: "MergeConfirmed", MergeCancelled: "MergeCancelled", FieldSelected: "FieldSelected" }, standalone: false, decls: 2, vars: 1, consts: [[1, "merge-panel", "merge-panel-empty"], [1, "merge-panel"], [1, "merge-header"], [1, "merge-header-info"], [1, "merge-title"], [1, "merge-entity-name"], [1, "merge-conflict-badge"], [1, "merge-header-actions"], [1, "merge-toggle-btn", 3, "click"], [1, "merge-columns"], [1, "merge-col-label", "merge-col-field"], [1, "merge-col-label", "merge-col-left"], ["title", "Select all from left", 1, "merge-select-all-btn", 3, "click"], [1, "fa-solid", "fa-check-double"], [1, "merge-col-label", "merge-col-right"], ["title", "Select all from right", 1, "merge-select-all-btn", 3, "click"], [1, "merge-fields"], [1, "merge-row", 3, "merge-row-conflict", "merge-row-readonly"], [1, "merge-footer"], [1, "merge-dialog-backdrop"], [1, "fa-solid", "fa-filter"], [1, "fa-solid", "fa-list"], [1, "merge-row"], [1, "merge-cell", "merge-cell-field"], [1, "merge-field-name"], ["title", "Read-only field", 1, "fa-solid", "fa-lock", "merge-readonly-icon"], [1, "merge-cell", "merge-cell-value", "merge-cell-left", 3, "click"], [1, "merge-value"], [1, "fa-solid", "fa-check", "merge-check-icon"], [1, "merge-cell", "merge-cell-value", "merge-cell-right", 3, "click"], [1, "merge-btn", "merge-btn-primary", 3, "click", "disabled"], [1, "merge-btn", "merge-btn-secondary", 3, "click", "disabled"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "fa-solid", "fa-code-merge"], [1, "merge-dialog-backdrop", 3, "click"], [1, "merge-dialog", 3, "click"], [1, "merge-dialog-header"], [1, "fa-solid", "fa-exclamation-triangle", "merge-dialog-warning-icon"], [1, "merge-dialog-text"], [1, "merge-dialog-actions"], [1, "merge-btn", "merge-btn-primary", 3, "click"], [1, "merge-btn", "merge-btn-secondary", 3, "click"], [1, "fa-solid", "fa-code-compare", "merge-empty-icon"]], template: function RecordMergePanelComponent_Template(rf, ctx) { if (rf & 1) {
|
|
322
|
+
i0.ɵɵconditionalCreate(0, RecordMergePanelComponent_Conditional_0_Template, 31, 8)(1, RecordMergePanelComponent_Conditional_1_Template, 4, 0, "div", 0);
|
|
323
|
+
} if (rf & 2) {
|
|
324
|
+
i0.ɵɵconditional(ctx.Config && ctx.Comparison ? 0 : 1);
|
|
325
|
+
} }, styles: ["\n\n\n.merge-panel[_ngcontent-%COMP%] {\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n background: var(--mj-bg-surface);\n overflow: hidden;\n display: flex;\n flex-direction: column;\n}\n\n.merge-panel-empty[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 3rem 1rem;\n gap: 0.75rem;\n color: var(--mj-text-muted);\n}\n\n.merge-empty-icon[_ngcontent-%COMP%] {\n font-size: 2.5rem;\n margin-bottom: 0.5rem;\n}\n\n\n\n.merge-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.75rem 1rem;\n border-bottom: 1px solid var(--mj-border-default);\n flex-wrap: wrap;\n gap: 0.5rem;\n}\n\n.merge-header-info[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n flex-wrap: wrap;\n}\n\n.merge-title[_ngcontent-%COMP%] {\n font-size: 1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0;\n}\n\n.merge-entity-name[_ngcontent-%COMP%] {\n font-size: 0.82rem;\n color: var(--mj-text-secondary);\n padding: 0.1rem 0.5rem;\n background: var(--mj-bg-surface-sunken);\n border-radius: 4px;\n}\n\n.merge-conflict-badge[_ngcontent-%COMP%] {\n font-size: 0.78rem;\n color: var(--mj-status-warning-text);\n background: var(--mj-status-warning-bg);\n padding: 0.15rem 0.5rem;\n border-radius: 9999px;\n}\n\n.merge-toggle-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n padding: 0.35rem 0.75rem;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n font-size: 0.78rem;\n cursor: pointer;\n transition: all 0.15s ease;\n}\n\n.merge-toggle-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n\n\n.merge-columns[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 1fr 1fr 1fr;\n border-bottom: 2px solid var(--mj-border-default);\n}\n\n.merge-col-label[_ngcontent-%COMP%] {\n padding: 0.5rem 0.75rem;\n font-weight: 600;\n font-size: 0.78rem;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.03em;\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.merge-select-all-btn[_ngcontent-%COMP%] {\n border: none;\n background: none;\n color: var(--mj-text-muted);\n font-size: 0.72rem;\n cursor: pointer;\n padding: 0.2rem;\n border-radius: 3px;\n}\n\n.merge-select-all-btn[_ngcontent-%COMP%]:hover {\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n\n\n.merge-fields[_ngcontent-%COMP%] {\n overflow-y: auto;\n max-height: 60vh;\n}\n\n.merge-row[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 1fr 1fr 1fr;\n border-bottom: 1px solid var(--mj-border-subtle);\n transition: background 0.1s ease;\n}\n\n.merge-row[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.merge-row-conflict[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-warning) 5%, var(--mj-bg-surface));\n}\n\n.merge-row-readonly[_ngcontent-%COMP%] {\n opacity: 0.7;\n}\n\n.merge-cell[_ngcontent-%COMP%] {\n padding: 0.5rem 0.75rem;\n font-size: 0.85rem;\n display: flex;\n align-items: center;\n gap: 0.4rem;\n min-height: 2.5rem;\n}\n\n.merge-cell-field[_ngcontent-%COMP%] {\n color: var(--mj-text-primary);\n font-weight: 500;\n border-right: 1px solid var(--mj-border-subtle);\n}\n\n.merge-field-name[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.merge-readonly-icon[_ngcontent-%COMP%] {\n font-size: 0.65rem;\n color: var(--mj-text-muted);\n}\n\n.merge-cell-value[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.merge-cell-selectable[_ngcontent-%COMP%] {\n cursor: pointer;\n transition: all 0.15s ease;\n}\n\n.merge-cell-selectable[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.merge-cell-selected[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n border-left: 3px solid var(--mj-brand-primary);\n}\n\n.merge-value[_ngcontent-%COMP%] {\n color: var(--mj-text-primary);\n flex: 1;\n word-break: break-word;\n}\n\n.merge-value-empty[_ngcontent-%COMP%] {\n color: var(--mj-text-disabled);\n font-style: italic;\n}\n\n.merge-check-icon[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 0.75rem;\n flex-shrink: 0;\n}\n\n\n\n.merge-footer[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.75rem 1rem;\n border-top: 1px solid var(--mj-border-default);\n}\n\n.merge-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n padding: 0.5rem 1rem;\n border-radius: 6px;\n font-size: 0.85rem;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n border: none;\n}\n\n.merge-btn[_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.merge-btn-primary[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.merge-btn-primary[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n}\n\n.merge-btn-secondary[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n border: 1px solid var(--mj-border-default);\n}\n\n.merge-btn-secondary[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-bg-surface-hover);\n}\n\n\n\n.merge-dialog-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n inset: 0;\n background: var(--mj-bg-overlay);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10000;\n}\n\n.merge-dialog[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n padding: 1.5rem;\n max-width: 420px;\n width: 100%;\n box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);\n}\n\n.merge-dialog-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n margin-bottom: 0.75rem;\n}\n\n.merge-dialog-header[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 1.1rem;\n color: var(--mj-text-primary);\n}\n\n.merge-dialog-warning-icon[_ngcontent-%COMP%] {\n color: var(--mj-status-warning);\n font-size: 1.2rem;\n}\n\n.merge-dialog-text[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-size: 0.9rem;\n line-height: 1.5;\n margin-bottom: 1.25rem;\n}\n\n.merge-dialog-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.5rem;\n}\n\n\n\n@media (max-width: 768px) {\n .merge-columns[_ngcontent-%COMP%], \n .merge-row[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n\n .merge-cell-field[_ngcontent-%COMP%] {\n border-right: none;\n border-bottom: 1px solid var(--mj-border-subtle);\n font-size: 0.78rem;\n }\n\n .merge-col-left[_ngcontent-%COMP%], \n .merge-col-right[_ngcontent-%COMP%] {\n padding-left: 1.5rem;\n }\n}"] });
|
|
326
|
+
}
|
|
327
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(RecordMergePanelComponent, [{
|
|
328
|
+
type: Component,
|
|
329
|
+
args: [{ standalone: false, selector: 'mj-record-merge-panel', template: "@if (Config && Comparison) {\n <div class=\"merge-panel\">\n <!-- Header -->\n <div class=\"merge-header\">\n <div class=\"merge-header-info\">\n <h3 class=\"merge-title\">Record Comparison</h3>\n <span class=\"merge-entity-name\">{{ Config.EntityName }}</span>\n <span class=\"merge-conflict-badge\">\n {{ Comparison.ConflictCount }} conflicts / {{ Comparison.TotalFieldCount }} fields\n </span>\n </div>\n <div class=\"merge-header-actions\">\n <button class=\"merge-toggle-btn\" (click)=\"ToggleShowAll()\">\n @if (ShowAllFields) {\n <i class=\"fa-solid fa-filter\"></i> Show Conflicts Only\n } @else {\n <i class=\"fa-solid fa-list\"></i> Show All Fields\n }\n </button>\n </div>\n </div>\n\n <!-- Column Headers -->\n <div class=\"merge-columns\">\n <div class=\"merge-col-label merge-col-field\">Field</div>\n <div class=\"merge-col-label merge-col-left\">\n <span>{{ Config.LeftLabel }}</span>\n <button class=\"merge-select-all-btn\" (click)=\"SelectAllLeft()\" title=\"Select all from left\">\n <i class=\"fa-solid fa-check-double\"></i>\n </button>\n </div>\n <div class=\"merge-col-label merge-col-right\">\n <span>{{ Config.RightLabel }}</span>\n <button class=\"merge-select-all-btn\" (click)=\"SelectAllRight()\" title=\"Select all from right\">\n <i class=\"fa-solid fa-check-double\"></i>\n </button>\n </div>\n </div>\n\n <!-- Field Rows -->\n <div class=\"merge-fields\">\n @for (field of GetVisibleFields(); track field.FieldName) {\n <div class=\"merge-row\" [class.merge-row-conflict]=\"field.HasConflict\" [class.merge-row-readonly]=\"field.IsReadOnly\">\n <div class=\"merge-cell merge-cell-field\">\n <span class=\"merge-field-name\">{{ field.DisplayLabel }}</span>\n @if (field.IsReadOnly) {\n <i class=\"fa-solid fa-lock merge-readonly-icon\" title=\"Read-only field\"></i>\n }\n </div>\n <div\n class=\"merge-cell merge-cell-value merge-cell-left\"\n [class.merge-cell-selected]=\"field.SelectedSide === 'left'\"\n [class.merge-cell-selectable]=\"!field.IsReadOnly\"\n (click)=\"SelectLeft(field)\"\n >\n <span class=\"merge-value\" [class.merge-value-empty]=\"field.LeftValue === null || field.LeftValue === undefined\">\n {{ FormatValue(field.LeftValue) }}\n </span>\n @if (field.SelectedSide === 'left' && !field.IsReadOnly) {\n <i class=\"fa-solid fa-check merge-check-icon\"></i>\n }\n </div>\n <div\n class=\"merge-cell merge-cell-value merge-cell-right\"\n [class.merge-cell-selected]=\"field.SelectedSide === 'right'\"\n [class.merge-cell-selectable]=\"!field.IsReadOnly\"\n (click)=\"SelectRight(field)\"\n >\n <span class=\"merge-value\" [class.merge-value-empty]=\"field.RightValue === null || field.RightValue === undefined\">\n {{ FormatValue(field.RightValue) }}\n </span>\n @if (field.SelectedSide === 'right' && !field.IsReadOnly) {\n <i class=\"fa-solid fa-check merge-check-icon\"></i>\n }\n </div>\n </div>\n }\n </div>\n\n <!-- Footer Actions -->\n @if (MergeEnabled) {\n <div class=\"merge-footer\">\n <button class=\"merge-btn merge-btn-primary\" (click)=\"ShowConfirmDialog()\" [disabled]=\"IsMerging\">\n @if (IsMerging) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Merging...\n } @else {\n <i class=\"fa-solid fa-code-merge\"></i> Merge Records\n }\n </button>\n <button class=\"merge-btn merge-btn-secondary\" (click)=\"CancelMerge()\" [disabled]=\"IsMerging\">\n Cancel\n </button>\n </div>\n }\n </div>\n\n <!-- Confirmation Dialog -->\n @if (ConfirmDialogVisible) {\n <div class=\"merge-dialog-backdrop\" (click)=\"ConfirmDialogVisible = false\">\n <div class=\"merge-dialog\" (click)=\"$event.stopPropagation()\">\n <div class=\"merge-dialog-header\">\n <i class=\"fa-solid fa-exclamation-triangle merge-dialog-warning-icon\"></i>\n <h4>Confirm Merge</h4>\n </div>\n <p class=\"merge-dialog-text\">\n This will merge the selected field values and create a merge log.\n This action cannot be undone. Are you sure?\n </p>\n <div class=\"merge-dialog-actions\">\n <button class=\"merge-btn merge-btn-primary\" (click)=\"ConfirmMerge()\">\n <i class=\"fa-solid fa-code-merge\"></i> Confirm Merge\n </button>\n <button class=\"merge-btn merge-btn-secondary\" (click)=\"ConfirmDialogVisible = false\">\n Cancel\n </button>\n </div>\n </div>\n </div>\n }\n} @else {\n <div class=\"merge-panel merge-panel-empty\">\n <i class=\"fa-solid fa-code-compare merge-empty-icon\"></i>\n <p>Select two records to compare</p>\n </div>\n}\n", styles: ["/* Record Merge Panel */\n\n.merge-panel {\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n background: var(--mj-bg-surface);\n overflow: hidden;\n display: flex;\n flex-direction: column;\n}\n\n.merge-panel-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 3rem 1rem;\n gap: 0.75rem;\n color: var(--mj-text-muted);\n}\n\n.merge-empty-icon {\n font-size: 2.5rem;\n margin-bottom: 0.5rem;\n}\n\n/* Header */\n.merge-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.75rem 1rem;\n border-bottom: 1px solid var(--mj-border-default);\n flex-wrap: wrap;\n gap: 0.5rem;\n}\n\n.merge-header-info {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n flex-wrap: wrap;\n}\n\n.merge-title {\n font-size: 1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0;\n}\n\n.merge-entity-name {\n font-size: 0.82rem;\n color: var(--mj-text-secondary);\n padding: 0.1rem 0.5rem;\n background: var(--mj-bg-surface-sunken);\n border-radius: 4px;\n}\n\n.merge-conflict-badge {\n font-size: 0.78rem;\n color: var(--mj-status-warning-text);\n background: var(--mj-status-warning-bg);\n padding: 0.15rem 0.5rem;\n border-radius: 9999px;\n}\n\n.merge-toggle-btn {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n padding: 0.35rem 0.75rem;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n font-size: 0.78rem;\n cursor: pointer;\n transition: all 0.15s ease;\n}\n\n.merge-toggle-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n/* Column Headers */\n.merge-columns {\n display: grid;\n grid-template-columns: 1fr 1fr 1fr;\n border-bottom: 2px solid var(--mj-border-default);\n}\n\n.merge-col-label {\n padding: 0.5rem 0.75rem;\n font-weight: 600;\n font-size: 0.78rem;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.03em;\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.merge-select-all-btn {\n border: none;\n background: none;\n color: var(--mj-text-muted);\n font-size: 0.72rem;\n cursor: pointer;\n padding: 0.2rem;\n border-radius: 3px;\n}\n\n.merge-select-all-btn:hover {\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n/* Field Rows */\n.merge-fields {\n overflow-y: auto;\n max-height: 60vh;\n}\n\n.merge-row {\n display: grid;\n grid-template-columns: 1fr 1fr 1fr;\n border-bottom: 1px solid var(--mj-border-subtle);\n transition: background 0.1s ease;\n}\n\n.merge-row:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.merge-row-conflict {\n background: color-mix(in srgb, var(--mj-status-warning) 5%, var(--mj-bg-surface));\n}\n\n.merge-row-readonly {\n opacity: 0.7;\n}\n\n.merge-cell {\n padding: 0.5rem 0.75rem;\n font-size: 0.85rem;\n display: flex;\n align-items: center;\n gap: 0.4rem;\n min-height: 2.5rem;\n}\n\n.merge-cell-field {\n color: var(--mj-text-primary);\n font-weight: 500;\n border-right: 1px solid var(--mj-border-subtle);\n}\n\n.merge-field-name {\n flex: 1;\n}\n\n.merge-readonly-icon {\n font-size: 0.65rem;\n color: var(--mj-text-muted);\n}\n\n.merge-cell-value {\n position: relative;\n}\n\n.merge-cell-selectable {\n cursor: pointer;\n transition: all 0.15s ease;\n}\n\n.merge-cell-selectable:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.merge-cell-selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n border-left: 3px solid var(--mj-brand-primary);\n}\n\n.merge-value {\n color: var(--mj-text-primary);\n flex: 1;\n word-break: break-word;\n}\n\n.merge-value-empty {\n color: var(--mj-text-disabled);\n font-style: italic;\n}\n\n.merge-check-icon {\n color: var(--mj-brand-primary);\n font-size: 0.75rem;\n flex-shrink: 0;\n}\n\n/* Footer */\n.merge-footer {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.75rem 1rem;\n border-top: 1px solid var(--mj-border-default);\n}\n\n.merge-btn {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n padding: 0.5rem 1rem;\n border-radius: 6px;\n font-size: 0.85rem;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n border: none;\n}\n\n.merge-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.merge-btn-primary {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.merge-btn-primary:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n}\n\n.merge-btn-secondary {\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n border: 1px solid var(--mj-border-default);\n}\n\n.merge-btn-secondary:hover:not(:disabled) {\n background: var(--mj-bg-surface-hover);\n}\n\n/* Confirmation Dialog */\n.merge-dialog-backdrop {\n position: fixed;\n inset: 0;\n background: var(--mj-bg-overlay);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10000;\n}\n\n.merge-dialog {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n padding: 1.5rem;\n max-width: 420px;\n width: 100%;\n box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);\n}\n\n.merge-dialog-header {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n margin-bottom: 0.75rem;\n}\n\n.merge-dialog-header h4 {\n margin: 0;\n font-size: 1.1rem;\n color: var(--mj-text-primary);\n}\n\n.merge-dialog-warning-icon {\n color: var(--mj-status-warning);\n font-size: 1.2rem;\n}\n\n.merge-dialog-text {\n color: var(--mj-text-secondary);\n font-size: 0.9rem;\n line-height: 1.5;\n margin-bottom: 1.25rem;\n}\n\n.merge-dialog-actions {\n display: flex;\n gap: 0.5rem;\n}\n\n/* Mobile responsive */\n@media (max-width: 768px) {\n .merge-columns,\n .merge-row {\n grid-template-columns: 1fr;\n }\n\n .merge-cell-field {\n border-right: none;\n border-bottom: 1px solid var(--mj-border-subtle);\n font-size: 0.78rem;\n }\n\n .merge-col-left,\n .merge-col-right {\n padding-left: 1.5rem;\n }\n}\n"] }]
|
|
330
|
+
}], null, { Fields: [{
|
|
331
|
+
type: Input
|
|
332
|
+
}], Config: [{
|
|
333
|
+
type: Input
|
|
334
|
+
}], ShowConflictsOnly: [{
|
|
335
|
+
type: Input
|
|
336
|
+
}], MergeEnabled: [{
|
|
337
|
+
type: Input
|
|
338
|
+
}], IsMerging: [{
|
|
339
|
+
type: Input
|
|
340
|
+
}], MergeConfirmed: [{
|
|
341
|
+
type: Output
|
|
342
|
+
}], MergeCancelled: [{
|
|
343
|
+
type: Output
|
|
344
|
+
}], FieldSelected: [{
|
|
345
|
+
type: Output
|
|
346
|
+
}] }); })();
|
|
347
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(RecordMergePanelComponent, { className: "RecordMergePanelComponent", filePath: "src/lib/record-merge-panel.component.ts", lineNumber: 32 }); })();
|
|
348
|
+
//# sourceMappingURL=record-merge-panel.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record-merge-panel.component.js","sourceRoot":"","sources":["../../src/lib/record-merge-panel.component.ts","../../src/lib/record-merge-panel.component.html"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Record Merge Panel Component\n *\n * Side-by-side field comparison panel for entity records.\n * Highlights conflicting values and allows field-by-field selection\n * of which value to keep in the merge result.\n */\n\nimport {\n Component,\n EventEmitter,\n Input,\n Output,\n OnInit,\n ChangeDetectorRef,\n inject\n} from '@angular/core';\nimport {\n FieldComparison,\n MergeConfig,\n MergeComparisonResult,\n MergeConfirmedEvent,\n FieldSelectionEvent\n} from './record-merge-types';\n\n@Component({\n standalone: false,\n selector: 'mj-record-merge-panel',\n templateUrl: './record-merge-panel.component.html',\n styleUrls: ['./record-merge-panel.component.css']\n})\nexport class RecordMergePanelComponent implements OnInit {\n private cdr = inject(ChangeDetectorRef);\n\n // --- Inputs ---\n\n /** Field comparisons to display */\n @Input() Fields: FieldComparison[] = [];\n\n /** Merge configuration */\n @Input() Config: MergeConfig | null = null;\n\n /** Whether to show only conflicting fields initially */\n @Input() ShowConflictsOnly = false;\n\n /** Whether the merge action is enabled */\n @Input() MergeEnabled = true;\n\n /** Whether a merge is in progress */\n @Input() IsMerging = false;\n\n // --- Outputs ---\n\n @Output() MergeConfirmed = new EventEmitter<MergeConfirmedEvent>();\n @Output() MergeCancelled = new EventEmitter<void>();\n @Output() FieldSelected = new EventEmitter<FieldSelectionEvent>();\n\n // --- Component State ---\n\n public ShowAllFields = true;\n public Comparison: MergeComparisonResult | null = null;\n public ConfirmDialogVisible = false;\n\n ngOnInit(): void {\n this.ShowAllFields = !this.ShowConflictsOnly;\n this.buildComparison();\n }\n\n /** Toggle between showing all fields and conflicts only */\n public ToggleShowAll(): void {\n this.ShowAllFields = !this.ShowAllFields;\n this.cdr.detectChanges();\n }\n\n /** Select the left value for a field */\n public SelectLeft(field: FieldComparison): void {\n if (field.IsReadOnly) return;\n field.SelectedSide = 'left';\n this.emitFieldSelection(field);\n }\n\n /** Select the right value for a field */\n public SelectRight(field: FieldComparison): void {\n if (field.IsReadOnly) return;\n field.SelectedSide = 'right';\n this.emitFieldSelection(field);\n }\n\n /** Select all fields from the left side */\n public SelectAllLeft(): void {\n for (const field of this.Fields) {\n if (!field.IsReadOnly) {\n field.SelectedSide = 'left';\n }\n }\n this.cdr.detectChanges();\n }\n\n /** Select all fields from the right side */\n public SelectAllRight(): void {\n for (const field of this.Fields) {\n if (!field.IsReadOnly) {\n field.SelectedSide = 'right';\n }\n }\n this.cdr.detectChanges();\n }\n\n /** Get fields to display based on current filter */\n public GetVisibleFields(): FieldComparison[] {\n if (this.ShowAllFields) {\n return this.Fields;\n }\n return this.Fields.filter(f => f.HasConflict);\n }\n\n /** Show the merge confirmation dialog */\n public ShowConfirmDialog(): void {\n this.ConfirmDialogVisible = true;\n this.cdr.detectChanges();\n }\n\n /** Confirm the merge */\n public ConfirmMerge(): void {\n if (!this.Config) return;\n this.ConfirmDialogVisible = false;\n this.MergeConfirmed.emit({\n Config: this.Config,\n ResolvedFields: this.Fields\n });\n }\n\n /** Cancel the merge */\n public CancelMerge(): void {\n this.ConfirmDialogVisible = false;\n this.MergeCancelled.emit();\n }\n\n /** Get the display value for a field value */\n public FormatValue(value: unknown): string {\n if (value === null || value === undefined) {\n return '(empty)';\n }\n if (value instanceof Date) {\n return value.toLocaleString();\n }\n if (typeof value === 'boolean') {\n return value ? 'Yes' : 'No';\n }\n return String(value);\n }\n\n /** Check if all conflict fields have been resolved */\n public AllConflictsResolved(): boolean {\n if (!this.Comparison) return true;\n return this.Comparison.ConflictFields.every(f => f.SelectedSide === 'left' || f.SelectedSide === 'right');\n }\n\n // --- Private Methods ---\n\n private buildComparison(): void {\n const conflictFields = this.Fields.filter(f => f.HasConflict);\n const matchingFields = this.Fields.filter(f => !f.HasConflict);\n this.Comparison = {\n Fields: this.Fields,\n ConflictFields: conflictFields,\n MatchingFields: matchingFields,\n TotalFieldCount: this.Fields.length,\n ConflictCount: conflictFields.length\n };\n }\n\n private emitFieldSelection(field: FieldComparison): void {\n const value = field.SelectedSide === 'left' ? field.LeftValue :\n field.SelectedSide === 'right' ? field.RightValue :\n field.CustomValue;\n this.FieldSelected.emit({\n FieldName: field.FieldName,\n SelectedSide: field.SelectedSide,\n Value: value\n });\n this.cdr.detectChanges();\n }\n}\n","@if (Config && Comparison) {\n <div class=\"merge-panel\">\n <!-- Header -->\n <div class=\"merge-header\">\n <div class=\"merge-header-info\">\n <h3 class=\"merge-title\">Record Comparison</h3>\n <span class=\"merge-entity-name\">{{ Config.EntityName }}</span>\n <span class=\"merge-conflict-badge\">\n {{ Comparison.ConflictCount }} conflicts / {{ Comparison.TotalFieldCount }} fields\n </span>\n </div>\n <div class=\"merge-header-actions\">\n <button class=\"merge-toggle-btn\" (click)=\"ToggleShowAll()\">\n @if (ShowAllFields) {\n <i class=\"fa-solid fa-filter\"></i> Show Conflicts Only\n } @else {\n <i class=\"fa-solid fa-list\"></i> Show All Fields\n }\n </button>\n </div>\n </div>\n\n <!-- Column Headers -->\n <div class=\"merge-columns\">\n <div class=\"merge-col-label merge-col-field\">Field</div>\n <div class=\"merge-col-label merge-col-left\">\n <span>{{ Config.LeftLabel }}</span>\n <button class=\"merge-select-all-btn\" (click)=\"SelectAllLeft()\" title=\"Select all from left\">\n <i class=\"fa-solid fa-check-double\"></i>\n </button>\n </div>\n <div class=\"merge-col-label merge-col-right\">\n <span>{{ Config.RightLabel }}</span>\n <button class=\"merge-select-all-btn\" (click)=\"SelectAllRight()\" title=\"Select all from right\">\n <i class=\"fa-solid fa-check-double\"></i>\n </button>\n </div>\n </div>\n\n <!-- Field Rows -->\n <div class=\"merge-fields\">\n @for (field of GetVisibleFields(); track field.FieldName) {\n <div class=\"merge-row\" [class.merge-row-conflict]=\"field.HasConflict\" [class.merge-row-readonly]=\"field.IsReadOnly\">\n <div class=\"merge-cell merge-cell-field\">\n <span class=\"merge-field-name\">{{ field.DisplayLabel }}</span>\n @if (field.IsReadOnly) {\n <i class=\"fa-solid fa-lock merge-readonly-icon\" title=\"Read-only field\"></i>\n }\n </div>\n <div\n class=\"merge-cell merge-cell-value merge-cell-left\"\n [class.merge-cell-selected]=\"field.SelectedSide === 'left'\"\n [class.merge-cell-selectable]=\"!field.IsReadOnly\"\n (click)=\"SelectLeft(field)\"\n >\n <span class=\"merge-value\" [class.merge-value-empty]=\"field.LeftValue === null || field.LeftValue === undefined\">\n {{ FormatValue(field.LeftValue) }}\n </span>\n @if (field.SelectedSide === 'left' && !field.IsReadOnly) {\n <i class=\"fa-solid fa-check merge-check-icon\"></i>\n }\n </div>\n <div\n class=\"merge-cell merge-cell-value merge-cell-right\"\n [class.merge-cell-selected]=\"field.SelectedSide === 'right'\"\n [class.merge-cell-selectable]=\"!field.IsReadOnly\"\n (click)=\"SelectRight(field)\"\n >\n <span class=\"merge-value\" [class.merge-value-empty]=\"field.RightValue === null || field.RightValue === undefined\">\n {{ FormatValue(field.RightValue) }}\n </span>\n @if (field.SelectedSide === 'right' && !field.IsReadOnly) {\n <i class=\"fa-solid fa-check merge-check-icon\"></i>\n }\n </div>\n </div>\n }\n </div>\n\n <!-- Footer Actions -->\n @if (MergeEnabled) {\n <div class=\"merge-footer\">\n <button class=\"merge-btn merge-btn-primary\" (click)=\"ShowConfirmDialog()\" [disabled]=\"IsMerging\">\n @if (IsMerging) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Merging...\n } @else {\n <i class=\"fa-solid fa-code-merge\"></i> Merge Records\n }\n </button>\n <button class=\"merge-btn merge-btn-secondary\" (click)=\"CancelMerge()\" [disabled]=\"IsMerging\">\n Cancel\n </button>\n </div>\n }\n </div>\n\n <!-- Confirmation Dialog -->\n @if (ConfirmDialogVisible) {\n <div class=\"merge-dialog-backdrop\" (click)=\"ConfirmDialogVisible = false\">\n <div class=\"merge-dialog\" (click)=\"$event.stopPropagation()\">\n <div class=\"merge-dialog-header\">\n <i class=\"fa-solid fa-exclamation-triangle merge-dialog-warning-icon\"></i>\n <h4>Confirm Merge</h4>\n </div>\n <p class=\"merge-dialog-text\">\n This will merge the selected field values and create a merge log.\n This action cannot be undone. Are you sure?\n </p>\n <div class=\"merge-dialog-actions\">\n <button class=\"merge-btn merge-btn-primary\" (click)=\"ConfirmMerge()\">\n <i class=\"fa-solid fa-code-merge\"></i> Confirm Merge\n </button>\n <button class=\"merge-btn merge-btn-secondary\" (click)=\"ConfirmDialogVisible = false\">\n Cancel\n </button>\n </div>\n </div>\n </div>\n }\n} @else {\n <div class=\"merge-panel merge-panel-empty\">\n <i class=\"fa-solid fa-code-compare merge-empty-icon\"></i>\n <p>Select two records to compare</p>\n </div>\n}\n"]}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Types for the record merge/comparison panel.
|
|
3
|
+
*
|
|
4
|
+
* Defines data contracts for field-by-field comparison of entity records,
|
|
5
|
+
* including conflict detection, merge selection, and merge operations.
|
|
6
|
+
*/
|
|
7
|
+
/** Represents a field-level comparison between two records */
|
|
8
|
+
export interface FieldComparison {
|
|
9
|
+
/** The field name */
|
|
10
|
+
FieldName: string;
|
|
11
|
+
/** Display label for the field */
|
|
12
|
+
DisplayLabel: string;
|
|
13
|
+
/** Value from the left (source) record */
|
|
14
|
+
LeftValue: unknown;
|
|
15
|
+
/** Value from the right (target) record */
|
|
16
|
+
RightValue: unknown;
|
|
17
|
+
/** Whether the values differ */
|
|
18
|
+
HasConflict: boolean;
|
|
19
|
+
/** Which side is selected for the merge result: 'left', 'right', or 'custom' */
|
|
20
|
+
SelectedSide: 'left' | 'right' | 'custom';
|
|
21
|
+
/** Custom value if the user provides one */
|
|
22
|
+
CustomValue?: unknown;
|
|
23
|
+
/** Whether this field is read-only (e.g., ID, computed fields) */
|
|
24
|
+
IsReadOnly: boolean;
|
|
25
|
+
/** The field data type for display formatting */
|
|
26
|
+
DataType: string;
|
|
27
|
+
}
|
|
28
|
+
/** Merge configuration */
|
|
29
|
+
export interface MergeConfig {
|
|
30
|
+
/** The entity name */
|
|
31
|
+
EntityName: string;
|
|
32
|
+
/** Record ID of the left (source) record */
|
|
33
|
+
LeftRecordID: string;
|
|
34
|
+
/** Record ID of the right (target) record */
|
|
35
|
+
RightRecordID: string;
|
|
36
|
+
/** Which record to keep as the survivor */
|
|
37
|
+
SurvivorSide: 'left' | 'right';
|
|
38
|
+
/** Display labels for each side */
|
|
39
|
+
LeftLabel: string;
|
|
40
|
+
RightLabel: string;
|
|
41
|
+
}
|
|
42
|
+
/** Result of a merge comparison */
|
|
43
|
+
export interface MergeComparisonResult {
|
|
44
|
+
/** All field comparisons */
|
|
45
|
+
Fields: FieldComparison[];
|
|
46
|
+
/** Fields with conflicts */
|
|
47
|
+
ConflictFields: FieldComparison[];
|
|
48
|
+
/** Fields without conflicts */
|
|
49
|
+
MatchingFields: FieldComparison[];
|
|
50
|
+
/** Total number of fields */
|
|
51
|
+
TotalFieldCount: number;
|
|
52
|
+
/** Number of conflicts */
|
|
53
|
+
ConflictCount: number;
|
|
54
|
+
}
|
|
55
|
+
/** Merge action result */
|
|
56
|
+
export interface MergeActionResult {
|
|
57
|
+
/** Whether the merge succeeded */
|
|
58
|
+
Success: boolean;
|
|
59
|
+
/** The surviving record ID */
|
|
60
|
+
SurvivorRecordID: string;
|
|
61
|
+
/** The merged record ID (deleted if applicable) */
|
|
62
|
+
MergedRecordID: string;
|
|
63
|
+
/** Error message if merge failed */
|
|
64
|
+
ErrorMessage?: string;
|
|
65
|
+
/** Number of fields updated */
|
|
66
|
+
UpdatedFieldCount: number;
|
|
67
|
+
}
|
|
68
|
+
/** Event emitted when the user confirms a merge */
|
|
69
|
+
export interface MergeConfirmedEvent {
|
|
70
|
+
/** The merge configuration */
|
|
71
|
+
Config: MergeConfig;
|
|
72
|
+
/** The resolved field values */
|
|
73
|
+
ResolvedFields: FieldComparison[];
|
|
74
|
+
}
|
|
75
|
+
/** Event emitted when the user selects a side for a field */
|
|
76
|
+
export interface FieldSelectionEvent {
|
|
77
|
+
/** The field name */
|
|
78
|
+
FieldName: string;
|
|
79
|
+
/** Which side was selected */
|
|
80
|
+
SelectedSide: 'left' | 'right' | 'custom';
|
|
81
|
+
/** The selected value */
|
|
82
|
+
Value: unknown;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=record-merge-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record-merge-types.d.ts","sourceRoot":"","sources":["../../src/lib/record-merge-types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,8DAA8D;AAC9D,MAAM,WAAW,eAAe;IAC5B,qBAAqB;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,kCAAkC;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,SAAS,EAAE,OAAO,CAAC;IACnB,2CAA2C;IAC3C,UAAU,EAAE,OAAO,CAAC;IACpB,gCAAgC;IAChC,WAAW,EAAE,OAAO,CAAC;IACrB,gFAAgF;IAChF,YAAY,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;IAC1C,4CAA4C;IAC5C,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,kEAAkE;IAClE,UAAU,EAAE,OAAO,CAAC;IACpB,iDAAiD;IACjD,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,0BAA0B;AAC1B,MAAM,WAAW,WAAW;IACxB,sBAAsB;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,4CAA4C;IAC5C,YAAY,EAAE,MAAM,CAAC;IACrB,6CAA6C;IAC7C,aAAa,EAAE,MAAM,CAAC;IACtB,2CAA2C;IAC3C,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC;IAC/B,mCAAmC;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACtB;AAED,mCAAmC;AACnC,MAAM,WAAW,qBAAqB;IAClC,4BAA4B;IAC5B,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,4BAA4B;IAC5B,cAAc,EAAE,eAAe,EAAE,CAAC;IAClC,+BAA+B;IAC/B,cAAc,EAAE,eAAe,EAAE,CAAC;IAClC,6BAA6B;IAC7B,eAAe,EAAE,MAAM,CAAC;IACxB,0BAA0B;IAC1B,aAAa,EAAE,MAAM,CAAC;CACzB;AAED,0BAA0B;AAC1B,MAAM,WAAW,iBAAiB;IAC9B,kCAAkC;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,8BAA8B;IAC9B,gBAAgB,EAAE,MAAM,CAAC;IACzB,mDAAmD;IACnD,cAAc,EAAE,MAAM,CAAC;IACvB,oCAAoC;IACpC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,+BAA+B;IAC/B,iBAAiB,EAAE,MAAM,CAAC;CAC7B;AAED,mDAAmD;AACnD,MAAM,WAAW,mBAAmB;IAChC,8BAA8B;IAC9B,MAAM,EAAE,WAAW,CAAC;IACpB,gCAAgC;IAChC,cAAc,EAAE,eAAe,EAAE,CAAC;CACrC;AAED,6DAA6D;AAC7D,MAAM,WAAW,mBAAmB;IAChC,qBAAqB;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,8BAA8B;IAC9B,YAAY,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;IAC1C,yBAAyB;IACzB,KAAK,EAAE,OAAO,CAAC;CAClB"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Types for the record merge/comparison panel.
|
|
3
|
+
*
|
|
4
|
+
* Defines data contracts for field-by-field comparison of entity records,
|
|
5
|
+
* including conflict detection, merge selection, and merge operations.
|
|
6
|
+
*/
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=record-merge-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record-merge-types.js","sourceRoot":"","sources":["../../src/lib/record-merge-types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG","sourcesContent":["/**\n * @fileoverview Types for the record merge/comparison panel.\n *\n * Defines data contracts for field-by-field comparison of entity records,\n * including conflict detection, merge selection, and merge operations.\n */\n\n/** Represents a field-level comparison between two records */\nexport interface FieldComparison {\n /** The field name */\n FieldName: string;\n /** Display label for the field */\n DisplayLabel: string;\n /** Value from the left (source) record */\n LeftValue: unknown;\n /** Value from the right (target) record */\n RightValue: unknown;\n /** Whether the values differ */\n HasConflict: boolean;\n /** Which side is selected for the merge result: 'left', 'right', or 'custom' */\n SelectedSide: 'left' | 'right' | 'custom';\n /** Custom value if the user provides one */\n CustomValue?: unknown;\n /** Whether this field is read-only (e.g., ID, computed fields) */\n IsReadOnly: boolean;\n /** The field data type for display formatting */\n DataType: string;\n}\n\n/** Merge configuration */\nexport interface MergeConfig {\n /** The entity name */\n EntityName: string;\n /** Record ID of the left (source) record */\n LeftRecordID: string;\n /** Record ID of the right (target) record */\n RightRecordID: string;\n /** Which record to keep as the survivor */\n SurvivorSide: 'left' | 'right';\n /** Display labels for each side */\n LeftLabel: string;\n RightLabel: string;\n}\n\n/** Result of a merge comparison */\nexport interface MergeComparisonResult {\n /** All field comparisons */\n Fields: FieldComparison[];\n /** Fields with conflicts */\n ConflictFields: FieldComparison[];\n /** Fields without conflicts */\n MatchingFields: FieldComparison[];\n /** Total number of fields */\n TotalFieldCount: number;\n /** Number of conflicts */\n ConflictCount: number;\n}\n\n/** Merge action result */\nexport interface MergeActionResult {\n /** Whether the merge succeeded */\n Success: boolean;\n /** The surviving record ID */\n SurvivorRecordID: string;\n /** The merged record ID (deleted if applicable) */\n MergedRecordID: string;\n /** Error message if merge failed */\n ErrorMessage?: string;\n /** Number of fields updated */\n UpdatedFieldCount: number;\n}\n\n/** Event emitted when the user confirms a merge */\nexport interface MergeConfirmedEvent {\n /** The merge configuration */\n Config: MergeConfig;\n /** The resolved field values */\n ResolvedFields: FieldComparison[];\n}\n\n/** Event emitted when the user selects a side for a field */\nexport interface FieldSelectionEvent {\n /** The field name */\n FieldName: string;\n /** Which side was selected */\n SelectedSide: 'left' | 'right' | 'custom';\n /** The selected value */\n Value: unknown;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public-api.d.ts","sourceRoot":"","sources":["../src/public-api.ts"],"names":[],"mappings":"AAIA,cAAc,0BAA0B,CAAC;AACzC,cAAc,oCAAoC,CAAC;AACnD,cAAc,cAAc,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public-api.js","sourceRoot":"","sources":["../src/public-api.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,0BAA0B,CAAC;AACzC,cAAc,oCAAoC,CAAC;AACnD,cAAc,cAAc,CAAC","sourcesContent":["/*\n * Public API Surface of @memberjunction/ng-record-merge\n */\n\nexport * from './lib/record-merge-types';\nexport * from './lib/record-merge-panel.component';\nexport * from './lib/module';\n"]}
|
package/package.json
CHANGED
|
@@ -1,10 +1,39 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memberjunction/ng-record-merge",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
"
|
|
9
|
-
]
|
|
3
|
+
"version": "5.23.0",
|
|
4
|
+
"description": "MemberJunction: Reusable record merge/comparison panel for side-by-side entity record comparison and field-by-field merge selection",
|
|
5
|
+
"main": "./dist/public-api.js",
|
|
6
|
+
"typings": "./dist/public-api.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"/dist"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "vitest run",
|
|
12
|
+
"build": "ngc",
|
|
13
|
+
"test:watch": "vitest"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [],
|
|
16
|
+
"author": "MemberJunction.com",
|
|
17
|
+
"license": "ISC",
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@angular/compiler": "21.1.3",
|
|
20
|
+
"@angular/compiler-cli": "21.1.3",
|
|
21
|
+
"vitest": "^4.0.18"
|
|
22
|
+
},
|
|
23
|
+
"peerDependencies": {
|
|
24
|
+
"@angular/common": "21.1.3",
|
|
25
|
+
"@angular/core": "21.1.3"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@memberjunction/core": "5.23.0",
|
|
29
|
+
"@memberjunction/global": "5.23.0",
|
|
30
|
+
"@memberjunction/ng-shared-generic": "5.23.0",
|
|
31
|
+
"rxjs": "^7.8.2",
|
|
32
|
+
"tslib": "^2.8.1"
|
|
33
|
+
},
|
|
34
|
+
"sideEffects": false,
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "https://github.com/MemberJunction/MJ"
|
|
38
|
+
}
|
|
10
39
|
}
|
package/README.md
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
# @memberjunction/ng-record-merge
|
|
2
|
-
|
|
3
|
-
## ⚠️ IMPORTANT NOTICE ⚠️
|
|
4
|
-
|
|
5
|
-
**This package is created solely for the purpose of setting up OIDC (OpenID Connect) trusted publishing with npm.**
|
|
6
|
-
|
|
7
|
-
This is **NOT** a functional package and contains **NO** code or functionality beyond the OIDC setup configuration.
|
|
8
|
-
|
|
9
|
-
## Purpose
|
|
10
|
-
|
|
11
|
-
This package exists to:
|
|
12
|
-
1. Configure OIDC trusted publishing for the package name `@memberjunction/ng-record-merge`
|
|
13
|
-
2. Enable secure, token-less publishing from CI/CD workflows
|
|
14
|
-
3. Establish provenance for packages published under this name
|
|
15
|
-
|
|
16
|
-
## What is OIDC Trusted Publishing?
|
|
17
|
-
|
|
18
|
-
OIDC trusted publishing allows package maintainers to publish packages directly from their CI/CD workflows without needing to manage npm access tokens. Instead, it uses OpenID Connect to establish trust between the CI/CD provider (like GitHub Actions) and npm.
|
|
19
|
-
|
|
20
|
-
## Setup Instructions
|
|
21
|
-
|
|
22
|
-
To properly configure OIDC trusted publishing for this package:
|
|
23
|
-
|
|
24
|
-
1. Go to [npmjs.com](https://www.npmjs.com/) and navigate to your package settings
|
|
25
|
-
2. Configure the trusted publisher (e.g., GitHub Actions)
|
|
26
|
-
3. Specify the repository and workflow that should be allowed to publish
|
|
27
|
-
4. Use the configured workflow to publish your actual package
|
|
28
|
-
|
|
29
|
-
## DO NOT USE THIS PACKAGE
|
|
30
|
-
|
|
31
|
-
This package is a placeholder for OIDC configuration only. It:
|
|
32
|
-
- Contains no executable code
|
|
33
|
-
- Provides no functionality
|
|
34
|
-
- Should not be installed as a dependency
|
|
35
|
-
- Exists only for administrative purposes
|
|
36
|
-
|
|
37
|
-
## More Information
|
|
38
|
-
|
|
39
|
-
For more details about npm's trusted publishing feature, see:
|
|
40
|
-
- [npm Trusted Publishing Documentation](https://docs.npmjs.com/generating-provenance-statements)
|
|
41
|
-
- [GitHub Actions OIDC Documentation](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect)
|
|
42
|
-
|
|
43
|
-
---
|
|
44
|
-
|
|
45
|
-
**Maintained for OIDC setup purposes only**
|