@esri/solution-deployer 6.0.5-alpha.0 → 6.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/package.json +15 -15
  2. package/dist/cjs/deploySolutionFromTemplate.d.ts +0 -55
  3. package/dist/cjs/deploySolutionFromTemplate.js +0 -334
  4. package/dist/cjs/deploySolutionFromTemplate.js.map +0 -1
  5. package/dist/cjs/deploySolutionItems.d.ts +0 -224
  6. package/dist/cjs/deploySolutionItems.js +0 -876
  7. package/dist/cjs/deploySolutionItems.js.map +0 -1
  8. package/dist/cjs/deployer.d.ts +0 -34
  9. package/dist/cjs/deployer.js +0 -99
  10. package/dist/cjs/deployer.js.map +0 -1
  11. package/dist/cjs/deployerUtils.d.ts +0 -47
  12. package/dist/cjs/deployerUtils.js +0 -120
  13. package/dist/cjs/deployerUtils.js.map +0 -1
  14. package/dist/cjs/helpers/post-process.d.ts +0 -29
  15. package/dist/cjs/helpers/post-process.js +0 -63
  16. package/dist/cjs/helpers/post-process.js.map +0 -1
  17. package/dist/cjs/helpers/share-templates-to-groups.d.ts +0 -24
  18. package/dist/cjs/helpers/share-templates-to-groups.js +0 -65
  19. package/dist/cjs/helpers/share-templates-to-groups.js.map +0 -1
  20. package/dist/cjs/helpers/sortTemplates.d.ts +0 -23
  21. package/dist/cjs/helpers/sortTemplates.js +0 -14
  22. package/dist/cjs/helpers/sortTemplates.js.map +0 -1
  23. package/dist/cjs/index.d.ts +0 -24
  24. package/dist/cjs/index.js +0 -28
  25. package/dist/cjs/index.js.map +0 -1
  26. package/dist/cjs/module-map.d.ts +0 -23
  27. package/dist/cjs/module-map.js +0 -234
  28. package/dist/cjs/module-map.js.map +0 -1
  29. package/dist/esm/deploySolutionFromTemplate.d.ts +0 -55
  30. package/dist/esm/deploySolutionFromTemplate.js +0 -319
  31. package/dist/esm/deploySolutionFromTemplate.js.map +0 -1
  32. package/dist/esm/deploySolutionItems.d.ts +0 -224
  33. package/dist/esm/deploySolutionItems.js +0 -853
  34. package/dist/esm/deploySolutionItems.js.map +0 -1
  35. package/dist/esm/deployer.d.ts +0 -34
  36. package/dist/esm/deployer.js +0 -94
  37. package/dist/esm/deployer.js.map +0 -1
  38. package/dist/esm/deployerUtils.d.ts +0 -47
  39. package/dist/esm/deployerUtils.js +0 -112
  40. package/dist/esm/deployerUtils.js.map +0 -1
  41. package/dist/esm/helpers/post-process.d.ts +0 -29
  42. package/dist/esm/helpers/post-process.js +0 -59
  43. package/dist/esm/helpers/post-process.js.map +0 -1
  44. package/dist/esm/helpers/share-templates-to-groups.d.ts +0 -24
  45. package/dist/esm/helpers/share-templates-to-groups.js +0 -61
  46. package/dist/esm/helpers/share-templates-to-groups.js.map +0 -1
  47. package/dist/esm/helpers/sortTemplates.d.ts +0 -23
  48. package/dist/esm/helpers/sortTemplates.js +0 -10
  49. package/dist/esm/helpers/sortTemplates.js.map +0 -1
  50. package/dist/esm/index.d.ts +0 -24
  51. package/dist/esm/index.js +0 -25
  52. package/dist/esm/index.js.map +0 -1
  53. package/dist/esm/module-map.d.ts +0 -23
  54. package/dist/esm/module-map.js +0 -230
  55. package/dist/esm/module-map.js.map +0 -1
@@ -1,876 +0,0 @@
1
- "use strict";
2
- /** @license
3
- * Copyright 2018 Esri
4
- *
5
- * Licensed under the Apache License, Version 2.0 (the "License");
6
- * you may not use this file except in compliance with the License.
7
- * You may obtain a copy of the License at
8
- *
9
- * http://www.apache.org/licenses/LICENSE-2.0
10
- *
11
- * Unless required by applicable law or agreed to in writing, software
12
- * distributed under the License is distributed on an "AS IS" BASIS,
13
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- * See the License for the specific language governing permissions and
15
- * limitations under the License.
16
- */
17
- Object.defineProperty(exports, "__esModule", { value: true });
18
- exports._getGroupUpdates = exports._estimateDeploymentCost = exports._createItemFromTemplateWhenReady = exports._findExistingItem = exports._findExistingItemByKeyword = exports._updateTemplateDictionaryById = exports._handleExistingItems = exports._updateTemplateDictionaryForError = exports._setFields = exports._updateTemplateDictionary = exports._setTypekeywordForExisting = exports._useExistingItems = exports._reuseDeployedItems = exports._getViews = exports._getViewHash = exports._updateViewTemplates = exports._evaluateSharedViewSources = exports._flagPatchItemsForPostProcessing = exports.deploySolutionItems = void 0;
19
- const tslib_1 = require("tslib");
20
- /**
21
- * Manages deployment of items via the REST API.
22
- *
23
- * @module deployItems
24
- */
25
- const common = tslib_1.__importStar(require("@esri/solution-common"));
26
- const module_map_1 = require("./module-map");
27
- const UNSUPPORTED = null;
28
- // ------------------------------------------------------------------------------------------------------------------ //
29
- /**
30
- * Deploys a set of items defined by templates.
31
- *
32
- * @param portalSharingUrl Server/sharing
33
- * @param storageItemId Id of storage item
34
- * @param templates A collection of AGO item templates
35
- * @param storageAuthentication Credentials for the organization with the source items
36
- * @param templateDictionary Hash of facts: org URL, adlib replacements
37
- * @param deployedSolutionId Id of deployed Solution item
38
- * @param destinationAuthentication Credentials for the destination organization
39
- * @param options Options to tune deployment
40
- * @returns A promise that will resolve with the list of information about the created items
41
- */
42
- function deploySolutionItems(portalSharingUrl, storageItemId, templates, storageAuthentication, templateDictionary, deployedSolutionId, destinationAuthentication, options) {
43
- return new Promise((resolve, reject) => {
44
- // Prepare feedback mechanism
45
- const totalEstimatedCost = _estimateDeploymentCost(templates) + 1; // solution items, plus avoid divide by 0
46
- let percentDone = 10; // allow for previous deployment work
47
- const progressPercentStep = (99 - percentDone) / totalEstimatedCost; // leave some % for caller for wrapup
48
- const failedTemplateItemIds = [];
49
- const deployedItemIds = [];
50
- let statusOK = true;
51
- // TODO: move to separate fn
52
- const itemProgressCallback = (itemId, status, costUsed, createdItemId) => {
53
- percentDone += progressPercentStep * costUsed;
54
- /* istanbul ignore else */
55
- if (options.progressCallback) {
56
- if (status === common.EItemProgressStatus.Finished) {
57
- const event = {
58
- event: common.SItemProgressStatus[status],
59
- data: itemId,
60
- };
61
- options.progressCallback(Math.round(percentDone), options.jobId, event);
62
- }
63
- else {
64
- options.progressCallback(Math.round(percentDone), options.jobId);
65
- }
66
- }
67
- /* istanbul ignore if */
68
- if (options.consoleProgress) {
69
- console.log(Date.now(), itemId, options.jobId ?? "", common.SItemProgressStatus[status], percentDone.toFixed(0) + "%", costUsed, createdItemId ? "==> " + createdItemId : "");
70
- }
71
- if (status === common.EItemProgressStatus.Created) {
72
- deployedItemIds.push(createdItemId);
73
- }
74
- else if (status === common.EItemProgressStatus.Failed) {
75
- failedTemplateItemIds.push(itemId);
76
- console.error("Item " + itemId + " has failed");
77
- statusOK = false;
78
- }
79
- return statusOK;
80
- // ---------------------------------------------------------------------------------------------------------------
81
- };
82
- // portal does not allow views of a single source to be created at the same time
83
- if (common.getProp(templateDictionary, "organization.isPortal")) {
84
- templates = _evaluateSharedViewSources(templates);
85
- }
86
- // Create an ordered graph of the templates so that dependencies are created before the items that need them.
87
- // Because cycles are permitted, we also keep track of items that need to be patched later because their
88
- // dependencies are necessarily created after they are created.
89
- const { buildOrder, itemsToBePatched } = common.topologicallySortItems(templates);
90
- // For each item in order from no dependencies to dependent on other items,
91
- // * replace template symbols using template dictionary
92
- // * create item in destination group
93
- // * add created item's id into the template dictionary
94
- const awaitAllItems = [];
95
- const reuseItemsDef = _reuseDeployedItems(templates, options.enableItemReuse ?? false, templateDictionary, destinationAuthentication);
96
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
97
- reuseItemsDef.then(() => {
98
- const useExistingItemsDef = _useExistingItems(templates, common.getProp(templateDictionary, "params.useExisting"), templateDictionary, destinationAuthentication);
99
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
100
- useExistingItemsDef.then(() => {
101
- templates = common.setNamesAndTitles(templates);
102
- buildOrder.forEach((id) => {
103
- // Get the item's template out of the list of templates
104
- const template = common.findTemplateInList(templates, id);
105
- if (template.type === "Form") {
106
- // Flag all forms for post processing of their webhooks
107
- itemsToBePatched[id] = [];
108
- }
109
- else if (template.type === "QuickCapture Project") {
110
- // Remove qc.project.json files from the resources--we don't use them from solutions
111
- template.resources = template.resources.filter((filename) => !filename.endsWith("qc.project.json"));
112
- }
113
- awaitAllItems.push(_createItemFromTemplateWhenReady(template, common.generateStorageFilePaths(portalSharingUrl, storageItemId, template.resources, options.storageVersion), storageAuthentication, templateDictionary, destinationAuthentication, itemProgressCallback));
114
- });
115
- // Wait until all items have been created
116
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
117
- Promise.all(awaitAllItems).then((clonedSolutionItems) => {
118
- if (failedTemplateItemIds.length === 0) {
119
- // Do we have any items to be patched (i.e., they refer to dependencies using the template id rather
120
- // than the cloned id because the item had to be created before the dependency)? Flag these items
121
- // for post processing in the list of clones.
122
- _flagPatchItemsForPostProcessing(itemsToBePatched, templateDictionary, clonedSolutionItems);
123
- resolve(clonedSolutionItems);
124
- }
125
- else {
126
- // Delete created items
127
- const progressOptions = {
128
- consoleProgress: true,
129
- };
130
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
131
- common
132
- .deleteSolutionByComponents(deployedSolutionId, deployedItemIds, templates, templateDictionary, destinationAuthentication, progressOptions)
133
- .then(() => reject(common.failWithIds(failedTemplateItemIds)));
134
- }
135
- });
136
- });
137
- }, (e) => {
138
- console.error(e);
139
- reject(common.fail(e));
140
- });
141
- });
142
- }
143
- exports.deploySolutionItems = deploySolutionItems;
144
- /**
145
- * For each item to be patched, convert it to its cloned id and mark the item as needing post processing.
146
- *
147
- * @param itemsToBePatched List of items that need to have their dependencies patched
148
- * @param templateDictionary Hash of facts: org URL, adlib replacements
149
- * @param templates A collection of AGO item templates
150
- * @private
151
- */
152
- function _flagPatchItemsForPostProcessing(itemsToBePatched, templateDictionary, templates) {
153
- let itemIdsToBePatched = Object.keys(itemsToBePatched);
154
- /* istanbul ignore else */
155
- if (itemIdsToBePatched.length > 0) {
156
- // Replace the ids of the items to be patched (which are template ids) with their cloned versions
157
- itemIdsToBePatched = itemIdsToBePatched.map((id) => templateDictionary[id].itemId);
158
- // Make sure that the items to be patched are flagged for post processing
159
- templates.forEach((item) => {
160
- /* istanbul ignore else */
161
- if (itemIdsToBePatched.includes(item.id)) {
162
- item.postProcess = true;
163
- }
164
- });
165
- }
166
- }
167
- exports._flagPatchItemsForPostProcessing = _flagPatchItemsForPostProcessing;
168
- /**
169
- * Portal does not allow views of a single source to be created at the same time.
170
- *
171
- * Update view templates with an array of other view template ids that it should wait on.
172
- *
173
- * @param templates a collection of AGO item templates
174
- *
175
- * @returns An updated array of item templates
176
- * @private
177
- */
178
- function _evaluateSharedViewSources(templates) {
179
- // update the templates so we can defer the deployment when more than one view shares the same source
180
- // these are not classic dependencies but are in some ways similar
181
- const views = _getViews(templates);
182
- _updateViewTemplates(templates, views);
183
- const viewHash = _getViewHash(views);
184
- let processed = [];
185
- const visited = [];
186
- Object.keys(viewHash).forEach((k) => {
187
- const _views = viewHash[k];
188
- _views.forEach((cv) => {
189
- const template = common.findTemplateInList(templates, cv);
190
- const syncViews = common.getProp(template, "properties.syncViews");
191
- /* istanbul ignore else */
192
- if (visited.indexOf(template.itemId) > -1) {
193
- processed = processed.concat(syncViews);
194
- }
195
- /* istanbul ignore else */
196
- if (syncViews && syncViews.length > 0) {
197
- // when a view has multiple dependencies we need to retain the syncViews if they have been set already...
198
- common.setProp(template, "properties.syncViews", common.cloneObject(processed));
199
- }
200
- /* istanbul ignore else */
201
- if (processed.indexOf(cv) < 0) {
202
- processed.push(cv);
203
- }
204
- /* istanbul ignore else */
205
- if (visited.indexOf(template.itemId) < 0) {
206
- visited.push(template.itemId);
207
- }
208
- });
209
- processed = [];
210
- });
211
- return templates;
212
- }
213
- exports._evaluateSharedViewSources = _evaluateSharedViewSources;
214
- /**
215
- * Add a syncViews array to each template that will hold all other view ids that
216
- * have the same FS dependency.
217
- * These arrays will be processed later to only contain ids that each view will need to wait on.
218
- *
219
- * @param templates a collection of AGO item templates
220
- * @param views an array of view template details
221
- *
222
- * @returns An updated array of item templates
223
- * @private
224
- */
225
- function _updateViewTemplates(templates, views) {
226
- views.forEach((v) => {
227
- v.dependencies.forEach((id) => {
228
- templates = templates.map((t) => {
229
- /* istanbul ignore else */
230
- if (common.getProp(t, "properties.service.isView") && t.dependencies.indexOf(id) > -1 && t.itemId !== v.id) {
231
- /* istanbul ignore else */
232
- if (!Array.isArray(t.properties.syncViews)) {
233
- t.properties.syncViews = [];
234
- }
235
- /* istanbul ignore else */
236
- if (t.properties.syncViews.indexOf(v.id) < 0) {
237
- t.properties.syncViews.push(v.id);
238
- }
239
- }
240
- return t;
241
- });
242
- });
243
- });
244
- return templates;
245
- }
246
- exports._updateViewTemplates = _updateViewTemplates;
247
- /**
248
- * Get all view templates from the source templates collection
249
- *
250
- * @param views A collection of view ID and dependencies
251
- *
252
- * @returns an array of objects with the source FS id as the key and a list of views that are
253
- * dependant upon it
254
- *
255
- * @private
256
- */
257
- function _getViewHash(views) {
258
- const viewHash = {};
259
- views.forEach((v) => {
260
- v.dependencies.forEach((d) => {
261
- /* istanbul ignore else */
262
- if (Object.keys(viewHash).indexOf(d) < 0) {
263
- viewHash[d] = [v.id];
264
- }
265
- else if (viewHash[d].indexOf(v.id) < 0) {
266
- viewHash[d].push(v.id);
267
- }
268
- });
269
- });
270
- return viewHash;
271
- }
272
- exports._getViewHash = _getViewHash;
273
- /**
274
- * Get all view templates from the source templates collection
275
- *
276
- * @param templates A collection of AGO item templates
277
- *
278
- * @returns an array with the view id and its dependencies
279
- *
280
- * @private
281
- */
282
- function _getViews(templates) {
283
- return templates.reduce((acc, v) => {
284
- /* istanbul ignore else */
285
- if (common.getProp(v, "properties.service.isView")) {
286
- acc.push({
287
- id: v.itemId,
288
- dependencies: v.dependencies,
289
- });
290
- }
291
- return acc;
292
- }, []);
293
- }
294
- exports._getViews = _getViews;
295
- /**
296
- * Search for existing items and update the templateDictionary with key details
297
- *
298
- * @param templates A collection of AGO item templates
299
- * @param reuseItems Option to search for existing items
300
- * @param templateDictionary Hash of facts: org URL, adlib replacements, deferreds for dependencies
301
- * @param authentication Credentials for the requests
302
- *
303
- * @returns A Promise that will resolve once existing items have been evaluated
304
- *
305
- * @private
306
- */
307
- function _reuseDeployedItems(templates, reuseItems, templateDictionary, authentication) {
308
- return new Promise((resolve, reject) => {
309
- if (reuseItems) {
310
- const findItemsByKeywordResponse = _findExistingItemByKeyword(templates, templateDictionary, authentication);
311
- const existingItemsByKeyword = findItemsByKeywordResponse.existingItemsDefs;
312
- const existingItemInfos = findItemsByKeywordResponse.existingItemInfos;
313
- Promise.all(existingItemsByKeyword).then((existingItemsByKeywordResponse) => {
314
- const findExistingItemsByTag = _handleExistingItems(existingItemsByKeywordResponse, existingItemInfos, templateDictionary, authentication, true);
315
- const existingItemsByTag = findExistingItemsByTag.existingItemsDefs;
316
- const existingItemInfosByTag = findExistingItemsByTag.existingItemInfos;
317
- Promise.all(existingItemsByTag).then((existingItemsByTagResponse) => {
318
- _handleExistingItems(existingItemsByTagResponse, existingItemInfosByTag, templateDictionary, authentication, false);
319
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
320
- _updateTemplateDictionary(templates, templateDictionary, authentication).then(resolve);
321
- }, (e) => reject(common.fail(e)));
322
- }, (e) => reject(common.fail(e)));
323
- }
324
- else {
325
- resolve(null);
326
- }
327
- });
328
- }
329
- exports._reuseDeployedItems = _reuseDeployedItems;
330
- /**
331
- * Search for existing items and update the templateDictionary with key details
332
- *
333
- * Subtle difference between _reuseDeployedItems and _useExistingItems
334
- * _reuseDeployedItems: will search all existing items based on specific type keywords
335
- * that would have been added by a previous deployment
336
- * _useExistingItems: will search for an existing item that the user provided
337
- * the item id for while configuring in the deployment app.
338
- * This type of item would not necessarily have been laid down by a previous deployment and
339
- * can thus not expect that it will have the type keywords
340
- *
341
- * @param templates A collection of AGO item templates
342
- * @param useExisting Option to search for existing items
343
- * @param templateDictionary Hash of facts: org URL, adlib replacements, deferreds for dependencies
344
- * @param authentication Credentials for the requests
345
- *
346
- * @returns A Promise that will resolve once existing items have been evaluated
347
- *
348
- * @private
349
- */
350
- function _useExistingItems(templates, useExisting, templateDictionary, authentication) {
351
- return new Promise((resolve) => {
352
- if (useExisting) {
353
- const itemDefs = [];
354
- const sourceIdHash = {};
355
- const itemIds = [];
356
- Object.keys(templateDictionary.params).forEach((k) => {
357
- const v = templateDictionary.params[k];
358
- /* istanbul ignore else */
359
- if (v.itemId && /[0-9A-F]{32}/i.test(k)) {
360
- _updateTemplateDictionaryById(templateDictionary, k, v.itemId, v);
361
- // need to check and set the typeKeyword if it doesn't exist on this service yet
362
- // when the user has passed in an itemId that does not come from a previous deployment
363
- itemDefs.push(common.getItemBase(v.itemId, authentication));
364
- sourceIdHash[v.itemId] = k;
365
- /* istanbul ignore else */
366
- if (itemIds.indexOf(k) < 0) {
367
- itemIds.push(k);
368
- }
369
- }
370
- });
371
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
372
- _setTypekeywordForExisting(itemDefs, sourceIdHash, authentication).then(() => {
373
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
374
- _updateTemplateDictionary(itemIds.map((id) => common.getTemplateById(templates, id)), templateDictionary, authentication).then(resolve);
375
- });
376
- }
377
- else {
378
- resolve(null);
379
- }
380
- });
381
- }
382
- exports._useExistingItems = _useExistingItems;
383
- /**
384
- * Verify if the existing item has the source-<itemId> typeKeyword and set it if not
385
- * This allows items that did not come from deployment to be found for reuse after they
386
- * have been used once via a custom itemId param
387
- *
388
- * @param itemDefs
389
- * @param sourceIdHash key value pairs..actual itemId is the key and the source itemId is the value
390
- * @param authentication credentials for the requests
391
- *
392
- * @returns a promise to indicate when the requests are complete
393
- * @private
394
- */
395
- function _setTypekeywordForExisting(itemDefs, sourceIdHash, authentication) {
396
- return new Promise((resolve) => {
397
- if (itemDefs.length > 0) {
398
- Promise.all(itemDefs).then((results) => {
399
- const itemUpdateDefs = [];
400
- results.forEach((result) => {
401
- const sourceId = sourceIdHash[result.id];
402
- /* istanbul ignore else */
403
- if (result && sourceId && result.typeKeywords) {
404
- const sourceKeyword = `source-${sourceId}`;
405
- const typeKeywords = result.typeKeywords;
406
- /* istanbul ignore else */
407
- if (typeKeywords.indexOf(sourceKeyword) < 0) {
408
- typeKeywords.push(sourceKeyword);
409
- const itemUpdate = { id: result.id, typeKeywords };
410
- itemUpdateDefs.push(common.updateItem(itemUpdate, authentication));
411
- }
412
- }
413
- });
414
- // wait for updates to finish before we resolve
415
- if (itemUpdateDefs.length > 0) {
416
- Promise.all(itemUpdateDefs).then(resolve, () => resolve(undefined));
417
- }
418
- else {
419
- resolve(undefined);
420
- }
421
- }, () => resolve(undefined));
422
- }
423
- else {
424
- resolve(undefined);
425
- }
426
- });
427
- }
428
- exports._setTypekeywordForExisting = _setTypekeywordForExisting;
429
- /**
430
- * Update the templateDictionary with key details by item type
431
- *
432
- * @param templates A collection of AGO item templates
433
- * @param templateDictionary Hash of facts: org URL, adlib replacements, deferreds for dependencies
434
- *
435
- * @private
436
- */
437
- function _updateTemplateDictionary(templates, templateDictionary, authentication) {
438
- return new Promise((resolve) => {
439
- const defs = [];
440
- const urls = [];
441
- const types = [];
442
- const ids = [];
443
- templates.forEach((t) => {
444
- const templateInfo = templateDictionary[t.itemId];
445
- /* istanbul ignore else */
446
- if (templateInfo && templateInfo.url && templateInfo.itemId) {
447
- /* istanbul ignore else */
448
- if (t.item.type === "Feature Service") {
449
- const enterpriseIDMapping = common.getProp(templateDictionary, `params.${t.itemId}.enterpriseIDMapping`);
450
- Object.assign(templateDictionary[t.itemId], common.getLayerSettings(common.getLayersAndTables(t), templateInfo.url, templateInfo.itemId, enterpriseIDMapping));
451
- // if the service has veiws keep track of the fields so we can use them to
452
- // compare with the view fields
453
- /* istanbul ignore else */
454
- if (common.getProp(t, "properties.service.hasViews")) {
455
- common._updateTemplateDictionaryFields(t, templateDictionary, false);
456
- }
457
- }
458
- // for fs query with its url...for non fs query the item
459
- // this is to verify situations where we have a stale search index that will
460
- // say some items exist when they don't really exist
461
- // searching the services url or with the item id will return an error when this condition occurs
462
- /* istanbul ignore else */
463
- if (urls.indexOf(templateInfo.url) < 0) {
464
- defs.push(t.item.type === "Feature Service"
465
- ? common.request(templateInfo.url, { authentication })
466
- : common.getItemBase(templateInfo.itemId, authentication));
467
- urls.push(templateInfo.url);
468
- types.push(t.item.type);
469
- ids.push(templateInfo.itemId);
470
- }
471
- }
472
- });
473
- if (defs.length > 0) {
474
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
475
- Promise.all(defs.map((p) => p.catch((e) => e))).then((results) => {
476
- /* istanbul ignore else */
477
- if (Array.isArray(results) && results.length > 0) {
478
- const fieldDefs = [];
479
- results.forEach((r, i) => {
480
- // a feature service result will contain a serviceItemId if it was successfully fetched
481
- if (r.serviceItemId && types[i] === "Feature Service") {
482
- Object.keys(templateDictionary).forEach((k) => {
483
- const v = templateDictionary[k];
484
- /* istanbul ignore else */
485
- if (v.itemId && v.itemId === r.serviceItemId) {
486
- common.setDefaultSpatialReference(templateDictionary, k, r.spatialReference);
487
- // keep the extent values from these responses as well
488
- common.setCreateProp(templateDictionary, `${k}.defaultExtent`, r.fullExtent || r.initialExtent);
489
- const layerIds = (r.layers || []).map((l) => l.id);
490
- const tablesIds = (r.tables || []).map((t) => t.id);
491
- fieldDefs.push(common.getExistingLayersAndTables(urls[i], layerIds.concat(tablesIds), authentication));
492
- }
493
- });
494
- }
495
- else {
496
- /* istanbul ignore else */
497
- if (types[i] === "Feature Service" || common.getProp(r, "response.error")) {
498
- // if an error is returned we need to clean up the templateDictionary
499
- templateDictionary = _updateTemplateDictionaryForError(templateDictionary, ids[i]);
500
- }
501
- }
502
- });
503
- if (fieldDefs.length > 0) {
504
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
505
- Promise.all(fieldDefs).then((layerTableResult) => {
506
- layerTableResult.forEach((l) => {
507
- l.forEach((ll) => {
508
- Object.keys(templateDictionary).forEach((k) => {
509
- /* istanbul ignore else */
510
- if (templateDictionary[k].itemId === ll.serviceItemId) {
511
- let sourceId = "";
512
- Object.keys(templateDictionary).some((_k) => {
513
- /* istanbul ignore else */
514
- if (templateDictionary[_k].itemId === ll.serviceItemId) {
515
- sourceId = _k;
516
- return true;
517
- }
518
- });
519
- const enterpriseIDMapping = common.getProp(templateDictionary, `params.${sourceId}.enterpriseIDMapping`);
520
- if (enterpriseIDMapping) {
521
- Object.keys(enterpriseIDMapping).forEach((id) => {
522
- if (enterpriseIDMapping[id].toString() === ll.id.toString()) {
523
- _setFields(templateDictionary, k, id, ll.fields);
524
- }
525
- });
526
- }
527
- else {
528
- _setFields(templateDictionary, k, ll.id, ll.fields);
529
- }
530
- }
531
- });
532
- });
533
- });
534
- resolve(null);
535
- });
536
- }
537
- else {
538
- resolve(null);
539
- }
540
- }
541
- else {
542
- resolve(null);
543
- }
544
- });
545
- }
546
- else {
547
- resolve(null);
548
- }
549
- });
550
- }
551
- exports._updateTemplateDictionary = _updateTemplateDictionary;
552
- /**
553
- * Add the fields from the source layer to the template dictionary for any required replacements
554
- *
555
- * @param templateDictionary Hash of facts: org URL, adlib replacements, deferreds for dependencies
556
- * @param itemId the id for the item
557
- * @param layerId the id for the layer
558
- * @param fields the fields to transfer
559
- *
560
- * @private
561
- */
562
- function _setFields(templateDictionary, itemId, layerId, fields) {
563
- const layerInfo = common.getProp(templateDictionary, `${itemId}.layer${layerId}`);
564
- /* istanbul ignore else */
565
- if (layerInfo && fields) {
566
- layerInfo.fields = fields;
567
- }
568
- }
569
- exports._setFields = _setFields;
570
- /**
571
- * In some cases an item id search will return a stale item reference
572
- * it will subsequently fail when we try to fetch the underlying service.
573
- *
574
- * We need to remove the item info that has been added to the template dictionary
575
- * and treat the item as we do other items that don't already exist on deployment.
576
- *
577
- * @param result the service request result
578
- * @param templateDictionary Hash of facts: org URL, adlib replacements, deferreds for dependencies
579
- *
580
- * @private
581
- */
582
- function _updateTemplateDictionaryForError(templateDictionary, itemId) {
583
- /* istanbul ignore else */
584
- if (itemId) {
585
- let removeKey = "";
586
- Object.keys(templateDictionary).some((k) => {
587
- /* istanbul ignore else */
588
- if (templateDictionary[k].itemId === itemId) {
589
- removeKey = k;
590
- return true;
591
- }
592
- });
593
- /* istanbul ignore else */
594
- if (removeKey !== "") {
595
- delete templateDictionary[removeKey];
596
- }
597
- }
598
- return templateDictionary;
599
- }
600
- exports._updateTemplateDictionaryForError = _updateTemplateDictionaryForError;
601
- /**
602
- * Optionally search by tags and then update the templateDictionary based on the search results
603
- *
604
- * @param existingItemsResponse response object from search by typeKeyword and type
605
- * @param existingItemIds list of the template ids we have queried
606
- * @param templateDictionary Hash of facts: org URL, adlib replacements, deferreds for dependencies
607
- * @param authentication Credentials for the request
608
- * @param addTagQuery Boolean to indicate if a search by tag should happen
609
- * @returns IFindExistingItemsResponse object with promise that will resolve with an array of results
610
- * and an array of item ids
611
- * @private
612
- */
613
- function _handleExistingItems(existingItemsResponse, existingItemInfos, templateDictionary, authentication, addTagQuery) {
614
- // if items are not found by type keyword search by tag
615
- const existingItemsByTag = [Promise.resolve(null)];
616
- const existingItemInfosByTag = [undefined];
617
- /* istanbul ignore else */
618
- if (existingItemsResponse && Array.isArray(existingItemsResponse)) {
619
- existingItemsResponse.forEach((existingItem, i) => {
620
- /* istanbul ignore else */
621
- if (Array.isArray(existingItem?.results)) {
622
- let result;
623
- const results = existingItem.results;
624
- if (results.length === 1) {
625
- result = results[0];
626
- }
627
- else if (results.length > 1) {
628
- result = results.reduce((a, b) => (a.created > b.created ? a : b));
629
- }
630
- else {
631
- if (addTagQuery && existingItemInfos[i]) {
632
- const itemInfo = existingItemInfos[i];
633
- const tagQuery = `tags:source-${itemInfo.itemId} type:${itemInfo.type} owner:${templateDictionary.user.username}`;
634
- existingItemsByTag.push(_findExistingItem(tagQuery, authentication));
635
- existingItemInfosByTag.push(existingItemInfos[i]);
636
- }
637
- }
638
- if (result) {
639
- const sourceId = existingItemInfos[i].itemId;
640
- /* istanbul ignore else */
641
- if (sourceId) {
642
- _updateTemplateDictionaryById(templateDictionary, sourceId, result.id, result);
643
- }
644
- }
645
- }
646
- });
647
- }
648
- return {
649
- existingItemsDefs: existingItemsByTag,
650
- existingItemInfos: existingItemInfosByTag,
651
- };
652
- }
653
- exports._handleExistingItems = _handleExistingItems;
654
- //TODO: function doc
655
- function _updateTemplateDictionaryById(templateDictionary, sourceId, itemId, v) {
656
- templateDictionary[sourceId] = Object.assign(templateDictionary[sourceId] || {}, {
657
- def: Promise.resolve(common.generateEmptyCreationResponse(v.type, itemId)),
658
- itemId,
659
- name: v.name,
660
- title: v.title,
661
- url: v.url,
662
- label: v.title,
663
- });
664
- }
665
- exports._updateTemplateDictionaryById = _updateTemplateDictionaryById;
666
- /**
667
- * Search items based on user query
668
- *
669
- * @param templates Templates to examine
670
- * @param templateDictionary Hash of facts: org URL, adlib replacements, deferreds for dependencies
671
- * @param authentication Credentials for the request
672
- * @returns IFindExistingItemsResponse object with promise that will resolve with an array of results
673
- * and an array of item ids
674
- * @private
675
- */
676
- function _findExistingItemByKeyword(templates, templateDictionary, authentication) {
677
- const existingItemsDefs = [];
678
- const existingItemInfos = [];
679
- templates.forEach((template) => {
680
- if (template.item.type === "Group") {
681
- const userGroups = templateDictionary.user?.groups;
682
- /* istanbul ignore else */
683
- if (Array.isArray(userGroups)) {
684
- existingItemsDefs.push(Promise.resolve({
685
- results: userGroups
686
- .filter((g) => g.tags.indexOf(`source-${template.itemId}`) > -1 ||
687
- g.typeKeywords.indexOf(`source-${template.itemId}`) > -1)
688
- .map((g) => {
689
- g.type = "Group";
690
- return g;
691
- }),
692
- sourceId: template.itemId,
693
- }));
694
- }
695
- }
696
- else {
697
- existingItemsDefs.push(_findExistingItem(`typekeywords:source-${template.itemId} type:${template.item.type} owner:${templateDictionary.user.username}`, authentication));
698
- }
699
- existingItemInfos.push({
700
- itemId: template.itemId,
701
- type: template.item.type,
702
- });
703
- });
704
- return {
705
- existingItemsDefs,
706
- existingItemInfos,
707
- };
708
- }
709
- exports._findExistingItemByKeyword = _findExistingItemByKeyword;
710
- /**
711
- * Search items based on user query
712
- *
713
- * @param query Query string to use
714
- * @param authentication Credentials for the request
715
- * @returns A promise that will resolve with an array of results
716
- * @private
717
- */
718
- function _findExistingItem(query, authentication) {
719
- const searchOptions = {
720
- q: query,
721
- authentication: authentication,
722
- pagingParam: { start: 1, num: 100 },
723
- };
724
- return common.searchItems(searchOptions);
725
- }
726
- exports._findExistingItem = _findExistingItem;
727
- /**
728
- * Creates an item from a template once the item's dependencies have been created.
729
- *
730
- * @param template Template of item to deploy
731
- * @param resourceFilePaths URL, folder, and filename for each item resource/metadata/thumbnail
732
- * @param templateDictionary Hash of facts: org URL, adlib replacements, deferreds for dependencies
733
- * @param userSession Options for the request
734
- * @param itemProgressCallback Function for reporting progress updates from type-specific template handlers
735
- * @returns A promise that will resolve with the id of the deployed item (which is simply returned if it's
736
- * already in the templates list
737
- * @private
738
- */
739
- function _createItemFromTemplateWhenReady(template, resourceFilePaths, storageAuthentication, templateDictionary, destinationAuthentication, itemProgressCallback) {
740
- const sourceItemId = template.itemId;
741
- // ensure this is present
742
- template.dependencies = template.dependencies || [];
743
- // if there is no entry in the templateDictionary
744
- // or if we have a basic entry without the deferred request for its creation, add it
745
- if (!templateDictionary.hasOwnProperty(template.itemId) ||
746
- !common.getProp(templateDictionary[template.itemId], "def")) {
747
- let createResponse;
748
- let statusCode = common.EItemProgressStatus.Unknown;
749
- let itemHandler;
750
- templateDictionary[template.itemId] = templateDictionary[template.itemId] || {};
751
- // Save the deferred for the use of items that depend on this item being created first
752
- templateDictionary[template.itemId].def = new Promise((resolve) => {
753
- // Wait until all of the item's dependencies are deployed
754
- const _awaitDependencies = template.dependencies.reduce((acc, id) => {
755
- const def = common.getProp(templateDictionary, `${id}.def`);
756
- // can't use maybePush as that clones the object, which does not work for Promises
757
- /* istanbul ignore else */
758
- if (def) {
759
- acc.push(def);
760
- }
761
- return acc;
762
- }, []);
763
- const syncViews = common.getProp(template, "properties.syncViews");
764
- const awaitDependencies = syncViews && syncViews.length > 0
765
- ? syncViews.reduce((acc, v) => {
766
- const def = common.getProp(templateDictionary, `${v}.def`);
767
- /* istanbul ignore else */
768
- if (def) {
769
- acc.push(def);
770
- }
771
- return acc;
772
- }, _awaitDependencies)
773
- : _awaitDependencies;
774
- Promise.all(awaitDependencies)
775
- .then(() => {
776
- // Find the conversion handler for this item type
777
- const templateType = template.type;
778
- itemHandler = module_map_1.moduleMap[templateType];
779
- if (template.type === "Geoprocessing Service") {
780
- itemHandler = template.item.typeKeywords.indexOf("Web Tool") > -1 ? itemHandler : UNSUPPORTED;
781
- }
782
- if (!itemHandler || itemHandler === UNSUPPORTED) {
783
- if (itemHandler === UNSUPPORTED) {
784
- statusCode = common.EItemProgressStatus.Ignored;
785
- throw new Error();
786
- }
787
- else {
788
- statusCode = common.EItemProgressStatus.Failed;
789
- throw new Error();
790
- }
791
- }
792
- // Get the item's thumbnail
793
- return common.getThumbnailFromStorageItem(storageAuthentication, resourceFilePaths);
794
- })
795
- .then((thumbnail) => {
796
- template.item.thumbnail = thumbnail;
797
- // Delegate the creation of the item to the handler
798
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
799
- return itemHandler.createItemFromTemplate(template, templateDictionary, destinationAuthentication, itemProgressCallback);
800
- })
801
- .then(async (response) => {
802
- if (response.id === "") {
803
- statusCode = common.EItemProgressStatus.Failed;
804
- throw new Error("handled"); // fails to create item
805
- }
806
- /* istanbul ignore else */
807
- createResponse = response;
808
- if (createResponse.item.item.url) {
809
- common.setCreateProp(templateDictionary, sourceItemId + ".url", createResponse.item.item.url);
810
- }
811
- if (resourceFilePaths.length > 0) {
812
- const destinationItemId = createResponse.id;
813
- // Update and copy form resource
814
- if (template.type === "Form") {
815
- // Filter out Form zip file
816
- let formZipFilePath;
817
- resourceFilePaths = resourceFilePaths.filter((filePath) => {
818
- if (filePath.filename.endsWith(".zip")) {
819
- formZipFilePath = filePath;
820
- return false;
821
- }
822
- else {
823
- return true;
824
- }
825
- });
826
- if (formZipFilePath) {
827
- // Fetch the form's zip file and send it to the item
828
- const zipObject = await common.fetchZipObject(formZipFilePath.url, storageAuthentication);
829
- await common.updateItemWithZipObject(zipObject, destinationItemId, destinationAuthentication);
830
- }
831
- }
832
- // Copy resources, metadata
833
- return common.copyFilesFromStorageItem(storageAuthentication, resourceFilePaths, sourceItemId, templateDictionary.folderId, destinationItemId, destinationAuthentication, createResponse.item, templateDictionary);
834
- }
835
- else {
836
- return Promise.resolve(null);
837
- }
838
- })
839
- .then(() => {
840
- resolve(createResponse);
841
- })
842
- .catch((error) => {
843
- if (!error || error.message !== "handled") {
844
- itemProgressCallback(sourceItemId, statusCode === common.EItemProgressStatus.Unknown ? common.EItemProgressStatus.Failed : statusCode, 0);
845
- }
846
- // Item type not supported or fails to get item dependencies
847
- resolve(common.generateEmptyCreationResponse(template.type));
848
- });
849
- });
850
- }
851
- return templateDictionary[sourceItemId].def;
852
- }
853
- exports._createItemFromTemplateWhenReady = _createItemFromTemplateWhenReady;
854
- /**
855
- * Accumulates the estimated deployment cost of a set of templates.
856
- *
857
- * @param templates Templates to examine
858
- * @returns Sum of estimated deployment costs
859
- * @private
860
- */
861
- function _estimateDeploymentCost(templates) {
862
- return templates.reduce((accumulatedEstimatedCost, template) => {
863
- return accumulatedEstimatedCost + (template.estimatedDeploymentCostFactor || 1);
864
- }, 0);
865
- }
866
- exports._estimateDeploymentCost = _estimateDeploymentCost;
867
- //TODO: function doc
868
- // TODO: Return a Promise vs array of promises
869
- function _getGroupUpdates(template, authentication, templateDictionary) {
870
- const groups = template.groups || [];
871
- return groups.map((sourceGroupId) => {
872
- return common.shareItem(templateDictionary[sourceGroupId].itemId, template.itemId, authentication, common.isTrackingViewTemplate(template) ? templateDictionary.locationTracking.owner : undefined);
873
- });
874
- }
875
- exports._getGroupUpdates = _getGroupUpdates;
876
- //# sourceMappingURL=deploySolutionItems.js.map