@contrail/flexplm 1.2.1 → 1.3.0-alpha.04c91a9
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/.github/pull_request_template.md +31 -31
- package/.github/workflows/flexplm-lib.yml +27 -27
- package/.github/workflows/publish-to-npm.yml +131 -0
- package/CHANGELOG.md +10 -0
- package/lib/entity-processor/base-entity-processor.d.ts +42 -42
- package/lib/entity-processor/base-entity-processor.js +385 -363
- package/lib/entity-processor/base-entity-processor.spec.d.ts +1 -1
- package/lib/entity-processor/base-entity-processor.spec.js +397 -302
- package/lib/flexplm-request.d.ts +3 -3
- package/lib/flexplm-request.js +34 -34
- package/lib/flexplm-utils.d.ts +5 -5
- package/lib/flexplm-utils.js +33 -33
- package/lib/flexplm-utils.spec.d.ts +1 -1
- package/lib/flexplm-utils.spec.js +26 -26
- package/lib/index.d.ts +22 -22
- package/lib/index.js +38 -38
- package/lib/interfaces/interfaces.d.ts +105 -105
- package/lib/interfaces/interfaces.js +2 -2
- package/lib/interfaces/item-family-changes.d.ts +20 -20
- package/lib/interfaces/item-family-changes.js +56 -56
- package/lib/interfaces/publish-change-data.d.ts +19 -19
- package/lib/interfaces/publish-change-data.js +32 -32
- package/lib/publish/base-process-publish-assortment-callback.d.ts +9 -9
- package/lib/publish/base-process-publish-assortment-callback.js +38 -38
- package/lib/publish/base-process-publish-assortment.d.ts +93 -93
- package/lib/publish/base-process-publish-assortment.js +944 -944
- package/lib/publish/base-process-publish-assortment.spec.d.ts +1 -1
- package/lib/publish/base-process-publish-assortment.spec.js +1670 -1670
- package/lib/publish/mockData.d.ts +1389 -1389
- package/lib/publish/mockData.js +4519 -4519
- package/lib/transform/identifier-conversion-spec-mockData.js +444 -444
- package/lib/transform/identifier-conversion.d.ts +15 -15
- package/lib/transform/identifier-conversion.js +212 -212
- package/lib/transform/identifier-conversion.spec.d.ts +1 -1
- package/lib/transform/identifier-conversion.spec.js +339 -339
- package/lib/util/config-defaults.d.ts +8 -8
- package/lib/util/config-defaults.js +85 -85
- package/lib/util/config-defaults.spec.d.ts +1 -1
- package/lib/util/config-defaults.spec.js +293 -293
- package/lib/util/data-converter-spec-mockData.js +205 -205
- package/lib/util/data-converter.d.ts +39 -39
- package/lib/util/data-converter.js +592 -592
- package/lib/util/data-converter.spec.d.ts +1 -1
- package/lib/util/data-converter.spec.js +904 -904
- package/lib/util/error-response-object.d.ts +4 -4
- package/lib/util/error-response-object.js +47 -47
- package/lib/util/error-response-object.spec.d.ts +1 -1
- package/lib/util/error-response-object.spec.js +99 -99
- package/lib/util/event-short-message-status.d.ts +19 -18
- package/lib/util/event-short-message-status.js +23 -22
- package/lib/util/federation.d.ts +15 -15
- package/lib/util/federation.js +149 -149
- package/lib/util/flexplm-connect.d.ts +22 -18
- package/lib/util/flexplm-connect.js +176 -171
- package/lib/util/flexplm-connect.spec.d.ts +1 -0
- package/lib/util/flexplm-connect.spec.js +88 -0
- package/lib/util/logger-config.d.ts +1 -1
- package/lib/util/logger-config.js +26 -26
- package/lib/util/map-util-spec-mockData.js +205 -205
- package/lib/util/map-utils.d.ts +6 -6
- package/lib/util/map-utils.js +15 -15
- package/lib/util/map-utils.spec.d.ts +1 -1
- package/lib/util/map-utils.spec.js +89 -89
- package/lib/util/mockData.d.ts +80 -79
- package/lib/util/mockData.js +103 -99
- package/lib/util/thumbnail-util.d.ts +34 -19
- package/lib/util/thumbnail-util.js +215 -114
- package/lib/util/thumbnail-util.spec.d.ts +1 -1
- package/lib/util/thumbnail-util.spec.js +434 -242
- package/lib/util/type-conversion-utils-spec-mockData.js +259 -241
- package/lib/util/type-conversion-utils.d.ts +23 -21
- package/lib/util/type-conversion-utils.js +265 -223
- package/lib/util/type-conversion-utils.spec.d.ts +1 -1
- package/lib/util/type-conversion-utils.spec.js +868 -708
- package/lib/util/type-defaults.d.ts +16 -16
- package/lib/util/type-defaults.js +221 -221
- package/lib/util/type-defaults.spec.d.ts +1 -1
- package/lib/util/type-defaults.spec.js +516 -516
- package/lib/util/type-utils.d.ts +13 -13
- package/lib/util/type-utils.js +114 -114
- package/lib/util/type-utils.spec.d.ts +1 -1
- package/lib/util/type-utils.spec.js +190 -190
- package/package.json +1 -1
- package/publish.bat +4 -4
- package/publish.sh +4 -4
- package/src/entity-processor/base-entity-processor.spec.ts +122 -0
- package/src/entity-processor/base-entity-processor.ts +31 -2
- package/src/flexplm-request.ts +28 -28
- package/src/flexplm-utils.spec.ts +27 -27
- package/src/flexplm-utils.ts +29 -29
- package/src/index.ts +21 -21
- package/src/interfaces/item-family-changes.ts +66 -66
- package/src/interfaces/publish-change-data.ts +42 -42
- package/src/publish/base-process-publish-assortment-callback.ts +50 -50
- package/src/transform/identifier-conversion-spec-mockData.ts +495 -495
- package/src/transform/identifier-conversion.spec.ts +353 -353
- package/src/transform/identifier-conversion.ts +281 -281
- package/src/util/config-defaults.spec.ts +350 -350
- package/src/util/config-defaults.ts +92 -92
- package/src/util/data-converter-spec-mockData.ts +230 -230
- package/src/util/error-response-object.spec.ts +115 -115
- package/src/util/error-response-object.ts +49 -49
- package/src/util/event-short-message-status.ts +1 -0
- package/src/util/federation.ts +172 -172
- package/src/util/flexplm-connect.spec.ts +132 -0
- package/src/util/flexplm-connect.ts +14 -5
- package/src/util/logger-config.ts +19 -19
- package/src/util/map-util-spec-mockData.ts +230 -230
- package/src/util/map-utils.spec.ts +102 -102
- package/src/util/map-utils.ts +40 -40
- package/src/util/mockData.ts +101 -97
- package/src/util/thumbnail-util.spec.ts +239 -0
- package/src/util/thumbnail-util.ts +140 -5
- package/src/util/type-conversion-utils-spec-mockData.ts +18 -0
- package/src/util/type-conversion-utils.spec.ts +184 -0
- package/src/util/type-conversion-utils.ts +75 -1
- package/src/util/type-defaults.spec.ts +668 -668
- package/src/util/type-defaults.ts +280 -280
- package/src/util/type-utils.spec.ts +227 -227
- package/src/util/type-utils.ts +144 -144
- package/tsconfig.json +23 -26
- package/tslint.json +57 -57
- package/.claude/settings.local.json +0 -8
- package/scripts/output.png +0 -0
- package/scripts/test-get-request.ts +0 -35
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import { Logger } from '@contrail/app-framework';
|
|
2
|
-
import { Entities } from '@contrail/sdk';
|
|
2
|
+
import { Content, Entities } from '@contrail/sdk';
|
|
3
3
|
import { FCConfig } from '../interfaces/interfaces';
|
|
4
|
+
import { FlexPLMConnect } from './flexplm-connect';
|
|
4
5
|
|
|
6
|
+
interface ContentCustomSize {
|
|
7
|
+
id: string;
|
|
8
|
+
slug: string;
|
|
9
|
+
name: string;
|
|
10
|
+
};
|
|
5
11
|
export class ThumbnailUtil {
|
|
12
|
+
/** The max_thumbnail_size is for limiting the size of the thumbnail being sent to FlexPLM. It is used when checking the size of the auto generated thumbnails (smallViewable, tinyViewable, etc.). */
|
|
6
13
|
private max_thumbnail_size = 5 * 1_024 * 1_024;
|
|
7
14
|
private entities: Entities;
|
|
8
15
|
static NEW_THUMBNAIL_ID = 'NEW_THUMBNAIL_ID';
|
|
@@ -54,7 +61,7 @@ export class ThumbnailUtil {
|
|
|
54
61
|
return false;
|
|
55
62
|
}
|
|
56
63
|
|
|
57
|
-
public async getFileId(primaryViewableId: string): Promise<string> {
|
|
64
|
+
public async getFileId(primaryViewableId: string): Promise<string | undefined> {
|
|
58
65
|
console.info('ThumbnailUtil.getFileId()-' + primaryViewableId);
|
|
59
66
|
const sizes = await this.getCustomSizes();
|
|
60
67
|
|
|
@@ -95,16 +102,16 @@ export class ThumbnailUtil {
|
|
|
95
102
|
return fileId;
|
|
96
103
|
}
|
|
97
104
|
|
|
98
|
-
async getCustomSizes() {
|
|
105
|
+
async getCustomSizes(): Promise<ContentCustomSize[]> {
|
|
99
106
|
const customSizes = await this.entities.get({
|
|
100
107
|
entityName: 'content-custom-size'
|
|
101
108
|
});
|
|
102
|
-
const sizes = [];
|
|
109
|
+
const sizes: ContentCustomSize[] = [];
|
|
103
110
|
sizes.push(...customSizes);
|
|
104
111
|
return sizes;
|
|
105
112
|
}
|
|
106
113
|
|
|
107
|
-
async getContentEntity(primaryViewableId: any, sizes:
|
|
114
|
+
async getContentEntity(primaryViewableId: any, sizes: ContentCustomSize[]) {
|
|
108
115
|
const relations = sizes.map(s => s.slug);
|
|
109
116
|
relations.push('primaryFile');
|
|
110
117
|
const content = await this.entities.get({
|
|
@@ -134,4 +141,132 @@ export class ThumbnailUtil {
|
|
|
134
141
|
}
|
|
135
142
|
}
|
|
136
143
|
|
|
144
|
+
/** Syncs the thumbnail from FlexPLM to VibeIQ. Handles creating, replacing, or removing
|
|
145
|
+
* the primary viewable content and persists the updates directly to the entity.
|
|
146
|
+
*
|
|
147
|
+
* @param entityId - The ID of the entity to update with thumbnail properties.
|
|
148
|
+
* @param primaryViewableId - The existing primary viewable content ID, if any.
|
|
149
|
+
* @param event - The inbound event containing thumbnail data (NEW_THUMBNAIL_ID / EXISTING_THUMBNAIL_ID).
|
|
150
|
+
* @param entityName - The entity type name (e.g. 'item', 'color') used for API calls.
|
|
151
|
+
* @returns The updated entity, or undefined if no thumbnail changes were needed.
|
|
152
|
+
*/
|
|
153
|
+
async syncThumbnailToVibeIQ({ entityId, primaryViewableId, event, entityName }: { entityId: string; primaryViewableId?: string; event: any; entityName: string }): Promise<any> {
|
|
154
|
+
console.debug(`syncThumbnailToVibeIQ: entityId=${entityId}, primaryViewableId=${primaryViewableId}, entityName=${entityName}`);
|
|
155
|
+
const eventData = event.data || {};
|
|
156
|
+
const newThumbnailId = eventData[ThumbnailUtil.NEW_THUMBNAIL_ID];
|
|
157
|
+
const existingThumbnailId = eventData[ThumbnailUtil.EXISTING_THUMBNAIL_ID];
|
|
158
|
+
const thumbnailUrl = newThumbnailId || existingThumbnailId;
|
|
159
|
+
|
|
160
|
+
// Case 1: REMOVE_THUMBNAIL
|
|
161
|
+
if (newThumbnailId === ThumbnailUtil.REMOVE_THUMBNAIL) {
|
|
162
|
+
if (primaryViewableId) {
|
|
163
|
+
await this.entities.delete({ entityName: 'content', id: primaryViewableId });
|
|
164
|
+
}
|
|
165
|
+
const clearUpdates = await this.getClearPrimaryViewableUpdates();
|
|
166
|
+
const updatedEntity = await this.entities.update({ entityName, id: entityId, object: clearUpdates });
|
|
167
|
+
console.debug(`syncThumbnailToVibeIQ: applied clear updates for entityId=${entityId}`);
|
|
168
|
+
return updatedEntity;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Early return if no thumbnail URL
|
|
172
|
+
if (!thumbnailUrl) {
|
|
173
|
+
console.debug(`syncThumbnailToVibeIQ: no thumbnail URL for entityId=${entityId}`);
|
|
174
|
+
return undefined;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Case 2: No existing primaryViewableId — create new content
|
|
178
|
+
if (!primaryViewableId) {
|
|
179
|
+
const content = await this.createContentFromFlexPLM(thumbnailUrl, entityId, entityName);
|
|
180
|
+
await this.entities.update({ entityName: 'content', id: content.id, object: { flexplmThumbnailUrl: thumbnailUrl } });
|
|
181
|
+
const primaryUpdates = await this.getPrimaryViewableUpdates(content);
|
|
182
|
+
const updatedEntity = await this.entities.update({ entityName, id: entityId, object: primaryUpdates });
|
|
183
|
+
console.debug(`syncThumbnailToVibeIQ: created new content ${content.id} for entityId=${entityId}`);
|
|
184
|
+
return updatedEntity;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Case 3: Has primaryViewableId — check if thumbnail changed
|
|
188
|
+
const primaryViewable = await this.entities.get({ entityName: 'content', id: primaryViewableId });
|
|
189
|
+
if (primaryViewable?.flexplmThumbnailUrl === thumbnailUrl) {
|
|
190
|
+
console.debug(`syncThumbnailToVibeIQ: thumbnail already synced for entityId=${entityId}`);
|
|
191
|
+
return undefined; // Already synced
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const content = await this.createContentFromFlexPLM(thumbnailUrl, entityId, entityName);
|
|
195
|
+
await this.entities.update({ entityName: 'content', id: content.id, object: { flexplmThumbnailUrl: thumbnailUrl } });
|
|
196
|
+
const primaryUpdates = await this.getPrimaryViewableUpdates(content);
|
|
197
|
+
const updatedEntity = await this.entities.update({ entityName, id: entityId, object: primaryUpdates });
|
|
198
|
+
await this.entities.delete({ entityName: 'content', id: primaryViewableId });
|
|
199
|
+
console.debug(`syncThumbnailToVibeIQ: replaced content ${primaryViewableId} with ${content.id} for entityId=${entityId}`);
|
|
200
|
+
return updatedEntity;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
private async createContentFromFlexPLM(thumbnailUrl: string, entityId: string, entityName: string): Promise<any> {
|
|
204
|
+
const urlParts = thumbnailUrl.split('/');
|
|
205
|
+
const fileName = urlParts[urlParts.length - 1] || 'thumbnail';
|
|
206
|
+
|
|
207
|
+
const encodedUrl = urlParts.map(part => encodeURIComponent(part)).join('/');
|
|
208
|
+
const flexPLMConnect = new FlexPLMConnect(this.config);
|
|
209
|
+
const response = await flexPLMConnect.getRequest({
|
|
210
|
+
urlPath: encodedUrl,
|
|
211
|
+
includeUrlContext: false,
|
|
212
|
+
returnFullResponse: true,
|
|
213
|
+
}) as Response;
|
|
214
|
+
|
|
215
|
+
const fileBuffer = await response.arrayBuffer();
|
|
216
|
+
const buffer = Buffer.from(fileBuffer);
|
|
217
|
+
const contentTypeHeader = response.headers.get('content-type');
|
|
218
|
+
const contentType = contentTypeHeader ? contentTypeHeader.split(';')[0] : 'application/octet-stream';
|
|
219
|
+
|
|
220
|
+
const contentHolderReference = `${entityName}:${entityId}`;
|
|
221
|
+
const content = await new Content().create({
|
|
222
|
+
fileBuffer: buffer,
|
|
223
|
+
fileName,
|
|
224
|
+
contentType,
|
|
225
|
+
contentHolderReference,
|
|
226
|
+
});
|
|
227
|
+
return content;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
private async getPrimaryViewableUpdates(content: any): Promise<any> {
|
|
231
|
+
const updates: any = {
|
|
232
|
+
primaryViewableId: content.id,
|
|
233
|
+
contentType: content.contentType,
|
|
234
|
+
fileName: content.fileName,
|
|
235
|
+
primaryFileUrl: content.primaryFileUrl,
|
|
236
|
+
largeViewableDownloadUrl: content.largeViewableUrl || content.primaryFileUrl,
|
|
237
|
+
mediumLargeViewableDownloadUrl: content.mediumLargeViewableUrl || content.primaryFileUrl,
|
|
238
|
+
mediumViewableDownloadUrl: content.mediumViewableUrl || content.primaryFileUrl,
|
|
239
|
+
smallViewableDownloadUrl: content.smallViewableUrl || content.primaryFileUrl,
|
|
240
|
+
tinyViewableDownloadUrl: content.tinyViewableUrl || content.primaryFileUrl,
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
const customSizes = await this.getCustomSizes();
|
|
244
|
+
for (const size of customSizes) {
|
|
245
|
+
updates[`${size.slug}DownloadUrl`] = content[`${size.slug}Url`] || content.primaryFileUrl;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return updates;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
private async getClearPrimaryViewableUpdates(): Promise<any> {
|
|
252
|
+
const updates: any = {
|
|
253
|
+
primaryViewableId: null,
|
|
254
|
+
contentType: null,
|
|
255
|
+
fileName: null,
|
|
256
|
+
primaryFileUrl: null,
|
|
257
|
+
largeViewableDownloadUrl: null,
|
|
258
|
+
mediumLargeViewableDownloadUrl: null,
|
|
259
|
+
mediumViewableDownloadUrl: null,
|
|
260
|
+
smallViewableDownloadUrl: null,
|
|
261
|
+
tinyViewableDownloadUrl: null,
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
const customSizes = await this.getCustomSizes();
|
|
265
|
+
for (const size of customSizes) {
|
|
266
|
+
updates[`${size.slug}DownloadUrl`] = null;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
return updates;
|
|
270
|
+
}
|
|
271
|
+
|
|
137
272
|
}
|
|
@@ -142,6 +142,12 @@ exports.mapping = {
|
|
|
142
142
|
isOutboundCreatable: (entity, context) => {
|
|
143
143
|
return false;
|
|
144
144
|
},
|
|
145
|
+
syncInboundImages: (entity, context) => {
|
|
146
|
+
return true;
|
|
147
|
+
},
|
|
148
|
+
syncOutboundImages: (entity, context) => {
|
|
149
|
+
return false;
|
|
150
|
+
},
|
|
145
151
|
vibe2flex: {
|
|
146
152
|
transformOrder: [{ processor: 'REKEY', rekeyDelete: true, rekeyTransformersKey: 'rekey' }],
|
|
147
153
|
rekey: {
|
|
@@ -175,6 +181,18 @@ exports.mapping = {
|
|
|
175
181
|
}
|
|
176
182
|
return true;
|
|
177
183
|
},
|
|
184
|
+
syncInboundImages: (entity, context) => {
|
|
185
|
+
if (context && context.skipImages) {
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
return true;
|
|
189
|
+
},
|
|
190
|
+
syncOutboundImages: (entity, context) => {
|
|
191
|
+
if (context && context.skipImages) {
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
return true;
|
|
195
|
+
},
|
|
178
196
|
vibe2flex: {
|
|
179
197
|
transformOrder: [{ processor: 'REKEY', rekeyDelete: true, rekeyTransformersKey: 'rekey' }],
|
|
180
198
|
rekey: {
|
|
@@ -781,4 +781,188 @@ describe('conversion-utils', () => {
|
|
|
781
781
|
});
|
|
782
782
|
|
|
783
783
|
});
|
|
784
|
+
|
|
785
|
+
describe('syncInboundImages', () =>{
|
|
786
|
+
const mapFileUtil = new MapFileUtil(new Entities());
|
|
787
|
+
|
|
788
|
+
it('should return true for Revisable Entity\\packaging (mapping entry true)', async () =>{
|
|
789
|
+
const spy = jest.spyOn(mapFileUtil, 'getMapFile')
|
|
790
|
+
.mockImplementation(async () =>{
|
|
791
|
+
return mapping;
|
|
792
|
+
});
|
|
793
|
+
const obj = {
|
|
794
|
+
flexPLMObjectClass: 'LCSRevisableEntity',
|
|
795
|
+
flexPLMTypePath: 'Revisable Entity\\packaging'
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
try{
|
|
799
|
+
const results = await TypeConversionUtils.syncInboundImages(TRANSFORM_MAP_FILE, mapFileUtil, obj);
|
|
800
|
+
expect(results).toBeTruthy();
|
|
801
|
+
|
|
802
|
+
} finally {
|
|
803
|
+
spy.mockRestore();
|
|
804
|
+
}
|
|
805
|
+
});
|
|
806
|
+
|
|
807
|
+
it('should return true for Revisable Entity\\prefix (mapping entry true)', async () =>{
|
|
808
|
+
const spy = jest.spyOn(mapFileUtil, 'getMapFile')
|
|
809
|
+
.mockImplementation(async () =>{
|
|
810
|
+
return mapping;
|
|
811
|
+
});
|
|
812
|
+
const obj = {
|
|
813
|
+
flexPLMObjectClass: 'LCSRevisableEntity',
|
|
814
|
+
flexPLMTypePath: 'Revisable Entity\\prefix'
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
try{
|
|
818
|
+
const results = await TypeConversionUtils.syncInboundImages(TRANSFORM_MAP_FILE, mapFileUtil, obj);
|
|
819
|
+
expect(results).toBeTruthy();
|
|
820
|
+
|
|
821
|
+
} finally {
|
|
822
|
+
spy.mockRestore();
|
|
823
|
+
}
|
|
824
|
+
});
|
|
825
|
+
|
|
826
|
+
it('should pass context to syncInboundImages function', async () =>{
|
|
827
|
+
const spy = jest.spyOn(mapFileUtil, 'getMapFile')
|
|
828
|
+
.mockImplementation(async () =>{
|
|
829
|
+
return mapping;
|
|
830
|
+
});
|
|
831
|
+
const obj = {
|
|
832
|
+
flexPLMObjectClass: 'LCSRevisableEntity',
|
|
833
|
+
flexPLMTypePath: 'Revisable Entity\\prefix'
|
|
834
|
+
}
|
|
835
|
+
const context = { skipImages: true };
|
|
836
|
+
|
|
837
|
+
try{
|
|
838
|
+
const results = await TypeConversionUtils.syncInboundImages(TRANSFORM_MAP_FILE, mapFileUtil, obj, context);
|
|
839
|
+
expect(results).toBeFalsy();
|
|
840
|
+
|
|
841
|
+
} finally {
|
|
842
|
+
spy.mockRestore();
|
|
843
|
+
}
|
|
844
|
+
});
|
|
845
|
+
|
|
846
|
+
it('should default to false when no mapping exists', async () =>{
|
|
847
|
+
const spy = jest.spyOn(mapFileUtil, 'getMapFile')
|
|
848
|
+
.mockImplementation(async () =>{
|
|
849
|
+
return mapping;
|
|
850
|
+
});
|
|
851
|
+
const obj = {
|
|
852
|
+
flexPLMObjectClass: 'LCSRevisableEntity',
|
|
853
|
+
flexPLMTypePath: 'Revisable Entity\\catName'
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
try{
|
|
857
|
+
const results = await TypeConversionUtils.syncInboundImages(TRANSFORM_MAP_FILE, mapFileUtil, obj);
|
|
858
|
+
expect(results).toBeFalsy();
|
|
859
|
+
|
|
860
|
+
} finally {
|
|
861
|
+
spy.mockRestore();
|
|
862
|
+
}
|
|
863
|
+
});
|
|
864
|
+
|
|
865
|
+
it('should default to false when no fileId', async () =>{
|
|
866
|
+
const obj = {
|
|
867
|
+
flexPLMObjectClass: 'LCSRevisableEntity',
|
|
868
|
+
flexPLMTypePath: 'Revisable Entity\\pack'
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
const results = await TypeConversionUtils.syncInboundImages('', mapFileUtil, obj);
|
|
872
|
+
expect(results).toBeFalsy();
|
|
873
|
+
});
|
|
874
|
+
|
|
875
|
+
});
|
|
876
|
+
|
|
877
|
+
describe('syncOutboundImages', () =>{
|
|
878
|
+
const mapFileUtil = new MapFileUtil(new Entities());
|
|
879
|
+
|
|
880
|
+
it('should return false for custom-entity:pack (mapping entry false)', async () =>{
|
|
881
|
+
const spy = jest.spyOn(mapFileUtil, 'getMapFile')
|
|
882
|
+
.mockImplementation(async () =>{
|
|
883
|
+
return mapping;
|
|
884
|
+
});
|
|
885
|
+
const entity = {
|
|
886
|
+
entityType: 'custom-entity',
|
|
887
|
+
typePath: 'custom-entity:pack'
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
try{
|
|
891
|
+
const results = await TypeConversionUtils.syncOutboundImages(TRANSFORM_MAP_FILE, mapFileUtil, entity);
|
|
892
|
+
expect(results).toBeFalsy();
|
|
893
|
+
|
|
894
|
+
} finally {
|
|
895
|
+
spy.mockRestore();
|
|
896
|
+
}
|
|
897
|
+
});
|
|
898
|
+
|
|
899
|
+
it('should return true for custom-entity:prefix (mapping entry true)', async () =>{
|
|
900
|
+
const spy = jest.spyOn(mapFileUtil, 'getMapFile')
|
|
901
|
+
.mockImplementation(async () =>{
|
|
902
|
+
return mapping;
|
|
903
|
+
});
|
|
904
|
+
const entity = {
|
|
905
|
+
entityType: 'custom-entity',
|
|
906
|
+
typePath: 'custom-entity:prefix'
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
try{
|
|
910
|
+
const results = await TypeConversionUtils.syncOutboundImages(TRANSFORM_MAP_FILE, mapFileUtil, entity);
|
|
911
|
+
expect(results).toBeTruthy();
|
|
912
|
+
|
|
913
|
+
} finally {
|
|
914
|
+
spy.mockRestore();
|
|
915
|
+
}
|
|
916
|
+
});
|
|
917
|
+
|
|
918
|
+
it('should pass context to syncOutboundImages function', async () =>{
|
|
919
|
+
const spy = jest.spyOn(mapFileUtil, 'getMapFile')
|
|
920
|
+
.mockImplementation(async () =>{
|
|
921
|
+
return mapping;
|
|
922
|
+
});
|
|
923
|
+
const entity = {
|
|
924
|
+
entityType: 'custom-entity',
|
|
925
|
+
typePath: 'custom-entity:prefix'
|
|
926
|
+
}
|
|
927
|
+
const context = { skipImages: true };
|
|
928
|
+
|
|
929
|
+
try{
|
|
930
|
+
const results = await TypeConversionUtils.syncOutboundImages(TRANSFORM_MAP_FILE, mapFileUtil, entity, context);
|
|
931
|
+
expect(results).toBeFalsy();
|
|
932
|
+
|
|
933
|
+
} finally {
|
|
934
|
+
spy.mockRestore();
|
|
935
|
+
}
|
|
936
|
+
});
|
|
937
|
+
|
|
938
|
+
it('should default to true when no mapping exists', async () =>{
|
|
939
|
+
const spy = jest.spyOn(mapFileUtil, 'getMapFile')
|
|
940
|
+
.mockImplementation(async () =>{
|
|
941
|
+
return mapping;
|
|
942
|
+
});
|
|
943
|
+
const entity = {
|
|
944
|
+
entityType: 'custom-entity',
|
|
945
|
+
typePath: 'custom-entity:catName'
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
try{
|
|
949
|
+
const results = await TypeConversionUtils.syncOutboundImages(TRANSFORM_MAP_FILE, mapFileUtil, entity);
|
|
950
|
+
expect(results).toBeTruthy();
|
|
951
|
+
|
|
952
|
+
} finally {
|
|
953
|
+
spy.mockRestore();
|
|
954
|
+
}
|
|
955
|
+
});
|
|
956
|
+
|
|
957
|
+
it('should default to true when no fileId', async () =>{
|
|
958
|
+
const entity = {
|
|
959
|
+
entityType: 'custom-entity',
|
|
960
|
+
typePath: 'custom-entity:pack'
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
const results = await TypeConversionUtils.syncOutboundImages('', mapFileUtil, entity);
|
|
964
|
+
expect(results).toBeTruthy();
|
|
965
|
+
});
|
|
966
|
+
|
|
967
|
+
});
|
|
784
968
|
});
|
|
@@ -323,7 +323,7 @@ export class TypeConversionUtils {
|
|
|
323
323
|
return TypeDefaults.getDefaultInformationalPropertiesFromObject(object);
|
|
324
324
|
}
|
|
325
325
|
|
|
326
|
-
static async getMapKeyFromObject(fileId, mapFileUtil: MapFileUtil, object: any, direction:string): Promise<string> {
|
|
326
|
+
static async getMapKeyFromObject(fileId, mapFileUtil: MapFileUtil, object: any, direction:string): Promise<string | undefined> {
|
|
327
327
|
const type = this.getObjectType(object);
|
|
328
328
|
if(fileId){
|
|
329
329
|
const mappingData = await mapFileUtil.getMappingSection(fileId, 'typeConversion', direction);
|
|
@@ -377,6 +377,80 @@ export class TypeConversionUtils {
|
|
|
377
377
|
return isOutboundCreatable;
|
|
378
378
|
}
|
|
379
379
|
|
|
380
|
+
/** Takes in a FlexPLM object and determines whether inbound
|
|
381
|
+
* images should be synced. In most cases, the creation owning system
|
|
382
|
+
* will also control image syncing. Defaults to false if no mapping exists.
|
|
383
|
+
* Map file entry in '<mapKey>:syncInboundImages()'
|
|
384
|
+
*
|
|
385
|
+
* @param fileId id for mapFile
|
|
386
|
+
* @param mapFileUtil class to get mapfile
|
|
387
|
+
* @param object FlexPLM object
|
|
388
|
+
* @param context optional context object
|
|
389
|
+
* @returns Promise<boolean>
|
|
390
|
+
*/
|
|
391
|
+
static async syncInboundImages(fileId: string, mapFileUtil: MapFileUtil, object: any, context?: any): Promise<boolean> {
|
|
392
|
+
|
|
393
|
+
let syncImages = false;
|
|
394
|
+
|
|
395
|
+
if (!fileId) {
|
|
396
|
+
return syncImages;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
let mapKey: string | undefined;
|
|
400
|
+
try {
|
|
401
|
+
mapKey = await this.getMapKeyFromObject(fileId, mapFileUtil, object, TypeConversionUtils.FLEX2VIBE_DIRECTION);
|
|
402
|
+
} catch {
|
|
403
|
+
return syncImages;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
if (!mapKey) {
|
|
407
|
+
return syncImages;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
const mapData = await MapUtil.getFullMapSection(fileId, mapFileUtil, mapKey);
|
|
411
|
+
if (mapData && mapData['syncInboundImages']) {
|
|
412
|
+
syncImages = await mapData['syncInboundImages'](object, context);
|
|
413
|
+
}
|
|
414
|
+
return syncImages;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/** Takes in a VibeIQ entity object and determines whether outbound
|
|
418
|
+
* images should be synced. In most cases, the creation owning system
|
|
419
|
+
* will also control image syncing. Defaults to true if no mapping exists.
|
|
420
|
+
* Map file entry in '<mapKey>:syncOutboundImages()'
|
|
421
|
+
*
|
|
422
|
+
* @param fileId id for mapFile
|
|
423
|
+
* @param mapFileUtil class to get mapfile
|
|
424
|
+
* @param entity VibeIQ entity
|
|
425
|
+
* @param context optional context object
|
|
426
|
+
* @returns Promise<boolean>
|
|
427
|
+
*/
|
|
428
|
+
static async syncOutboundImages(fileId: string, mapFileUtil: MapFileUtil, entity: any, context?: any): Promise<boolean> {
|
|
429
|
+
|
|
430
|
+
let syncImages = true;
|
|
431
|
+
|
|
432
|
+
if (!fileId) {
|
|
433
|
+
return syncImages;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
let mapKey: string | undefined;
|
|
437
|
+
try {
|
|
438
|
+
mapKey = await this.getMapKey(fileId, mapFileUtil, entity, TypeConversionUtils.VIBE2FLEX_DIRECTION);
|
|
439
|
+
} catch {
|
|
440
|
+
return syncImages;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
if (!mapKey) {
|
|
444
|
+
return syncImages;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
const mapData = await MapUtil.getFullMapSection(fileId, mapFileUtil, mapKey);
|
|
448
|
+
if (mapData && mapData['syncOutboundImages']) {
|
|
449
|
+
syncImages = await mapData['syncOutboundImages'](entity, context);
|
|
450
|
+
}
|
|
451
|
+
return syncImages;
|
|
452
|
+
}
|
|
453
|
+
|
|
380
454
|
static getObjectType(object:any) {
|
|
381
455
|
let objectType = object['flexPLMObjectClass'];
|
|
382
456
|
return objectType;
|