@memberjunction/ng-record-clone 0.0.0 → 6.2.0-edge.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +183 -0
- package/README.md +225 -28
- package/dist/lib/clone-lineage-chip.component.d.ts +50 -0
- package/dist/lib/clone-lineage-chip.component.d.ts.map +1 -0
- package/dist/lib/clone-lineage-chip.component.js +448 -0
- package/dist/lib/clone-lineage-chip.component.js.map +1 -0
- package/dist/lib/clone-plan-tree.component.d.ts +51 -0
- package/dist/lib/clone-plan-tree.component.d.ts.map +1 -0
- package/dist/lib/clone-plan-tree.component.js +634 -0
- package/dist/lib/clone-plan-tree.component.js.map +1 -0
- package/dist/lib/clone-progress.component.d.ts +12 -0
- package/dist/lib/clone-progress.component.d.ts.map +1 -0
- package/dist/lib/clone-progress.component.js +151 -0
- package/dist/lib/clone-progress.component.js.map +1 -0
- package/dist/lib/clone-result.component.d.ts +40 -0
- package/dist/lib/clone-result.component.d.ts.map +1 -0
- package/dist/lib/clone-result.component.js +357 -0
- package/dist/lib/clone-result.component.js.map +1 -0
- package/dist/lib/clone-review.component.d.ts +58 -0
- package/dist/lib/clone-review.component.d.ts.map +1 -0
- package/dist/lib/clone-review.component.js +581 -0
- package/dist/lib/clone-review.component.js.map +1 -0
- package/dist/lib/clone-scope-controls.component.d.ts +81 -0
- package/dist/lib/clone-scope-controls.component.d.ts.map +1 -0
- package/dist/lib/clone-scope-controls.component.js +394 -0
- package/dist/lib/clone-scope-controls.component.js.map +1 -0
- package/dist/lib/clone-values.component.d.ts +55 -0
- package/dist/lib/clone-values.component.d.ts.map +1 -0
- package/dist/lib/clone-values.component.js +493 -0
- package/dist/lib/clone-values.component.js.map +1 -0
- package/dist/lib/record-clone-panel.component.d.ts +247 -0
- package/dist/lib/record-clone-panel.component.d.ts.map +1 -0
- package/dist/lib/record-clone-panel.component.js +1252 -0
- package/dist/lib/record-clone-panel.component.js.map +1 -0
- package/dist/lib/record-clone-slide-in.component.d.ts +83 -0
- package/dist/lib/record-clone-slide-in.component.d.ts.map +1 -0
- package/dist/lib/record-clone-slide-in.component.js +206 -0
- package/dist/lib/record-clone-slide-in.component.js.map +1 -0
- package/dist/lib/record-clone-types.d.ts +89 -0
- package/dist/lib/record-clone-types.d.ts.map +1 -0
- package/dist/lib/record-clone-types.js +29 -0
- package/dist/lib/record-clone-types.js.map +1 -0
- package/dist/lib/record-clone.module.d.ts +16 -0
- package/dist/lib/record-clone.module.d.ts.map +1 -0
- package/dist/lib/record-clone.module.js +69 -0
- package/dist/lib/record-clone.module.js.map +1 -0
- package/dist/lib/record-clone.service.d.ts +42 -0
- package/dist/lib/record-clone.service.d.ts.map +1 -0
- package/dist/lib/record-clone.service.js +123 -0
- package/dist/lib/record-clone.service.js.map +1 -0
- package/dist/public-api.d.ts +16 -0
- package/dist/public-api.d.ts.map +1 -0
- package/dist/public-api.js +16 -0
- package/dist/public-api.js.map +1 -0
- package/package.json +49 -7
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record-clone-types.d.ts","sourceRoot":"","sources":["../../src/lib/record-clone-types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Type definitions for the record cloning Angular UI layer.
|
|
3
|
+
*/
|
|
4
|
+
/** Converts a CompositeKey (any number of primary key columns) to the wire-level RecordCloneKey. */
|
|
5
|
+
export function CompositeKeyToRecordCloneKey(key) {
|
|
6
|
+
return {
|
|
7
|
+
KeyValuePairs: key.KeyValuePairs.map((p) => ({
|
|
8
|
+
FieldName: p.FieldName,
|
|
9
|
+
Value: String(p.Value ?? ''),
|
|
10
|
+
})),
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
/** Helper to extract a RecordCloneKey from an active BaseEntity record */
|
|
14
|
+
export function EntityToRecordCloneKey(record) {
|
|
15
|
+
const pairs = record.PrimaryKey?.KeyValuePairs || [];
|
|
16
|
+
return {
|
|
17
|
+
KeyValuePairs: pairs.map((p) => ({
|
|
18
|
+
FieldName: p.FieldName,
|
|
19
|
+
Value: String(p.Value ?? ''),
|
|
20
|
+
})),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/** Convert a RecordCloneKey to a pipe-delimited string representation */
|
|
24
|
+
export function RecordCloneKeyToString(key) {
|
|
25
|
+
if (!key || !key.KeyValuePairs || key.KeyValuePairs.length === 0)
|
|
26
|
+
return '';
|
|
27
|
+
return key.KeyValuePairs.map((kvp) => kvp.Value).join('|');
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=record-clone-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record-clone-types.js","sourceRoot":"","sources":["../../src/lib/record-clone-types.ts"],"names":[],"mappings":"AAAA;;GAEG;AA8GH,oGAAoG;AACpG,MAAM,UAAU,4BAA4B,CAAC,GAAiB;IAC1D,OAAO;QACH,aAAa,EAAE,GAAG,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACzC,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;SAC/B,CAAC,CAAC;KACN,CAAC;AACN,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,sBAAsB,CAAC,MAAkB;IACrD,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,EAAE,aAAa,IAAI,EAAE,CAAC;IACrD,OAAO;QACH,aAAa,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC7B,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;SAC/B,CAAC,CAAC;KACN,CAAC;AACN,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,sBAAsB,CAAC,GAA2B;IAC9D,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,aAAa,IAAI,GAAG,CAAC,aAAa,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAC5E,OAAO,GAAG,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/D,CAAC","sourcesContent":["/**\n * @fileoverview Type definitions for the record cloning Angular UI layer.\n */\n\nimport type { BaseEntity, CompositeKey } from '@memberjunction/core';\nimport type {\n RecordCloneKey,\n RecordCloneKeyValuePair,\n RecordClonePlanDetails,\n RecordClonePlanNode,\n RecordClonePlanEdge,\n RecordCloneExecuteOutput,\n RecordClonePlanWarning,\n} from '@memberjunction/core-entities';\n\n/** Active step in the clone wizard. */\nexport type RecordCloneStep = 'scope' | 'values' | 'review';\n\n/** State of the clone wizard. */\nexport type RecordClonePanelState =\n | 'loading'\n | 'scope'\n | 'values'\n | 'review'\n | 'executing'\n | 'done'\n | 'blocked'\n | 'plan_changed'\n | 'failed'\n | 'not_cloneable';\n\n/** Emitted when record cloning completes successfully. */\nexport interface CloneCompletedEvent {\n EntityName: string;\n TargetKey: string;\n CloneLogID: string | null;\n CreatedRecordsCount: number;\n Result?: RecordCloneExecuteOutput;\n}\n\n/** A branch policy the user changed in the plan tree; sent to the planner as an edge override. */\nexport interface CloneEdgePolicyChange {\n RelationshipID: string;\n Policy: 'Deep' | 'Reference' | 'Skip';\n /** Related entity of the branch, for labels such as the \"Skipped branches\" list. Not sent to the server. */\n RelatedEntityName?: string;\n}\n\n/** Emitted when describe, plan or execute fails. */\nexport interface CloneFailedEvent {\n EntityName: string;\n /** The message the panel shows; names the failing node when the server reports one. */\n Message: string;\n /** Server result code, e.g. `PLAN_CHANGED`, `FORBIDDEN`, `EXECUTION_ERROR`, when there is one. */\n ResultCode?: string;\n}\n\n/**\n * Asks the host to open a record. The clone widgets never navigate themselves; a host maps\n * this onto its own navigation (base-forms turns it into a `FormNavigationEvent`).\n */\nexport interface CloneNavigationEvent {\n Kind: 'record';\n EntityName: string;\n /** Record-id string in compact URL-segment form; parse with `CompositeKey.FromURLSegment`. */\n RecordKey: string;\n}\n\n/** View model representing a node in the visual clone plan tree. */\nexport interface CloneTreeNodeViewModel {\n Node: RecordClonePlanNode;\n ParentEdge: RecordClonePlanEdge | null;\n Children: CloneTreeNodeViewModel[];\n Expanded: boolean;\n Level: number;\n}\n\n/** Field prompt item required for the clone values step. */\nexport interface ClonePromptFieldItem {\n FieldName: string;\n DisplayName: string;\n Type: string;\n DefaultValue?: string | number | boolean | null;\n IsRequired: boolean;\n Description?: string;\n}\n\n/** Foreign key retarget item configured under UI.RetargetFields. */\nexport interface CloneRetargetFieldItem {\n FieldName: string;\n DisplayName: string;\n RelatedEntity: string;\n CurrentValue: string | null;\n NewValue: string | null;\n CurrentDisplayName?: string;\n}\n\n/** Progress update payload during long-running clone execution. */\nexport interface CloneProgressUpdate {\n Percent?: number;\n PercentComplete?: number;\n Processed?: number;\n CompletedRecords?: number;\n Total?: number;\n TotalRecords?: number;\n Message?: string;\n Phase?: string;\n CurrentNodeKey?: string;\n CurrentEntityName?: string;\n CloneLogID?: string;\n}\n\n/** Converts a CompositeKey (any number of primary key columns) to the wire-level RecordCloneKey. */\nexport function CompositeKeyToRecordCloneKey(key: CompositeKey): RecordCloneKey {\n return {\n KeyValuePairs: key.KeyValuePairs.map((p) => ({\n FieldName: p.FieldName,\n Value: String(p.Value ?? ''),\n })),\n };\n}\n\n/** Helper to extract a RecordCloneKey from an active BaseEntity record */\nexport function EntityToRecordCloneKey(record: BaseEntity): RecordCloneKey {\n const pairs = record.PrimaryKey?.KeyValuePairs || [];\n return {\n KeyValuePairs: pairs.map((p) => ({\n FieldName: p.FieldName,\n Value: String(p.Value ?? ''),\n })),\n };\n}\n\n/** Convert a RecordCloneKey to a pipe-delimited string representation */\nexport function RecordCloneKeyToString(key?: RecordCloneKey | null): string {\n if (!key || !key.KeyValuePairs || key.KeyValuePairs.length === 0) return '';\n return key.KeyValuePairs.map((kvp) => kvp.Value).join('|');\n}\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as i0 from "@angular/core";
|
|
2
|
+
import * as i1 from "./record-clone-panel.component";
|
|
3
|
+
import * as i2 from "./record-clone-slide-in.component";
|
|
4
|
+
import * as i3 from "./clone-scope-controls.component";
|
|
5
|
+
import * as i4 from "./clone-plan-tree.component";
|
|
6
|
+
import * as i5 from "./clone-values.component";
|
|
7
|
+
import * as i6 from "./clone-review.component";
|
|
8
|
+
import * as i7 from "./clone-progress.component";
|
|
9
|
+
import * as i8 from "./clone-result.component";
|
|
10
|
+
import * as i9 from "./clone-lineage-chip.component";
|
|
11
|
+
export declare class RecordCloneModule {
|
|
12
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<RecordCloneModule, never>;
|
|
13
|
+
static ɵmod: i0.ɵɵNgModuleDeclaration<RecordCloneModule, never, [typeof i1.RecordClonePanelComponent, typeof i2.RecordCloneSlideInComponent, typeof i3.CloneScopeControlsComponent, typeof i4.ClonePlanTreeComponent, typeof i5.CloneValuesComponent, typeof i6.CloneReviewComponent, typeof i7.CloneProgressComponent, typeof i8.CloneResultComponent, typeof i9.CloneLineageChipComponent], [typeof i1.RecordClonePanelComponent, typeof i2.RecordCloneSlideInComponent, typeof i3.CloneScopeControlsComponent, typeof i4.ClonePlanTreeComponent, typeof i5.CloneValuesComponent, typeof i6.CloneReviewComponent, typeof i7.CloneProgressComponent, typeof i8.CloneResultComponent, typeof i9.CloneLineageChipComponent]>;
|
|
14
|
+
static ɵinj: i0.ɵɵInjectorDeclaration<RecordCloneModule>;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=record-clone.module.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record-clone.module.d.ts","sourceRoot":"","sources":["../../src/lib/record-clone.module.ts"],"names":[],"mappings":";;;;;;;;;;AAWA,qBAwBa,iBAAiB;yCAAjB,iBAAiB;0CAAjB,iBAAiB;0CAAjB,iBAAiB;CAAG"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { NgModule } from '@angular/core';
|
|
2
|
+
import { RecordClonePanelComponent } from './record-clone-panel.component';
|
|
3
|
+
import { RecordCloneSlideInComponent } from './record-clone-slide-in.component';
|
|
4
|
+
import { CloneScopeControlsComponent } from './clone-scope-controls.component';
|
|
5
|
+
import { ClonePlanTreeComponent } from './clone-plan-tree.component';
|
|
6
|
+
import { CloneValuesComponent } from './clone-values.component';
|
|
7
|
+
import { CloneReviewComponent } from './clone-review.component';
|
|
8
|
+
import { CloneProgressComponent } from './clone-progress.component';
|
|
9
|
+
import { CloneResultComponent } from './clone-result.component';
|
|
10
|
+
import { CloneLineageChipComponent } from './clone-lineage-chip.component';
|
|
11
|
+
import * as i0 from "@angular/core";
|
|
12
|
+
export class RecordCloneModule {
|
|
13
|
+
static ɵfac = function RecordCloneModule_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || RecordCloneModule)(); };
|
|
14
|
+
static ɵmod = /*@__PURE__*/ i0.ɵɵdefineNgModule({ type: RecordCloneModule });
|
|
15
|
+
static ɵinj = /*@__PURE__*/ i0.ɵɵdefineInjector({ imports: [RecordClonePanelComponent,
|
|
16
|
+
RecordCloneSlideInComponent,
|
|
17
|
+
CloneScopeControlsComponent,
|
|
18
|
+
ClonePlanTreeComponent,
|
|
19
|
+
CloneValuesComponent,
|
|
20
|
+
CloneReviewComponent,
|
|
21
|
+
CloneProgressComponent,
|
|
22
|
+
CloneResultComponent,
|
|
23
|
+
CloneLineageChipComponent] });
|
|
24
|
+
}
|
|
25
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(RecordCloneModule, [{
|
|
26
|
+
type: NgModule,
|
|
27
|
+
args: [{
|
|
28
|
+
imports: [
|
|
29
|
+
RecordClonePanelComponent,
|
|
30
|
+
RecordCloneSlideInComponent,
|
|
31
|
+
CloneScopeControlsComponent,
|
|
32
|
+
ClonePlanTreeComponent,
|
|
33
|
+
CloneValuesComponent,
|
|
34
|
+
CloneReviewComponent,
|
|
35
|
+
CloneProgressComponent,
|
|
36
|
+
CloneResultComponent,
|
|
37
|
+
CloneLineageChipComponent,
|
|
38
|
+
],
|
|
39
|
+
exports: [
|
|
40
|
+
RecordClonePanelComponent,
|
|
41
|
+
RecordCloneSlideInComponent,
|
|
42
|
+
CloneScopeControlsComponent,
|
|
43
|
+
ClonePlanTreeComponent,
|
|
44
|
+
CloneValuesComponent,
|
|
45
|
+
CloneReviewComponent,
|
|
46
|
+
CloneProgressComponent,
|
|
47
|
+
CloneResultComponent,
|
|
48
|
+
CloneLineageChipComponent,
|
|
49
|
+
],
|
|
50
|
+
}]
|
|
51
|
+
}], null, null); })();
|
|
52
|
+
(function () { (typeof ngJitMode === "undefined" || ngJitMode) && i0.ɵɵsetNgModuleScope(RecordCloneModule, { imports: [RecordClonePanelComponent,
|
|
53
|
+
RecordCloneSlideInComponent,
|
|
54
|
+
CloneScopeControlsComponent,
|
|
55
|
+
ClonePlanTreeComponent,
|
|
56
|
+
CloneValuesComponent,
|
|
57
|
+
CloneReviewComponent,
|
|
58
|
+
CloneProgressComponent,
|
|
59
|
+
CloneResultComponent,
|
|
60
|
+
CloneLineageChipComponent], exports: [RecordClonePanelComponent,
|
|
61
|
+
RecordCloneSlideInComponent,
|
|
62
|
+
CloneScopeControlsComponent,
|
|
63
|
+
ClonePlanTreeComponent,
|
|
64
|
+
CloneValuesComponent,
|
|
65
|
+
CloneReviewComponent,
|
|
66
|
+
CloneProgressComponent,
|
|
67
|
+
CloneResultComponent,
|
|
68
|
+
CloneLineageChipComponent] }); })();
|
|
69
|
+
//# sourceMappingURL=record-clone.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record-clone.module.js","sourceRoot":"","sources":["../../src/lib/record-clone.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAC;AAC3E,OAAO,EAAE,2BAA2B,EAAE,MAAM,mCAAmC,CAAC;AAChF,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAC/E,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAC;;AA0B3E,MAAM,OAAO,iBAAiB;2GAAjB,iBAAiB;4DAAjB,iBAAiB;gEAtBtB,yBAAyB;YACzB,2BAA2B;YAC3B,2BAA2B;YAC3B,sBAAsB;YACtB,oBAAoB;YACpB,oBAAoB;YACpB,sBAAsB;YACtB,oBAAoB;YACpB,yBAAyB;;iFAcpB,iBAAiB;cAxB7B,QAAQ;eAAC;gBACN,OAAO,EAAE;oBACL,yBAAyB;oBACzB,2BAA2B;oBAC3B,2BAA2B;oBAC3B,sBAAsB;oBACtB,oBAAoB;oBACpB,oBAAoB;oBACpB,sBAAsB;oBACtB,oBAAoB;oBACpB,yBAAyB;iBAC5B;gBACD,OAAO,EAAE;oBACL,yBAAyB;oBACzB,2BAA2B;oBAC3B,2BAA2B;oBAC3B,sBAAsB;oBACtB,oBAAoB;oBACpB,oBAAoB;oBACpB,sBAAsB;oBACtB,oBAAoB;oBACpB,yBAAyB;iBAC5B;aACJ;;wFACY,iBAAiB,cAtBtB,yBAAyB;QACzB,2BAA2B;QAC3B,2BAA2B;QAC3B,sBAAsB;QACtB,oBAAoB;QACpB,oBAAoB;QACpB,sBAAsB;QACtB,oBAAoB;QACpB,yBAAyB,aAGzB,yBAAyB;QACzB,2BAA2B;QAC3B,2BAA2B;QAC3B,sBAAsB;QACtB,oBAAoB;QACpB,oBAAoB;QACpB,sBAAsB;QACtB,oBAAoB;QACpB,yBAAyB","sourcesContent":["import { NgModule } from '@angular/core';\nimport { RecordClonePanelComponent } from './record-clone-panel.component';\nimport { RecordCloneSlideInComponent } from './record-clone-slide-in.component';\nimport { CloneScopeControlsComponent } from './clone-scope-controls.component';\nimport { ClonePlanTreeComponent } from './clone-plan-tree.component';\nimport { CloneValuesComponent } from './clone-values.component';\nimport { CloneReviewComponent } from './clone-review.component';\nimport { CloneProgressComponent } from './clone-progress.component';\nimport { CloneResultComponent } from './clone-result.component';\nimport { CloneLineageChipComponent } from './clone-lineage-chip.component';\n\n@NgModule({\n imports: [\n RecordClonePanelComponent,\n RecordCloneSlideInComponent,\n CloneScopeControlsComponent,\n ClonePlanTreeComponent,\n CloneValuesComponent,\n CloneReviewComponent,\n CloneProgressComponent,\n CloneResultComponent,\n CloneLineageChipComponent,\n ],\n exports: [\n RecordClonePanelComponent,\n RecordCloneSlideInComponent,\n CloneScopeControlsComponent,\n ClonePlanTreeComponent,\n CloneValuesComponent,\n CloneReviewComponent,\n CloneProgressComponent,\n CloneResultComponent,\n CloneLineageChipComponent,\n ],\n})\nexport class RecordCloneModule {}\n"]}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { IMetadataProvider } from '@memberjunction/core';
|
|
2
|
+
import { type RecordCloneDescribeInput, type RecordCloneDescribeOutput, type RecordClonePlanInput, type RecordClonePlanOutput, type RecordCloneExecuteInput, type RecordCloneExecuteOutput, type RecordCloneGetLineageInput, type RecordCloneGetLineageOutput } from '@memberjunction/core-entities';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
/**
|
|
5
|
+
* Client for the four RecordClone remote operations. Every method takes an optional
|
|
6
|
+
* provider so multi-provider hosts target the right server; omitted, it uses `Metadata.Provider`.
|
|
7
|
+
*/
|
|
8
|
+
export declare class RecordCloneService {
|
|
9
|
+
/** Describe answers per provider, then per entity. Holds the promise so concurrent callers share one request. */
|
|
10
|
+
private readonly _describeCache;
|
|
11
|
+
/**
|
|
12
|
+
* Inspect an entity (and optionally a specific record key) to discover cloning
|
|
13
|
+
* capabilities, default options, user-editable knobs, and relationship policies.
|
|
14
|
+
* Caches the result per provider and entity name for the session unless
|
|
15
|
+
* `forceRefresh` is true or a specific record key is inspected. A failed call is not cached.
|
|
16
|
+
*/
|
|
17
|
+
DescribeRecord(input: RecordCloneDescribeInput, provider?: IMetadataProvider | null, forceRefresh?: boolean): Promise<RecordCloneDescribeOutput>;
|
|
18
|
+
/**
|
|
19
|
+
* Compute a complete clone plan (dry run) for a source record graph without writing
|
|
20
|
+
* any database changes. Returns the planned nodes, edges, field changes, and warnings.
|
|
21
|
+
*/
|
|
22
|
+
PlanClone(input: RecordClonePlanInput, provider?: IMetadataProvider | null): Promise<RecordClonePlanOutput>;
|
|
23
|
+
/**
|
|
24
|
+
* Execute a planned record clone graph with optional overrides. Supports optimistic
|
|
25
|
+
* plan hashing (ExpectedPlanHash), progress reporting, and full transactional rollback.
|
|
26
|
+
*/
|
|
27
|
+
ExecuteClone(input: RecordCloneExecuteInput, provider?: IMetadataProvider | null): Promise<RecordCloneExecuteOutput>;
|
|
28
|
+
/**
|
|
29
|
+
* Retrieve the clone lineage for a record — traversing ClonedFrom links upward to
|
|
30
|
+
* ancestors and downward to descendant clones.
|
|
31
|
+
*/
|
|
32
|
+
GetLineage(input: RecordCloneGetLineageInput, provider?: IMetadataProvider | null): Promise<RecordCloneGetLineageOutput>;
|
|
33
|
+
/**
|
|
34
|
+
* Clear the in-memory session Describe cache for a specific entity or all entities.
|
|
35
|
+
*/
|
|
36
|
+
ClearDescribeCache(entityName?: string, provider?: IMetadataProvider | null): void;
|
|
37
|
+
private cacheBucket;
|
|
38
|
+
private describe;
|
|
39
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<RecordCloneService, never>;
|
|
40
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<RecordCloneService>;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=record-clone.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record-clone.service.d.ts","sourceRoot":"","sources":["../../src/lib/record-clone.service.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,iBAAiB,EAAY,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAKH,KAAK,wBAAwB,EAC7B,KAAK,yBAAyB,EAC9B,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,uBAAuB,EAC5B,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,EAC/B,KAAK,2BAA2B,EACnC,MAAM,+BAA+B,CAAC;;AAKvC;;;GAGG;AACH,qBACa,kBAAkB;IAC3B,iHAAiH;IACjH,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA0E;IAEzG;;;;;OAKG;IACU,cAAc,CACvB,KAAK,EAAE,wBAAwB,EAC/B,QAAQ,CAAC,EAAE,iBAAiB,GAAG,IAAI,EACnC,YAAY,UAAQ,GACrB,OAAO,CAAC,yBAAyB,CAAC;IAsBrC;;;OAGG;IACU,SAAS,CAClB,KAAK,EAAE,oBAAoB,EAC3B,QAAQ,CAAC,EAAE,iBAAiB,GAAG,IAAI,GACpC,OAAO,CAAC,qBAAqB,CAAC;IAYjC;;;OAGG;IACU,YAAY,CACrB,KAAK,EAAE,uBAAuB,EAC9B,QAAQ,CAAC,EAAE,iBAAiB,GAAG,IAAI,GACpC,OAAO,CAAC,wBAAwB,CAAC;IAYpC;;;OAGG;IACU,UAAU,CACnB,KAAK,EAAE,0BAA0B,EACjC,QAAQ,CAAC,EAAE,iBAAiB,GAAG,IAAI,GACpC,OAAO,CAAC,2BAA2B,CAAC;IAYvC;;OAEG;IACI,kBAAkB,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,iBAAiB,GAAG,IAAI,GAAG,IAAI;IASzF,OAAO,CAAC,WAAW;YAUL,QAAQ;yCAnHb,kBAAkB;6CAAlB,kBAAkB;CA2H9B"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Angular service wrapping server-side Record Cloning remote operations.
|
|
3
|
+
*
|
|
4
|
+
* Implements §11.5 and §12.3 of the Record Cloning architectural blueprint. Resolves
|
|
5
|
+
* the IMetadataProvider (multi-provider aware), delegates directly to the typed
|
|
6
|
+
* BaseRemotableOperation subclasses emitted into @memberjunction/core-entities, and
|
|
7
|
+
* maintains an in-memory session cache of Describe results per provider and entity.
|
|
8
|
+
*/
|
|
9
|
+
import { Injectable } from '@angular/core';
|
|
10
|
+
import { Metadata } from '@memberjunction/core';
|
|
11
|
+
import { RecordCloneDescribeOperation, RecordClonePlanOperation, RecordCloneExecuteOperation, RecordCloneGetLineageOperation, } from '@memberjunction/core-entities';
|
|
12
|
+
import * as i0 from "@angular/core";
|
|
13
|
+
/** Cache bucket used when no provider can be resolved (tests, early bootstrap). */
|
|
14
|
+
const NO_PROVIDER = {};
|
|
15
|
+
/**
|
|
16
|
+
* Client for the four RecordClone remote operations. Every method takes an optional
|
|
17
|
+
* provider so multi-provider hosts target the right server; omitted, it uses `Metadata.Provider`.
|
|
18
|
+
*/
|
|
19
|
+
export class RecordCloneService {
|
|
20
|
+
/** Describe answers per provider, then per entity. Holds the promise so concurrent callers share one request. */
|
|
21
|
+
_describeCache = new WeakMap();
|
|
22
|
+
/**
|
|
23
|
+
* Inspect an entity (and optionally a specific record key) to discover cloning
|
|
24
|
+
* capabilities, default options, user-editable knobs, and relationship policies.
|
|
25
|
+
* Caches the result per provider and entity name for the session unless
|
|
26
|
+
* `forceRefresh` is true or a specific record key is inspected. A failed call is not cached.
|
|
27
|
+
*/
|
|
28
|
+
async DescribeRecord(input, provider, forceRefresh = false) {
|
|
29
|
+
const p = provider ?? Metadata.Provider;
|
|
30
|
+
const isGenericQuery = !input.Key || !input.Key.KeyValuePairs || input.Key.KeyValuePairs.length === 0;
|
|
31
|
+
if (!isGenericQuery) {
|
|
32
|
+
return this.describe(input, p);
|
|
33
|
+
}
|
|
34
|
+
const bucket = this.cacheBucket(p);
|
|
35
|
+
const cacheKey = input.EntityName.trim().toLowerCase();
|
|
36
|
+
const cached = bucket.get(cacheKey);
|
|
37
|
+
if (cached && !forceRefresh) {
|
|
38
|
+
return cached;
|
|
39
|
+
}
|
|
40
|
+
const pending = this.describe(input, p);
|
|
41
|
+
bucket.set(cacheKey, pending);
|
|
42
|
+
pending.catch(() => {
|
|
43
|
+
if (bucket.get(cacheKey) === pending)
|
|
44
|
+
bucket.delete(cacheKey);
|
|
45
|
+
});
|
|
46
|
+
return pending;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Compute a complete clone plan (dry run) for a source record graph without writing
|
|
50
|
+
* any database changes. Returns the planned nodes, edges, field changes, and warnings.
|
|
51
|
+
*/
|
|
52
|
+
async PlanClone(input, provider) {
|
|
53
|
+
const p = provider ?? Metadata.Provider;
|
|
54
|
+
const op = new RecordClonePlanOperation();
|
|
55
|
+
const result = await op.Execute(input, { provider: p ?? undefined });
|
|
56
|
+
if (!result.Success || !result.Output) {
|
|
57
|
+
throw new Error(result.ErrorMessage || 'Failed to compute clone plan');
|
|
58
|
+
}
|
|
59
|
+
return result.Output;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Execute a planned record clone graph with optional overrides. Supports optimistic
|
|
63
|
+
* plan hashing (ExpectedPlanHash), progress reporting, and full transactional rollback.
|
|
64
|
+
*/
|
|
65
|
+
async ExecuteClone(input, provider) {
|
|
66
|
+
const p = provider ?? Metadata.Provider;
|
|
67
|
+
const op = new RecordCloneExecuteOperation();
|
|
68
|
+
const result = await op.Execute(input, { provider: p ?? undefined });
|
|
69
|
+
if (!result.Success || !result.Output) {
|
|
70
|
+
throw new Error(result.ErrorMessage || 'Failed to execute record clone');
|
|
71
|
+
}
|
|
72
|
+
return result.Output;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Retrieve the clone lineage for a record — traversing ClonedFrom links upward to
|
|
76
|
+
* ancestors and downward to descendant clones.
|
|
77
|
+
*/
|
|
78
|
+
async GetLineage(input, provider) {
|
|
79
|
+
const p = provider ?? Metadata.Provider;
|
|
80
|
+
const op = new RecordCloneGetLineageOperation();
|
|
81
|
+
const result = await op.Execute(input, { provider: p ?? undefined });
|
|
82
|
+
if (!result.Success || !result.Output) {
|
|
83
|
+
throw new Error(result.ErrorMessage || 'Failed to retrieve clone lineage');
|
|
84
|
+
}
|
|
85
|
+
return result.Output;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Clear the in-memory session Describe cache for a specific entity or all entities.
|
|
89
|
+
*/
|
|
90
|
+
ClearDescribeCache(entityName, provider) {
|
|
91
|
+
const bucket = this.cacheBucket(provider ?? Metadata.Provider);
|
|
92
|
+
if (entityName) {
|
|
93
|
+
bucket.delete(entityName.trim().toLowerCase());
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
bucket.clear();
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
cacheBucket(provider) {
|
|
100
|
+
const owner = provider ?? NO_PROVIDER;
|
|
101
|
+
let bucket = this._describeCache.get(owner);
|
|
102
|
+
if (!bucket) {
|
|
103
|
+
bucket = new Map();
|
|
104
|
+
this._describeCache.set(owner, bucket);
|
|
105
|
+
}
|
|
106
|
+
return bucket;
|
|
107
|
+
}
|
|
108
|
+
async describe(input, provider) {
|
|
109
|
+
const op = new RecordCloneDescribeOperation();
|
|
110
|
+
const result = await op.Execute(input, { provider: provider ?? undefined });
|
|
111
|
+
if (!result.Success || !result.Output) {
|
|
112
|
+
throw new Error(result.ErrorMessage || 'Failed to inspect record cloning capability');
|
|
113
|
+
}
|
|
114
|
+
return result.Output;
|
|
115
|
+
}
|
|
116
|
+
static ɵfac = function RecordCloneService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || RecordCloneService)(); };
|
|
117
|
+
static ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: RecordCloneService, factory: RecordCloneService.ɵfac, providedIn: 'root' });
|
|
118
|
+
}
|
|
119
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(RecordCloneService, [{
|
|
120
|
+
type: Injectable,
|
|
121
|
+
args: [{ providedIn: 'root' }]
|
|
122
|
+
}], null, null); })();
|
|
123
|
+
//# sourceMappingURL=record-clone.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record-clone.service.js","sourceRoot":"","sources":["../../src/lib/record-clone.service.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Angular service wrapping server-side Record Cloning remote operations.\n *\n * Implements §11.5 and §12.3 of the Record Cloning architectural blueprint. Resolves\n * the IMetadataProvider (multi-provider aware), delegates directly to the typed\n * BaseRemotableOperation subclasses emitted into @memberjunction/core-entities, and\n * maintains an in-memory session cache of Describe results per provider and entity.\n */\n\nimport { Injectable } from '@angular/core';\nimport { IMetadataProvider, Metadata } from '@memberjunction/core';\nimport {\n RecordCloneDescribeOperation,\n RecordClonePlanOperation,\n RecordCloneExecuteOperation,\n RecordCloneGetLineageOperation,\n type RecordCloneDescribeInput,\n type RecordCloneDescribeOutput,\n type RecordClonePlanInput,\n type RecordClonePlanOutput,\n type RecordCloneExecuteInput,\n type RecordCloneExecuteOutput,\n type RecordCloneGetLineageInput,\n type RecordCloneGetLineageOutput,\n} from '@memberjunction/core-entities';\n\n/** Cache bucket used when no provider can be resolved (tests, early bootstrap). */\nconst NO_PROVIDER = {};\n\n/**\n * Client for the four RecordClone remote operations. Every method takes an optional\n * provider so multi-provider hosts target the right server; omitted, it uses `Metadata.Provider`.\n */\n@Injectable({ providedIn: 'root' })\nexport class RecordCloneService {\n /** Describe answers per provider, then per entity. Holds the promise so concurrent callers share one request. */\n private readonly _describeCache = new WeakMap<object, Map<string, Promise<RecordCloneDescribeOutput>>>();\n\n /**\n * Inspect an entity (and optionally a specific record key) to discover cloning\n * capabilities, default options, user-editable knobs, and relationship policies.\n * Caches the result per provider and entity name for the session unless\n * `forceRefresh` is true or a specific record key is inspected. A failed call is not cached.\n */\n public async DescribeRecord(\n input: RecordCloneDescribeInput,\n provider?: IMetadataProvider | null,\n forceRefresh = false\n ): Promise<RecordCloneDescribeOutput> {\n const p = provider ?? Metadata.Provider;\n const isGenericQuery = !input.Key || !input.Key.KeyValuePairs || input.Key.KeyValuePairs.length === 0;\n if (!isGenericQuery) {\n return this.describe(input, p);\n }\n\n const bucket = this.cacheBucket(p);\n const cacheKey = input.EntityName.trim().toLowerCase();\n const cached = bucket.get(cacheKey);\n if (cached && !forceRefresh) {\n return cached;\n }\n\n const pending = this.describe(input, p);\n bucket.set(cacheKey, pending);\n pending.catch(() => {\n if (bucket.get(cacheKey) === pending) bucket.delete(cacheKey);\n });\n return pending;\n }\n\n /**\n * Compute a complete clone plan (dry run) for a source record graph without writing\n * any database changes. Returns the planned nodes, edges, field changes, and warnings.\n */\n public async PlanClone(\n input: RecordClonePlanInput,\n provider?: IMetadataProvider | null\n ): Promise<RecordClonePlanOutput> {\n const p = provider ?? Metadata.Provider;\n const op = new RecordClonePlanOperation();\n const result = await op.Execute(input, { provider: p ?? undefined });\n\n if (!result.Success || !result.Output) {\n throw new Error(result.ErrorMessage || 'Failed to compute clone plan');\n }\n\n return result.Output;\n }\n\n /**\n * Execute a planned record clone graph with optional overrides. Supports optimistic\n * plan hashing (ExpectedPlanHash), progress reporting, and full transactional rollback.\n */\n public async ExecuteClone(\n input: RecordCloneExecuteInput,\n provider?: IMetadataProvider | null\n ): Promise<RecordCloneExecuteOutput> {\n const p = provider ?? Metadata.Provider;\n const op = new RecordCloneExecuteOperation();\n const result = await op.Execute(input, { provider: p ?? undefined });\n\n if (!result.Success || !result.Output) {\n throw new Error(result.ErrorMessage || 'Failed to execute record clone');\n }\n\n return result.Output;\n }\n\n /**\n * Retrieve the clone lineage for a record — traversing ClonedFrom links upward to\n * ancestors and downward to descendant clones.\n */\n public async GetLineage(\n input: RecordCloneGetLineageInput,\n provider?: IMetadataProvider | null\n ): Promise<RecordCloneGetLineageOutput> {\n const p = provider ?? Metadata.Provider;\n const op = new RecordCloneGetLineageOperation();\n const result = await op.Execute(input, { provider: p ?? undefined });\n\n if (!result.Success || !result.Output) {\n throw new Error(result.ErrorMessage || 'Failed to retrieve clone lineage');\n }\n\n return result.Output;\n }\n\n /**\n * Clear the in-memory session Describe cache for a specific entity or all entities.\n */\n public ClearDescribeCache(entityName?: string, provider?: IMetadataProvider | null): void {\n const bucket = this.cacheBucket(provider ?? Metadata.Provider);\n if (entityName) {\n bucket.delete(entityName.trim().toLowerCase());\n } else {\n bucket.clear();\n }\n }\n\n private cacheBucket(provider: IMetadataProvider | null | undefined): Map<string, Promise<RecordCloneDescribeOutput>> {\n const owner: object = provider ?? NO_PROVIDER;\n let bucket = this._describeCache.get(owner);\n if (!bucket) {\n bucket = new Map();\n this._describeCache.set(owner, bucket);\n }\n return bucket;\n }\n\n private async describe(input: RecordCloneDescribeInput, provider: IMetadataProvider | null | undefined): Promise<RecordCloneDescribeOutput> {\n const op = new RecordCloneDescribeOperation();\n const result = await op.Execute(input, { provider: provider ?? undefined });\n if (!result.Success || !result.Output) {\n throw new Error(result.ErrorMessage || 'Failed to inspect record cloning capability');\n }\n return result.Output;\n }\n}\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public API Surface of @memberjunction/ng-record-clone
|
|
3
|
+
*/
|
|
4
|
+
export * from './lib/record-clone-types';
|
|
5
|
+
export * from './lib/record-clone.service';
|
|
6
|
+
export * from './lib/record-clone.module';
|
|
7
|
+
export * from './lib/record-clone-panel.component';
|
|
8
|
+
export * from './lib/record-clone-slide-in.component';
|
|
9
|
+
export * from './lib/clone-scope-controls.component';
|
|
10
|
+
export * from './lib/clone-plan-tree.component';
|
|
11
|
+
export * from './lib/clone-values.component';
|
|
12
|
+
export * from './lib/clone-review.component';
|
|
13
|
+
export * from './lib/clone-progress.component';
|
|
14
|
+
export * from './lib/clone-result.component';
|
|
15
|
+
export * from './lib/clone-lineage-chip.component';
|
|
16
|
+
//# sourceMappingURL=public-api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public-api.d.ts","sourceRoot":"","sources":["../src/public-api.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oCAAoC,CAAC;AACnD,cAAc,uCAAuC,CAAC;AACtD,cAAc,sCAAsC,CAAC;AACrD,cAAc,iCAAiC,CAAC;AAChD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,oCAAoC,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public API Surface of @memberjunction/ng-record-clone
|
|
3
|
+
*/
|
|
4
|
+
export * from './lib/record-clone-types';
|
|
5
|
+
export * from './lib/record-clone.service';
|
|
6
|
+
export * from './lib/record-clone.module';
|
|
7
|
+
export * from './lib/record-clone-panel.component';
|
|
8
|
+
export * from './lib/record-clone-slide-in.component';
|
|
9
|
+
export * from './lib/clone-scope-controls.component';
|
|
10
|
+
export * from './lib/clone-plan-tree.component';
|
|
11
|
+
export * from './lib/clone-values.component';
|
|
12
|
+
export * from './lib/clone-review.component';
|
|
13
|
+
export * from './lib/clone-progress.component';
|
|
14
|
+
export * from './lib/clone-result.component';
|
|
15
|
+
export * from './lib/clone-lineage-chip.component';
|
|
16
|
+
//# sourceMappingURL=public-api.js.map
|
|
@@ -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,4BAA4B,CAAC;AAC3C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oCAAoC,CAAC;AACnD,cAAc,uCAAuC,CAAC;AACtD,cAAc,sCAAsC,CAAC;AACrD,cAAc,iCAAiC,CAAC;AAChD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,oCAAoC,CAAC","sourcesContent":["/**\n * Public API Surface of @memberjunction/ng-record-clone\n */\n\nexport * from './lib/record-clone-types';\nexport * from './lib/record-clone.service';\nexport * from './lib/record-clone.module';\nexport * from './lib/record-clone-panel.component';\nexport * from './lib/record-clone-slide-in.component';\nexport * from './lib/clone-scope-controls.component';\nexport * from './lib/clone-plan-tree.component';\nexport * from './lib/clone-values.component';\nexport * from './lib/clone-review.component';\nexport * from './lib/clone-progress.component';\nexport * from './lib/clone-result.component';\nexport * from './lib/clone-lineage-chip.component';\n"]}
|
package/package.json
CHANGED
|
@@ -1,10 +1,52 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memberjunction/ng-record-clone",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "6.2.0-edge.2",
|
|
4
|
+
"description": "MemberJunction: Reusable record clone panel, plan tree, review, and toolbar integration for entity record cloning",
|
|
5
|
+
"main": "./dist/public-api.js",
|
|
6
|
+
"typings": "./dist/public-api.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"/dist"
|
|
9
|
+
],
|
|
5
10
|
"keywords": [
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
"memberjunction",
|
|
12
|
+
"angular",
|
|
13
|
+
"record-clone",
|
|
14
|
+
"clone",
|
|
15
|
+
"cloning"
|
|
16
|
+
],
|
|
17
|
+
"author": "MemberJunction.com",
|
|
18
|
+
"license": "BUSL-1.1",
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@angular/compiler": "21.2.22",
|
|
21
|
+
"@angular/compiler-cli": "21.2.22",
|
|
22
|
+
"@memberjunction/ng-test-utils": "6.2.0-edge.2",
|
|
23
|
+
"vitest": "^4.0.18"
|
|
24
|
+
},
|
|
25
|
+
"peerDependencies": {
|
|
26
|
+
"@angular/common": "^21.2.22",
|
|
27
|
+
"@angular/core": "^21.2.22",
|
|
28
|
+
"@angular/forms": "^21.2.22"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@memberjunction/core": "6.2.0-edge.2",
|
|
32
|
+
"@memberjunction/core-entities": "6.2.0-edge.2",
|
|
33
|
+
"@memberjunction/global": "6.2.0-edge.2",
|
|
34
|
+
"@memberjunction/ng-base-types": "6.2.0-edge.2",
|
|
35
|
+
"@memberjunction/ng-shared-generic": "6.2.0-edge.2",
|
|
36
|
+
"@memberjunction/ng-ui-components": "6.2.0-edge.2",
|
|
37
|
+
"@memberjunction/record-cloning-base": "6.2.0-edge.2",
|
|
38
|
+
"tslib": "^2.8.1"
|
|
39
|
+
},
|
|
40
|
+
"sideEffects": false,
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "https://github.com/MemberJunction/MJ"
|
|
44
|
+
},
|
|
45
|
+
"mjUILayer": "widgets",
|
|
46
|
+
"scripts": {
|
|
47
|
+
"test": "vitest run",
|
|
48
|
+
"test:types": "tsc --noEmit -p tsconfig.spec.json",
|
|
49
|
+
"build": "ngc",
|
|
50
|
+
"test:watch": "vitest"
|
|
51
|
+
}
|
|
52
|
+
}
|