@talxis/base-controls 1.2605.2-alpha → 1.2606.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/dist/components/Grid/cells/cell/Cell.js +2 -6
- package/dist/components/Grid/cells/cell/Cell.js.map +1 -1
- package/dist/components/Grid/column-headers/column-header/ColumnHeader.js +1 -1
- package/dist/components/Grid/column-headers/column-header/ColumnHeader.js.map +1 -1
- package/dist/components/Grid/grid/ag-grid/AgGridModel.js +1 -1
- package/dist/components/Grid/grid/ag-grid/AgGridModel.js.map +1 -1
- package/dist/components/Lookup/components/TargetSelector.js +1 -1
- package/dist/components/Lookup/components/TargetSelector.js.map +1 -1
- package/dist/components/Lookup/hooks/useLookup.d.ts +4 -0
- package/dist/components/Lookup/translations.d.ts +4 -0
- package/dist/components/Lookup/translations.js +4 -0
- package/dist/components/Lookup/translations.js.map +1 -1
- package/dist/components/TaskGrid/TaskGrid.js +2 -2
- package/dist/components/TaskGrid/TaskGrid.js.map +1 -1
- package/dist/components/TaskGrid/TaskGridDatasetControl.d.ts +2 -0
- package/dist/components/TaskGrid/TaskGridDatasetControl.js +42 -28
- package/dist/components/TaskGrid/TaskGridDatasetControl.js.map +1 -1
- package/dist/components/TaskGrid/TaskGridDatasetControlFactory.js +3 -0
- package/dist/components/TaskGrid/TaskGridDatasetControlFactory.js.map +1 -1
- package/dist/components/TaskGrid/components/grid/cell-renderers/lookup-many/LookupManyCellRenderer.js +6 -3
- package/dist/components/TaskGrid/components/grid/cell-renderers/lookup-many/LookupManyCellRenderer.js.map +1 -1
- package/dist/components/TaskGrid/components/grid/cell-renderers/percent-complete/PercentComplete.js +2 -4
- package/dist/components/TaskGrid/components/grid/cell-renderers/percent-complete/PercentComplete.js.map +1 -1
- package/dist/components/TaskGrid/components/grid/cell-renderers/percent-complete/styles.d.ts +0 -6
- package/dist/components/TaskGrid/components/grid/cell-renderers/percent-complete/styles.js +0 -6
- package/dist/components/TaskGrid/components/grid/cell-renderers/percent-complete/styles.js.map +1 -1
- package/dist/components/TaskGrid/components/grid/grid-customizer/GridCustomizer.js +10 -5
- package/dist/components/TaskGrid/components/grid/grid-customizer/GridCustomizer.js.map +1 -1
- package/dist/components/TaskGrid/components/grid/group-cell/styles.d.ts +3 -0
- package/dist/components/TaskGrid/components/grid/group-cell/styles.js +3 -0
- package/dist/components/TaskGrid/components/grid/group-cell/styles.js.map +1 -1
- package/dist/components/TaskGrid/components/grid/lookup-many/LookupMany.d.ts +1 -1
- package/dist/components/TaskGrid/components/grid/lookup-many/LookupMany.js +3 -1
- package/dist/components/TaskGrid/components/grid/lookup-many/LookupMany.js.map +1 -1
- package/dist/components/TaskGrid/components/grid/lookup-many/colorful-lookup-many/components/index.d.ts +1 -1
- package/dist/components/TaskGrid/components/grid/lookup-many/colorful-lookup-many/components/index.js +1 -1
- package/dist/components/TaskGrid/components/grid/lookup-many/colorful-lookup-many/components/index.js.map +1 -1
- package/dist/components/TaskGrid/components/grid/lookup-many/components/components.d.ts +11 -0
- package/dist/components/TaskGrid/components/grid/lookup-many/components/components.js +17 -0
- package/dist/components/TaskGrid/components/grid/lookup-many/components/components.js.map +1 -0
- package/dist/components/TaskGrid/components/grid/lookup-many/components/index.d.ts +1 -10
- package/dist/components/TaskGrid/components/grid/lookup-many/components/index.js +1 -14
- package/dist/components/TaskGrid/components/grid/lookup-many/components/index.js.map +1 -1
- package/dist/components/TaskGrid/components/grid/lookup-many/components/menu/Menu.d.ts +3 -0
- package/dist/components/TaskGrid/components/grid/lookup-many/components/menu/Menu.js +10 -0
- package/dist/components/TaskGrid/components/grid/lookup-many/components/menu/Menu.js.map +1 -0
- package/dist/components/TaskGrid/components/grid/lookup-many/components/menu/index.d.ts +1 -0
- package/dist/components/TaskGrid/components/grid/lookup-many/components/menu/index.js +2 -0
- package/dist/components/TaskGrid/components/grid/lookup-many/components/menu/index.js.map +1 -0
- package/dist/components/TaskGrid/components/grid/lookup-many/components/multi-value-container/MultiValueContainer.d.ts +5 -1
- package/dist/components/TaskGrid/components/grid/lookup-many/components/multi-value-container/MultiValueContainer.js +3 -2
- package/dist/components/TaskGrid/components/grid/lookup-many/components/multi-value-container/MultiValueContainer.js.map +1 -1
- package/dist/components/TaskGrid/components/grid/lookup-many/people-lookup-many/PeopleLookupMany.js +1 -1
- package/dist/components/TaskGrid/components/grid/lookup-many/people-lookup-many/PeopleLookupMany.js.map +1 -1
- package/dist/components/TaskGrid/components/grid/lookup-many/people-lookup-many/components/components.d.ts +2 -0
- package/dist/components/TaskGrid/components/grid/lookup-many/people-lookup-many/components/components.js +15 -0
- package/dist/components/TaskGrid/components/grid/lookup-many/people-lookup-many/components/components.js.map +1 -0
- package/dist/components/TaskGrid/components/grid/lookup-many/people-lookup-many/components/index.d.ts +1 -2
- package/dist/components/TaskGrid/components/grid/lookup-many/people-lookup-many/components/index.js +1 -12
- package/dist/components/TaskGrid/components/grid/lookup-many/people-lookup-many/components/index.js.map +1 -1
- package/dist/components/TaskGrid/components/grid/lookup-many/people-lookup-many/components/multi-value-container/MultiValueContainer.d.ts +3 -0
- package/dist/components/TaskGrid/components/grid/lookup-many/people-lookup-many/components/multi-value-container/MultiValueContainer.js +12 -0
- package/dist/components/TaskGrid/components/grid/lookup-many/people-lookup-many/components/multi-value-container/MultiValueContainer.js.map +1 -0
- package/dist/components/TaskGrid/components/grid/lookup-many/people-lookup-many/components/multi-value-container/index.d.ts +1 -0
- package/dist/components/TaskGrid/components/grid/lookup-many/people-lookup-many/components/multi-value-container/index.js +2 -0
- package/dist/components/TaskGrid/components/grid/lookup-many/people-lookup-many/components/multi-value-container/index.js.map +1 -0
- package/dist/components/TaskGrid/components/grid/lookup-many/people-lookup-many/components/multi-value-container/styles.d.ts +9 -0
- package/dist/components/TaskGrid/components/grid/lookup-many/people-lookup-many/components/multi-value-container/styles.js +18 -0
- package/dist/components/TaskGrid/components/grid/lookup-many/people-lookup-many/components/multi-value-container/styles.js.map +1 -0
- package/dist/components/TaskGrid/components/grid/lookup-many/people-lookup-many/components/multi-value-label/MultiValueLabel.js +1 -1
- package/dist/components/TaskGrid/components/grid/lookup-many/people-lookup-many/components/multi-value-label/MultiValueLabel.js.map +1 -1
- package/dist/components/TaskGrid/components/grid/multi-record-selector/components/multi-value-label/MultiValueLabel.d.ts +1 -1
- package/dist/components/TaskGrid/components/grid/multi-record-selector/components/multi-value-label/MultiValueLabel.js +3 -2
- package/dist/components/TaskGrid/components/grid/multi-record-selector/components/multi-value-label/MultiValueLabel.js.map +1 -1
- package/dist/components/TaskGrid/components/header/Header.d.ts +1 -1
- package/dist/components/TaskGrid/components/header/Header.js +58 -44
- package/dist/components/TaskGrid/components/header/Header.js.map +1 -1
- package/dist/components/TaskGrid/extensions/dataverse/DataverseCustomColumnsStrategy.d.ts +12 -6
- package/dist/components/TaskGrid/extensions/dataverse/DataverseCustomColumnsStrategy.js +23 -20
- package/dist/components/TaskGrid/extensions/dataverse/DataverseCustomColumnsStrategy.js.map +1 -1
- package/dist/components/TaskGrid/extensions/dataverse/DataverseGridCustomizerStrategy.d.ts +3 -3
- package/dist/components/TaskGrid/extensions/dataverse/DataverseGridCustomizerStrategy.js +4 -5
- package/dist/components/TaskGrid/extensions/dataverse/DataverseGridCustomizerStrategy.js.map +1 -1
- package/dist/components/TaskGrid/extensions/dataverse/DataverseSavedQueryStrategy.js +15 -15
- package/dist/components/TaskGrid/extensions/dataverse/DataverseSavedQueryStrategy.js.map +1 -1
- package/dist/components/TaskGrid/extensions/dataverse/DataverseTaskGridDescriptor.d.ts +27 -25
- package/dist/components/TaskGrid/extensions/dataverse/DataverseTaskGridDescriptor.js +68 -29
- package/dist/components/TaskGrid/extensions/dataverse/DataverseTaskGridDescriptor.js.map +1 -1
- package/dist/components/TaskGrid/extensions/dataverse/DataverseTaskStrategy.d.ts +19 -17
- package/dist/components/TaskGrid/extensions/dataverse/DataverseTaskStrategy.js +119 -74
- package/dist/components/TaskGrid/extensions/dataverse/DataverseTaskStrategy.js.map +1 -1
- package/dist/components/TaskGrid/extensions/dataverse/index.js +1 -1
- package/dist/components/TaskGrid/extensions/dataverse/lookup-many/LookupManyHandler.d.ts +18 -2
- package/dist/components/TaskGrid/extensions/dataverse/lookup-many/LookupManyHandler.js +80 -17
- package/dist/components/TaskGrid/extensions/dataverse/lookup-many/LookupManyHandler.js.map +1 -1
- package/dist/components/TaskGrid/extensions/dataverse/lookup-many/cell-renderer/FetchXmlLookupManyCellRenderer.js +10 -4
- package/dist/components/TaskGrid/extensions/dataverse/lookup-many/cell-renderer/FetchXmlLookupManyCellRenderer.js.map +1 -1
- package/dist/components/TaskGrid/interfaces.d.ts +36 -22
- package/dist/components/TaskGrid/providers/custom-columns/CustomColumnsDataProvider.d.ts +7 -1
- package/dist/components/TaskGrid/providers/custom-columns/CustomColumnsDataProvider.js +3 -0
- package/dist/components/TaskGrid/providers/custom-columns/CustomColumnsDataProvider.js.map +1 -1
- package/dist/components/TaskGrid/providers/saved-query/SavedQueryDataProvider.d.ts +1 -1
- package/dist/components/TaskGrid/providers/saved-query/SavedQueryDataProvider.js +9 -26
- package/dist/components/TaskGrid/providers/saved-query/SavedQueryDataProvider.js.map +1 -1
- package/dist/components/TaskGrid/providers/task/TaskDataProvider.d.ts +13 -20
- package/dist/components/TaskGrid/providers/task/TaskDataProvider.js +30 -22
- package/dist/components/TaskGrid/providers/task/TaskDataProvider.js.map +1 -1
- package/dist/components/TaskGrid/providers/task/record-tree/RecordTree.d.ts +8 -0
- package/dist/components/TaskGrid/providers/task/record-tree/RecordTree.js.map +1 -1
- package/dist/index.d.ts +68 -42
- package/dist/utils/dataset/adapters/VirtualDatasetAdapter.js.map +1 -1
- package/package.json +4 -4
- package/dist/components/TaskGrid/extensions/LexoRank.d.ts +0 -7
|
@@ -4,8 +4,6 @@ var RelationshipType;
|
|
|
4
4
|
RelationshipType[RelationshipType["OneToMany"] = 0] = "OneToMany";
|
|
5
5
|
RelationshipType[RelationshipType["ManyToMany"] = 1] = "ManyToMany";
|
|
6
6
|
})(RelationshipType || (RelationshipType = {}));
|
|
7
|
-
/** Suffix used for lookup-many task grid stub columns. */
|
|
8
|
-
const LOOKUP_MANY_COLUMN_NAME_SUFFIX = '_stub';
|
|
9
7
|
/**
|
|
10
8
|
* Handles metadata resolution and associate/disassociate operations
|
|
11
9
|
* for lookup-many fields in task grid records.
|
|
@@ -15,12 +13,16 @@ class LookupManyHandler {
|
|
|
15
13
|
this._initialized = false;
|
|
16
14
|
this._navigationPropertyName = params.navigationPropertyName;
|
|
17
15
|
this._entityName = params.entityName;
|
|
16
|
+
this._customIntersection = params.customIntersection;
|
|
18
17
|
}
|
|
19
18
|
/** Initializes the handler and caches relationship metadata. */
|
|
20
19
|
async init() {
|
|
21
20
|
if (this._initialized)
|
|
22
21
|
return;
|
|
23
22
|
this._relationship = await this._fetchRelationship();
|
|
23
|
+
if (this._customIntersection) {
|
|
24
|
+
this._customIntersectionEntityMetadata = await window.Xrm.Utility.getEntityMetadata(this._getRelatedEntityName());
|
|
25
|
+
}
|
|
24
26
|
this._initialized = true;
|
|
25
27
|
}
|
|
26
28
|
/**
|
|
@@ -28,15 +30,33 @@ class LookupManyHandler {
|
|
|
28
30
|
* @param select Optional comma-separated projection for expanded records.
|
|
29
31
|
*/
|
|
30
32
|
getExpand(select) {
|
|
33
|
+
if (this.isCustomIntersection()) {
|
|
34
|
+
const intersectionMetadata = this.getCustomIntersectionEntityMetadata();
|
|
35
|
+
const intersectionIdField = intersectionMetadata.PrimaryIdAttribute;
|
|
36
|
+
const relatedNavProp = this._customIntersection.referencingEntityNavigationPropertyName;
|
|
37
|
+
const expandClause = select ? `($select=${select})` : '';
|
|
38
|
+
return `${this._navigationPropertyName}($select=${intersectionIdField};$expand=${relatedNavProp}${expandClause})`;
|
|
39
|
+
}
|
|
31
40
|
const relationship = this._getRelationship();
|
|
32
41
|
//@ts-ignore - typings
|
|
33
42
|
if (relationship.RelationshipType === RelationshipType.OneToMany) {
|
|
34
43
|
return `${relationship.ReferencedEntityNavigationPropertyName}${select ? `($select=${select})` : ''}`;
|
|
35
44
|
}
|
|
36
45
|
else {
|
|
37
|
-
|
|
38
|
-
|
|
46
|
+
return `${this._navigationPropertyName}${select ? `($select=${select})` : ''}`;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
isCustomIntersection() {
|
|
50
|
+
return !!this._customIntersection;
|
|
51
|
+
}
|
|
52
|
+
getCustomIntersectionEntityMetadata() {
|
|
53
|
+
if (!this._customIntersection) {
|
|
54
|
+
throw new Error('Custom intersection configuration is missing. Please provide referencingEntityNavigationPropertyName in the constructor parameters.');
|
|
39
55
|
}
|
|
56
|
+
if (!this._customIntersectionEntityMetadata) {
|
|
57
|
+
throw new Error('Custom intersection metadata is not available. Ensure init() was called before metadata access.');
|
|
58
|
+
}
|
|
59
|
+
return this._customIntersectionEntityMetadata;
|
|
40
60
|
}
|
|
41
61
|
/**
|
|
42
62
|
* Persists association changes by comparing current values with original values.
|
|
@@ -57,8 +77,8 @@ class LookupManyHandler {
|
|
|
57
77
|
fields: [],
|
|
58
78
|
};
|
|
59
79
|
}
|
|
60
|
-
const deleteResult = await this._executeAssociation('Disassociate', recordId, toRemove
|
|
61
|
-
const addResult = await this._executeAssociation('Associate', recordId, toAdd
|
|
80
|
+
const deleteResult = await this._executeAssociation('Disassociate', recordId, toRemove);
|
|
81
|
+
const addResult = await this._executeAssociation('Associate', recordId, toAdd);
|
|
62
82
|
const success = (deleteResult?.success ?? true) && (addResult?.success ?? true);
|
|
63
83
|
const errors = [...(deleteResult?.errors ?? []), ...(addResult?.errors ?? [])];
|
|
64
84
|
return {
|
|
@@ -93,22 +113,32 @@ class LookupManyHandler {
|
|
|
93
113
|
}
|
|
94
114
|
return relationship;
|
|
95
115
|
}
|
|
96
|
-
async _executeAssociation(operationName, parentId,
|
|
97
|
-
if (
|
|
116
|
+
async _executeAssociation(operationName, parentId, relatedRecords) {
|
|
117
|
+
if (relatedRecords.length === 0) {
|
|
98
118
|
return null;
|
|
99
119
|
}
|
|
100
120
|
try {
|
|
101
121
|
if (operationName === 'Disassociate') {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
122
|
+
if (this._customIntersection) {
|
|
123
|
+
await this._deleteCustomIntersectionRecord(parentId, relatedRecords);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
await Promise.all(relatedRecords.map(record => window.Xrm.WebApi.online.execute({
|
|
127
|
+
...this._buildBaseRequest(operationName, parentId),
|
|
128
|
+
relatedEntityId: record.id.guid,
|
|
129
|
+
})));
|
|
130
|
+
}
|
|
106
131
|
}
|
|
107
132
|
else {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
133
|
+
if (this._customIntersection) {
|
|
134
|
+
await Promise.all(relatedRecords.map(record => this._createCustomIntersectionRecord(parentId, record)));
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
await window.Xrm.WebApi.online.execute({
|
|
138
|
+
...this._buildBaseRequest(operationName, parentId),
|
|
139
|
+
relatedEntities: relatedRecords.map(record => ({ id: record.id.guid, entityType: this._getRelatedEntityName() })),
|
|
140
|
+
});
|
|
141
|
+
}
|
|
112
142
|
}
|
|
113
143
|
return { recordId: parentId, success: true, fields: [] };
|
|
114
144
|
}
|
|
@@ -116,6 +146,39 @@ class LookupManyHandler {
|
|
|
116
146
|
return { recordId: parentId, success: false, fields: [], errors: [{ message: err.message }] };
|
|
117
147
|
}
|
|
118
148
|
}
|
|
149
|
+
async _createCustomIntersectionRecord(parentId, relatedRecord) {
|
|
150
|
+
const parentEntityMetadata = await window.Xrm.Utility.getEntityMetadata(this._entityName);
|
|
151
|
+
const intersectionEntityMetadata = this.getCustomIntersectionEntityMetadata();
|
|
152
|
+
const relatedEntityRelationship = intersectionEntityMetadata.ManyToOneRelationships.getAll().find((rel) => rel.ReferencingEntityNavigationPropertyName === this._getCustomIntersection().referencingEntityNavigationPropertyName);
|
|
153
|
+
const relatedEntityMetadata = await window.Xrm.Utility.getEntityMetadata(relatedEntityRelationship.ReferencedEntity);
|
|
154
|
+
const payload = {
|
|
155
|
+
//@ts-ignore - typings
|
|
156
|
+
[`${this._getRelationship().ReferencingEntityNavigationPropertyName}@odata.bind`]: `${parentEntityMetadata.EntitySetName}(${parentId})`,
|
|
157
|
+
[`${this._getCustomIntersection().referencingEntityNavigationPropertyName}@odata.bind`]: `${relatedEntityMetadata.EntitySetName}(${relatedRecord.id.guid})`
|
|
158
|
+
};
|
|
159
|
+
const result = await window.Xrm.WebApi.createRecord(intersectionEntityMetadata.LogicalName, payload);
|
|
160
|
+
//this should be done through setValue
|
|
161
|
+
relatedRecord.rawData = {
|
|
162
|
+
...relatedRecord.rawData,
|
|
163
|
+
__intersectionId: result.id
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
async _deleteCustomIntersectionRecord(parentId, relatedRecords) {
|
|
167
|
+
const intersectionEntityMetadata = this.getCustomIntersectionEntityMetadata();
|
|
168
|
+
await Promise.all(relatedRecords.map(async (record) => {
|
|
169
|
+
const intersectionId = record.rawData?.__intersectionId;
|
|
170
|
+
if (!intersectionId) {
|
|
171
|
+
throw new Error('Missing intersection record ID for disassociation. Cannot proceed with custom intersection deletion.');
|
|
172
|
+
}
|
|
173
|
+
await window.Xrm.WebApi.deleteRecord(intersectionEntityMetadata.LogicalName, intersectionId);
|
|
174
|
+
}));
|
|
175
|
+
}
|
|
176
|
+
_getCustomIntersection() {
|
|
177
|
+
if (!this._customIntersection) {
|
|
178
|
+
throw new Error('Custom intersection configuration is missing. Please provide referencingEntityNavigationPropertyName in the constructor parameters.');
|
|
179
|
+
}
|
|
180
|
+
return this._customIntersection;
|
|
181
|
+
}
|
|
119
182
|
_buildBaseRequest(operationName, parentId) {
|
|
120
183
|
return {
|
|
121
184
|
getMetadata: () => ({
|
|
@@ -141,5 +204,5 @@ class LookupManyHandler {
|
|
|
141
204
|
}
|
|
142
205
|
}
|
|
143
206
|
|
|
144
|
-
export {
|
|
207
|
+
export { LookupManyHandler };
|
|
145
208
|
//# sourceMappingURL=LookupManyHandler.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LookupManyHandler.js","sources":["../../../../../../src/components/TaskGrid/extensions/dataverse/lookup-many/LookupManyHandler.ts"],"sourcesContent":["import { IRecord, IRecordSaveOperationResult } from \"@talxis/client-libraries\";\nimport { IManyToManyRelationship, IRelationship } from \"@talxis/client-metadata/dist/interfaces/entity/IEntityDefinition\";\n\n\n/** Supported Dataverse relationship kinds used by the handler. */\nenum RelationshipType {\n OneToMany = 0,\n ManyToMany = 1\n}\n\n/** Suffix used for lookup-many task grid stub columns. */\nexport const LOOKUP_MANY_COLUMN_NAME_SUFFIX = '_stub';\n\n/** Constructor parameters required to resolve relationship metadata. */\ninterface IManyToManyTestParams {\n /** Parent entity navigation property name that identifies the relationship. */\n navigationPropertyName: string;\n /** Logical name of the source entity for association operations. */\n entityName: string;\n}\n\n/** Contract for a lookup-many relationship handler. */\nexport interface ILookupManyHandler {\n /** Loads relationship metadata and prepares the handler for usage. */\n init(): Promise<void>;\n /** Returns OData expand segment for the configured relationship. */\n getExpand(select?: string): string;\n /** Saves lookup-many association changes for a record. */\n saveRecord(record: IRecord, lookupManyColName: string): Promise<IRecordSaveOperationResult>;\n}\n\n\n/**\n * Handles metadata resolution and associate/disassociate operations\n * for lookup-many fields in task grid records.\n */\nexport class LookupManyHandler implements ILookupManyHandler {\n private _relationship?: IRelationship | IManyToManyRelationship;\n private _initialized: boolean = false;\n private _entityName: string;\n private _navigationPropertyName: string;\n\n constructor(params: IManyToManyTestParams) {\n this._navigationPropertyName = params.navigationPropertyName;\n this._entityName = params.entityName;\n }\n\n /** Initializes the handler and caches relationship metadata. */\n public async init() {\n if (this._initialized) return;\n this._relationship = await this._fetchRelationship();\n this._initialized = true;\n }\n\n /**\n * Builds an OData expand clause for the configured relationship.\n * @param select Optional comma-separated projection for expanded records.\n */\n public getExpand(select?: string): string {\n const relationship = this._getRelationship();\n //@ts-ignore - typings\n if (relationship.RelationshipType === RelationshipType.OneToMany) {\n return `${(relationship as IRelationship).ReferencedEntityNavigationPropertyName}${select ? `($select=${select})` : ''}`;\n }\n else {\n const rel = relationship as IManyToManyRelationship;\n return `${rel.Entity1NavigationPropertyName}${select ? `($select=${select})` : ''}`;\n }\n }\n\n /**\n * Persists association changes by comparing current values with original values.\n * @param record Record being saved.\n * @param lookupManyColName Logical column name for the lookup-many field.\n */\n public async saveRecord(record: IRecord, lookupManyColName: string): Promise<IRecordSaveOperationResult> {\n const recordId = record.getRecordId();\n const newValue = record.getValue(lookupManyColName) ?? [];\n //@ts-ignore - typings\n const previousValue = record.getField(lookupManyColName)._originalValue ?? [];\n\n const toAdd: ComponentFramework.EntityReference[] = newValue.filter((newValue: ComponentFramework.EntityReference) =>\n !previousValue.some((origValue: ComponentFramework.EntityReference) => origValue.id.guid === newValue.id.guid)\n );\n const toRemove: ComponentFramework.EntityReference[] = previousValue.filter((origValue: ComponentFramework.EntityReference) =>\n !newValue.some((newValue: ComponentFramework.EntityReference) => newValue.id.guid === origValue.id.guid)\n );\n if (toAdd.length === 0 && toRemove.length === 0) {\n return {\n success: true,\n recordId: recordId,\n fields: [],\n }\n }\n\n const deleteResult = await this._executeAssociation('Disassociate', recordId, toRemove.map(a => a.id.guid));\n const addResult = await this._executeAssociation('Associate', recordId, toAdd.map(a => a.id.guid));\n const success = (deleteResult?.success ?? true) && (addResult?.success ?? true);\n const errors = [...(deleteResult?.errors ?? []), ...(addResult?.errors ?? [])];\n\n return {\n success,\n recordId: recordId,\n fields: [lookupManyColName],\n errors\n };\n\n }\n\n private _getRelationship(): IRelationship | IManyToManyRelationship {\n if (!this._relationship) {\n throw new Error('Relationship not loaded. Have you called init()?');\n }\n return this._relationship;\n }\n\n private async _fetchRelationship(): Promise<IRelationship | IManyToManyRelationship> {\n const metadata: any = await window.Xrm.Utility.getEntityMetadata(this._entityName);\n const relationships: (IRelationship | IManyToManyRelationship)[] = [...metadata.OneToManyRelationships.getAll(), ...metadata.ManyToManyRelationships.getAll()];\n const relationship = relationships.find(rel => {\n //@ts-ignore - typings\n if (rel.RelationshipType === RelationshipType.ManyToMany) {\n const m2m = rel as IManyToManyRelationship;\n return m2m.Entity1NavigationPropertyName === this._navigationPropertyName ||\n m2m.Entity2NavigationPropertyName === this._navigationPropertyName;\n }\n const o2m = rel as IRelationship;\n return o2m.ReferencedEntityNavigationPropertyName === this._navigationPropertyName ||\n o2m.ReferencingEntityNavigationPropertyName === this._navigationPropertyName;\n\n });\n if (!relationship) {\n throw new Error(`Could not find navigation property name ${this._navigationPropertyName} on ${metadata.LogicalName}`);\n }\n return relationship;\n }\n\n private async _executeAssociation(operationName: 'Associate' | 'Disassociate', parentId: string, recordIds: string[]): Promise<IRecordSaveOperationResult | null> {\n if (recordIds.length === 0) {\n return null;\n }\n try {\n if (operationName === 'Disassociate') {\n await Promise.all(recordIds.map(id =>\n window.Xrm.WebApi.online.execute({\n ...this._buildBaseRequest(operationName, parentId),\n relatedEntityId: id,\n })\n ));\n }\n else {\n await window.Xrm.WebApi.online.execute({\n ...this._buildBaseRequest(operationName, parentId),\n relatedEntities: recordIds.map(id => ({ id, entityType: this._getRelatedEntityName() })),\n });\n }\n return { recordId: parentId, success: true, fields: [] };\n }\n catch (err: any) {\n return { recordId: parentId, success: false, fields: [], errors: [{ message: err.message }] };\n }\n }\n\n private _buildBaseRequest(operationName: 'Associate' | 'Disassociate', parentId: string) {\n return {\n getMetadata: () => ({\n operationType: 2,\n operationName,\n parameterTypes: {},\n }),\n target: { id: parentId, entityType: this._entityName },\n relationship: this._getRelationship().SchemaName,\n };\n }\n\n private _getRelatedEntityName(): string {\n const relationship = this._getRelationship();\n //@ts-ignore - typings\n if (relationship.RelationshipType === RelationshipType.ManyToMany) {\n const rel = relationship as IManyToManyRelationship;\n const isEntity1Source = rel.Entity1LogicalName === this._entityName;\n return isEntity1Source ? rel.Entity2LogicalName : rel.Entity1LogicalName;\n }\n else {\n return (relationship as IRelationship).ReferencingEntity;\n }\n }\n\n}"],"names":[],"mappings":"AAIA;AACA,IAAK,gBAGJ,CAAA;AAHD,CAAA,UAAK,gBAAgB,EAAA;AACjB,IAAA,gBAAA,CAAA,gBAAA,CAAA,WAAA,CAAA,GAAA,CAAA,CAAA,GAAA,WAAa,CAAA;AACb,IAAA,gBAAA,CAAA,gBAAA,CAAA,YAAA,CAAA,GAAA,CAAA,CAAA,GAAA,YAAc,CAAA;AAClB,CAAC,EAHI,gBAAgB,KAAhB,gBAAgB,GAGpB,EAAA,CAAA,CAAA,CAAA;AAED;AACO,MAAM,8BAA8B,GAAG,QAAQ;AAqBtD;;;AAGG;MACU,iBAAiB,CAAA;AAM1B,IAAA,WAAA,CAAY,MAA6B,EAAA;QAJjC,IAAY,CAAA,YAAA,GAAY,KAAK,CAAC;AAKlC,QAAA,IAAI,CAAC,uBAAuB,GAAG,MAAM,CAAC,sBAAsB,CAAC;AAC7D,QAAA,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,UAAU,CAAC;KACxC;;AAGM,IAAA,MAAM,IAAI,GAAA;QACb,IAAI,IAAI,CAAC,YAAY;YAAE,OAAO;QAC9B,IAAI,CAAC,aAAa,GAAG,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAC;AACrD,QAAA,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;KAC5B;AAED;;;AAGG;AACI,IAAA,SAAS,CAAC,MAAe,EAAA;AAC5B,QAAA,MAAM,YAAY,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;;AAE7C,QAAA,IAAI,YAAY,CAAC,gBAAgB,KAAK,gBAAgB,CAAC,SAAS,EAAE;AAC9D,YAAA,OAAO,GAAI,YAA8B,CAAC,sCAAsC,CAAA,EAAG,MAAM,GAAG,CAAA,SAAA,EAAY,MAAM,CAAG,CAAA,CAAA,GAAG,EAAE,EAAE,CAAC;AAC5H,SAAA;AACI,aAAA;YACD,MAAM,GAAG,GAAG,YAAuC,CAAC;AACpD,YAAA,OAAO,GAAG,GAAG,CAAC,6BAA6B,CAAA,EAAG,MAAM,GAAG,CAAA,SAAA,EAAY,MAAM,CAAG,CAAA,CAAA,GAAG,EAAE,EAAE,CAAC;AACvF,SAAA;KACJ;AAED;;;;AAIG;AACI,IAAA,MAAM,UAAU,CAAC,MAAe,EAAE,iBAAyB,EAAA;AAC9D,QAAA,MAAM,QAAQ,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;QACtC,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC;;AAE1D,QAAA,MAAM,aAAa,GAAG,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC,cAAc,IAAI,EAAE,CAAC;AAE9E,QAAA,MAAM,KAAK,GAAyC,QAAQ,CAAC,MAAM,CAAC,CAAC,QAA4C,KAC7G,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,SAA6C,KAAK,SAAS,CAAC,EAAE,CAAC,IAAI,KAAK,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,CACjH,CAAC;AACF,QAAA,MAAM,QAAQ,GAAyC,aAAa,CAAC,MAAM,CAAC,CAAC,SAA6C,KACtH,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,QAA4C,KAAK,QAAQ,CAAC,EAAE,CAAC,IAAI,KAAK,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,CAC3G,CAAC;QACF,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE;YAC7C,OAAO;AACH,gBAAA,OAAO,EAAE,IAAI;AACb,gBAAA,QAAQ,EAAE,QAAQ;AAClB,gBAAA,MAAM,EAAE,EAAE;aACb,CAAA;AACJ,SAAA;QAED,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,cAAc,EAAE,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;QAC5G,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,WAAW,EAAE,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;AACnG,QAAA,MAAM,OAAO,GAAG,CAAC,YAAY,EAAE,OAAO,IAAI,IAAI,MAAM,SAAS,EAAE,OAAO,IAAI,IAAI,CAAC,CAAC;QAChF,MAAM,MAAM,GAAG,CAAC,IAAI,YAAY,EAAE,MAAM,IAAI,EAAE,CAAC,EAAE,IAAI,SAAS,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC;QAE/E,OAAO;YACH,OAAO;AACP,YAAA,QAAQ,EAAE,QAAQ;YAClB,MAAM,EAAE,CAAC,iBAAiB,CAAC;YAC3B,MAAM;SACT,CAAC;KAEL;IAEO,gBAAgB,GAAA;AACpB,QAAA,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE;AACrB,YAAA,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;AACvE,SAAA;QACD,OAAO,IAAI,CAAC,aAAa,CAAC;KAC7B;AAEO,IAAA,MAAM,kBAAkB,GAAA;AAC5B,QAAA,MAAM,QAAQ,GAAQ,MAAM,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,iBAAiB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;AACnF,QAAA,MAAM,aAAa,GAAgD,CAAC,GAAG,QAAQ,CAAC,sBAAsB,CAAC,MAAM,EAAE,EAAE,GAAG,QAAQ,CAAC,uBAAuB,CAAC,MAAM,EAAE,CAAC,CAAC;QAC/J,MAAM,YAAY,GAAG,aAAa,CAAC,IAAI,CAAC,GAAG,IAAG;;AAE1C,YAAA,IAAI,GAAG,CAAC,gBAAgB,KAAK,gBAAgB,CAAC,UAAU,EAAE;gBACtD,MAAM,GAAG,GAAG,GAA8B,CAAC;AAC3C,gBAAA,OAAO,GAAG,CAAC,6BAA6B,KAAK,IAAI,CAAC,uBAAuB;AAClE,oBAAA,GAAG,CAAC,6BAA6B,KAAK,IAAI,CAAC,uBAAuB,CAAC;AAC7E,aAAA;YACD,MAAM,GAAG,GAAG,GAAoB,CAAC;AACjC,YAAA,OAAO,GAAG,CAAC,sCAAsC,KAAK,IAAI,CAAC,uBAAuB;AAC3E,gBAAA,GAAG,CAAC,uCAAuC,KAAK,IAAI,CAAC,uBAAuB,CAAC;AAExF,SAAC,CAAC,CAAC;QACH,IAAI,CAAC,YAAY,EAAE;AACf,YAAA,MAAM,IAAI,KAAK,CAAC,CAAA,wCAAA,EAA2C,IAAI,CAAC,uBAAuB,CAAA,IAAA,EAAO,QAAQ,CAAC,WAAW,CAAA,CAAE,CAAC,CAAC;AACzH,SAAA;AACD,QAAA,OAAO,YAAY,CAAC;KACvB;AAEO,IAAA,MAAM,mBAAmB,CAAC,aAA2C,EAAE,QAAgB,EAAE,SAAmB,EAAA;AAChH,QAAA,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE;AACxB,YAAA,OAAO,IAAI,CAAC;AACf,SAAA;QACD,IAAI;YACA,IAAI,aAAa,KAAK,cAAc,EAAE;gBAClC,MAAM,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,IAC9B,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;AAC7B,oBAAA,GAAG,IAAI,CAAC,iBAAiB,CAAC,aAAa,EAAE,QAAQ,CAAC;AAClD,oBAAA,eAAe,EAAE,EAAE;iBACtB,CAAC,CACL,CAAC,CAAC;AACN,aAAA;AACI,iBAAA;gBACD,MAAM,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;AACnC,oBAAA,GAAG,IAAI,CAAC,iBAAiB,CAAC,aAAa,EAAE,QAAQ,CAAC;oBAClD,eAAe,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,CAAC,qBAAqB,EAAE,EAAE,CAAC,CAAC;AAC3F,iBAAA,CAAC,CAAC;AACN,aAAA;AACD,YAAA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;AAC5D,SAAA;AACD,QAAA,OAAO,GAAQ,EAAE;YACb,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;AACjG,SAAA;KACJ;IAEO,iBAAiB,CAAC,aAA2C,EAAE,QAAgB,EAAA;QACnF,OAAO;AACH,YAAA,WAAW,EAAE,OAAO;AAChB,gBAAA,aAAa,EAAE,CAAC;gBAChB,aAAa;AACb,gBAAA,cAAc,EAAE,EAAE;aACrB,CAAC;YACF,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,CAAC,WAAW,EAAE;AACtD,YAAA,YAAY,EAAE,IAAI,CAAC,gBAAgB,EAAE,CAAC,UAAU;SACnD,CAAC;KACL;IAEO,qBAAqB,GAAA;AACzB,QAAA,MAAM,YAAY,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;;AAE7C,QAAA,IAAI,YAAY,CAAC,gBAAgB,KAAK,gBAAgB,CAAC,UAAU,EAAE;YAC/D,MAAM,GAAG,GAAG,YAAuC,CAAC;YACpD,MAAM,eAAe,GAAG,GAAG,CAAC,kBAAkB,KAAK,IAAI,CAAC,WAAW,CAAC;AACpE,YAAA,OAAO,eAAe,GAAG,GAAG,CAAC,kBAAkB,GAAG,GAAG,CAAC,kBAAkB,CAAC;AAC5E,SAAA;AACI,aAAA;YACD,OAAQ,YAA8B,CAAC,iBAAiB,CAAC;AAC5D,SAAA;KACJ;AAEJ;;;;"}
|
|
1
|
+
{"version":3,"file":"LookupManyHandler.js","sources":["../../../../../../src/components/TaskGrid/extensions/dataverse/lookup-many/LookupManyHandler.ts"],"sourcesContent":["import { IRecord, IRecordSaveOperationResult } from \"@talxis/client-libraries\";\nimport { IManyToManyRelationship, IRelationship } from \"@talxis/client-metadata/dist/interfaces/entity/IEntityDefinition\";\n\n\n/** Supported Dataverse relationship kinds used by the handler. */\nenum RelationshipType {\n OneToMany = 0,\n ManyToMany = 1\n}\n\n/** Constructor parameters required to resolve relationship metadata. */\ninterface IManyToManyTestParams {\n /** Parent entity navigation property name that identifies the relationship. */\n navigationPropertyName: string;\n /** Logical name of the source entity for association operations. */\n entityName: string;\n\n /** Optional custom intersection configuration for non-standard many-to-many persistence. */\n customIntersection?: ICustomIntersection;\n}\n\n/** Custom intersection mapping used for manual association/disassociation. */\ninterface ICustomIntersection {\n /** Navigation property name from intersection entity to related entity. */\n referencingEntityNavigationPropertyName: string;\n}\n\n/** Extended entity reference used to carry raw lookup payload and custom intersection ids. */\ninterface IRelatedEntityReference extends ComponentFramework.EntityReference {\n rawData?: {\n [key: string]: any;\n __intersectionId?: string;\n }\n}\n\n/** Contract for a lookup-many relationship handler. */\nexport interface ILookupManyHandler {\n /** Loads relationship metadata and prepares the handler for usage. */\n init(): Promise<void>;\n /** Returns OData expand segment for the configured relationship. */\n getExpand(select?: string): string;\n //*/ Indicates whether this handler uses a custom intersection entity for association management. */\n isCustomIntersection(): boolean;\n /** Returns cached metadata for the custom intersection entity. Throws if custom intersection is not configured or metadata is unavailable. */\n getCustomIntersectionEntityMetadata: () => Xrm.Metadata.EntityMetadata;\n /** Saves lookup-many association changes for a record. */\n saveRecord(record: IRecord, lookupManyColName: string): Promise<IRecordSaveOperationResult>;\n}\n\n\n/**\n * Handles metadata resolution and associate/disassociate operations\n * for lookup-many fields in task grid records.\n */\nexport class LookupManyHandler implements ILookupManyHandler {\n private _relationship?: IRelationship | IManyToManyRelationship;\n private _initialized: boolean = false;\n private _customIntersection?: ICustomIntersection;\n private _customIntersectionEntityMetadata?: Xrm.Metadata.EntityMetadata | null;\n private _entityName: string;\n private _navigationPropertyName: string;\n\n constructor(params: IManyToManyTestParams) {\n this._navigationPropertyName = params.navigationPropertyName;\n this._entityName = params.entityName;\n this._customIntersection = params.customIntersection;\n }\n\n /** Initializes the handler and caches relationship metadata. */\n public async init() {\n if (this._initialized) return;\n this._relationship = await this._fetchRelationship();\n if(this._customIntersection) {\n this._customIntersectionEntityMetadata = await window.Xrm.Utility.getEntityMetadata(this._getRelatedEntityName());\n }\n this._initialized = true;\n }\n\n /**\n * Builds an OData expand clause for the configured relationship.\n * @param select Optional comma-separated projection for expanded records.\n */\n public getExpand(select?: string): string {\n if (this.isCustomIntersection()) {\n const intersectionMetadata = this.getCustomIntersectionEntityMetadata();\n const intersectionIdField = intersectionMetadata.PrimaryIdAttribute;\n const relatedNavProp = this._customIntersection!.referencingEntityNavigationPropertyName;\n const expandClause = select ? `($select=${select})` : '';\n return `${this._navigationPropertyName}($select=${intersectionIdField};$expand=${relatedNavProp}${expandClause})`;\n }\n const relationship = this._getRelationship();\n //@ts-ignore - typings\n if (relationship.RelationshipType === RelationshipType.OneToMany) {\n return `${(relationship as IRelationship).ReferencedEntityNavigationPropertyName}${select ? `($select=${select})` : ''}`;\n }\n else {\n const rel = relationship as IManyToManyRelationship;\n return `${this._navigationPropertyName}${select ? `($select=${select})` : ''}`;\n }\n }\n\n public isCustomIntersection(): boolean {\n return !!this._customIntersection;\n }\n\n public getCustomIntersectionEntityMetadata(): Xrm.Metadata.EntityMetadata {\n if (!this._customIntersection) {\n throw new Error('Custom intersection configuration is missing. Please provide referencingEntityNavigationPropertyName in the constructor parameters.');\n }\n if (!this._customIntersectionEntityMetadata) {\n throw new Error('Custom intersection metadata is not available. Ensure init() was called before metadata access.');\n }\n return this._customIntersectionEntityMetadata;\n }\n\n /**\n * Persists association changes by comparing current values with original values.\n * @param record Record being saved.\n * @param lookupManyColName Logical column name for the lookup-many field.\n */\n public async saveRecord(record: IRecord, lookupManyColName: string): Promise<IRecordSaveOperationResult> {\n const recordId = record.getRecordId();\n const newValue = record.getValue(lookupManyColName) ?? [];\n //@ts-ignore - typings\n const previousValue = record.getField(lookupManyColName)._originalValue ?? [];\n\n const toAdd: ComponentFramework.EntityReference[] = newValue.filter((newValue: ComponentFramework.EntityReference) =>\n !previousValue.some((origValue: ComponentFramework.EntityReference) => origValue.id.guid === newValue.id.guid)\n );\n const toRemove: ComponentFramework.EntityReference[] = previousValue.filter((origValue: ComponentFramework.EntityReference) =>\n !newValue.some((newValue: ComponentFramework.EntityReference) => newValue.id.guid === origValue.id.guid)\n );\n if (toAdd.length === 0 && toRemove.length === 0) {\n return {\n success: true,\n recordId: recordId,\n fields: [],\n }\n }\n\n const deleteResult = await this._executeAssociation('Disassociate', recordId, toRemove);\n const addResult = await this._executeAssociation('Associate', recordId, toAdd);\n const success = (deleteResult?.success ?? true) && (addResult?.success ?? true);\n const errors = [...(deleteResult?.errors ?? []), ...(addResult?.errors ?? [])];\n\n return {\n success,\n recordId: recordId,\n fields: [lookupManyColName],\n errors\n };\n\n }\n\n private _getRelationship(): IRelationship | IManyToManyRelationship {\n if (!this._relationship) {\n throw new Error('Relationship not loaded. Have you called init()?');\n }\n return this._relationship;\n }\n\n private async _fetchRelationship(): Promise<IRelationship | IManyToManyRelationship> {\n const metadata: any = await window.Xrm.Utility.getEntityMetadata(this._entityName);\n const relationships: (IRelationship | IManyToManyRelationship)[] = [...metadata.OneToManyRelationships.getAll(), ...metadata.ManyToManyRelationships.getAll()];\n const relationship = relationships.find(rel => {\n //@ts-ignore - typings\n if (rel.RelationshipType === RelationshipType.ManyToMany) {\n const m2m = rel as IManyToManyRelationship;\n return m2m.Entity1NavigationPropertyName === this._navigationPropertyName ||\n m2m.Entity2NavigationPropertyName === this._navigationPropertyName;\n }\n const o2m = rel as IRelationship;\n return o2m.ReferencedEntityNavigationPropertyName === this._navigationPropertyName ||\n o2m.ReferencingEntityNavigationPropertyName === this._navigationPropertyName;\n\n });\n if (!relationship) {\n throw new Error(`Could not find navigation property name ${this._navigationPropertyName} on ${metadata.LogicalName}`);\n }\n return relationship;\n }\n\n private async _executeAssociation(operationName: 'Associate' | 'Disassociate', parentId: string, relatedRecords: IRelatedEntityReference[]): Promise<IRecordSaveOperationResult | null> {\n if (relatedRecords.length === 0) {\n return null;\n }\n try {\n if (operationName === 'Disassociate') {\n if (this._customIntersection) {\n await this._deleteCustomIntersectionRecord(parentId, relatedRecords);\n }\n else {\n await Promise.all(relatedRecords.map(record =>\n window.Xrm.WebApi.online.execute({\n ...this._buildBaseRequest(operationName, parentId),\n relatedEntityId: record.id.guid,\n })\n ));\n }\n }\n else {\n if (this._customIntersection) {\n await Promise.all(relatedRecords.map(record => this._createCustomIntersectionRecord(parentId, record)));\n }\n else {\n await window.Xrm.WebApi.online.execute({\n ...this._buildBaseRequest(operationName, parentId),\n relatedEntities: relatedRecords.map(record => ({ id: record.id.guid, entityType: this._getRelatedEntityName() })),\n });\n }\n }\n return { recordId: parentId, success: true, fields: [] };\n }\n catch (err: any) {\n return { recordId: parentId, success: false, fields: [], errors: [{ message: err.message }] };\n }\n }\n\n private async _createCustomIntersectionRecord(parentId: string, relatedRecord: IRelatedEntityReference): Promise<void> {\n const parentEntityMetadata = await window.Xrm.Utility.getEntityMetadata(this._entityName);\n const intersectionEntityMetadata: any = this.getCustomIntersectionEntityMetadata();\n const relatedEntityRelationship = intersectionEntityMetadata.ManyToOneRelationships.getAll().find((rel: any) => rel.ReferencingEntityNavigationPropertyName === this._getCustomIntersection().referencingEntityNavigationPropertyName);\n const relatedEntityMetadata = await window.Xrm.Utility.getEntityMetadata(relatedEntityRelationship.ReferencedEntity);\n\n const payload = {\n //@ts-ignore - typings\n [`${this._getRelationship().ReferencingEntityNavigationPropertyName}@odata.bind`]: `${parentEntityMetadata.EntitySetName}(${parentId})`,\n [`${this._getCustomIntersection().referencingEntityNavigationPropertyName}@odata.bind`]: `${relatedEntityMetadata.EntitySetName}(${relatedRecord.id.guid})`\n }\n const result = await window.Xrm.WebApi.createRecord(intersectionEntityMetadata.LogicalName, payload);\n //this should be done through setValue\n relatedRecord.rawData = {\n ...relatedRecord.rawData,\n __intersectionId: result.id\n }\n\n }\n\n private async _deleteCustomIntersectionRecord(parentId: string, relatedRecords: IRelatedEntityReference[]): Promise<void> {\n const intersectionEntityMetadata: any = this.getCustomIntersectionEntityMetadata();\n await Promise.all(relatedRecords.map(async record => {\n const intersectionId = record.rawData?.__intersectionId;\n if (!intersectionId) {\n throw new Error('Missing intersection record ID for disassociation. Cannot proceed with custom intersection deletion.');\n }\n await window.Xrm.WebApi.deleteRecord(intersectionEntityMetadata.LogicalName, intersectionId);\n }))\n }\n\n private _getCustomIntersection() {\n if (!this._customIntersection) {\n throw new Error('Custom intersection configuration is missing. Please provide referencingEntityNavigationPropertyName in the constructor parameters.');\n }\n return this._customIntersection;\n }\n\n private _buildBaseRequest(operationName: 'Associate' | 'Disassociate', parentId: string) {\n return {\n getMetadata: () => ({\n operationType: 2,\n operationName,\n parameterTypes: {},\n }),\n target: { id: parentId, entityType: this._entityName },\n relationship: this._getRelationship().SchemaName,\n };\n }\n\n private _getRelatedEntityName(): string {\n const relationship = this._getRelationship();\n //@ts-ignore - typings\n if (relationship.RelationshipType === RelationshipType.ManyToMany) {\n const rel = relationship as IManyToManyRelationship;\n const isEntity1Source = rel.Entity1LogicalName === this._entityName;\n return isEntity1Source ? rel.Entity2LogicalName : rel.Entity1LogicalName;\n }\n else {\n return (relationship as IRelationship).ReferencingEntity;\n }\n }\n\n}"],"names":[],"mappings":"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"}
|
|
@@ -8,19 +8,25 @@ const FetchXmlLookupManyCellRenderer = (props) => {
|
|
|
8
8
|
const { baseColumn } = props;
|
|
9
9
|
const record = props.data;
|
|
10
10
|
const strategy = useTaskDataProvider().getStrategy();
|
|
11
|
-
const
|
|
11
|
+
const projectRecord = strategy.getProjectRecord();
|
|
12
12
|
const customControl = record.getColumnInfo(baseColumn.name).ui.getCustomControls([])?.[0];
|
|
13
13
|
const fetchXml = customControl?.bindings?.FetchXml.value;
|
|
14
14
|
const taskId = record.getRecordId();
|
|
15
15
|
const dataProvider = React__default.useMemo(() => FetchXmlDataProviderFactory.create({
|
|
16
16
|
fetchXml: fetchXml,
|
|
17
17
|
variables: {
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
task: {
|
|
19
|
+
id: taskId,
|
|
20
|
+
...record.getRawData()
|
|
21
|
+
},
|
|
22
|
+
project: {
|
|
23
|
+
id: projectRecord?.getRecordId(),
|
|
24
|
+
...projectRecord?.getRawData()
|
|
25
|
+
}
|
|
20
26
|
}
|
|
21
27
|
}), []);
|
|
22
28
|
if (!fetchXml) {
|
|
23
|
-
throw new Error('FetchXml for LookupMany is not defined in column metadata. Define it using the "
|
|
29
|
+
throw new Error('FetchXml for LookupMany is not defined in column metadata. Define it using the "FetchXml" property.');
|
|
24
30
|
}
|
|
25
31
|
return jsx(LookupManyCellRenderer, { ...props, dataProvider: dataProvider });
|
|
26
32
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FetchXmlLookupManyCellRenderer.js","sources":["../../../../../../../src/components/TaskGrid/extensions/dataverse/lookup-many/cell-renderer/FetchXmlLookupManyCellRenderer.tsx"],"sourcesContent":["import { IRecord } from \"@talxis/client-libraries\";\nimport { useTaskDataProvider } from \"../../../../..\";\nimport { FetchXmlDataProviderFactory } from \"./FetchXmlDataProviderFactory\";\nimport React from \"react\";\nimport { LookupManyCellRenderer } from '../../../../components/grid/cell-renderers/lookup-many'\nimport { ICellProps } from \"../../../../../Grid/cells/cell/Cell\";\nimport { IDataverseTaskStrategy } from \"../../DataverseTaskStrategy\";\n\nexport const FetchXmlLookupManyCellRenderer = (props: ICellProps) => {\n const { baseColumn } = props;\n const record: IRecord = props.data;\n const strategy: IDataverseTaskStrategy = useTaskDataProvider().getStrategy();\n const
|
|
1
|
+
{"version":3,"file":"FetchXmlLookupManyCellRenderer.js","sources":["../../../../../../../src/components/TaskGrid/extensions/dataverse/lookup-many/cell-renderer/FetchXmlLookupManyCellRenderer.tsx"],"sourcesContent":["import { IRecord } from \"@talxis/client-libraries\";\nimport { useTaskDataProvider } from \"../../../../..\";\nimport { FetchXmlDataProviderFactory } from \"./FetchXmlDataProviderFactory\";\nimport React from \"react\";\nimport { LookupManyCellRenderer } from '../../../../components/grid/cell-renderers/lookup-many'\nimport { ICellProps } from \"../../../../../Grid/cells/cell/Cell\";\nimport { IDataverseTaskStrategy } from \"../../DataverseTaskStrategy\";\n\nexport const FetchXmlLookupManyCellRenderer = (props: ICellProps) => {\n const { baseColumn } = props;\n const record: IRecord = props.data;\n const strategy: IDataverseTaskStrategy = useTaskDataProvider().getStrategy();\n const projectRecord = strategy.getProjectRecord();\n const customControl = record.getColumnInfo(baseColumn.name).ui.getCustomControls([])?.[0];\n const fetchXml = customControl?.bindings?.FetchXml.value;\n const taskId = record.getRecordId();\n const dataProvider = React.useMemo(() => FetchXmlDataProviderFactory.create({\n fetchXml: fetchXml,\n variables: {\n task: {\n id: taskId,\n ...record.getRawData()\n },\n project: {\n id: projectRecord?.getRecordId(),\n ...projectRecord?.getRawData()\n }\n }\n }), []);\n\n if (!fetchXml) {\n throw new Error('FetchXml for LookupMany is not defined in column metadata. Define it using the \"FetchXml\" property.');\n }\n\n return <LookupManyCellRenderer \n {...props} \n dataProvider={dataProvider} />\n\n}"],"names":["React","_jsx"],"mappings":";;;;;;AAQa,MAAA,8BAA8B,GAAG,CAAC,KAAiB,KAAI;AAChE,IAAA,MAAM,EAAE,UAAU,EAAE,GAAG,KAAK,CAAC;AAC7B,IAAA,MAAM,MAAM,GAAY,KAAK,CAAC,IAAI,CAAC;AACnC,IAAA,MAAM,QAAQ,GAA2B,mBAAmB,EAAE,CAAC,WAAW,EAAE,CAAC;AAC7E,IAAA,MAAM,aAAa,GAAG,QAAQ,CAAC,gBAAgB,EAAE,CAAC;IAClD,MAAM,aAAa,GAAG,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1F,MAAM,QAAQ,GAAG,aAAa,EAAE,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC;AACzD,IAAA,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;AACpC,IAAA,MAAM,YAAY,GAAGA,cAAK,CAAC,OAAO,CAAC,MAAM,2BAA2B,CAAC,MAAM,CAAC;AACxE,QAAA,QAAQ,EAAE,QAAQ;AAClB,QAAA,SAAS,EAAE;AACP,YAAA,IAAI,EAAE;AACF,gBAAA,EAAE,EAAE,MAAM;gBACV,GAAG,MAAM,CAAC,UAAU,EAAE;AACzB,aAAA;AACD,YAAA,OAAO,EAAE;AACL,gBAAA,EAAE,EAAE,aAAa,EAAE,WAAW,EAAE;gBAChC,GAAG,aAAa,EAAE,UAAU,EAAE;AACjC,aAAA;AACJ,SAAA;KACJ,CAAC,EAAE,EAAE,CAAC,CAAC;IAER,IAAI,CAAC,QAAQ,EAAE;AACX,QAAA,MAAM,IAAI,KAAK,CAAC,qGAAqG,CAAC,CAAC;AAC1H,KAAA;IAED,OAAOC,GAAA,CAAC,sBAAsB,EACtB,EAAA,GAAA,KAAK,EACT,YAAY,EAAE,YAAY,EAAA,CAAI,CAAA;AAEtC;;;;"}
|
|
@@ -34,47 +34,56 @@ export interface INativeColumns extends IFieldMapping {
|
|
|
34
34
|
}
|
|
35
35
|
/** Feature flags that control which UI elements are rendered in the grid header and ribbon. */
|
|
36
36
|
export interface ITaskGridParameters {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
/** Show drag handles and allow rows to be dragged for reordering. Defaults to `true`. Automatically suppressed when flat-list mode is active or sorting by a non-stack-rank column. */
|
|
37
|
+
agGridLicenseKey?: string;
|
|
38
|
+
/** Show drag handles and allow rows to be dragged for reordering. Defaults to `false`. Automatically suppressed when flat-list mode is active or sorting by a non-stack-rank column. */
|
|
40
39
|
enableRowDragging?: boolean;
|
|
41
|
-
/** Show the *Edit Columns* button in the ribbon. Defaults to `
|
|
40
|
+
/** Show the *Edit Columns* button in the ribbon. Defaults to `false`. */
|
|
42
41
|
enableEditColumns?: boolean;
|
|
43
|
-
/** Enable editing of tasks directly in the grid. Defaults to `
|
|
42
|
+
/** Enable editing of tasks directly in the grid. Defaults to `false`. */
|
|
44
43
|
enableTaskEditing?: boolean;
|
|
45
|
-
/** Enable creation of new tasks. Defaults to `
|
|
44
|
+
/** Enable creation of new tasks. Defaults to `false`. */
|
|
46
45
|
enableTaskCreation?: boolean;
|
|
47
|
-
/** Enable deletion of tasks. Defaults to `
|
|
46
|
+
/** Enable deletion of tasks. Defaults to `false`. */
|
|
48
47
|
enableTaskDeletion?: boolean;
|
|
49
|
-
/** Show the search / quick-find input. Defaults to `
|
|
48
|
+
/** Show the search / quick-find input. Defaults to `false`. */
|
|
50
49
|
enableQuickFind?: boolean;
|
|
51
|
-
/** Show the view-switcher dropdown. Defaults to `
|
|
50
|
+
/** Show the view-switcher dropdown. Defaults to `false`. */
|
|
52
51
|
enableViewSwitcher?: boolean;
|
|
53
|
-
/** Show the *Show hierarchy* toggle. Defaults to `
|
|
52
|
+
/** Show the *Show hierarchy* toggle. Defaults to `false`. */
|
|
54
53
|
enableShowHierarchyToggle?: boolean;
|
|
55
|
-
/** Show the *Hide inactive tasks* toggle. Defaults to `
|
|
54
|
+
/** Show the *Hide inactive tasks* toggle. Defaults to `false`. */
|
|
56
55
|
enableHideInactiveTasksToggle?: boolean;
|
|
57
|
-
/** Show the personal/system scope selector inside the Edit Columns panel. Defaults to `
|
|
56
|
+
/** Show the personal/system scope selector inside the Edit Columns panel. Defaults to `false`. */
|
|
58
57
|
enableEditColumnsScopeSelector?: boolean;
|
|
59
|
-
/** Enable user queries. Defaults to `
|
|
58
|
+
/** Enable user queries. Defaults to `false`. */
|
|
60
59
|
enableUserQueries?: boolean;
|
|
61
|
-
/** Show the query manager. Defaults to `
|
|
60
|
+
/** Show the query manager. Defaults to `false`. */
|
|
62
61
|
enableQueryManager?: boolean;
|
|
63
|
-
/** Show the "Save as new" button in the query manager. Defaults to `
|
|
62
|
+
/** Show the "Save as new" button in the query manager. Defaults to `false`. */
|
|
64
63
|
enableSaveAsNewQuery?: boolean;
|
|
65
|
-
/** Show the "Save changes" button in the query manager. Defaults to `
|
|
64
|
+
/** Show the "Save changes" button in the query manager. Defaults to `false`. */
|
|
66
65
|
enableSaveQueryChanges?: boolean;
|
|
67
|
-
/** Enable creation of custom columns. Defaults to `
|
|
66
|
+
/** Enable creation of custom columns. Defaults to `false`. */
|
|
68
67
|
enableCustomColumnCreation?: boolean;
|
|
69
|
-
/** Enable editing of custom columns. Defaults to `
|
|
68
|
+
/** Enable editing of custom columns. Defaults to `false`. */
|
|
70
69
|
enableCustomColumnEditing?: boolean;
|
|
71
|
-
/** Enable deletion of custom columns. Defaults to `
|
|
70
|
+
/** Enable deletion of custom columns. Defaults to `false`. */
|
|
72
71
|
enableCustomColumnDeletion?: boolean;
|
|
73
|
-
/** Enable inline creation of tasks. Defaults to `
|
|
72
|
+
/** Enable inline creation of tasks. Defaults to `false`. */
|
|
74
73
|
enableInlineCreation?: boolean;
|
|
74
|
+
/** Enable navigation within the grid. Defaults to `false`. */
|
|
75
|
+
enableNavigation?: boolean;
|
|
76
|
+
/** Enable column sorting in the grid. Defaults to `false`. */
|
|
77
|
+
enableSorting?: boolean;
|
|
78
|
+
/** Enable column filtering in the grid. Defaults to `false`. */
|
|
79
|
+
enableFiltering?: boolean;
|
|
80
|
+
/** Override the default row height in pixels. Uses the AG Grid default when omitted. */
|
|
81
|
+
rowHeight?: number;
|
|
75
82
|
}
|
|
76
83
|
/** Available data providers injected into `ITaskDataProviderStrategy` at construction time. */
|
|
77
84
|
export interface ITaskStrategyDeps {
|
|
85
|
+
enableInlineCreation: boolean;
|
|
86
|
+
enableTaskEditing: boolean;
|
|
78
87
|
/** Present when the consumer provided `onCreateCustomColumnsStrategy`. */
|
|
79
88
|
customColumnsDataProvider?: ICustomColumnsDataProvider;
|
|
80
89
|
/** Present when the consumer provided `onCreateTemplateDataProvider`. */
|
|
@@ -93,14 +102,14 @@ export interface ITaskGridDescriptor {
|
|
|
93
102
|
onCreateTaskStrategy: (deps: ITaskStrategyDeps) => ITaskDataProviderStrategy;
|
|
94
103
|
/** Returns an `IDataProvider` that drives the user-query creation/update dialog. */
|
|
95
104
|
onCreateUserQueryDataProvider: () => IDataProvider;
|
|
105
|
+
/** (Optional) Returns the container height as a CSS string. Falls back to a default stretch when omitted. */
|
|
106
|
+
onGetHeight?: () => string | undefined;
|
|
96
107
|
/** (Optional) Returns the strategy for managing dynamic (user-defined) columns. When provided, the custom-columns feature is enabled. */
|
|
97
108
|
onCreateCustomColumnsStrategy?: () => ICustomColumnsStrategy | undefined;
|
|
98
109
|
/** (Optional) Returns an `IDataProvider` for task templates. When provided, the template-based task creation feature is enabled. */
|
|
99
110
|
onCreateTemplateDataProvider?: () => IDataProvider | undefined;
|
|
100
111
|
/** (Optional) Returns a strategy for deep customization of AG Grid column definitions, renderers, editors, and row class rules. */
|
|
101
112
|
onCreateGridCustomizerStrategy?: () => IGridCustomizerStrategy | undefined;
|
|
102
|
-
/** (Optional) Returns the AG Grid Enterprise license key. */
|
|
103
|
-
onGetAgGridLicenseKey?: () => string | undefined;
|
|
104
113
|
/** (Optional) Returns a stable DOM/control identifier. Auto-generated as a UUID when omitted. */
|
|
105
114
|
onGetControlId?: () => string;
|
|
106
115
|
/** (Optional) Async hook called before any data provider is created. Use for lazy loading or authentication. */
|
|
@@ -159,6 +168,10 @@ export interface ITaskGridDatasetControl extends IDatasetControl {
|
|
|
159
168
|
isTaskEditingEnabled: () => boolean;
|
|
160
169
|
/** Returns `true` when task deletion is enabled. */
|
|
161
170
|
isTaskDeletingEnabled: () => boolean;
|
|
171
|
+
/** Whether the view-switcher dropdown is visible (from `ITaskGridParameters.enableViewSwitcher`). */
|
|
172
|
+
isViewSwitcherEnabled: () => boolean;
|
|
173
|
+
/** Whether grid navigation is enabled (from `ITaskGridParameters.enableNavigation`). */
|
|
174
|
+
isNavigationEnabled: () => boolean;
|
|
162
175
|
/** Returns `true` when a custom columns strategy was supplied through the descriptor. */
|
|
163
176
|
isCustomColumnsEnabled: () => boolean;
|
|
164
177
|
/** Whether the view manager is enabled (from `ITaskGridParameters.enableQueryManager`). */
|
|
@@ -175,5 +188,6 @@ export interface ITaskGridDatasetControl extends IDatasetControl {
|
|
|
175
188
|
isCustomColumnDeletionEnabled: () => boolean;
|
|
176
189
|
/** Whether user queries are enabled (from `ITaskGridParameters.enableUserQueries`). */
|
|
177
190
|
isUserQueriesFeatureEnabled: () => boolean;
|
|
191
|
+
/** Whether inline task creation is enabled (from `ITaskGridParameters.enableInlineCreation`). */
|
|
178
192
|
isInlineCreateEnabled: () => boolean;
|
|
179
193
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IColumn, IEventEmitter, IRawRecord } from "@talxis/client-libraries";
|
|
1
|
+
import { IColumn, IEventEmitter, IRawRecord, IRecordSaveOperationResult } from "@talxis/client-libraries";
|
|
2
2
|
/** Strategy interface for managing user-defined (dynamic) column definitions. */
|
|
3
3
|
export interface ICustomColumnsStrategy {
|
|
4
4
|
/** @returns The created column name, or `null` if the operation was cancelled by the user. Throws on unexpected failure. */
|
|
@@ -15,6 +15,8 @@ export interface ICustomColumnsStrategy {
|
|
|
15
15
|
onGetRawRecords: () => Promise<IRawRecord[]>;
|
|
16
16
|
/** Fetches a single raw record by its ID. */
|
|
17
17
|
onGetRawRecord: (recordId: string) => Promise<IRawRecord>;
|
|
18
|
+
/** Persists a cell value for a custom column on the given record. */
|
|
19
|
+
onSaveValue: (regardingRecordId: string, column: IColumn, value: any) => Promise<IRecordSaveOperationResult>;
|
|
18
20
|
}
|
|
19
21
|
/** Manages the lifecycle of dynamic (user-defined) columns and wraps the strategy with error handling. */
|
|
20
22
|
export interface ICustomColumnsDataProvider {
|
|
@@ -30,10 +32,13 @@ export interface ICustomColumnsDataProvider {
|
|
|
30
32
|
refresh: () => Promise<IColumn[]>;
|
|
31
33
|
/** Returns the currently cached list of custom columns. */
|
|
32
34
|
getColumns: () => IColumn[];
|
|
35
|
+
/** Persists a cell value for a custom column on the given record. */
|
|
36
|
+
saveValue: (regardingRecordId: string, column: IColumn, value: any) => Promise<IRecordSaveOperationResult>;
|
|
33
37
|
/** Returns the underlying strategy cast to the given type for strategy-specific operations. */
|
|
34
38
|
getStrategy<T extends ICustomColumnsStrategy>(): T;
|
|
35
39
|
/** Returns `true` when the given column name is a custom (dynamic) column. */
|
|
36
40
|
isCustomColumn: (columnName: string) => boolean;
|
|
41
|
+
/** Disposes event listeners and releases all resources held by the provider. */
|
|
37
42
|
destroy: () => void;
|
|
38
43
|
}
|
|
39
44
|
export interface ICustomColumnsDataProviderEvents {
|
|
@@ -47,6 +52,7 @@ export declare class CustomColumnsDataProvider implements ICustomColumnsDataProv
|
|
|
47
52
|
createColumn(): Promise<string | null>;
|
|
48
53
|
deleteColumn(columnName: string): Promise<string | null>;
|
|
49
54
|
updateColumn(columnName: string): Promise<string | null>;
|
|
55
|
+
saveValue(regardingRecordId: string, column: IColumn, value: any): Promise<IRecordSaveOperationResult>;
|
|
50
56
|
destroy(): void;
|
|
51
57
|
getColumns(): IColumn[];
|
|
52
58
|
refresh(): Promise<IColumn[]>;
|
|
@@ -27,6 +27,9 @@ class CustomColumnsDataProvider {
|
|
|
27
27
|
onError: (error, message) => this.events.dispatchEvent('onError', error, message)
|
|
28
28
|
});
|
|
29
29
|
}
|
|
30
|
+
saveValue(regardingRecordId, column, value) {
|
|
31
|
+
return this._strategy.onSaveValue(regardingRecordId, column, value);
|
|
32
|
+
}
|
|
30
33
|
destroy() {
|
|
31
34
|
this.events.clearEventListeners();
|
|
32
35
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CustomColumnsDataProvider.js","sources":["../../../../../src/components/TaskGrid/providers/custom-columns/CustomColumnsDataProvider.ts"],"sourcesContent":["import { DatasetConstants, IColumn, IEventEmitter, EventEmitter, IRawRecord } from \"@talxis/client-libraries\";\nimport { ErrorHelper } from \"../../../../utils\";\n\n\n/** Strategy interface for managing user-defined (dynamic) column definitions. */\nexport interface ICustomColumnsStrategy {\n /** @returns The created column name, or `null` if the operation was cancelled by the user. Throws on unexpected failure. */\n onCreateColumn: () => Promise<string | null>;\n /** @returns The deleted column name, or `null` if the operation was cancelled by the user. Throws on unexpected failure. */\n onDeleteColumn: (columnName: string) => Promise<string | null>;\n /** @returns The updated column name, or `null` if the operation was cancelled by the user. Throws on unexpected failure. */\n onUpdateColumn: (columnName: string) => Promise<string | null>;\n /** Fetches/reloads all custom column definitions and returns the resolved `IColumn[]`. */\n onRefresh: () => Promise<IColumn[]>;\n /** Returns the currently loaded custom columns synchronously without a network fetch. */\n onGetColumns: () => IColumn[];\n /** Fetches the raw records for custom columns. */\n onGetRawRecords: () => Promise<IRawRecord[]>;\n /** Fetches a single raw record by its ID. */\n onGetRawRecord: (recordId: string) => Promise<IRawRecord>;\n}\n\n/** Manages the lifecycle of dynamic (user-defined) columns and wraps the strategy with error handling. */\nexport interface ICustomColumnsDataProvider {\n /** EventEmitter for error events raised by column operations. */\n events: IEventEmitter<ICustomColumnsDataProviderEvents>;\n /** @returns The created column name, or `null` if the operation was cancelled by the user. Throws on unexpected failure. */\n createColumn: () => Promise<string | null>;\n /** @returns The deleted column name, or `null` if the operation was cancelled by the user. Throws on unexpected failure. */\n deleteColumn: (columnName: string) => Promise<string | null>;\n /** @returns The updated column name, or `null` if the operation was cancelled by the user. Throws on unexpected failure. */\n updateColumn: (columnName: string) => Promise<string | null>;\n /** Refreshes the list of custom columns from the underlying strategy. */\n refresh: () => Promise<IColumn[]>;\n /** Returns the currently cached list of custom columns. */\n getColumns: () => IColumn[];\n /** Returns the underlying strategy cast to the given type for strategy-specific operations. */\n getStrategy<T extends ICustomColumnsStrategy>(): T;\n /** Returns `true` when the given column name is a custom (dynamic) column. */\n isCustomColumn: (columnName: string) => boolean;\n destroy: () => void;\n}\n\nexport interface ICustomColumnsDataProviderEvents {\n onError: (error: any, message: string) => void;\n}\n\nexport class CustomColumnsDataProvider implements ICustomColumnsDataProvider {\n private _strategy: ICustomColumnsStrategy;\n public events: IEventEmitter<ICustomColumnsDataProviderEvents> = new EventEmitter();\n\n constructor(strategy: ICustomColumnsStrategy) {\n this._strategy = strategy;\n }\n public getStrategy<T extends ICustomColumnsStrategy>(): T {\n return this._strategy as T;\n }\n public async createColumn(): Promise<string | null> {\n return ErrorHelper.executeWithErrorHandling({\n operation: () => this._strategy.onCreateColumn(),\n onError: (error, message) => this.events.dispatchEvent('onError', error, message)\n })\n }\n public async deleteColumn(columnName: string): Promise<string | null> {\n return ErrorHelper.executeWithErrorHandling({\n operation: () => this._strategy.onDeleteColumn(columnName),\n onError: (error, message) => this.events.dispatchEvent('onError', error, message)\n })\n }\n public async updateColumn(columnName: string): Promise<string | null> {\n return ErrorHelper.executeWithErrorHandling({\n operation: () => this._strategy.onUpdateColumn(columnName),\n onError: (error, message) => this.events.dispatchEvent('onError', error, message)\n })\n }\n public destroy(): void {\n this.events.clearEventListeners();\n }\n public getColumns(): IColumn[] {\n return this._strategy.onGetColumns();\n }\n public async refresh(): Promise<IColumn[]> {\n return await this._strategy.onRefresh();\n }\n public isCustomColumn(columnName: string): boolean {\n return columnName.endsWith(DatasetConstants.CUSTOM_COLUMN_NAME_SUFFIX);\n }\n}"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"CustomColumnsDataProvider.js","sources":["../../../../../src/components/TaskGrid/providers/custom-columns/CustomColumnsDataProvider.ts"],"sourcesContent":["import { DatasetConstants, IColumn, IEventEmitter, EventEmitter, IRawRecord, IRecordSaveOperationResult } from \"@talxis/client-libraries\";\nimport { ErrorHelper } from \"../../../../utils\";\n\n\n/** Strategy interface for managing user-defined (dynamic) column definitions. */\nexport interface ICustomColumnsStrategy {\n /** @returns The created column name, or `null` if the operation was cancelled by the user. Throws on unexpected failure. */\n onCreateColumn: () => Promise<string | null>;\n /** @returns The deleted column name, or `null` if the operation was cancelled by the user. Throws on unexpected failure. */\n onDeleteColumn: (columnName: string) => Promise<string | null>;\n /** @returns The updated column name, or `null` if the operation was cancelled by the user. Throws on unexpected failure. */\n onUpdateColumn: (columnName: string) => Promise<string | null>;\n /** Fetches/reloads all custom column definitions and returns the resolved `IColumn[]`. */\n onRefresh: () => Promise<IColumn[]>;\n /** Returns the currently loaded custom columns synchronously without a network fetch. */\n onGetColumns: () => IColumn[];\n /** Fetches the raw records for custom columns. */\n onGetRawRecords: () => Promise<IRawRecord[]>;\n /** Fetches a single raw record by its ID. */\n onGetRawRecord: (recordId: string) => Promise<IRawRecord>;\n\n /** Persists a cell value for a custom column on the given record. */\n onSaveValue: (regardingRecordId: string, column: IColumn, value: any) => Promise<IRecordSaveOperationResult>;\n}\n\n/** Manages the lifecycle of dynamic (user-defined) columns and wraps the strategy with error handling. */\nexport interface ICustomColumnsDataProvider {\n /** EventEmitter for error events raised by column operations. */\n events: IEventEmitter<ICustomColumnsDataProviderEvents>;\n /** @returns The created column name, or `null` if the operation was cancelled by the user. Throws on unexpected failure. */\n createColumn: () => Promise<string | null>;\n /** @returns The deleted column name, or `null` if the operation was cancelled by the user. Throws on unexpected failure. */\n deleteColumn: (columnName: string) => Promise<string | null>;\n /** @returns The updated column name, or `null` if the operation was cancelled by the user. Throws on unexpected failure. */\n updateColumn: (columnName: string) => Promise<string | null>;\n /** Refreshes the list of custom columns from the underlying strategy. */\n refresh: () => Promise<IColumn[]>;\n /** Returns the currently cached list of custom columns. */\n getColumns: () => IColumn[];\n\n /** Persists a cell value for a custom column on the given record. */\n saveValue: (regardingRecordId: string, column: IColumn, value: any) => Promise<IRecordSaveOperationResult>;\n /** Returns the underlying strategy cast to the given type for strategy-specific operations. */\n getStrategy<T extends ICustomColumnsStrategy>(): T;\n /** Returns `true` when the given column name is a custom (dynamic) column. */\n isCustomColumn: (columnName: string) => boolean;\n /** Disposes event listeners and releases all resources held by the provider. */\n destroy: () => void;\n}\n\nexport interface ICustomColumnsDataProviderEvents {\n onError: (error: any, message: string) => void;\n}\n\nexport class CustomColumnsDataProvider implements ICustomColumnsDataProvider {\n private _strategy: ICustomColumnsStrategy;\n public events: IEventEmitter<ICustomColumnsDataProviderEvents> = new EventEmitter();\n\n constructor(strategy: ICustomColumnsStrategy) {\n this._strategy = strategy;\n }\n public getStrategy<T extends ICustomColumnsStrategy>(): T {\n return this._strategy as T;\n }\n public async createColumn(): Promise<string | null> {\n return ErrorHelper.executeWithErrorHandling({\n operation: () => this._strategy.onCreateColumn(),\n onError: (error, message) => this.events.dispatchEvent('onError', error, message)\n })\n }\n public async deleteColumn(columnName: string): Promise<string | null> {\n return ErrorHelper.executeWithErrorHandling({\n operation: () => this._strategy.onDeleteColumn(columnName),\n onError: (error, message) => this.events.dispatchEvent('onError', error, message)\n })\n }\n public async updateColumn(columnName: string): Promise<string | null> {\n return ErrorHelper.executeWithErrorHandling({\n operation: () => this._strategy.onUpdateColumn(columnName),\n onError: (error, message) => this.events.dispatchEvent('onError', error, message)\n })\n }\n\n public saveValue(regardingRecordId: string, column: IColumn, value: any): Promise<IRecordSaveOperationResult> {\n return this._strategy.onSaveValue(regardingRecordId, column, value);\n }\n \n public destroy(): void {\n this.events.clearEventListeners();\n }\n public getColumns(): IColumn[] {\n return this._strategy.onGetColumns();\n }\n public async refresh(): Promise<IColumn[]> {\n return await this._strategy.onRefresh();\n }\n public isCustomColumn(columnName: string): boolean {\n return columnName.endsWith(DatasetConstants.CUSTOM_COLUMN_NAME_SUFFIX);\n }\n}"],"names":[],"mappings":";;;MAsDa,yBAAyB,CAAA;AAIlC,IAAA,WAAA,CAAY,QAAgC,EAAA;AAFrC,QAAA,IAAA,CAAA,MAAM,GAAoD,IAAI,YAAY,EAAE,CAAC;AAGhF,QAAA,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;KAC7B;IACM,WAAW,GAAA;QACd,OAAO,IAAI,CAAC,SAAc,CAAC;KAC9B;AACM,IAAA,MAAM,YAAY,GAAA;QACrB,OAAO,WAAW,CAAC,wBAAwB,CAAC;YACxC,SAAS,EAAE,MAAM,IAAI,CAAC,SAAS,CAAC,cAAc,EAAE;AAChD,YAAA,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC;AACpF,SAAA,CAAC,CAAA;KACL;IACM,MAAM,YAAY,CAAC,UAAkB,EAAA;QACxC,OAAO,WAAW,CAAC,wBAAwB,CAAC;YACxC,SAAS,EAAE,MAAM,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,UAAU,CAAC;AAC1D,YAAA,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC;AACpF,SAAA,CAAC,CAAA;KACL;IACM,MAAM,YAAY,CAAC,UAAkB,EAAA;QACxC,OAAO,WAAW,CAAC,wBAAwB,CAAC;YACxC,SAAS,EAAE,MAAM,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,UAAU,CAAC;AAC1D,YAAA,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC;AACpF,SAAA,CAAC,CAAA;KACL;AAEM,IAAA,SAAS,CAAC,iBAAyB,EAAE,MAAe,EAAE,KAAU,EAAA;AACnE,QAAA,OAAO,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,iBAAiB,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;KACvE;IAEM,OAAO,GAAA;AACV,QAAA,IAAI,CAAC,MAAM,CAAC,mBAAmB,EAAE,CAAC;KACrC;IACM,UAAU,GAAA;AACb,QAAA,OAAO,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,CAAC;KACxC;AACM,IAAA,MAAM,OAAO,GAAA;AAChB,QAAA,OAAO,MAAM,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC;KAC3C;AACM,IAAA,cAAc,CAAC,UAAkB,EAAA;QACpC,OAAO,UAAU,CAAC,QAAQ,CAAC,gBAAgB,CAAC,yBAAyB,CAAC,CAAC;KAC1E;AACJ;;;;"}
|
|
@@ -86,6 +86,7 @@ export interface ISavedQueryDataProvider {
|
|
|
86
86
|
deleteUserQueries: (queryIds: string[]) => Promise<IDeletedUserQueriesResult>;
|
|
87
87
|
/** Fetches system and user queries from the strategy and sets the initial active query. */
|
|
88
88
|
refresh: () => Promise<void>;
|
|
89
|
+
/** Disposes event listeners and releases all resources held by the provider. */
|
|
89
90
|
destroy: () => void;
|
|
90
91
|
}
|
|
91
92
|
interface ISavedQueryDataProviderParameters {
|
|
@@ -124,7 +125,6 @@ export declare class SavedQueryDataProvider implements ISavedQueryDataProvider {
|
|
|
124
125
|
private _includePathColumn;
|
|
125
126
|
private _getMetadataForSavedQuery;
|
|
126
127
|
private _addPropToMetadataQueryCol;
|
|
127
|
-
private _isCustomColumnResolvable;
|
|
128
128
|
private _parseSavedQueryMetadata;
|
|
129
129
|
}
|
|
130
130
|
export {};
|
|
@@ -93,7 +93,14 @@ class SavedQueryDataProvider {
|
|
|
93
93
|
const allQueries = [...systemQueries, ...userQueries];
|
|
94
94
|
this._systemQueries = systemQueries;
|
|
95
95
|
this._userQueries = userQueries;
|
|
96
|
-
|
|
96
|
+
const systemQueryColumnEntries = systemQueries.flatMap(query => query.columns.map(col => [col.name, col]));
|
|
97
|
+
const customColumnEntries = this._customColumnsDataProvider
|
|
98
|
+
? this._customColumnsDataProvider.getColumns().map(col => [col.name, col])
|
|
99
|
+
: [];
|
|
100
|
+
this._systemQueriesColumnsMap = new Map([
|
|
101
|
+
...systemQueryColumnEntries,
|
|
102
|
+
...customColumnEntries
|
|
103
|
+
]);
|
|
97
104
|
const preferredQueryInAllQueries = allQueries.find(q => q.id === this._preferredQuery?.id);
|
|
98
105
|
this._currentQuery = preferredQueryInAllQueries ?? userQueries[0] ?? systemQueries[0];
|
|
99
106
|
//preferred query might have some required columns missing
|
|
@@ -190,38 +197,14 @@ class SavedQueryDataProvider {
|
|
|
190
197
|
col[propName] = propValue;
|
|
191
198
|
}
|
|
192
199
|
}
|
|
193
|
-
_isCustomColumnResolvable(name, customColumnsMap) {
|
|
194
|
-
return !this._customColumnsDataProvider.isCustomColumn(name) ||
|
|
195
|
-
!!customColumnsMap.get(name);
|
|
196
|
-
}
|
|
197
200
|
_parseSavedQueryMetadata(metadata) {
|
|
198
201
|
const parsed = metadata;
|
|
199
202
|
// Enrich partial column definitions with full definitions from system queries
|
|
200
203
|
let columns = parsed.columns.map(col => {
|
|
201
204
|
const systemCol = this._systemQueriesColumnsMap.get(col.name);
|
|
202
|
-
if (!systemCol && col.isVirtual) {
|
|
203
|
-
throw new Error(`Virtual column ${col.name} is missing from system queries. Make sure all virtual columns are included in the system queries returned by the strategy's onGetSystemQueries method.`);
|
|
204
|
-
}
|
|
205
205
|
return systemCol ? { ...systemCol, ...col, metadata: { ...systemCol.metadata, ...col.metadata } } : col;
|
|
206
206
|
});
|
|
207
|
-
|
|
208
|
-
return { ...parsed, columns };
|
|
209
|
-
}
|
|
210
|
-
const customColumnsMap = new Map(this._customColumnsDataProvider.getColumns().map(col => [col.name, col]));
|
|
211
|
-
columns = columns.filter(col => this._isCustomColumnResolvable(col.name, customColumnsMap));
|
|
212
|
-
columns = columns.map(col => {
|
|
213
|
-
const customCol = customColumnsMap.get(col.name);
|
|
214
|
-
return customCol ? { ...customCol, ...col, metadata: { ...customCol.metadata, ...col.metadata } } : col;
|
|
215
|
-
});
|
|
216
|
-
return {
|
|
217
|
-
...parsed,
|
|
218
|
-
sorting: parsed.sorting?.filter(sort => this._isCustomColumnResolvable(sort.name, customColumnsMap)),
|
|
219
|
-
columns: columns,
|
|
220
|
-
filtering: parsed.filtering ? {
|
|
221
|
-
...parsed.filtering,
|
|
222
|
-
conditions: parsed.filtering.conditions.filter(condition => this._isCustomColumnResolvable(condition.attributeName, customColumnsMap))
|
|
223
|
-
} : undefined
|
|
224
|
-
};
|
|
207
|
+
return { ...parsed, columns };
|
|
225
208
|
}
|
|
226
209
|
}
|
|
227
210
|
|