@esri/solution-deployer 1.1.2 → 1.2.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 (38) hide show
  1. package/dist/esm/deploySolutionFromTemplate.js +70 -66
  2. package/dist/esm/deploySolutionFromTemplate.js.map +1 -1
  3. package/dist/esm/deploySolutionItems.js +159 -166
  4. package/dist/esm/deploySolutionItems.js.map +1 -1
  5. package/dist/esm/deployer.js +13 -14
  6. package/dist/esm/deployer.js.map +1 -1
  7. package/dist/esm/deployerUtils.js +17 -22
  8. package/dist/esm/deployerUtils.js.map +1 -1
  9. package/dist/esm/helpers/post-process.js +12 -14
  10. package/dist/esm/helpers/post-process.js.map +1 -1
  11. package/dist/esm/helpers/share-templates-to-groups.js +29 -6
  12. package/dist/esm/helpers/share-templates-to-groups.js.map +1 -1
  13. package/dist/esm/helpers/sortTemplates.js +2 -4
  14. package/dist/esm/helpers/sortTemplates.js.map +1 -1
  15. package/dist/esm/module-map.js +2 -2
  16. package/dist/esm/module-map.js.map +1 -1
  17. package/dist/node/deploySolutionFromTemplate.js +76 -72
  18. package/dist/node/deploySolutionFromTemplate.js.map +1 -1
  19. package/dist/node/deploySolutionItems.js +161 -168
  20. package/dist/node/deploySolutionItems.js.map +1 -1
  21. package/dist/node/deployer.js +16 -17
  22. package/dist/node/deployer.js.map +1 -1
  23. package/dist/node/deployerUtils.js +18 -23
  24. package/dist/node/deployerUtils.js.map +1 -1
  25. package/dist/node/helpers/post-process.js +16 -18
  26. package/dist/node/helpers/post-process.js.map +1 -1
  27. package/dist/node/helpers/share-templates-to-groups.js +30 -7
  28. package/dist/node/helpers/share-templates-to-groups.js.map +1 -1
  29. package/dist/node/helpers/sortTemplates.js +2 -4
  30. package/dist/node/helpers/sortTemplates.js.map +1 -1
  31. package/dist/node/index.js +1 -1
  32. package/dist/node/module-map.js +9 -9
  33. package/dist/node/module-map.js.map +1 -1
  34. package/dist/umd/deployer.umd.js +1647 -1651
  35. package/dist/umd/deployer.umd.js.map +1 -1
  36. package/dist/umd/deployer.umd.min.js +3 -3
  37. package/dist/umd/deployer.umd.min.js.map +1 -1
  38. package/package.json +33 -33
@@ -1,7 +1,7 @@
1
1
  /* @preserve
2
- * @esri/solution-deployer - v1.1.2 - Apache-2.0
2
+ * @esri/solution-deployer - v1.2.0 - Apache-2.0
3
3
  * Copyright (c) 2018-2021 Esri, Inc.
4
- * Tue Aug 31 2021 00:03:54 GMT-0700 (Pacific Daylight Time)
4
+ * Thu Dec 09 2021 16:06:07 GMT-0800 (Pacific Standard Time)
5
5
  *
6
6
  * Licensed under the Apache License, Version 2.0 (the "License");
7
7
  * you may not use this file except in compliance with the License.
@@ -16,1666 +16,1662 @@
16
16
  * limitations under the License.
17
17
  */
18
18
  (function (global, factory) {
19
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@esri/solution-common'), require('@esri/solution-feature-layer'), require('@esri/solution-file'), require('@esri/solution-form'), require('@esri/solution-group'), require('@esri/solution-simple-types'), require('@esri/solution-storymap'), require('@esri/solution-velocity'), require('@esri/solution-web-experience'), require('@esri/solution-hub-types'), require('@esri/hub-common'), require('@esri/arcgis-rest-portal')) :
20
- typeof define === 'function' && define.amd ? define(['exports', '@esri/solution-common', '@esri/solution-feature-layer', '@esri/solution-file', '@esri/solution-form', '@esri/solution-group', '@esri/solution-simple-types', '@esri/solution-storymap', '@esri/solution-velocity', '@esri/solution-web-experience', '@esri/solution-hub-types', '@esri/hub-common', '@esri/arcgis-rest-portal'], factory) :
21
- (global = global || self, factory(global.arcgisSolution = global.arcgisSolution || {}, global.arcgisSolution, global.arcgisSolution, global.arcgisSolution, global.arcgisSolution, global.arcgisSolution, global.arcgisSolution, global.arcgisSolution, global.arcgisSolution, global.arcgisSolution, global.arcgisSolution, global.arcgisHub, global.arcgisRest));
22
- }(this, (function (exports, common, featureLayer, fileProcessor, formProcessor, group, solutionSimpleTypes, solutionStorymap, solutionVelocity, solutionWebExperience, solutionHubTypes, hubCommon, portal) { 'use strict';
19
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@esri/solution-common'), require('@esri/solution-feature-layer'), require('@esri/solution-file'), require('@esri/solution-form'), require('@esri/solution-group'), require('@esri/solution-simple-types'), require('@esri/solution-storymap'), require('@esri/solution-velocity'), require('@esri/solution-web-experience'), require('@esri/solution-hub-types'), require('@esri/hub-common'), require('@esri/arcgis-rest-portal')) :
20
+ typeof define === 'function' && define.amd ? define(['exports', '@esri/solution-common', '@esri/solution-feature-layer', '@esri/solution-file', '@esri/solution-form', '@esri/solution-group', '@esri/solution-simple-types', '@esri/solution-storymap', '@esri/solution-velocity', '@esri/solution-web-experience', '@esri/solution-hub-types', '@esri/hub-common', '@esri/arcgis-rest-portal'], factory) :
21
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.arcgisSolution = global.arcgisSolution || {}, global.arcgisSolution, global.arcgisSolution, global.arcgisSolution, global.arcgisSolution, global.arcgisSolution, global.arcgisSolution, global.arcgisSolution, global.arcgisSolution, global.arcgisSolution, global.arcgisSolution, global.arcgisHub, global.arcgisRest));
22
+ })(this, (function (exports, common, featureLayer, fileProcessor, formProcessor, group, solutionSimpleTypes, solutionStorymap, solutionVelocity, solutionWebExperience, solutionHubTypes, hubCommon, portal) { 'use strict';
23
23
 
24
- /*! *****************************************************************************
25
- Copyright (c) Microsoft Corporation. All rights reserved.
26
- Licensed under the Apache License, Version 2.0 (the "License"); you may not use
27
- this file except in compliance with the License. You may obtain a copy of the
28
- License at http://www.apache.org/licenses/LICENSE-2.0
29
-
30
- THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
31
- KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
32
- WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
33
- MERCHANTABLITY OR NON-INFRINGEMENT.
34
-
35
- See the Apache Version 2.0 License for specific language governing permissions
36
- and limitations under the License.
37
- ***************************************************************************** */
38
-
39
- var __assign = function() {
40
- __assign = Object.assign || function __assign(t) {
41
- for (var s, i = 1, n = arguments.length; i < n; i++) {
42
- s = arguments[i];
43
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
44
- }
45
- return t;
46
- };
47
- return __assign.apply(this, arguments);
48
- };
49
-
50
- function __read(o, n) {
51
- var m = typeof Symbol === "function" && o[Symbol.iterator];
52
- if (!m) return o;
53
- var i = m.call(o), r, ar = [], e;
54
- try {
55
- while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
56
- }
57
- catch (error) { e = { error: error }; }
58
- finally {
59
- try {
60
- if (r && !r.done && (m = i["return"])) m.call(i);
61
- }
62
- finally { if (e) throw e.error; }
63
- }
64
- return ar;
24
+ function _interopNamespace(e) {
25
+ if (e && e.__esModule) return e;
26
+ var n = Object.create(null);
27
+ if (e) {
28
+ Object.keys(e).forEach(function (k) {
29
+ if (k !== 'default') {
30
+ var d = Object.getOwnPropertyDescriptor(e, k);
31
+ Object.defineProperty(n, k, d.get ? d : {
32
+ enumerable: true,
33
+ get: function () { return e[k]; }
34
+ });
35
+ }
36
+ });
65
37
  }
38
+ n["default"] = e;
39
+ return Object.freeze(n);
40
+ }
66
41
 
67
- /** @license
68
- * Copyright 2020 Esri
69
- *
70
- * Licensed under the Apache License, Version 2.0 (the "License");
71
- * you may not use this file except in compliance with the License.
72
- * You may obtain a copy of the License at
73
- *
74
- * http://www.apache.org/licenses/LICENSE-2.0
75
- *
76
- * Unless required by applicable law or agreed to in writing, software
77
- * distributed under the License is distributed on an "AS IS" BASIS,
78
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
79
- * See the License for the specific language governing permissions and
80
- * limitations under the License.
81
- */
82
- var UNSUPPORTED = null;
83
- /**
84
- * Mapping from item type to module with type-specific template-handling code.
85
- * AGO types come from a blend of arcgis-portal-app\src\js\arcgisonline\pages\item\_Info.js and
86
- * arcgis-portal-app\src\js\arcgis-components\src\_utils\metadata\item\displayName.ts
87
- */
88
- var moduleMap = {
89
- ////////////////////////////////////////////////////////
90
- // Group type
91
- Group: group,
92
- ////////////////////////////////////////////////////////
93
- // Layer types
94
- "Big Data Analytic": solutionVelocity.VelocityProcessor,
95
- "Feature Collection": solutionSimpleTypes.simpleTypes,
96
- "Feature Service": featureLayer,
97
- Feed: solutionVelocity.VelocityProcessor,
98
- "Geocoding Service": undefined,
99
- "Geodata Service": undefined,
100
- "Geometry Service": undefined,
101
- "Geoprocessing Service": undefined,
102
- "Globe Service": undefined,
103
- "Image Service": undefined,
104
- KML: undefined,
105
- "Map Service": featureLayer,
106
- "Network Analysis Service": undefined,
107
- "Real Time Analytic": solutionVelocity.VelocityProcessor,
108
- "Relational Database Connection": undefined,
109
- "Scene Service": undefined,
110
- "Stream Service": undefined,
111
- Tool: undefined,
112
- "Vector Tile Service": undefined,
113
- WFS: undefined,
114
- WMS: undefined,
115
- WMTS: undefined,
116
- "Workflow Manager Service": undefined,
117
- ////////////////////////////////////////////////////////
118
- // Map types
119
- "3D Web Scene": undefined,
120
- "Web Map": solutionSimpleTypes.simpleTypes,
121
- "Web Scene": solutionSimpleTypes.simpleTypes,
122
- ////////////////////////////////////////////////////////
123
- // App types
124
- Application: undefined,
125
- Dashboard: solutionSimpleTypes.simpleTypes,
126
- "Data Store": undefined,
127
- "Desktop Application": undefined,
128
- "Excalibur Imagery Project": undefined,
129
- Form: formProcessor,
130
- "Hub Initiative": UNSUPPORTED,
131
- "Hub Page": solutionHubTypes.HubPageProcessor,
132
- "Hub Site Application": solutionHubTypes.HubSiteProcessor,
133
- "Insights Model": solutionSimpleTypes.simpleTypes,
134
- "Insights Page": undefined,
135
- "Insights Theme": undefined,
136
- "Insights Workbook": undefined,
137
- Mission: undefined,
138
- "Mobile Application": undefined,
139
- Notebook: solutionSimpleTypes.notebookProcessor,
140
- "Oriented Imagery Catalog": solutionSimpleTypes.simpleTypes,
141
- "Ortho Mapping Project": undefined,
142
- "QuickCapture Project": solutionSimpleTypes.quickcaptureProcessor,
143
- "Site Application": solutionHubTypes.HubSiteProcessor,
144
- "Site Page": solutionHubTypes.HubPageProcessor,
145
- Solution: UNSUPPORTED,
146
- StoryMap: solutionStorymap.StoryMapProcessor,
147
- "Urban Model": undefined,
148
- "Web Experience Template": undefined,
149
- "Web Experience": solutionWebExperience.WebExperienceProcessor,
150
- "Web Mapping Application": solutionSimpleTypes.simpleTypes,
151
- "Workforce Project": solutionSimpleTypes.simpleTypes,
152
- ////////////////////////////////////////////////////////
153
- // File types
154
- "360 VR Experience": fileProcessor,
155
- "AppBuilder Extension": fileProcessor,
156
- "AppBuilder Widget Package": fileProcessor,
157
- "Application Configuration": fileProcessor,
158
- "ArcGIS Pro Add In": fileProcessor,
159
- "ArcGIS Pro Configuration": fileProcessor,
160
- "ArcPad Package": fileProcessor,
161
- "Basemap Package": fileProcessor,
162
- "CAD Drawing": fileProcessor,
163
- "CityEngine Web Scene": fileProcessor,
164
- "Code Attachment": UNSUPPORTED,
165
- "Code Sample": fileProcessor,
166
- "Color Set": fileProcessor,
167
- "Compact Tile Package": fileProcessor,
168
- "CSV Collection": fileProcessor,
169
- CSV: fileProcessor,
170
- "Deep Learning Package": fileProcessor,
171
- "Desktop Add In": fileProcessor,
172
- "Desktop Application Template": fileProcessor,
173
- "Desktop Style": fileProcessor,
174
- "Document Link": fileProcessor,
175
- "Explorer Add In": fileProcessor,
176
- "Explorer Layer": fileProcessor,
177
- "Explorer Map": fileProcessor,
178
- "Feature Collection Template": fileProcessor,
179
- "File Geodatabase": fileProcessor,
180
- GeoJson: fileProcessor,
181
- GeoPackage: fileProcessor,
182
- "Geoprocessing Package": fileProcessor,
183
- "Geoprocessing Sample": fileProcessor,
184
- "Globe Document": fileProcessor,
185
- "Image Collection": fileProcessor,
186
- Image: fileProcessor,
187
- "iWork Keynote": fileProcessor,
188
- "iWork Numbers": fileProcessor,
189
- "iWork Pages": fileProcessor,
190
- "KML Collection": fileProcessor,
191
- "Layer Package": fileProcessor,
192
- "Layer Template": fileProcessor,
193
- Layer: fileProcessor,
194
- Layout: fileProcessor,
195
- "Locator Package": fileProcessor,
196
- "Map Document": fileProcessor,
197
- "Map Package": fileProcessor,
198
- "Map Template": fileProcessor,
199
- "Microsoft Excel": fileProcessor,
200
- "Microsoft Powerpoint": fileProcessor,
201
- "Microsoft Word": fileProcessor,
202
- "Mobile Basemap Package": fileProcessor,
203
- "Mobile Map Package": fileProcessor,
204
- "Mobile Scene Package": fileProcessor,
205
- "Native Application": fileProcessor,
206
- "Native Application Installer": fileProcessor,
207
- "Native Application Template": fileProcessor,
208
- netCDF: fileProcessor,
209
- "Operation View": fileProcessor,
210
- "Operations Dashboard Add In": fileProcessor,
211
- "Operations Dashboard Extension": fileProcessor,
212
- PDF: fileProcessor,
213
- "Pro Layer Package": fileProcessor,
214
- "Pro Layer": fileProcessor,
215
- "Pro Map Package": fileProcessor,
216
- "Pro Map": fileProcessor,
217
- "Pro Report": fileProcessor,
218
- "Project Package": fileProcessor,
219
- "Project Template": fileProcessor,
220
- "Published Map": fileProcessor,
221
- "Raster function template": fileProcessor,
222
- "Report Template": fileProcessor,
223
- "Rule Package": fileProcessor,
224
- "Scene Document": fileProcessor,
225
- "Scene Package": fileProcessor,
226
- "Service Definition": fileProcessor,
227
- Shapefile: fileProcessor,
228
- "Statistical Data Collection": fileProcessor,
229
- Style: fileProcessor,
230
- "Survey123 Add In": fileProcessor,
231
- "Symbol Set": fileProcessor,
232
- "Task File": fileProcessor,
233
- "Tile Package": fileProcessor,
234
- "Toolbox Package": fileProcessor,
235
- "Vector Tile Package": fileProcessor,
236
- "Viewer Configuration": fileProcessor,
237
- "Visio Document": fileProcessor,
238
- "Window Mobile Package": fileProcessor,
239
- "Windows Mobile Package": fileProcessor,
240
- "Windows Viewer Add In": fileProcessor,
241
- "Windows Viewer Configuration": fileProcessor,
242
- "Workflow Manager Package": fileProcessor,
243
- ////////////////////////////////////////////////////////
244
- // Testing "types"
245
- Undefined: undefined,
246
- Unsupported: UNSUPPORTED
247
- };
42
+ var common__namespace = /*#__PURE__*/_interopNamespace(common);
43
+ var featureLayer__namespace = /*#__PURE__*/_interopNamespace(featureLayer);
44
+ var fileProcessor__namespace = /*#__PURE__*/_interopNamespace(fileProcessor);
45
+ var formProcessor__namespace = /*#__PURE__*/_interopNamespace(formProcessor);
46
+ var group__namespace = /*#__PURE__*/_interopNamespace(group);
47
+ var portal__namespace = /*#__PURE__*/_interopNamespace(portal);
248
48
 
249
- /** @license
250
- * Copyright 2018 Esri
251
- *
252
- * Licensed under the Apache License, Version 2.0 (the "License");
253
- * you may not use this file except in compliance with the License.
254
- * You may obtain a copy of the License at
255
- *
256
- * http://www.apache.org/licenses/LICENSE-2.0
257
- *
258
- * Unless required by applicable law or agreed to in writing, software
259
- * distributed under the License is distributed on an "AS IS" BASIS,
260
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
261
- * See the License for the specific language governing permissions and
262
- * limitations under the License.
263
- */
264
- var UNSUPPORTED$1 = null;
265
- // ------------------------------------------------------------------------------------------------------------------ //
266
- /**
267
- * Deploys a set of items defined by templates.
268
- *
269
- * @param portalSharingUrl Server/sharing
270
- * @param storageItemId Id of storage item
271
- * @param templates A collection of AGO item templates
272
- * @param storageAuthentication Credentials for the organization with the source items
273
- * @param templateDictionary Hash of facts: org URL, adlib replacements
274
- * @param deployedSolutionId Id of deployed Solution item
275
- * @param destinationAuthentication Credentials for the destination organization
276
- * @param options Options to tune deployment
277
- * @return A promise that will resolve with the list of information about the created items
278
- */
279
- function deploySolutionItems(portalSharingUrl, storageItemId, templates, storageAuthentication, templateDictionary, deployedSolutionId, destinationAuthentication, options) {
280
- return new Promise(function (resolve, reject) {
281
- var _a;
282
- // Prepare feedback mechanism
283
- var totalEstimatedCost = _estimateDeploymentCost(templates) + 1; // solution items, plus avoid divide by 0
284
- var percentDone = 10; // allow for previous deployment work
285
- var progressPercentStep = (99 - percentDone) / totalEstimatedCost; // leave some % for caller for wrapup
286
- var failedTemplateItemIds = [];
287
- var deployedItemIds = [];
288
- var statusOK = true;
289
- // TODO: move to separate fn
290
- var itemProgressCallback = function (itemId, status, costUsed, createdItemId // supplied when status is EItemProgressStatus.Created or .Finished
291
- ) {
292
- var _a;
293
- percentDone += progressPercentStep * costUsed;
294
- /* istanbul ignore else */
295
- if (options.progressCallback) {
296
- if (status === common.EItemProgressStatus.Finished) {
297
- var event_1 = {
298
- event: common.SItemProgressStatus[status],
299
- data: itemId
300
- };
301
- options.progressCallback(Math.round(percentDone), options.jobId, event_1);
302
- }
303
- else {
304
- options.progressCallback(Math.round(percentDone), options.jobId);
305
- }
306
- }
307
- /* istanbul ignore if */
308
- if (options.consoleProgress) {
309
- console.log(Date.now(), itemId, (_a = options.jobId) !== null && _a !== void 0 ? _a : "", common.SItemProgressStatus[status], percentDone.toFixed(0) + "%", costUsed, createdItemId ? "==> " + createdItemId : "");
310
- }
311
- if (status === common.EItemProgressStatus.Created) {
312
- deployedItemIds.push(createdItemId);
313
- }
314
- else if (status === common.EItemProgressStatus.Failed) {
315
- failedTemplateItemIds.push(itemId);
316
- console.error("Item " + itemId + " has failed");
317
- statusOK = false;
318
- }
319
- return statusOK;
320
- // ---------------------------------------------------------------------------------------------------------------
321
- };
322
- // portal does not allow views of a single source to be created at the same time
323
- if (common.getProp(templateDictionary, "organization.isPortal")) {
324
- templates = _evaluateSharedViewSources(templates);
325
- }
326
- // Create an ordered graph of the templates so that dependencies are created before the items that need them.
327
- // Because cycles are permitted, we also keep track of items that need to be patched later because their
328
- // dependencies are necessarily created after they are created.
329
- var _b = common.topologicallySortItems(templates), buildOrder = _b.buildOrder, itemsToBePatched = _b.itemsToBePatched;
330
- // For each item in order from no dependencies to dependent on other items,
331
- // * replace template symbols using template dictionary
332
- // * create item in destination group
333
- // * add created item's id into the template dictionary
334
- var awaitAllItems = [];
335
- var reuseItemsDef = _reuseDeployedItems(templates, (_a = options.enableItemReuse) !== null && _a !== void 0 ? _a : false, templateDictionary, destinationAuthentication);
336
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
337
- reuseItemsDef.then(function () {
338
- var useExistingItemsDef = _useExistingItems(templates, common.getProp(templateDictionary, "params.useExisting"), templateDictionary, destinationAuthentication);
339
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
340
- useExistingItemsDef.then(function () {
341
- templates = common.setNamesAndTitles(templates, templateDictionary.solutionItemId);
342
- buildOrder.forEach(function (id) {
343
- // Get the item's template out of the list of templates
344
- var template = common.findTemplateInList(templates, id);
345
- awaitAllItems.push(_createItemFromTemplateWhenReady(template, common.generateStorageFilePaths(portalSharingUrl, storageItemId, template.resources, options.storageVersion), storageAuthentication, templateDictionary, destinationAuthentication, itemProgressCallback));
346
- });
347
- // Wait until all items have been created
348
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
349
- Promise.all(awaitAllItems).then(function (clonedSolutionItems) {
350
- if (failedTemplateItemIds.length === 0) {
351
- // Do we have any items to be patched (i.e., they refer to dependencies using the template id rather
352
- // than the cloned id because the item had to be created before the dependency)? Flag these items
353
- // for post processing in the list of clones.
354
- _flagPatchItemsForPostProcessing(itemsToBePatched, templateDictionary, clonedSolutionItems);
355
- resolve(clonedSolutionItems);
356
- }
357
- else {
358
- // Delete created items
359
- var progressOptions = {
360
- consoleProgress: true
361
- };
362
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
363
- common.deleteSolutionByComponents(deployedSolutionId, deployedItemIds, templates, templateDictionary, destinationAuthentication, progressOptions)
364
- .then(function () {
365
- return reject(common.failWithIds(failedTemplateItemIds));
366
- });
367
- }
368
- });
369
- });
370
- }, function (e) {
371
- console.error(e);
372
- reject(common.fail(e));
373
- });
374
- });
375
- }
376
- /**
377
- * For each item to be patched, convert it to its cloned id and mark the item as needing post processing.
378
- *
379
- * @param itemsToBePatched List of items that need to have their dependencies patched
380
- * @param templateDictionary Hash of facts: org URL, adlib replacements
381
- * @param templates A collection of AGO item templates
382
- */
383
- function _flagPatchItemsForPostProcessing(itemsToBePatched, templateDictionary, templates) {
384
- var itemIdsToBePatched = Object.keys(itemsToBePatched);
385
- /* istanbul ignore else */
386
- if (itemIdsToBePatched.length > 0) {
387
- // Replace the ids of the items to be patched (which are template ids) with their cloned versions
388
- itemIdsToBePatched = itemIdsToBePatched.map(function (id) { return templateDictionary[id].itemId; });
389
- // Make sure that the items to be patched are flagged for post processing
390
- templates.forEach(function (item) {
391
- /* istanbul ignore else */
392
- if (itemIdsToBePatched.includes(item.id)) {
393
- item.postProcess = true;
394
- }
395
- });
396
- }
397
- }
398
- /**
399
- * Portal does not allow views of a single source to be created at the same time.
400
- *
401
- * Update view templates with an array of other view template ids that it should wait on.
402
- *
403
- * @param templates a collection of AGO item templates
404
- *
405
- * @returns An updated array of item templates
406
- *
407
- */
408
- function _evaluateSharedViewSources(templates) {
409
- // update the templates so we can defer the deployment when more than one view shares the same source
410
- // these are not classic dependencies but are in some ways similar
411
- var views = _getViews(templates);
412
- _updateViewTemplates(templates, views);
413
- var viewHash = _getViewHash(views);
414
- var processed = [];
415
- var visited = [];
416
- Object.keys(viewHash).forEach(function (k) {
417
- var _views = viewHash[k];
418
- _views.forEach(function (cv) {
419
- var template = common.findTemplateInList(templates, cv);
420
- var syncViews = common.getProp(template, "properties.syncViews");
421
- /* istanbul ignore else */
422
- if (visited.indexOf(template.itemId) > -1) {
423
- processed = processed.concat(syncViews);
424
- }
425
- /* istanbul ignore else */
426
- if (syncViews && syncViews.length > 0) {
427
- // when a view has multiple dependencies we need to retain the syncViews if they have been set already...
428
- common.setProp(template, "properties.syncViews", common.cloneObject(processed));
429
- }
430
- /* istanbul ignore else */
431
- if (processed.indexOf(cv) < 0) {
432
- processed.push(cv);
433
- }
434
- /* istanbul ignore else */
435
- if (visited.indexOf(template.itemId) < 0) {
436
- visited.push(template.itemId);
437
- }
438
- });
439
- processed = [];
440
- });
441
- return templates;
442
- }
443
- /**
444
- * Add a syncViews array to each template that will hold all other view ids that
445
- * have the same FS dependency.
446
- * These arrays will be processed later to only contain ids that each view will need to wait on.
447
- *
448
- * @param templates a collection of AGO item templates
449
- * @param views an array of view template details
450
- *
451
- * @returns An updated array of item templates
452
- *
453
- */
454
- function _updateViewTemplates(templates, views) {
455
- views.forEach(function (v) {
456
- v.dependencies.forEach(function (id) {
457
- templates = templates.map(function (t) {
458
- /* istanbul ignore else */
459
- if (common.getProp(t, "properties.service.isView") &&
460
- t.dependencies.indexOf(id) > -1 &&
461
- t.itemId !== v.id) {
462
- /* istanbul ignore else */
463
- if (!Array.isArray(t.properties.syncViews)) {
464
- t.properties.syncViews = [];
465
- }
466
- /* istanbul ignore else */
467
- if (t.properties.syncViews.indexOf(v.id) < 0) {
468
- t.properties.syncViews.push(v.id);
469
- }
470
- }
471
- return t;
472
- });
473
- });
474
- });
475
- return templates;
476
- }
477
- /**
478
- * Get all view templates from the source templates collection
479
- *
480
- * @param views A collection of view ID and dependencies
481
- *
482
- * @returns an array of objects with the source FS id as the key and a list of views that are
483
- * dependant upon it
484
- *
485
- * @protected
486
- */
487
- function _getViewHash(views) {
488
- var viewHash = {};
489
- views.forEach(function (v) {
490
- v.dependencies.forEach(function (d) {
491
- /* istanbul ignore else */
492
- if (Object.keys(viewHash).indexOf(d) < 0) {
493
- viewHash[d] = [v.id];
494
- }
495
- else if (viewHash[d].indexOf(v.id) < 0) {
496
- viewHash[d].push(v.id);
497
- }
498
- });
499
- });
500
- return viewHash;
501
- }
502
- /**
503
- * Get all view templates from the source templates collection
504
- *
505
- * @param templates A collection of AGO item templates
506
- *
507
- * @returns an array with the view id and its dependencies
508
- *
509
- * @protected
510
- */
511
- function _getViews(templates) {
512
- return templates.reduce(function (acc, v) {
513
- /* istanbul ignore else */
514
- if (common.getProp(v, "properties.service.isView")) {
515
- acc.push({
516
- id: v.itemId,
517
- dependencies: v.dependencies
518
- });
519
- }
520
- return acc;
521
- }, []);
522
- }
523
- /**
524
- * Search for existing items and update the templateDictionary with key details
525
- *
526
- * @param templates A collection of AGO item templates
527
- * @param reuseItems Option to search for existing items
528
- * @param templateDictionary Hash of facts: org URL, adlib replacements, deferreds for dependencies
529
- * @param authentication Credentials for the requests
530
- *
531
- * @returns A Promise that will resolve once existing items have been evaluated
532
- *
533
- * @protected
534
- */
535
- function _reuseDeployedItems(templates, reuseItems, templateDictionary, authentication) {
536
- return new Promise(function (resolve, reject) {
537
- if (reuseItems) {
538
- var existingItemsByKeyword = _findExistingItemByKeyword(templates, templateDictionary, authentication);
539
- Promise.all(existingItemsByKeyword).then(function (existingItemsByKeywordResponse) {
540
- var existingItemsByTag = _handleExistingItems(existingItemsByKeywordResponse, templateDictionary, authentication, true);
541
- Promise.all(existingItemsByTag).then(function (existingItemsByTagResponse) {
542
- _handleExistingItems(existingItemsByTagResponse, templateDictionary, authentication, false);
543
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
544
- _updateTemplateDictionary(templates, templateDictionary, authentication).then(resolve);
545
- }, function (e) { return reject(common.fail(e)); });
546
- }, function (e) { return reject(common.fail(e)); });
547
- }
548
- else {
549
- resolve(null);
550
- }
551
- });
552
- }
553
- /**
554
- * Search for existing items and update the templateDictionary with key details
555
- *
556
- * Subtle difference between _reuseDeployedItems and _useExistingItems
557
- * _reuseDeployedItems: will search all existing items based on specific type keywords
558
- * that would have been added by a previous deployment
559
- * _useExistingItems: will search for an existing item that the user provided
560
- * the item id for while configuring in the deployment app.
561
- * This type of item would not necessarily have been laid down by a previous deployment and
562
- * can thus not expect that it will have the type keywords
563
- *
564
- * @param templates A collection of AGO item templates
565
- * @param useExisting Option to search for existing items
566
- * @param templateDictionary Hash of facts: org URL, adlib replacements, deferreds for dependencies
567
- * @param authentication Credentials for the requests
568
- *
569
- * @returns A Promise that will resolve once existing items have been evaluated
570
- *
571
- * @protected
572
- */
573
- function _useExistingItems(templates, useExisting, templateDictionary, authentication) {
574
- return new Promise(function (resolve) {
575
- if (useExisting) {
576
- var itemDefs_1 = [];
577
- var sourceIdHash_1 = {};
578
- var itemIds_1 = [];
579
- Object.keys(templateDictionary.params).forEach(function (k) {
580
- var v = templateDictionary.params[k];
581
- /* istanbul ignore else */
582
- if (v.itemId && /[0-9A-F]{32}/i.test(k)) {
583
- _updateTemplateDictionaryById(templateDictionary, k, v.itemId, v);
584
- // need to check and set the typeKeyword if it doesn't exist on this service yet
585
- // when the user has passed in an itemId that does not come from a previous deployment
586
- itemDefs_1.push(common.getItemBase(v.itemId, authentication));
587
- sourceIdHash_1[v.itemId] = k;
588
- /* istanbul ignore else */
589
- if (itemIds_1.indexOf(k) < 0) {
590
- itemIds_1.push(k);
591
- }
592
- }
593
- });
594
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
595
- _setTypekeywordForExisting(itemDefs_1, sourceIdHash_1, authentication).then(function () {
596
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
597
- _updateTemplateDictionary(itemIds_1.map(function (id) { return common.getTemplateById(templates, id); }), templateDictionary, authentication).then(resolve);
598
- });
599
- }
600
- else {
601
- resolve(null);
602
- }
603
- });
604
- }
605
- /**
606
- * Verify if the existing item has the source-<itemId> typeKeyword and set it if not
607
- * This allows items that did not come from deployment to be found for reuse after they
608
- * have been used once via a custom itemId param
609
- *
610
- * @param itemDefs
611
- * @param sourceIdHash key value pairs..actual itemId is the key and the source itemId is the value
612
- * @param authentication credentials for the requests
613
- *
614
- * @return a promise to indicate when the requests are complete
615
- */
616
- function _setTypekeywordForExisting(itemDefs, sourceIdHash, authentication) {
617
- return new Promise(function (resolve) {
618
- if (itemDefs.length > 0) {
619
- Promise.all(itemDefs).then(function (results) {
620
- var itemUpdateDefs = [];
621
- results.forEach(function (result) {
622
- var sourceId = sourceIdHash[result.id];
623
- /* istanbul ignore else */
624
- if (result && sourceId && result.typeKeywords) {
625
- var sourceKeyword = "source-" + sourceId;
626
- var typeKeywords = result.typeKeywords;
627
- /* istanbul ignore else */
628
- if (typeKeywords.indexOf(sourceKeyword) < 0) {
629
- typeKeywords.push(sourceKeyword);
630
- var itemUpdate = { id: result.id, typeKeywords: typeKeywords };
631
- itemUpdateDefs.push(common.updateItem(itemUpdate, authentication));
632
- }
633
- }
634
- });
635
- // wait for updates to finish before we resolve
636
- if (itemUpdateDefs.length > 0) {
637
- Promise.all(itemUpdateDefs).then(resolve, function () { return resolve(undefined); });
638
- }
639
- else {
640
- resolve(undefined);
641
- }
642
- }, function () { return resolve(undefined); });
643
- }
644
- else {
645
- resolve(undefined);
646
- }
647
- });
648
- }
649
- /**
650
- * Update the templateDictionary with key details by item type
651
- *
652
- * @param templates A collection of AGO item templates
653
- * @param templateDictionary Hash of facts: org URL, adlib replacements, deferreds for dependencies
654
- *
655
- * @protected
656
- */
657
- function _updateTemplateDictionary(templates, templateDictionary, authentication) {
658
- return new Promise(function (resolve) {
659
- var defs = [];
660
- var urls = [];
661
- var types = [];
662
- var ids = [];
663
- templates.forEach(function (t) {
664
- var templateInfo = templateDictionary[t.itemId];
665
- /* istanbul ignore else */
666
- if (templateInfo && templateInfo.url && templateInfo.itemId) {
667
- /* istanbul ignore else */
668
- if (t.item.type === "Feature Service") {
669
- var enterpriseIDMapping = common.getProp(templateDictionary, "params." + t.itemId + ".enterpriseIDMapping");
670
- Object.assign(templateDictionary[t.itemId], common.getLayerSettings(common.getLayersAndTables(t), templateInfo.url, templateInfo.itemId, enterpriseIDMapping));
671
- // if the service has veiws keep track of the fields so we can use them to
672
- // compare with the view fields
673
- /* istanbul ignore else */
674
- if (common.getProp(t, "properties.service.hasViews")) {
675
- common._updateTemplateDictionaryFields(t, templateDictionary, false);
676
- }
677
- }
678
- // for fs query with its url...for non fs query the item
679
- // this is to verify situations where we have a stale search index that will
680
- // say some items exist when they don't really exist
681
- // searching the services url or with the item id will return an error when this condition occurs
682
- /* istanbul ignore else */
683
- if (urls.indexOf(templateInfo.url) < 0) {
684
- defs.push(t.item.type === "Feature Service"
685
- ? common.rest_request(templateInfo.url, { authentication: authentication })
686
- : common.getItemBase(templateInfo.itemId, authentication));
687
- urls.push(templateInfo.url);
688
- types.push(t.item.type);
689
- ids.push(templateInfo.itemId);
690
- }
691
- }
692
- });
693
- if (defs.length > 0) {
694
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
695
- Promise.all(defs.map(function (p) { return p.catch(function (e) { return e; }); })).then(function (results) {
696
- /* istanbul ignore else */
697
- if (Array.isArray(results) && results.length > 0) {
698
- var fieldDefs_1 = [];
699
- results.forEach(function (r, i) {
700
- // a feature service result will contain a serviceItemId if it was successfully fetched
701
- if (r.serviceItemId && types[i] === "Feature Service") {
702
- Object.keys(templateDictionary).forEach(function (k) {
703
- var v = templateDictionary[k];
704
- /* istanbul ignore else */
705
- if (v.itemId && v.itemId === r.serviceItemId) {
706
- common.setDefaultSpatialReference(templateDictionary, k, r.spatialReference);
707
- // keep the extent values from these responses as well
708
- common.setCreateProp(templateDictionary, k + ".defaultExtent", r.fullExtent || r.initialExtent);
709
- var layerIds = (r.layers || []).map(function (l) { return l.id; });
710
- var tablesIds = (r.tables || []).map(function (t) { return t.id; });
711
- fieldDefs_1.push(common.getExistingLayersAndTables(urls[i], layerIds.concat(tablesIds), authentication));
712
- }
713
- });
714
- }
715
- else {
716
- /* istanbul ignore else */
717
- if (types[i] === "Feature Service" ||
718
- common.getProp(r, "response.error")) {
719
- // if an error is returned we need to clean up the templateDictionary
720
- templateDictionary = _updateTemplateDictionaryForError(templateDictionary, ids[i]);
721
- }
722
- }
723
- });
724
- if (fieldDefs_1.length > 0) {
725
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
726
- Promise.all(fieldDefs_1).then(function (layerTableResult) {
727
- layerTableResult.forEach(function (l) {
728
- l.forEach(function (ll) {
729
- Object.keys(templateDictionary).forEach(function (k) {
730
- /* istanbul ignore else */
731
- if (templateDictionary[k].itemId === ll.serviceItemId) {
732
- var sourceId_1 = "";
733
- Object.keys(templateDictionary).some(function (_k) {
734
- /* istanbul ignore else */
735
- if (templateDictionary[_k].itemId === ll.serviceItemId) {
736
- sourceId_1 = _k;
737
- return true;
738
- }
739
- });
740
- var enterpriseIDMapping_1 = common.getProp(templateDictionary, "params." + sourceId_1 + ".enterpriseIDMapping");
741
- if (enterpriseIDMapping_1) {
742
- Object.keys(enterpriseIDMapping_1).forEach(function (id) {
743
- if (enterpriseIDMapping_1[id].toString() ===
744
- ll.id.toString()) {
745
- _setFields(templateDictionary, k, id, ll.fields);
746
- }
747
- });
748
- }
749
- else {
750
- _setFields(templateDictionary, k, ll.id, ll.fields);
751
- }
752
- }
753
- });
754
- });
755
- });
756
- resolve(null);
757
- });
758
- }
759
- else {
760
- resolve(null);
761
- }
762
- }
763
- else {
764
- resolve(null);
765
- }
766
- });
767
- }
768
- else {
769
- resolve(null);
770
- }
771
- });
772
- }
773
- /**
774
- * Add the fields from the source layer to the template dictionary for any required replacements
775
- *
776
- * @param templateDictionary Hash of facts: org URL, adlib replacements, deferreds for dependencies
777
- * @param itemId the id for the item
778
- * @param layerId the id for the layer
779
- * @param fields the fields to transfer
780
- *
781
- * @protected
782
- */
783
- function _setFields(templateDictionary, itemId, layerId, fields) {
784
- var layerInfo = common.getProp(templateDictionary, itemId + ".layer" + layerId);
785
- /* istanbul ignore else */
786
- if (layerInfo && fields) {
787
- layerInfo.fields = fields;
788
- }
789
- }
790
- /**
791
- * In some cases an item id search will return a stale item reference
792
- * it will subsequently fail when we try to fetch the underlying service.
793
- *
794
- * We need to remove the item info that has been added to the template dictionary
795
- * and treat the item as we do other items that don't already exist on deployment.
796
- *
797
- * @param result the service request result
798
- * @param templateDictionary Hash of facts: org URL, adlib replacements, deferreds for dependencies
799
- *
800
- * @protected
801
- */
802
- function _updateTemplateDictionaryForError(templateDictionary, itemId) {
803
- /* istanbul ignore else */
804
- if (itemId) {
805
- var removeKey_1 = "";
806
- Object.keys(templateDictionary).some(function (k) {
807
- /* istanbul ignore else */
808
- if (templateDictionary[k].itemId === itemId) {
809
- removeKey_1 = k;
810
- return true;
811
- }
812
- });
813
- /* istanbul ignore else */
814
- if (removeKey_1 !== "") {
815
- delete templateDictionary[removeKey_1];
816
- }
817
- }
818
- return templateDictionary;
819
- }
820
- /**
821
- * Optionally search by tags and then update the templateDictionary based on the search results
822
- *
823
- * @param existingItemsResponse response object from search by typeKeyword and type
824
- * @param templateDictionary Hash of facts: org URL, adlib replacements, deferreds for dependencies
825
- * @param authentication Credentials for the request
826
- * @param addTagQuery Boolean to indicate if a search by tag should happen
827
- * @return A promise that will resolve with an array of results
828
- * @protected
829
- */
830
- function _handleExistingItems(existingItemsResponse, templateDictionary, authentication, addTagQuery) {
831
- // if items are not found by type keyword search by tag
832
- var existingItemsByTag = [Promise.resolve(null)];
833
- /* istanbul ignore else */
834
- if (existingItemsResponse && Array.isArray(existingItemsResponse)) {
835
- existingItemsResponse.forEach(function (existingItem) {
836
- /* istanbul ignore else */
837
- if (Array.isArray(existingItem === null || existingItem === void 0 ? void 0 : existingItem.results)) {
838
- var result = void 0;
839
- var results = existingItem.results;
840
- if (results.length === 1) {
841
- result = results[0];
842
- }
843
- else if (results.length > 1) {
844
- result = results.reduce(function (a, b) {
845
- return a.created > b.created ? a : b;
846
- });
847
- }
848
- else {
849
- if (addTagQuery && existingItem.query) {
850
- var tagQuery = existingItem.query.replace("typekeywords", "tags");
851
- existingItemsByTag.push(_findExistingItem(tagQuery, authentication));
852
- }
853
- }
854
- if (result) {
855
- var sourceId = existingItem.query
856
- ? existingItem.query.match(/[0-9A-F]{32}/i)[0]
857
- : existingItem.sourceId;
858
- /* istanbul ignore else */
859
- if (sourceId) {
860
- _updateTemplateDictionaryById(templateDictionary, sourceId, result.id, result);
861
- }
862
- }
863
- }
864
- });
865
- }
866
- return existingItemsByTag;
867
- }
868
- function _updateTemplateDictionaryById(templateDictionary, sourceId, itemId, v) {
869
- templateDictionary[sourceId] = Object.assign(templateDictionary[sourceId] || {}, {
870
- def: Promise.resolve(common.generateEmptyCreationResponse(v.type, itemId)),
871
- itemId: itemId,
872
- name: v.name,
873
- title: v.title,
874
- url: v.url
875
- });
876
- }
877
- /**
878
- * Search items based on user query
879
- *
880
- * @param query Query string to use
881
- * @param authentication Credentials for the request
882
- * @return A promise that will resolve with an array of results
883
- * @protected
884
- */
885
- function _findExistingItemByKeyword(templates, templateDictionary, authentication) {
886
- var existingItemsDefs = [];
887
- templates.forEach(function (template) {
888
- var _a;
889
- if (template.item.type === "Group") {
890
- var userGroups = (_a = templateDictionary.user) === null || _a === void 0 ? void 0 : _a.groups;
891
- /* istanbul ignore else */
892
- if (Array.isArray(userGroups)) {
893
- existingItemsDefs.push(Promise.resolve({
894
- results: userGroups
895
- .filter(function (g) { return g.tags.indexOf("source-" + template.itemId) > -1; })
896
- .map(function (g) {
897
- g.type = "Group";
898
- return g;
899
- }),
900
- sourceId: template.itemId
901
- }));
902
- }
903
- }
904
- else {
905
- existingItemsDefs.push(_findExistingItem("typekeywords:source-" + template.itemId + " type:" + template.item.type + " owner:" + templateDictionary.user.username, authentication));
906
- }
907
- });
908
- return existingItemsDefs;
909
- }
910
- /**
911
- * Search items based on user query
912
- *
913
- * @param query Query string to use
914
- * @param authentication Credentials for the request
915
- * @return A promise that will resolve with an array of results
916
- * @protected
917
- */
918
- function _findExistingItem(query, authentication) {
919
- var searchOptions = {
920
- q: query,
921
- authentication: authentication,
922
- pagingParam: { start: 1, num: 100 }
923
- };
924
- return common.searchItems(searchOptions);
925
- }
926
- /**
927
- * Creates an item from a template once the item's dependencies have been created.
928
- *
929
- * @param template Template of item to deploy
930
- * @param resourceFilePaths URL, folder, and filename for each item resource/metadata/thumbnail
931
- * @param templateDictionary Hash of facts: org URL, adlib replacements, deferreds for dependencies
932
- * @param userSession Options for the request
933
- * @param itemProgressCallback Function for reporting progress updates from type-specific template handlers
934
- * @return A promise that will resolve with the id of the deployed item (which is simply returned if it's
935
- * already in the templates list
936
- * @protected
937
- */
938
- function _createItemFromTemplateWhenReady(template, resourceFilePaths, storageAuthentication, templateDictionary, destinationAuthentication, itemProgressCallback) {
939
- // ensure this is present
940
- template.dependencies = template.dependencies || [];
941
- // if there is no entry in the templateDictionary
942
- // or if we have a basic entry without the deferred request for its creation, add it
943
- if (!templateDictionary.hasOwnProperty(template.itemId) ||
944
- !common.getProp(templateDictionary[template.itemId], "def")) {
945
- var createResponse_1;
946
- var statusCode_1 = common.EItemProgressStatus.Unknown;
947
- var itemHandler_1;
948
- templateDictionary[template.itemId] =
949
- templateDictionary[template.itemId] || {};
950
- // Save the deferred for the use of items that depend on this item being created first
951
- templateDictionary[template.itemId].def = new Promise(function (resolve) {
952
- // Wait until all of the item's dependencies are deployed
953
- var _awaitDependencies = template.dependencies.reduce(function (acc, id) {
954
- var def = common.getProp(templateDictionary, id + ".def");
955
- // can't use maybePush as that clones the object, which does not work for Promises
956
- /* istanbul ignore else */
957
- if (def) {
958
- acc.push(def);
959
- }
960
- return acc;
961
- }, []);
962
- var syncViews = common.getProp(template, "properties.syncViews");
963
- var awaitDependencies = syncViews && syncViews.length > 0
964
- ? syncViews.reduce(function (acc, v) {
965
- var def = common.getProp(templateDictionary, v + ".def");
966
- /* istanbul ignore else */
967
- if (def) {
968
- acc.push(def);
969
- }
970
- return acc;
971
- }, _awaitDependencies)
972
- : _awaitDependencies;
973
- Promise.all(awaitDependencies)
974
- .then(function () {
975
- // Find the conversion handler for this item type
976
- var templateType = template.type;
977
- itemHandler_1 = moduleMap[templateType];
978
- if (!itemHandler_1 || itemHandler_1 === UNSUPPORTED$1) {
979
- if (itemHandler_1 === UNSUPPORTED$1) {
980
- statusCode_1 = common.EItemProgressStatus.Ignored;
981
- throw new Error();
982
- }
983
- else {
984
- statusCode_1 = common.EItemProgressStatus.Failed;
985
- throw new Error();
986
- }
987
- }
988
- // Get the item's thumbnail
989
- return common.getThumbnailFromStorageItem(storageAuthentication, resourceFilePaths);
990
- })
991
- .then(function (thumbnail) {
992
- template.item.thumbnail = thumbnail;
993
- // Delegate the creation of the item to the handler
994
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
995
- return itemHandler_1.createItemFromTemplate(template, templateDictionary, destinationAuthentication, itemProgressCallback);
996
- })
997
- .then(function (response) {
998
- if (response.id === "") {
999
- statusCode_1 = common.EItemProgressStatus.Failed;
1000
- throw new Error("handled"); // fails to create item
1001
- }
1002
- /* istanbul ignore else */
1003
- createResponse_1 = response;
1004
- if (createResponse_1.item.item.url) {
1005
- common.setCreateProp(templateDictionary, template.itemId + ".url", createResponse_1.item.item.url);
1006
- }
1007
- if (resourceFilePaths.length > 0) {
1008
- // Copy resources, metadata, form
1009
- return common.copyFilesFromStorageItem(storageAuthentication, resourceFilePaths, templateDictionary.folderId, createResponse_1.id, destinationAuthentication, createResponse_1.item);
1010
- }
1011
- else {
1012
- return Promise.resolve(null);
1013
- }
1014
- })
1015
- .then(function () {
1016
- resolve(createResponse_1);
1017
- })
1018
- .catch(function (error) {
1019
- if (!error || error.message !== "handled") {
1020
- itemProgressCallback(template.itemId, statusCode_1 === common.EItemProgressStatus.Unknown
1021
- ? common.EItemProgressStatus.Failed
1022
- : statusCode_1, 0);
1023
- }
1024
- // Item type not supported or fails to get item dependencies
1025
- resolve(common.generateEmptyCreationResponse(template.type));
1026
- });
1027
- });
1028
- }
1029
- return templateDictionary[template.itemId].def;
1030
- }
1031
- /**
1032
- * Accumulates the estimated deployment cost of a set of templates.
1033
- *
1034
- * @param templates Templates to examine
1035
- * @return Sum of estimated deployment costs
1036
- * @protected
1037
- */
1038
- function _estimateDeploymentCost(templates) {
1039
- return templates.reduce(function (accumulatedEstimatedCost, template) {
1040
- return (accumulatedEstimatedCost + (template.estimatedDeploymentCostFactor || 1));
1041
- }, 0);
1042
- }
1043
- // TODO: Return a Promise vs array of promises
1044
- function _getGroupUpdates(template, authentication, templateDictionary) {
1045
- var groups = template.groups || [];
1046
- return groups.map(function (sourceGroupId) {
1047
- return common.shareItem(templateDictionary[sourceGroupId].itemId, template.itemId, authentication);
1048
- });
1049
- }
49
+ /** @license
50
+ * Copyright 2020 Esri
51
+ *
52
+ * Licensed under the Apache License, Version 2.0 (the "License");
53
+ * you may not use this file except in compliance with the License.
54
+ * You may obtain a copy of the License at
55
+ *
56
+ * http://www.apache.org/licenses/LICENSE-2.0
57
+ *
58
+ * Unless required by applicable law or agreed to in writing, software
59
+ * distributed under the License is distributed on an "AS IS" BASIS,
60
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
61
+ * See the License for the specific language governing permissions and
62
+ * limitations under the License.
63
+ */
64
+ const UNSUPPORTED$1 = null;
65
+ /**
66
+ * Mapping from item type to module with type-specific template-handling code.
67
+ * AGO types come from a blend of arcgis-portal-app\src\js\arcgisonline\pages\item\_Info.js and
68
+ * arcgis-portal-app\src\js\arcgis-components\src\_utils\metadata\item\displayName.ts
69
+ */
70
+ const moduleMap = {
71
+ ////////////////////////////////////////////////////////
72
+ // Group type
73
+ Group: group__namespace,
74
+ ////////////////////////////////////////////////////////
75
+ // Layer types
76
+ "Big Data Analytic": solutionVelocity.VelocityProcessor,
77
+ "Feature Collection": solutionSimpleTypes.simpleTypes,
78
+ "Feature Service": featureLayer__namespace,
79
+ Feed: solutionVelocity.VelocityProcessor,
80
+ "Geocoding Service": undefined,
81
+ "Geodata Service": undefined,
82
+ "Geometry Service": undefined,
83
+ "Geoprocessing Service": undefined,
84
+ "Globe Service": undefined,
85
+ "Image Service": undefined,
86
+ KML: undefined,
87
+ "Map Service": featureLayer__namespace,
88
+ "Network Analysis Service": undefined,
89
+ "Real Time Analytic": solutionVelocity.VelocityProcessor,
90
+ "Relational Database Connection": undefined,
91
+ "Scene Service": undefined,
92
+ "Stream Service": undefined,
93
+ Tool: undefined,
94
+ "Vector Tile Service": undefined,
95
+ WFS: undefined,
96
+ WMS: undefined,
97
+ WMTS: undefined,
98
+ "Workflow Manager Service": undefined,
99
+ ////////////////////////////////////////////////////////
100
+ // Map types
101
+ "3D Web Scene": undefined,
102
+ "Web Map": solutionSimpleTypes.simpleTypes,
103
+ "Web Scene": solutionSimpleTypes.simpleTypes,
104
+ ////////////////////////////////////////////////////////
105
+ // App types
106
+ Application: undefined,
107
+ Dashboard: solutionSimpleTypes.simpleTypes,
108
+ "Data Store": undefined,
109
+ "Desktop Application": undefined,
110
+ "Excalibur Imagery Project": undefined,
111
+ Form: formProcessor__namespace,
112
+ "Hub Initiative": UNSUPPORTED$1,
113
+ "Hub Page": solutionHubTypes.HubPageProcessor,
114
+ "Hub Site Application": solutionHubTypes.HubSiteProcessor,
115
+ "Insights Model": solutionSimpleTypes.simpleTypes,
116
+ "Insights Page": undefined,
117
+ "Insights Theme": undefined,
118
+ "Insights Workbook": undefined,
119
+ Mission: undefined,
120
+ "Mobile Application": undefined,
121
+ Notebook: solutionSimpleTypes.notebookProcessor,
122
+ "Oriented Imagery Catalog": solutionSimpleTypes.simpleTypes,
123
+ "Ortho Mapping Project": undefined,
124
+ "QuickCapture Project": solutionSimpleTypes.quickcaptureProcessor,
125
+ "Site Application": solutionHubTypes.HubSiteProcessor,
126
+ "Site Page": solutionHubTypes.HubPageProcessor,
127
+ Solution: UNSUPPORTED$1,
128
+ StoryMap: solutionStorymap.StoryMapProcessor,
129
+ "Urban Model": undefined,
130
+ "Web Experience Template": undefined,
131
+ "Web Experience": solutionWebExperience.WebExperienceProcessor,
132
+ "Web Mapping Application": solutionSimpleTypes.simpleTypes,
133
+ "Workforce Project": solutionSimpleTypes.simpleTypes,
134
+ ////////////////////////////////////////////////////////
135
+ // File types
136
+ "360 VR Experience": fileProcessor__namespace,
137
+ "AppBuilder Extension": fileProcessor__namespace,
138
+ "AppBuilder Widget Package": fileProcessor__namespace,
139
+ "Application Configuration": fileProcessor__namespace,
140
+ "ArcGIS Pro Add In": fileProcessor__namespace,
141
+ "ArcGIS Pro Configuration": fileProcessor__namespace,
142
+ "ArcPad Package": fileProcessor__namespace,
143
+ "Basemap Package": fileProcessor__namespace,
144
+ "CAD Drawing": fileProcessor__namespace,
145
+ "CityEngine Web Scene": fileProcessor__namespace,
146
+ "Code Attachment": UNSUPPORTED$1,
147
+ "Code Sample": fileProcessor__namespace,
148
+ "Color Set": fileProcessor__namespace,
149
+ "Compact Tile Package": fileProcessor__namespace,
150
+ "CSV Collection": fileProcessor__namespace,
151
+ CSV: fileProcessor__namespace,
152
+ "Deep Learning Package": fileProcessor__namespace,
153
+ "Desktop Add In": fileProcessor__namespace,
154
+ "Desktop Application Template": fileProcessor__namespace,
155
+ "Desktop Style": fileProcessor__namespace,
156
+ "Document Link": fileProcessor__namespace,
157
+ "Explorer Add In": fileProcessor__namespace,
158
+ "Explorer Layer": fileProcessor__namespace,
159
+ "Explorer Map": fileProcessor__namespace,
160
+ "Feature Collection Template": fileProcessor__namespace,
161
+ "File Geodatabase": fileProcessor__namespace,
162
+ GeoJson: fileProcessor__namespace,
163
+ GeoPackage: fileProcessor__namespace,
164
+ "Geoprocessing Package": fileProcessor__namespace,
165
+ "Geoprocessing Sample": fileProcessor__namespace,
166
+ "Globe Document": fileProcessor__namespace,
167
+ "Image Collection": fileProcessor__namespace,
168
+ Image: fileProcessor__namespace,
169
+ "iWork Keynote": fileProcessor__namespace,
170
+ "iWork Numbers": fileProcessor__namespace,
171
+ "iWork Pages": fileProcessor__namespace,
172
+ "KML Collection": fileProcessor__namespace,
173
+ "Layer Package": fileProcessor__namespace,
174
+ "Layer Template": fileProcessor__namespace,
175
+ Layer: fileProcessor__namespace,
176
+ Layout: fileProcessor__namespace,
177
+ "Locator Package": fileProcessor__namespace,
178
+ "Map Document": fileProcessor__namespace,
179
+ "Map Package": fileProcessor__namespace,
180
+ "Map Template": fileProcessor__namespace,
181
+ "Microsoft Excel": fileProcessor__namespace,
182
+ "Microsoft Powerpoint": fileProcessor__namespace,
183
+ "Microsoft Word": fileProcessor__namespace,
184
+ "Mobile Basemap Package": fileProcessor__namespace,
185
+ "Mobile Map Package": fileProcessor__namespace,
186
+ "Mobile Scene Package": fileProcessor__namespace,
187
+ "Native Application": fileProcessor__namespace,
188
+ "Native Application Installer": fileProcessor__namespace,
189
+ "Native Application Template": fileProcessor__namespace,
190
+ netCDF: fileProcessor__namespace,
191
+ "Operation View": fileProcessor__namespace,
192
+ "Operations Dashboard Add In": fileProcessor__namespace,
193
+ "Operations Dashboard Extension": fileProcessor__namespace,
194
+ PDF: fileProcessor__namespace,
195
+ "Pro Layer Package": fileProcessor__namespace,
196
+ "Pro Layer": fileProcessor__namespace,
197
+ "Pro Map Package": fileProcessor__namespace,
198
+ "Pro Map": fileProcessor__namespace,
199
+ "Pro Report": fileProcessor__namespace,
200
+ "Project Package": fileProcessor__namespace,
201
+ "Project Template": fileProcessor__namespace,
202
+ "Published Map": fileProcessor__namespace,
203
+ "Raster function template": fileProcessor__namespace,
204
+ "Report Template": fileProcessor__namespace,
205
+ "Rule Package": fileProcessor__namespace,
206
+ "Scene Document": fileProcessor__namespace,
207
+ "Scene Package": fileProcessor__namespace,
208
+ "Service Definition": fileProcessor__namespace,
209
+ Shapefile: fileProcessor__namespace,
210
+ "Statistical Data Collection": fileProcessor__namespace,
211
+ Style: fileProcessor__namespace,
212
+ "Survey123 Add In": fileProcessor__namespace,
213
+ "Symbol Set": fileProcessor__namespace,
214
+ "Task File": fileProcessor__namespace,
215
+ "Tile Package": fileProcessor__namespace,
216
+ "Toolbox Package": fileProcessor__namespace,
217
+ "Vector Tile Package": fileProcessor__namespace,
218
+ "Viewer Configuration": fileProcessor__namespace,
219
+ "Visio Document": fileProcessor__namespace,
220
+ "Window Mobile Package": fileProcessor__namespace,
221
+ "Windows Mobile Package": fileProcessor__namespace,
222
+ "Windows Viewer Add In": fileProcessor__namespace,
223
+ "Windows Viewer Configuration": fileProcessor__namespace,
224
+ "Workflow Manager Package": fileProcessor__namespace,
225
+ ////////////////////////////////////////////////////////
226
+ // Testing "types"
227
+ Undefined: undefined,
228
+ Unsupported: UNSUPPORTED$1
229
+ };
1050
230
 
1051
- /** @license
1052
- * Copyright 2020 Esri
1053
- *
1054
- * Licensed under the Apache License, Version 2.0 (the "License");
1055
- * you may not use this file except in compliance with the License.
1056
- * You may obtain a copy of the License at
1057
- *
1058
- * http://www.apache.org/licenses/LICENSE-2.0
1059
- *
1060
- * Unless required by applicable law or agreed to in writing, software
1061
- * distributed under the License is distributed on an "AS IS" BASIS,
1062
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1063
- * See the License for the specific language governing permissions and
1064
- * limitations under the License.
1065
- */
1066
- /**
1067
- * Given the created templates
1068
- *
1069
- * @param templates
1070
- * @param templateDictionary
1071
- * @param authentication
1072
- */
1073
- function shareTemplatesToGroups(templates, templateDictionary, authentication) {
1074
- // Filter to entries with groups to share to
1075
- var templatesWithGroups = templates.filter(function (e) {
1076
- return e.groups && e.groups.length > 0;
1077
- });
1078
- // fire off all the promises
1079
- return Promise.all(templatesWithGroups.map(function (tmpl) {
1080
- var groupIds = tmpl.groups.reduce(function (acc, sourceGroupId) {
1081
- return hubCommon.maybePush(common.getProp(templateDictionary, sourceGroupId + ".itemId"), acc);
1082
- }, []);
1083
- return common.shareItemToGroups(groupIds, tmpl.itemId, authentication);
1084
- }));
1085
- }
231
+ /** @license
232
+ * Copyright 2018 Esri
233
+ *
234
+ * Licensed under the Apache License, Version 2.0 (the "License");
235
+ * you may not use this file except in compliance with the License.
236
+ * You may obtain a copy of the License at
237
+ *
238
+ * http://www.apache.org/licenses/LICENSE-2.0
239
+ *
240
+ * Unless required by applicable law or agreed to in writing, software
241
+ * distributed under the License is distributed on an "AS IS" BASIS,
242
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
243
+ * See the License for the specific language governing permissions and
244
+ * limitations under the License.
245
+ */
246
+ const UNSUPPORTED = null;
247
+ // ------------------------------------------------------------------------------------------------------------------ //
248
+ /**
249
+ * Deploys a set of items defined by templates.
250
+ *
251
+ * @param portalSharingUrl Server/sharing
252
+ * @param storageItemId Id of storage item
253
+ * @param templates A collection of AGO item templates
254
+ * @param storageAuthentication Credentials for the organization with the source items
255
+ * @param templateDictionary Hash of facts: org URL, adlib replacements
256
+ * @param deployedSolutionId Id of deployed Solution item
257
+ * @param destinationAuthentication Credentials for the destination organization
258
+ * @param options Options to tune deployment
259
+ * @return A promise that will resolve with the list of information about the created items
260
+ */
261
+ function deploySolutionItems(portalSharingUrl, storageItemId, templates, storageAuthentication, templateDictionary, deployedSolutionId, destinationAuthentication, options) {
262
+ return new Promise((resolve, reject) => {
263
+ // Prepare feedback mechanism
264
+ const totalEstimatedCost = _estimateDeploymentCost(templates) + 1; // solution items, plus avoid divide by 0
265
+ let percentDone = 10; // allow for previous deployment work
266
+ const progressPercentStep = (99 - percentDone) / totalEstimatedCost; // leave some % for caller for wrapup
267
+ const failedTemplateItemIds = [];
268
+ const deployedItemIds = [];
269
+ let statusOK = true;
270
+ // TODO: move to separate fn
271
+ const itemProgressCallback = (itemId, status, costUsed, createdItemId // supplied when status is EItemProgressStatus.Created or .Finished
272
+ ) => {
273
+ percentDone += progressPercentStep * costUsed;
274
+ /* istanbul ignore else */
275
+ if (options.progressCallback) {
276
+ if (status === common__namespace.EItemProgressStatus.Finished) {
277
+ const event = {
278
+ event: common__namespace.SItemProgressStatus[status],
279
+ data: itemId
280
+ };
281
+ options.progressCallback(Math.round(percentDone), options.jobId, event);
282
+ }
283
+ else {
284
+ options.progressCallback(Math.round(percentDone), options.jobId);
285
+ }
286
+ }
287
+ /* istanbul ignore if */
288
+ if (options.consoleProgress) {
289
+ console.log(Date.now(), itemId, options.jobId ?? "", common__namespace.SItemProgressStatus[status], percentDone.toFixed(0) + "%", costUsed, createdItemId ? "==> " + createdItemId : "");
290
+ }
291
+ if (status === common__namespace.EItemProgressStatus.Created) {
292
+ deployedItemIds.push(createdItemId);
293
+ }
294
+ else if (status === common__namespace.EItemProgressStatus.Failed) {
295
+ failedTemplateItemIds.push(itemId);
296
+ console.error("Item " + itemId + " has failed");
297
+ statusOK = false;
298
+ }
299
+ return statusOK;
300
+ // ---------------------------------------------------------------------------------------------------------------
301
+ };
302
+ // portal does not allow views of a single source to be created at the same time
303
+ if (common__namespace.getProp(templateDictionary, "organization.isPortal")) {
304
+ templates = _evaluateSharedViewSources(templates);
305
+ }
306
+ // Create an ordered graph of the templates so that dependencies are created before the items that need them.
307
+ // Because cycles are permitted, we also keep track of items that need to be patched later because their
308
+ // dependencies are necessarily created after they are created.
309
+ const { buildOrder, itemsToBePatched } = common__namespace.topologicallySortItems(templates);
310
+ // For each item in order from no dependencies to dependent on other items,
311
+ // * replace template symbols using template dictionary
312
+ // * create item in destination group
313
+ // * add created item's id into the template dictionary
314
+ const awaitAllItems = [];
315
+ const reuseItemsDef = _reuseDeployedItems(templates, options.enableItemReuse ?? false, templateDictionary, destinationAuthentication);
316
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
317
+ reuseItemsDef.then(() => {
318
+ const useExistingItemsDef = _useExistingItems(templates, common__namespace.getProp(templateDictionary, "params.useExisting"), templateDictionary, destinationAuthentication);
319
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
320
+ useExistingItemsDef.then(() => {
321
+ templates = common__namespace.setNamesAndTitles(templates, templateDictionary.solutionItemId);
322
+ buildOrder.forEach((id) => {
323
+ // Get the item's template out of the list of templates
324
+ const template = common__namespace.findTemplateInList(templates, id);
325
+ awaitAllItems.push(_createItemFromTemplateWhenReady(template, common__namespace.generateStorageFilePaths(portalSharingUrl, storageItemId, template.resources, options.storageVersion), storageAuthentication, templateDictionary, destinationAuthentication, itemProgressCallback));
326
+ });
327
+ // Wait until all items have been created
328
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
329
+ Promise.all(awaitAllItems).then((clonedSolutionItems) => {
330
+ if (failedTemplateItemIds.length === 0) {
331
+ // Do we have any items to be patched (i.e., they refer to dependencies using the template id rather
332
+ // than the cloned id because the item had to be created before the dependency)? Flag these items
333
+ // for post processing in the list of clones.
334
+ _flagPatchItemsForPostProcessing(itemsToBePatched, templateDictionary, clonedSolutionItems);
335
+ resolve(clonedSolutionItems);
336
+ }
337
+ else {
338
+ // Delete created items
339
+ const progressOptions = {
340
+ consoleProgress: true
341
+ };
342
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
343
+ common__namespace
344
+ .deleteSolutionByComponents(deployedSolutionId, deployedItemIds, templates, templateDictionary, destinationAuthentication, progressOptions)
345
+ .then(() => reject(common__namespace.failWithIds(failedTemplateItemIds)));
346
+ }
347
+ });
348
+ });
349
+ }, e => {
350
+ console.error(e);
351
+ reject(common__namespace.fail(e));
352
+ });
353
+ });
354
+ }
355
+ /**
356
+ * For each item to be patched, convert it to its cloned id and mark the item as needing post processing.
357
+ *
358
+ * @param itemsToBePatched List of items that need to have their dependencies patched
359
+ * @param templateDictionary Hash of facts: org URL, adlib replacements
360
+ * @param templates A collection of AGO item templates
361
+ */
362
+ function _flagPatchItemsForPostProcessing(itemsToBePatched, templateDictionary, templates) {
363
+ let itemIdsToBePatched = Object.keys(itemsToBePatched);
364
+ /* istanbul ignore else */
365
+ if (itemIdsToBePatched.length > 0) {
366
+ // Replace the ids of the items to be patched (which are template ids) with their cloned versions
367
+ itemIdsToBePatched = itemIdsToBePatched.map(id => templateDictionary[id].itemId);
368
+ // Make sure that the items to be patched are flagged for post processing
369
+ templates.forEach(item => {
370
+ /* istanbul ignore else */
371
+ if (itemIdsToBePatched.includes(item.id)) {
372
+ item.postProcess = true;
373
+ }
374
+ });
375
+ }
376
+ }
377
+ /**
378
+ * Portal does not allow views of a single source to be created at the same time.
379
+ *
380
+ * Update view templates with an array of other view template ids that it should wait on.
381
+ *
382
+ * @param templates a collection of AGO item templates
383
+ *
384
+ * @returns An updated array of item templates
385
+ *
386
+ */
387
+ function _evaluateSharedViewSources(templates) {
388
+ // update the templates so we can defer the deployment when more than one view shares the same source
389
+ // these are not classic dependencies but are in some ways similar
390
+ const views = _getViews(templates);
391
+ _updateViewTemplates(templates, views);
392
+ const viewHash = _getViewHash(views);
393
+ let processed = [];
394
+ const visited = [];
395
+ Object.keys(viewHash).forEach(k => {
396
+ const _views = viewHash[k];
397
+ _views.forEach(cv => {
398
+ const template = common__namespace.findTemplateInList(templates, cv);
399
+ const syncViews = common__namespace.getProp(template, "properties.syncViews");
400
+ /* istanbul ignore else */
401
+ if (visited.indexOf(template.itemId) > -1) {
402
+ processed = processed.concat(syncViews);
403
+ }
404
+ /* istanbul ignore else */
405
+ if (syncViews && syncViews.length > 0) {
406
+ // when a view has multiple dependencies we need to retain the syncViews if they have been set already...
407
+ common__namespace.setProp(template, "properties.syncViews", common__namespace.cloneObject(processed));
408
+ }
409
+ /* istanbul ignore else */
410
+ if (processed.indexOf(cv) < 0) {
411
+ processed.push(cv);
412
+ }
413
+ /* istanbul ignore else */
414
+ if (visited.indexOf(template.itemId) < 0) {
415
+ visited.push(template.itemId);
416
+ }
417
+ });
418
+ processed = [];
419
+ });
420
+ return templates;
421
+ }
422
+ /**
423
+ * Add a syncViews array to each template that will hold all other view ids that
424
+ * have the same FS dependency.
425
+ * These arrays will be processed later to only contain ids that each view will need to wait on.
426
+ *
427
+ * @param templates a collection of AGO item templates
428
+ * @param views an array of view template details
429
+ *
430
+ * @returns An updated array of item templates
431
+ *
432
+ */
433
+ function _updateViewTemplates(templates, views) {
434
+ views.forEach(v => {
435
+ v.dependencies.forEach((id) => {
436
+ templates = templates.map(t => {
437
+ /* istanbul ignore else */
438
+ if (common__namespace.getProp(t, "properties.service.isView") &&
439
+ t.dependencies.indexOf(id) > -1 &&
440
+ t.itemId !== v.id) {
441
+ /* istanbul ignore else */
442
+ if (!Array.isArray(t.properties.syncViews)) {
443
+ t.properties.syncViews = [];
444
+ }
445
+ /* istanbul ignore else */
446
+ if (t.properties.syncViews.indexOf(v.id) < 0) {
447
+ t.properties.syncViews.push(v.id);
448
+ }
449
+ }
450
+ return t;
451
+ });
452
+ });
453
+ });
454
+ return templates;
455
+ }
456
+ /**
457
+ * Get all view templates from the source templates collection
458
+ *
459
+ * @param views A collection of view ID and dependencies
460
+ *
461
+ * @returns an array of objects with the source FS id as the key and a list of views that are
462
+ * dependant upon it
463
+ *
464
+ * @protected
465
+ */
466
+ function _getViewHash(views) {
467
+ const viewHash = {};
468
+ views.forEach(v => {
469
+ v.dependencies.forEach((d) => {
470
+ /* istanbul ignore else */
471
+ if (Object.keys(viewHash).indexOf(d) < 0) {
472
+ viewHash[d] = [v.id];
473
+ }
474
+ else if (viewHash[d].indexOf(v.id) < 0) {
475
+ viewHash[d].push(v.id);
476
+ }
477
+ });
478
+ });
479
+ return viewHash;
480
+ }
481
+ /**
482
+ * Get all view templates from the source templates collection
483
+ *
484
+ * @param templates A collection of AGO item templates
485
+ *
486
+ * @returns an array with the view id and its dependencies
487
+ *
488
+ * @protected
489
+ */
490
+ function _getViews(templates) {
491
+ return templates.reduce((acc, v) => {
492
+ /* istanbul ignore else */
493
+ if (common__namespace.getProp(v, "properties.service.isView")) {
494
+ acc.push({
495
+ id: v.itemId,
496
+ dependencies: v.dependencies
497
+ });
498
+ }
499
+ return acc;
500
+ }, []);
501
+ }
502
+ /**
503
+ * Search for existing items and update the templateDictionary with key details
504
+ *
505
+ * @param templates A collection of AGO item templates
506
+ * @param reuseItems Option to search for existing items
507
+ * @param templateDictionary Hash of facts: org URL, adlib replacements, deferreds for dependencies
508
+ * @param authentication Credentials for the requests
509
+ *
510
+ * @returns A Promise that will resolve once existing items have been evaluated
511
+ *
512
+ * @protected
513
+ */
514
+ function _reuseDeployedItems(templates, reuseItems, templateDictionary, authentication) {
515
+ return new Promise((resolve, reject) => {
516
+ if (reuseItems) {
517
+ const existingItemsByKeyword = _findExistingItemByKeyword(templates, templateDictionary, authentication);
518
+ Promise.all(existingItemsByKeyword).then((existingItemsByKeywordResponse) => {
519
+ const existingItemsByTag = _handleExistingItems(existingItemsByKeywordResponse, templateDictionary, authentication, true);
520
+ Promise.all(existingItemsByTag).then(existingItemsByTagResponse => {
521
+ _handleExistingItems(existingItemsByTagResponse, templateDictionary, authentication, false);
522
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
523
+ _updateTemplateDictionary(templates, templateDictionary, authentication).then(resolve);
524
+ }, e => reject(common__namespace.fail(e)));
525
+ }, e => reject(common__namespace.fail(e)));
526
+ }
527
+ else {
528
+ resolve(null);
529
+ }
530
+ });
531
+ }
532
+ /**
533
+ * Search for existing items and update the templateDictionary with key details
534
+ *
535
+ * Subtle difference between _reuseDeployedItems and _useExistingItems
536
+ * _reuseDeployedItems: will search all existing items based on specific type keywords
537
+ * that would have been added by a previous deployment
538
+ * _useExistingItems: will search for an existing item that the user provided
539
+ * the item id for while configuring in the deployment app.
540
+ * This type of item would not necessarily have been laid down by a previous deployment and
541
+ * can thus not expect that it will have the type keywords
542
+ *
543
+ * @param templates A collection of AGO item templates
544
+ * @param useExisting Option to search for existing items
545
+ * @param templateDictionary Hash of facts: org URL, adlib replacements, deferreds for dependencies
546
+ * @param authentication Credentials for the requests
547
+ *
548
+ * @returns A Promise that will resolve once existing items have been evaluated
549
+ *
550
+ * @protected
551
+ */
552
+ function _useExistingItems(templates, useExisting, templateDictionary, authentication) {
553
+ return new Promise(resolve => {
554
+ if (useExisting) {
555
+ const itemDefs = [];
556
+ const sourceIdHash = {};
557
+ const itemIds = [];
558
+ Object.keys(templateDictionary.params).forEach(k => {
559
+ const v = templateDictionary.params[k];
560
+ /* istanbul ignore else */
561
+ if (v.itemId && /[0-9A-F]{32}/i.test(k)) {
562
+ _updateTemplateDictionaryById(templateDictionary, k, v.itemId, v);
563
+ // need to check and set the typeKeyword if it doesn't exist on this service yet
564
+ // when the user has passed in an itemId that does not come from a previous deployment
565
+ itemDefs.push(common__namespace.getItemBase(v.itemId, authentication));
566
+ sourceIdHash[v.itemId] = k;
567
+ /* istanbul ignore else */
568
+ if (itemIds.indexOf(k) < 0) {
569
+ itemIds.push(k);
570
+ }
571
+ }
572
+ });
573
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
574
+ _setTypekeywordForExisting(itemDefs, sourceIdHash, authentication).then(() => {
575
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
576
+ _updateTemplateDictionary(itemIds.map(id => common__namespace.getTemplateById(templates, id)), templateDictionary, authentication).then(resolve);
577
+ });
578
+ }
579
+ else {
580
+ resolve(null);
581
+ }
582
+ });
583
+ }
584
+ /**
585
+ * Verify if the existing item has the source-<itemId> typeKeyword and set it if not
586
+ * This allows items that did not come from deployment to be found for reuse after they
587
+ * have been used once via a custom itemId param
588
+ *
589
+ * @param itemDefs
590
+ * @param sourceIdHash key value pairs..actual itemId is the key and the source itemId is the value
591
+ * @param authentication credentials for the requests
592
+ *
593
+ * @return a promise to indicate when the requests are complete
594
+ */
595
+ function _setTypekeywordForExisting(itemDefs, sourceIdHash, authentication) {
596
+ return new Promise(resolve => {
597
+ if (itemDefs.length > 0) {
598
+ Promise.all(itemDefs).then(results => {
599
+ const itemUpdateDefs = [];
600
+ results.forEach(result => {
601
+ const sourceId = sourceIdHash[result.id];
602
+ /* istanbul ignore else */
603
+ if (result && sourceId && result.typeKeywords) {
604
+ const sourceKeyword = `source-${sourceId}`;
605
+ const typeKeywords = result.typeKeywords;
606
+ /* istanbul ignore else */
607
+ if (typeKeywords.indexOf(sourceKeyword) < 0) {
608
+ typeKeywords.push(sourceKeyword);
609
+ const itemUpdate = { id: result.id, typeKeywords };
610
+ itemUpdateDefs.push(common__namespace.updateItem(itemUpdate, authentication));
611
+ }
612
+ }
613
+ });
614
+ // wait for updates to finish before we resolve
615
+ if (itemUpdateDefs.length > 0) {
616
+ Promise.all(itemUpdateDefs).then(resolve, () => resolve(undefined));
617
+ }
618
+ else {
619
+ resolve(undefined);
620
+ }
621
+ }, () => resolve(undefined));
622
+ }
623
+ else {
624
+ resolve(undefined);
625
+ }
626
+ });
627
+ }
628
+ /**
629
+ * Update the templateDictionary with key details by item type
630
+ *
631
+ * @param templates A collection of AGO item templates
632
+ * @param templateDictionary Hash of facts: org URL, adlib replacements, deferreds for dependencies
633
+ *
634
+ * @protected
635
+ */
636
+ function _updateTemplateDictionary(templates, templateDictionary, authentication) {
637
+ return new Promise(resolve => {
638
+ const defs = [];
639
+ const urls = [];
640
+ const types = [];
641
+ const ids = [];
642
+ templates.forEach(t => {
643
+ const templateInfo = templateDictionary[t.itemId];
644
+ /* istanbul ignore else */
645
+ if (templateInfo && templateInfo.url && templateInfo.itemId) {
646
+ /* istanbul ignore else */
647
+ if (t.item.type === "Feature Service") {
648
+ const enterpriseIDMapping = common__namespace.getProp(templateDictionary, `params.${t.itemId}.enterpriseIDMapping`);
649
+ Object.assign(templateDictionary[t.itemId], common__namespace.getLayerSettings(common__namespace.getLayersAndTables(t), templateInfo.url, templateInfo.itemId, enterpriseIDMapping));
650
+ // if the service has veiws keep track of the fields so we can use them to
651
+ // compare with the view fields
652
+ /* istanbul ignore else */
653
+ if (common__namespace.getProp(t, "properties.service.hasViews")) {
654
+ common__namespace._updateTemplateDictionaryFields(t, templateDictionary, false);
655
+ }
656
+ }
657
+ // for fs query with its url...for non fs query the item
658
+ // this is to verify situations where we have a stale search index that will
659
+ // say some items exist when they don't really exist
660
+ // searching the services url or with the item id will return an error when this condition occurs
661
+ /* istanbul ignore else */
662
+ if (urls.indexOf(templateInfo.url) < 0) {
663
+ defs.push(t.item.type === "Feature Service"
664
+ ? common__namespace.rest_request(templateInfo.url, { authentication })
665
+ : common__namespace.getItemBase(templateInfo.itemId, authentication));
666
+ urls.push(templateInfo.url);
667
+ types.push(t.item.type);
668
+ ids.push(templateInfo.itemId);
669
+ }
670
+ }
671
+ });
672
+ if (defs.length > 0) {
673
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
674
+ Promise.all(defs.map(p => p.catch(e => e))).then(results => {
675
+ /* istanbul ignore else */
676
+ if (Array.isArray(results) && results.length > 0) {
677
+ const fieldDefs = [];
678
+ results.forEach((r, i) => {
679
+ // a feature service result will contain a serviceItemId if it was successfully fetched
680
+ if (r.serviceItemId && types[i] === "Feature Service") {
681
+ Object.keys(templateDictionary).forEach(k => {
682
+ const v = templateDictionary[k];
683
+ /* istanbul ignore else */
684
+ if (v.itemId && v.itemId === r.serviceItemId) {
685
+ common__namespace.setDefaultSpatialReference(templateDictionary, k, r.spatialReference);
686
+ // keep the extent values from these responses as well
687
+ common__namespace.setCreateProp(templateDictionary, `${k}.defaultExtent`, r.fullExtent || r.initialExtent);
688
+ const layerIds = (r.layers || []).map((l) => l.id);
689
+ const tablesIds = (r.tables || []).map((t) => t.id);
690
+ fieldDefs.push(common__namespace.getExistingLayersAndTables(urls[i], layerIds.concat(tablesIds), authentication));
691
+ }
692
+ });
693
+ }
694
+ else {
695
+ /* istanbul ignore else */
696
+ if (types[i] === "Feature Service" ||
697
+ common__namespace.getProp(r, "response.error")) {
698
+ // if an error is returned we need to clean up the templateDictionary
699
+ templateDictionary = _updateTemplateDictionaryForError(templateDictionary, ids[i]);
700
+ }
701
+ }
702
+ });
703
+ if (fieldDefs.length > 0) {
704
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
705
+ Promise.all(fieldDefs).then(layerTableResult => {
706
+ layerTableResult.forEach(l => {
707
+ l.forEach((ll) => {
708
+ Object.keys(templateDictionary).forEach(k => {
709
+ /* istanbul ignore else */
710
+ if (templateDictionary[k].itemId === ll.serviceItemId) {
711
+ let sourceId = "";
712
+ Object.keys(templateDictionary).some(_k => {
713
+ /* istanbul ignore else */
714
+ if (templateDictionary[_k].itemId === ll.serviceItemId) {
715
+ sourceId = _k;
716
+ return true;
717
+ }
718
+ });
719
+ const enterpriseIDMapping = common__namespace.getProp(templateDictionary, `params.${sourceId}.enterpriseIDMapping`);
720
+ if (enterpriseIDMapping) {
721
+ Object.keys(enterpriseIDMapping).forEach(id => {
722
+ if (enterpriseIDMapping[id].toString() ===
723
+ ll.id.toString()) {
724
+ _setFields(templateDictionary, k, id, ll.fields);
725
+ }
726
+ });
727
+ }
728
+ else {
729
+ _setFields(templateDictionary, k, ll.id, ll.fields);
730
+ }
731
+ }
732
+ });
733
+ });
734
+ });
735
+ resolve(null);
736
+ });
737
+ }
738
+ else {
739
+ resolve(null);
740
+ }
741
+ }
742
+ else {
743
+ resolve(null);
744
+ }
745
+ });
746
+ }
747
+ else {
748
+ resolve(null);
749
+ }
750
+ });
751
+ }
752
+ /**
753
+ * Add the fields from the source layer to the template dictionary for any required replacements
754
+ *
755
+ * @param templateDictionary Hash of facts: org URL, adlib replacements, deferreds for dependencies
756
+ * @param itemId the id for the item
757
+ * @param layerId the id for the layer
758
+ * @param fields the fields to transfer
759
+ *
760
+ * @protected
761
+ */
762
+ function _setFields(templateDictionary, itemId, layerId, fields) {
763
+ const layerInfo = common__namespace.getProp(templateDictionary, `${itemId}.layer${layerId}`);
764
+ /* istanbul ignore else */
765
+ if (layerInfo && fields) {
766
+ layerInfo.fields = fields;
767
+ }
768
+ }
769
+ /**
770
+ * In some cases an item id search will return a stale item reference
771
+ * it will subsequently fail when we try to fetch the underlying service.
772
+ *
773
+ * We need to remove the item info that has been added to the template dictionary
774
+ * and treat the item as we do other items that don't already exist on deployment.
775
+ *
776
+ * @param result the service request result
777
+ * @param templateDictionary Hash of facts: org URL, adlib replacements, deferreds for dependencies
778
+ *
779
+ * @protected
780
+ */
781
+ function _updateTemplateDictionaryForError(templateDictionary, itemId) {
782
+ /* istanbul ignore else */
783
+ if (itemId) {
784
+ let removeKey = "";
785
+ Object.keys(templateDictionary).some(k => {
786
+ /* istanbul ignore else */
787
+ if (templateDictionary[k].itemId === itemId) {
788
+ removeKey = k;
789
+ return true;
790
+ }
791
+ });
792
+ /* istanbul ignore else */
793
+ if (removeKey !== "") {
794
+ delete templateDictionary[removeKey];
795
+ }
796
+ }
797
+ return templateDictionary;
798
+ }
799
+ /**
800
+ * Optionally search by tags and then update the templateDictionary based on the search results
801
+ *
802
+ * @param existingItemsResponse response object from search by typeKeyword and type
803
+ * @param templateDictionary Hash of facts: org URL, adlib replacements, deferreds for dependencies
804
+ * @param authentication Credentials for the request
805
+ * @param addTagQuery Boolean to indicate if a search by tag should happen
806
+ * @return A promise that will resolve with an array of results
807
+ * @protected
808
+ */
809
+ function _handleExistingItems(existingItemsResponse, templateDictionary, authentication, addTagQuery) {
810
+ // if items are not found by type keyword search by tag
811
+ const existingItemsByTag = [Promise.resolve(null)];
812
+ /* istanbul ignore else */
813
+ if (existingItemsResponse && Array.isArray(existingItemsResponse)) {
814
+ existingItemsResponse.forEach(existingItem => {
815
+ /* istanbul ignore else */
816
+ if (Array.isArray(existingItem?.results)) {
817
+ let result;
818
+ const results = existingItem.results;
819
+ if (results.length === 1) {
820
+ result = results[0];
821
+ }
822
+ else if (results.length > 1) {
823
+ result = results.reduce((a, b) => a.created > b.created ? a : b);
824
+ }
825
+ else {
826
+ if (addTagQuery && existingItem.query) {
827
+ const tagQuery = existingItem.query.replace("typekeywords", "tags");
828
+ existingItemsByTag.push(_findExistingItem(tagQuery, authentication));
829
+ }
830
+ }
831
+ if (result) {
832
+ const sourceId = existingItem.query
833
+ ? existingItem.query.match(/[0-9A-F]{32}/i)[0]
834
+ : existingItem.sourceId;
835
+ /* istanbul ignore else */
836
+ if (sourceId) {
837
+ _updateTemplateDictionaryById(templateDictionary, sourceId, result.id, result);
838
+ }
839
+ }
840
+ }
841
+ });
842
+ }
843
+ return existingItemsByTag;
844
+ }
845
+ function _updateTemplateDictionaryById(templateDictionary, sourceId, itemId, v) {
846
+ templateDictionary[sourceId] = Object.assign(templateDictionary[sourceId] || {}, {
847
+ def: Promise.resolve(common__namespace.generateEmptyCreationResponse(v.type, itemId)),
848
+ itemId,
849
+ name: v.name,
850
+ title: v.title,
851
+ url: v.url
852
+ });
853
+ }
854
+ /**
855
+ * Search items based on user query
856
+ *
857
+ * @param query Query string to use
858
+ * @param authentication Credentials for the request
859
+ * @return A promise that will resolve with an array of results
860
+ * @protected
861
+ */
862
+ function _findExistingItemByKeyword(templates, templateDictionary, authentication) {
863
+ const existingItemsDefs = [];
864
+ templates.forEach(template => {
865
+ if (template.item.type === "Group") {
866
+ const userGroups = templateDictionary.user?.groups;
867
+ /* istanbul ignore else */
868
+ if (Array.isArray(userGroups)) {
869
+ existingItemsDefs.push(Promise.resolve({
870
+ results: userGroups
871
+ .filter(g => g.tags.indexOf(`source-${template.itemId}`) > -1)
872
+ .map(g => {
873
+ g.type = "Group";
874
+ return g;
875
+ }),
876
+ sourceId: template.itemId
877
+ }));
878
+ }
879
+ }
880
+ else {
881
+ existingItemsDefs.push(_findExistingItem(`typekeywords:source-${template.itemId} type:${template.item.type} owner:${templateDictionary.user.username}`, authentication));
882
+ }
883
+ });
884
+ return existingItemsDefs;
885
+ }
886
+ /**
887
+ * Search items based on user query
888
+ *
889
+ * @param query Query string to use
890
+ * @param authentication Credentials for the request
891
+ * @return A promise that will resolve with an array of results
892
+ * @protected
893
+ */
894
+ function _findExistingItem(query, authentication) {
895
+ const searchOptions = {
896
+ q: query,
897
+ authentication: authentication,
898
+ pagingParam: { start: 1, num: 100 }
899
+ };
900
+ return common__namespace.searchItems(searchOptions);
901
+ }
902
+ /**
903
+ * Creates an item from a template once the item's dependencies have been created.
904
+ *
905
+ * @param template Template of item to deploy
906
+ * @param resourceFilePaths URL, folder, and filename for each item resource/metadata/thumbnail
907
+ * @param templateDictionary Hash of facts: org URL, adlib replacements, deferreds for dependencies
908
+ * @param userSession Options for the request
909
+ * @param itemProgressCallback Function for reporting progress updates from type-specific template handlers
910
+ * @return A promise that will resolve with the id of the deployed item (which is simply returned if it's
911
+ * already in the templates list
912
+ * @protected
913
+ */
914
+ function _createItemFromTemplateWhenReady(template, resourceFilePaths, storageAuthentication, templateDictionary, destinationAuthentication, itemProgressCallback) {
915
+ // ensure this is present
916
+ template.dependencies = template.dependencies || [];
917
+ // if there is no entry in the templateDictionary
918
+ // or if we have a basic entry without the deferred request for its creation, add it
919
+ if (!templateDictionary.hasOwnProperty(template.itemId) ||
920
+ !common__namespace.getProp(templateDictionary[template.itemId], "def")) {
921
+ let createResponse;
922
+ let statusCode = common__namespace.EItemProgressStatus.Unknown;
923
+ let itemHandler;
924
+ templateDictionary[template.itemId] =
925
+ templateDictionary[template.itemId] || {};
926
+ // Save the deferred for the use of items that depend on this item being created first
927
+ templateDictionary[template.itemId].def = new Promise(resolve => {
928
+ // Wait until all of the item's dependencies are deployed
929
+ const _awaitDependencies = template.dependencies.reduce((acc, id) => {
930
+ const def = common__namespace.getProp(templateDictionary, `${id}.def`);
931
+ // can't use maybePush as that clones the object, which does not work for Promises
932
+ /* istanbul ignore else */
933
+ if (def) {
934
+ acc.push(def);
935
+ }
936
+ return acc;
937
+ }, []);
938
+ const syncViews = common__namespace.getProp(template, "properties.syncViews");
939
+ const awaitDependencies = syncViews && syncViews.length > 0
940
+ ? syncViews.reduce((acc, v) => {
941
+ const def = common__namespace.getProp(templateDictionary, `${v}.def`);
942
+ /* istanbul ignore else */
943
+ if (def) {
944
+ acc.push(def);
945
+ }
946
+ return acc;
947
+ }, _awaitDependencies)
948
+ : _awaitDependencies;
949
+ Promise.all(awaitDependencies)
950
+ .then(() => {
951
+ // Find the conversion handler for this item type
952
+ const templateType = template.type;
953
+ itemHandler = moduleMap[templateType];
954
+ if (!itemHandler || itemHandler === UNSUPPORTED) {
955
+ if (itemHandler === UNSUPPORTED) {
956
+ statusCode = common__namespace.EItemProgressStatus.Ignored;
957
+ throw new Error();
958
+ }
959
+ else {
960
+ statusCode = common__namespace.EItemProgressStatus.Failed;
961
+ throw new Error();
962
+ }
963
+ }
964
+ // Get the item's thumbnail
965
+ return common__namespace.getThumbnailFromStorageItem(storageAuthentication, resourceFilePaths);
966
+ })
967
+ .then(thumbnail => {
968
+ template.item.thumbnail = thumbnail;
969
+ // Delegate the creation of the item to the handler
970
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
971
+ return itemHandler.createItemFromTemplate(template, templateDictionary, destinationAuthentication, itemProgressCallback);
972
+ })
973
+ .then((response) => {
974
+ if (response.id === "") {
975
+ statusCode = common__namespace.EItemProgressStatus.Failed;
976
+ throw new Error("handled"); // fails to create item
977
+ }
978
+ /* istanbul ignore else */
979
+ createResponse = response;
980
+ if (createResponse.item.item.url) {
981
+ common__namespace.setCreateProp(templateDictionary, template.itemId + ".url", createResponse.item.item.url);
982
+ }
983
+ if (resourceFilePaths.length > 0) {
984
+ // Copy resources, metadata, form
985
+ return common__namespace.copyFilesFromStorageItem(storageAuthentication, resourceFilePaths, templateDictionary.folderId, createResponse.id, destinationAuthentication, createResponse.item);
986
+ }
987
+ else {
988
+ return Promise.resolve(null);
989
+ }
990
+ })
991
+ .then(() => {
992
+ resolve(createResponse);
993
+ })
994
+ .catch(error => {
995
+ if (!error || error.message !== "handled") {
996
+ itemProgressCallback(template.itemId, statusCode === common__namespace.EItemProgressStatus.Unknown
997
+ ? common__namespace.EItemProgressStatus.Failed
998
+ : statusCode, 0);
999
+ }
1000
+ // Item type not supported or fails to get item dependencies
1001
+ resolve(common__namespace.generateEmptyCreationResponse(template.type));
1002
+ });
1003
+ });
1004
+ }
1005
+ return templateDictionary[template.itemId].def;
1006
+ }
1007
+ /**
1008
+ * Accumulates the estimated deployment cost of a set of templates.
1009
+ *
1010
+ * @param templates Templates to examine
1011
+ * @return Sum of estimated deployment costs
1012
+ * @protected
1013
+ */
1014
+ function _estimateDeploymentCost(templates) {
1015
+ return templates.reduce((accumulatedEstimatedCost, template) => {
1016
+ return (accumulatedEstimatedCost + (template.estimatedDeploymentCostFactor || 1));
1017
+ }, 0);
1018
+ }
1019
+ // TODO: Return a Promise vs array of promises
1020
+ function _getGroupUpdates(template, authentication, templateDictionary) {
1021
+ const groups = template.groups || [];
1022
+ return groups.map((sourceGroupId) => {
1023
+ return common__namespace.shareItem(templateDictionary[sourceGroupId].itemId, template.itemId, authentication, common__namespace.isTrackingViewTemplate(template) ? templateDictionary.locationTracking.owner : undefined);
1024
+ });
1025
+ }
1086
1026
 
1087
- /** @license
1088
- * Copyright 2020 Esri
1089
- *
1090
- * Licensed under the Apache License, Version 2.0 (the "License");
1091
- * you may not use this file except in compliance with the License.
1092
- * You may obtain a copy of the License at
1093
- *
1094
- * http://www.apache.org/licenses/LICENSE-2.0
1095
- *
1096
- * Unless required by applicable law or agreed to in writing, software
1097
- * distributed under the License is distributed on an "AS IS" BASIS,
1098
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1099
- * See the License for the specific language governing permissions and
1100
- * limitations under the License.
1101
- */
1102
- /**
1103
- * Delegate post-processing to the type specific
1104
- * processors. This allows each type to have fine-grained
1105
- * control over what they do. Common post-processing is
1106
- * exposed as functions that can be imported
1107
- *
1108
- * @param deployedSolutionId
1109
- * @param templates
1110
- * @param clonedSolutions
1111
- * @param authentication
1112
- * @param templateDictionary
1113
- */
1114
- function postProcess(deployedSolutionId, templates, clonedSolutions, authentication, templateDictionary) {
1115
- // connect the solution with its items; groups cannot be connected
1116
- var relationshipPromises = clonedSolutions
1117
- .filter(function (entry) { return entry.type !== "Group"; })
1118
- .map(function (entry) {
1119
- return portal.addItemRelationship({
1120
- originItemId: deployedSolutionId,
1121
- destinationItemId: entry.id,
1122
- relationshipType: "Solution2Item",
1123
- authentication: authentication
1124
- });
1125
- } // TODO: remove `as any`, which is here until arcgis-rest-js' ItemRelationshipType defn catches up
1126
- );
1127
- // delegate sharing to groups
1128
- var sharePromises = shareTemplatesToGroups(templates, templateDictionary, authentication);
1129
- // what needs post processing?
1130
- var itemsToProcess = clonedSolutions.filter(function (entry) { return entry.postProcess; });
1131
- // map over these items
1132
- var postProcessPromises = itemsToProcess.reduce(function (acc, entry) {
1133
- var itemHandler = moduleMap[entry.type];
1134
- // only delegate if the handler has a postProcess method
1135
- if (itemHandler && itemHandler.postProcess) {
1136
- acc.push(itemHandler.postProcess(entry.id, entry.type, clonedSolutions, common.getTemplateById(templates, entry.id), templates, templateDictionary, authentication));
1137
- }
1138
- return acc;
1139
- }, []);
1140
- return Promise.all([sharePromises].concat(postProcessPromises, relationshipPromises));
1141
- }
1027
+ /** @license
1028
+ * Copyright 2020 Esri
1029
+ *
1030
+ * Licensed under the Apache License, Version 2.0 (the "License");
1031
+ * you may not use this file except in compliance with the License.
1032
+ * You may obtain a copy of the License at
1033
+ *
1034
+ * http://www.apache.org/licenses/LICENSE-2.0
1035
+ *
1036
+ * Unless required by applicable law or agreed to in writing, software
1037
+ * distributed under the License is distributed on an "AS IS" BASIS,
1038
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1039
+ * See the License for the specific language governing permissions and
1040
+ * limitations under the License.
1041
+ */
1042
+ /**
1043
+ * Given the created templates
1044
+ *
1045
+ * @param templates
1046
+ * @param templateDictionary
1047
+ * @param authentication
1048
+ */
1049
+ function shareTemplatesToGroups(templates, templateDictionary, authentication) {
1050
+ // Filter to entries with groups to share to
1051
+ const templatesWithGroups = templates.filter(e => {
1052
+ return e.groups && e.groups.length > 0;
1053
+ });
1054
+ // fire off all the promises
1055
+ return Promise.all(templatesWithGroups.map(tmpl => {
1056
+ const groupIds = tmpl.groups.reduce((acc, sourceGroupId) => {
1057
+ return hubCommon.maybePush(common.getProp(templateDictionary, `${sourceGroupId}.itemId`), acc);
1058
+ }, []);
1059
+ // need to pass the tracking owner when sharing to tracking group
1060
+ if (common.isTrackingViewTemplate(tmpl) && !common.getProp(templateDictionary, "locationTracking.userIsOwner")) {
1061
+ const trackingGroupId = common.getProp(tmpl, "item.properties.trackViewGroup");
1062
+ const owner = common.getProp(templateDictionary, "locationTracking.owner");
1063
+ /* istanbul ignore else */
1064
+ if (trackingGroupId && owner) {
1065
+ const trackerGroupIds = groupIds.filter(id => {
1066
+ return id === common.replaceInTemplate(trackingGroupId, templateDictionary);
1067
+ });
1068
+ if (trackerGroupIds.length !== groupIds.length) {
1069
+ const nonTrackerGroupIds = groupIds.filter(id => id !== trackingGroupId);
1070
+ return Promise.all([
1071
+ common.shareItemToGroups(trackerGroupIds, tmpl.itemId, authentication, owner),
1072
+ common.shareItemToGroups(nonTrackerGroupIds, tmpl.itemId, authentication)
1073
+ ]);
1074
+ }
1075
+ else {
1076
+ return common.shareItemToGroups(groupIds, tmpl.itemId, authentication, owner);
1077
+ }
1078
+ }
1079
+ }
1080
+ else {
1081
+ return common.shareItemToGroups(groupIds, tmpl.itemId, authentication);
1082
+ }
1083
+ }));
1084
+ }
1142
1085
 
1143
- /**
1144
- * Sorts a list of templates in place to match a provided sort-order list.
1145
- *
1146
- * @param templates List of templates in a Solution
1147
- * @param sortOrderIds List of template ids in the desired sort order
1148
- */
1149
- function sortTemplates(templates, sortOrderIds) {
1150
- templates.sort(function (template1, template2) {
1151
- return sortOrderIds.indexOf(template1.itemId) -
1152
- sortOrderIds.indexOf(template2.itemId);
1153
- });
1154
- }
1086
+ /** @license
1087
+ * Copyright 2020 Esri
1088
+ *
1089
+ * Licensed under the Apache License, Version 2.0 (the "License");
1090
+ * you may not use this file except in compliance with the License.
1091
+ * You may obtain a copy of the License at
1092
+ *
1093
+ * http://www.apache.org/licenses/LICENSE-2.0
1094
+ *
1095
+ * Unless required by applicable law or agreed to in writing, software
1096
+ * distributed under the License is distributed on an "AS IS" BASIS,
1097
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1098
+ * See the License for the specific language governing permissions and
1099
+ * limitations under the License.
1100
+ */
1101
+ /**
1102
+ * Delegate post-processing to the type specific
1103
+ * processors. This allows each type to have fine-grained
1104
+ * control over what they do. Common post-processing is
1105
+ * exposed as functions that can be imported
1106
+ *
1107
+ * @param deployedSolutionId
1108
+ * @param templates
1109
+ * @param clonedSolutions
1110
+ * @param authentication
1111
+ * @param templateDictionary
1112
+ */
1113
+ function postProcess(deployedSolutionId, templates, clonedSolutions, authentication, templateDictionary) {
1114
+ // connect the solution with its items; groups cannot be connected
1115
+ const relationshipPromises = clonedSolutions
1116
+ .filter(entry => entry.type !== "Group")
1117
+ .map(entry => portal.addItemRelationship({
1118
+ originItemId: deployedSolutionId,
1119
+ destinationItemId: entry.id,
1120
+ relationshipType: "Solution2Item",
1121
+ authentication: authentication
1122
+ }) // TODO: remove `as any`, which is here until arcgis-rest-js' ItemRelationshipType defn catches up
1123
+ );
1124
+ // delegate sharing to groups
1125
+ const sharePromises = shareTemplatesToGroups(templates, templateDictionary, authentication);
1126
+ // what needs post processing?
1127
+ const itemsToProcess = clonedSolutions.filter(entry => entry.postProcess);
1128
+ // map over these items
1129
+ const postProcessPromises = itemsToProcess.reduce((acc, entry) => {
1130
+ const itemHandler = moduleMap[entry.type];
1131
+ // only delegate if the handler has a postProcess method
1132
+ if (itemHandler && itemHandler.postProcess) {
1133
+ acc.push(itemHandler.postProcess(entry.id, entry.type, clonedSolutions, common.getTemplateById(templates, entry.id), templates, templateDictionary, authentication));
1134
+ }
1135
+ return acc;
1136
+ }, []);
1137
+ return Promise.all([sharePromises].concat(postProcessPromises, relationshipPromises));
1138
+ }
1155
1139
 
1156
- /** @license
1157
- * Copyright 2018 Esri
1158
- *
1159
- * Licensed under the Apache License, Version 2.0 (the "License");
1160
- * you may not use this file except in compliance with the License.
1161
- * You may obtain a copy of the License at
1162
- *
1163
- * http://www.apache.org/licenses/LICENSE-2.0
1164
- *
1165
- * Unless required by applicable law or agreed to in writing, software
1166
- * distributed under the License is distributed on an "AS IS" BASIS,
1167
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1168
- * See the License for the specific language governing permissions and
1169
- * limitations under the License.
1170
- */
1171
- // NOTE: Moved to separate file to allow stubbing in main deploySolution tests
1172
- function deploySolutionFromTemplate(templateSolutionId, solutionTemplateBase, solutionTemplateData, authentication, options) {
1173
- options.storageVersion = common.extractSolutionVersion(solutionTemplateData);
1174
- return new Promise(function (resolve, reject) {
1175
- var _a;
1176
- // It is possible to provide a separate authentication for the source
1177
- var storageAuthentication = options.storageAuthentication
1178
- ? options.storageAuthentication
1179
- : authentication;
1180
- // Replacement dictionary and high-level deployment ids for cleanup
1181
- // TODO: Extract all templateDictionary prep into a separate function
1182
- var templateDictionary = (_a = options.templateDictionary) !== null && _a !== void 0 ? _a : {};
1183
- var deployedFolderId;
1184
- var deployedSolutionId;
1185
- _applySourceToDeployOptions(options, solutionTemplateBase, templateDictionary, authentication);
1186
- if (options.additionalTypeKeywords) {
1187
- solutionTemplateBase.typeKeywords = [].concat(solutionTemplateBase.typeKeywords, options.additionalTypeKeywords);
1188
- }
1189
- // Get the thumbnail file
1190
- var thumbFilename = "thumbnail";
1191
- var thumbDef = Promise.resolve(null);
1192
- if (!options.thumbnail && options.thumbnailurl) {
1193
- // Figure out the thumbnail's filename
1194
- thumbFilename =
1195
- common.getFilenameFromUrl(options.thumbnailurl) || thumbFilename;
1196
- var thumbnailurl = common.appendQueryParam(options.thumbnailurl, "w=400");
1197
- delete options.thumbnailurl;
1198
- // Fetch the thumbnail
1199
- thumbDef = common.getBlobAsFile(thumbnailurl, thumbFilename, storageAuthentication, [400]);
1200
- }
1201
- _replaceParamVariables(solutionTemplateData, templateDictionary);
1202
- // Get information about deployment environment
1203
- Promise.all([
1204
- common.getPortal("", authentication),
1205
- common.getUser(authentication),
1206
- common.getFoldersAndGroups(authentication),
1207
- thumbDef
1208
- ])
1209
- .then(function (responses) {
1210
- var _a = __read(responses, 4), portalResponse = _a[0], userResponse = _a[1], foldersAndGroupsResponse = _a[2], thumbnailFile = _a[3];
1211
- if (!options.thumbnail && thumbnailFile) {
1212
- options.thumbnail = thumbnailFile;
1213
- }
1214
- // update template items with source-itemId type keyword
1215
- solutionTemplateData.templates = solutionTemplateData.templates.map(function (template) {
1216
- var sourceId = "source-" + template.itemId;
1217
- /* istanbul ignore else */
1218
- if (template.item) {
1219
- /* istanbul ignore else */
1220
- if (template.item.typeKeywords) {
1221
- template.item.typeKeywords.push(sourceId);
1222
- }
1223
- /* istanbul ignore else */
1224
- if (template.item.tags &&
1225
- common.getProp(template, "item.type") === "Group") {
1226
- template.item.tags.push(sourceId);
1227
- }
1228
- }
1229
- return template;
1230
- });
1231
- templateDictionary.isPortal = portalResponse.isPortal;
1232
- templateDictionary.organization = Object.assign(templateDictionary.organization || {}, portalResponse);
1233
- // TODO: Add more computed properties here
1234
- // portal: portalResponse
1235
- // orgextent as bbox for assignment onto items
1236
- // more info in #266 https://github.com/Esri/solution.js/issues/266
1237
- templateDictionary.portalBaseUrl = _getPortalBaseUrl(portalResponse, authentication);
1238
- templateDictionary.user = userResponse;
1239
- templateDictionary.user.folders = foldersAndGroupsResponse.folders;
1240
- templateDictionary.user.groups = foldersAndGroupsResponse.groups.filter(function (group) {
1241
- return group.owner === templateDictionary.user.username;
1242
- });
1243
- // Create a folder to hold the deployed solution. We use the solution name, appending a sequential
1244
- // suffix if the folder exists, e.g.,
1245
- // * Manage Right of Way Activities
1246
- // * Manage Right of Way Activities 1
1247
- // * Manage Right of Way Activities 2
1248
- var folderPromise = common.createUniqueFolder(solutionTemplateBase.title, templateDictionary, authentication);
1249
- // Apply the portal extents to the solution
1250
- var portalExtent = portalResponse.defaultExtent;
1251
- var extentsPromise = common.convertExtentWithFallback(portalExtent, undefined, { wkid: 4326 }, portalResponse.helperServices.geometry.url, authentication);
1252
- // Await completion of async actions: folder creation & extents conversion
1253
- return Promise.all([folderPromise, extentsPromise]);
1254
- })
1255
- .then(function (responses) {
1256
- var _a = __read(responses, 2), folderResponse = _a[0], wgs84Extent = _a[1];
1257
- deployedFolderId = folderResponse.folder.id;
1258
- templateDictionary.folderId = deployedFolderId;
1259
- templateDictionary.solutionItemExtent =
1260
- wgs84Extent.xmin +
1261
- "," +
1262
- wgs84Extent.ymin +
1263
- "," +
1264
- wgs84Extent.xmax +
1265
- "," +
1266
- wgs84Extent.ymax;
1267
- // Hub Solutions depend on organization defaultExtentBBox as a nested array not a string
1268
- templateDictionary.organization.defaultExtentBBox = [
1269
- [wgs84Extent.xmin, wgs84Extent.ymin],
1270
- [wgs84Extent.xmax, wgs84Extent.ymax]
1271
- ];
1272
- // Create a deployed Solution item
1273
- var createSolutionItemBase = __assign(__assign({}, common.sanitizeJSONAndReportChanges(solutionTemplateBase)), { type: "Solution", typeKeywords: ["Solution"] });
1274
- if (options.additionalTypeKeywords) {
1275
- createSolutionItemBase.typeKeywords = ["Solution"].concat(options.additionalTypeKeywords);
1276
- }
1277
- // Create deployed solution item
1278
- createSolutionItemBase.thumbnail = options.thumbnail;
1279
- return common.createItemWithData(createSolutionItemBase, {}, authentication, deployedFolderId);
1280
- })
1281
- .then(function (createSolutionResponse) {
1282
- deployedSolutionId = createSolutionResponse.id;
1283
- // Protect the solution item
1284
- var protectOptions = {
1285
- id: deployedSolutionId,
1286
- authentication: authentication
1287
- };
1288
- return portal.protectItem(protectOptions);
1289
- })
1290
- .then(function () {
1291
- // TODO: Attach the whole solution model so we can
1292
- // have stuff like `{{solution.item.title}}
1293
- templateDictionary.solutionItemId = deployedSolutionId;
1294
- solutionTemplateBase.id = deployedSolutionId;
1295
- solutionTemplateBase.tryitUrl = _checkedReplaceAll(solutionTemplateBase.tryitUrl, templateSolutionId, deployedSolutionId);
1296
- solutionTemplateBase.url = _checkedReplaceAll(solutionTemplateBase.url, templateSolutionId, deployedSolutionId);
1297
- // Handle the contained item templates
1298
- return deploySolutionItems(storageAuthentication.portal, templateSolutionId, solutionTemplateData.templates, storageAuthentication, templateDictionary, deployedSolutionId, authentication, options);
1299
- })
1300
- .then(function (clonedSolutionsResponse) {
1301
- solutionTemplateData.templates = solutionTemplateData.templates.map(function (itemTemplate) {
1302
- // Update ids present in template dictionary
1303
- itemTemplate.itemId = common.getProp(templateDictionary, itemTemplate.itemId + ".itemId");
1304
- // Update the dependencies hash to point to the new item ids
1305
- itemTemplate.dependencies = itemTemplate.dependencies.map(function (id) {
1306
- return hubCommon.getWithDefault(templateDictionary, id + ".itemId", id);
1307
- });
1308
- return itemTemplate;
1309
- });
1310
- // Sort the templates into build order, which is provided by clonedSolutionsResponse
1311
- sortTemplates(solutionTemplateData.templates, clonedSolutionsResponse.map(function (response) { return response.id; }));
1312
- // Wrap up with post-processing, in which we deal with groups and cycle remnants
1313
- return postProcess(deployedSolutionId, solutionTemplateData.templates, clonedSolutionsResponse, authentication, templateDictionary);
1314
- })
1315
- .then(function () {
1316
- // Update solution item using internal representation & and the updated data JSON
1317
- solutionTemplateBase.typeKeywords = [].concat(solutionTemplateBase.typeKeywords, ["Deployed"]);
1318
- var iTemplateKeyword = solutionTemplateBase.typeKeywords.indexOf("Template");
1319
- /* istanbul ignore else */
1320
- if (iTemplateKeyword >= 0) {
1321
- solutionTemplateBase.typeKeywords.splice(iTemplateKeyword, 1);
1322
- }
1323
- solutionTemplateData.templates = solutionTemplateData.templates.map(function (itemTemplate) {
1324
- return _purgeTemplateProperties(itemTemplate);
1325
- });
1326
- solutionTemplateData.templates = _updateGroupReferences(solutionTemplateData.templates, templateDictionary);
1327
- // Update solution items data using template dictionary, and then update the
1328
- // itemId & dependencies in each item template
1329
- solutionTemplateBase.data = common.replaceInTemplate(solutionTemplateData, templateDictionary);
1330
- // Write any user defined params to the solution
1331
- /* istanbul ignore else */
1332
- if (templateDictionary.params) {
1333
- solutionTemplateBase.data.params = templateDictionary.params;
1334
- }
1335
- return common.updateItem(solutionTemplateBase, authentication, deployedFolderId);
1336
- })
1337
- .then(function () { return resolve(solutionTemplateBase.id); }, reject);
1338
- });
1339
- }
1340
- /**
1341
- * Update the deployOptions with the group properties
1342
- *
1343
- * @param deployOptions
1344
- * @param sourceInfo
1345
- * @param authentication
1346
- * @param isGroup Boolean to indicate if the files are associated with a group or item
1347
- * @internal
1348
- */
1349
- function _applySourceToDeployOptions(deployOptions, solutionTemplateBase, templateDictionary, authentication) {
1350
- // Deploy a solution from the template's contents,
1351
- // using the template's information as defaults for the deployed solution item
1352
- ["title", "snippet", "description", "tags"].forEach(function (prop) {
1353
- var _a;
1354
- deployOptions[prop] = (_a = deployOptions[prop]) !== null && _a !== void 0 ? _a : solutionTemplateBase[prop];
1355
- if (deployOptions[prop]) {
1356
- solutionTemplateBase[prop] = deployOptions[prop];
1357
- // carry these options forward on the templateDict
1358
- templateDictionary[prop] = deployOptions[prop];
1359
- }
1360
- });
1361
- if (!deployOptions.thumbnailurl && solutionTemplateBase.thumbnail) {
1362
- // Get the full path to the thumbnail
1363
- deployOptions.thumbnailurl = common.generateSourceThumbnailUrl(authentication.portal, solutionTemplateBase.id, solutionTemplateBase.thumbnail);
1364
- delete solutionTemplateBase.thumbnail;
1365
- }
1366
- return deployOptions;
1367
- }
1368
- function _replaceParamVariables(solutionTemplateData, templateDictionary) {
1369
- // a custom params object can be passed in with the options to deploy a solution
1370
- // in most cases we can defer to the item type handlers to use these values
1371
- // for variable replacement
1372
- // for spatial reference specifically we need to replace up front so the default extent
1373
- // logic can execute as expected
1374
- solutionTemplateData.templates = solutionTemplateData.templates.map(function (template) {
1375
- // can't do this as it causes other values that don't exist in the dict yet to revert to defaults they may have defined
1376
- // return common.replaceInTemplate(template, templateDictionary);
1377
- /* istanbul ignore else */
1378
- if (template.type === "Feature Service") {
1379
- var paramsLookup = "params.";
1380
- var wkidItemPath = "item.spatialReference.wkid";
1381
- template = _updateProp(template, wkidItemPath, paramsLookup, templateDictionary);
1382
- var wkidServicePath = "properties.service.spatialReference.wkid";
1383
- template = _updateProp(template, wkidServicePath, paramsLookup, templateDictionary);
1384
- }
1385
- return template;
1386
- });
1387
- }
1388
- function _updateProp(template, path, lookup, templateDictionary) {
1389
- var wkid = common.getProp(template, path);
1390
- /* istanbul ignore else */
1391
- if (wkid && typeof wkid === "string" && wkid.indexOf(lookup) > -1) {
1392
- common.setProp(template, path, common.replaceInTemplate(wkid, templateDictionary));
1393
- }
1394
- return template;
1395
- }
1396
- function _checkedReplaceAll(template, oldValue, newValue) {
1397
- var newTemplate;
1398
- if (template && template.indexOf(oldValue) > -1) {
1399
- var re = new RegExp(oldValue, "g");
1400
- newTemplate = template.replace(re, newValue);
1401
- }
1402
- else {
1403
- newTemplate = template;
1404
- }
1405
- return newTemplate;
1406
- }
1407
- function _getPortalBaseUrl(portalResponse, authentication) {
1408
- // As of Spring 2020, only HTTPS (see
1409
- // https://www.esri.com/arcgis-blog/products/product/administration/2019-arcgis-transport-security-improvements/)
1410
- var scheme = "https"; // portalResponse.allSSL ? "https" : "http";
1411
- var urlKey = common.getProp(portalResponse, "urlKey");
1412
- var customBaseUrl = common.getProp(portalResponse, "customBaseUrl");
1413
- var enterpriseBaseUrl = common.getProp(portalResponse, "portalHostname");
1414
- return urlKey && customBaseUrl
1415
- ? scheme + "://" + urlKey + "." + customBaseUrl
1416
- : enterpriseBaseUrl
1417
- ? scheme + "://" + enterpriseBaseUrl
1418
- : authentication.portal.replace("/sharing/rest", "");
1419
- }
1420
- function _updateGroupReferences(itemTemplates, templateDictionary) {
1421
- var groupIds = itemTemplates.reduce(function (result, t) {
1422
- if (t.type === "Group") {
1423
- result.push(t.itemId);
1424
- }
1425
- return result;
1426
- }, []);
1427
- Object.keys(templateDictionary).forEach(function (k) {
1428
- var newId = templateDictionary[k].itemId;
1429
- if (groupIds.indexOf(newId) > -1) {
1430
- itemTemplates.forEach(function (t) {
1431
- t.groups = t.groups.map(function (id) { return (id === k ? newId : id); });
1432
- });
1433
- }
1434
- });
1435
- return itemTemplates;
1436
- }
1437
- function _purgeTemplateProperties(itemTemplate) {
1438
- var retainProps = ["itemId", "type", "dependencies", "groups"];
1439
- var deleteProps = Object.keys(itemTemplate).filter(function (k) { return retainProps.indexOf(k) < 0; });
1440
- common.deleteProps(itemTemplate, deleteProps);
1441
- return itemTemplate;
1442
- }
1140
+ /**
1141
+ * Sorts a list of templates in place to match a provided sort-order list.
1142
+ *
1143
+ * @param templates List of templates in a Solution
1144
+ * @param sortOrderIds List of template ids in the desired sort order
1145
+ */
1146
+ function sortTemplates(templates, sortOrderIds) {
1147
+ templates.sort((template1, template2) => sortOrderIds.indexOf(template1.itemId) -
1148
+ sortOrderIds.indexOf(template2.itemId));
1149
+ }
1443
1150
 
1444
- /** @license
1445
- * Copyright 2018 Esri
1446
- *
1447
- * Licensed under the Apache License, Version 2.0 (the "License");
1448
- * you may not use this file except in compliance with the License.
1449
- * You may obtain a copy of the License at
1450
- *
1451
- * http://www.apache.org/licenses/LICENSE-2.0
1452
- *
1453
- * Unless required by applicable law or agreed to in writing, software
1454
- * distributed under the License is distributed on an "AS IS" BASIS,
1455
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1456
- * See the License for the specific language governing permissions and
1457
- * limitations under the License.
1458
- */
1459
- /**
1460
- * Given an itemId or an object, either fetch the item or
1461
- * resolve using the object, if it is structured as expected
1462
- *
1463
- * @param idOrObject string || object like `{item:{...}, data: {...}}`
1464
- * @param authentication UserSession
1465
- */
1466
- function getSolutionTemplateItem(idOrObject, authentication) {
1467
- if (typeof idOrObject === "string") {
1468
- // get the item + data
1469
- return Promise.all([
1470
- common.getItemBase(idOrObject, authentication),
1471
- common.getItemDataAsJson(idOrObject, authentication)
1472
- ]).then(function (_a) {
1473
- var _b = __read(_a, 2), item = _b[0], data = _b[1];
1474
- // format into a model and migrate the schema
1475
- return common.migrateSchema({
1476
- item: item,
1477
- data: data
1478
- });
1479
- });
1480
- }
1481
- else {
1482
- // check if it is a "Model"
1483
- if (_isModel(idOrObject)) {
1484
- // run migrations
1485
- return common.migrateSchema(idOrObject);
1486
- }
1487
- else {
1488
- return Promise.reject(common.fail("getSolutionTemplateItem must be passed an item id or a model object"));
1489
- }
1490
- }
1491
- }
1492
- /**
1493
- * Update the Deploy Options with information from the
1494
- * Solution Template item
1495
- *
1496
- * @param deployOptions
1497
- * @param item
1498
- * @param authentication
1499
- */
1500
- function updateDeployOptions(deployOptions, item, authentication) {
1501
- var _a, _b, _c, _d, _e;
1502
- deployOptions.jobId = (_a = deployOptions.jobId) !== null && _a !== void 0 ? _a : item.id;
1503
- deployOptions.title = (_b = deployOptions.title) !== null && _b !== void 0 ? _b : item.title;
1504
- deployOptions.snippet = (_c = deployOptions.snippet) !== null && _c !== void 0 ? _c : item.snippet;
1505
- deployOptions.description = (_d = deployOptions.description) !== null && _d !== void 0 ? _d : item.description;
1506
- deployOptions.tags = (_e = deployOptions.tags) !== null && _e !== void 0 ? _e : item.tags;
1507
- // add the thumbnail url
1508
- deployOptions.thumbnailurl = item.thumbnail
1509
- ? common.getItemThumbnailUrl(item.id, item.thumbnail, false, authentication)
1510
- : null;
1511
- return deployOptions;
1512
- }
1513
- /**
1514
- * Check if an object is an Model
1515
- *
1516
- * @param obj any object
1517
- */
1518
- function _isModel(obj) {
1519
- var result = false;
1520
- // TODO Hoist into common?
1521
- var isNotStringOrArray = function (v) {
1522
- return v != null &&
1523
- typeof v !== "string" &&
1524
- !Array.isArray(v) &&
1525
- typeof v === "object";
1526
- };
1527
- if (isNotStringOrArray(obj)) {
1528
- result = ["item", "data"].reduce(function (acc, prop) {
1529
- if (acc) {
1530
- acc = isNotStringOrArray(obj[prop]);
1531
- }
1532
- return acc;
1533
- }, true);
1534
- }
1535
- return result;
1536
- }
1537
- /**
1538
- * Does the item have the correct type and keywords
1539
- * to be a Solution Template item?
1540
- *
1541
- * @param item IItem
1542
- */
1543
- function isSolutionTemplateItem(item) {
1544
- var kwds = item.typeKeywords;
1545
- // Solution items
1546
- var result = false;
1547
- if (item.type === "Solution") {
1548
- if (kwds.indexOf("Solution") > -1 &&
1549
- (kwds.indexOf("Template") > -1 || kwds.indexOf("solutionTemplate") > -1)) {
1550
- result = true;
1551
- }
1552
- }
1553
- // Older Hub Solutions used Web Mapping Application items
1554
- if (item.type === "Web Mapping Application") {
1555
- if (kwds.indexOf("hubSolutionTemplate") > -1) {
1556
- result = true;
1557
- }
1558
- }
1559
- return result;
1560
- }
1151
+ /** @license
1152
+ * Copyright 2018 Esri
1153
+ *
1154
+ * Licensed under the Apache License, Version 2.0 (the "License");
1155
+ * you may not use this file except in compliance with the License.
1156
+ * You may obtain a copy of the License at
1157
+ *
1158
+ * http://www.apache.org/licenses/LICENSE-2.0
1159
+ *
1160
+ * Unless required by applicable law or agreed to in writing, software
1161
+ * distributed under the License is distributed on an "AS IS" BASIS,
1162
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1163
+ * See the License for the specific language governing permissions and
1164
+ * limitations under the License.
1165
+ */
1166
+ // NOTE: Moved to separate file to allow stubbing in main deploySolution tests
1167
+ function deploySolutionFromTemplate(templateSolutionId, solutionTemplateBase, solutionTemplateData, authentication, options) {
1168
+ options.storageVersion = common__namespace.extractSolutionVersion(solutionTemplateData);
1169
+ return new Promise((resolve, reject) => {
1170
+ // It is possible to provide a separate authentication for the source
1171
+ const storageAuthentication = options.storageAuthentication
1172
+ ? options.storageAuthentication
1173
+ : authentication;
1174
+ // Replacement dictionary and high-level deployment ids for cleanup
1175
+ // TODO: Extract all templateDictionary prep into a separate function
1176
+ const templateDictionary = options.templateDictionary ?? {};
1177
+ let deployedFolderId;
1178
+ let deployedSolutionId;
1179
+ _applySourceToDeployOptions(options, solutionTemplateBase, templateDictionary, authentication);
1180
+ if (options.additionalTypeKeywords) {
1181
+ solutionTemplateBase.typeKeywords = [].concat(solutionTemplateBase.typeKeywords, options.additionalTypeKeywords);
1182
+ }
1183
+ // Get the thumbnail file
1184
+ let thumbFilename = "thumbnail";
1185
+ let thumbDef = Promise.resolve(null);
1186
+ if (!options.thumbnail && options.thumbnailurl) {
1187
+ // Figure out the thumbnail's filename
1188
+ thumbFilename =
1189
+ common__namespace.getFilenameFromUrl(options.thumbnailurl) || thumbFilename;
1190
+ const thumbnailurl = common__namespace.appendQueryParam(options.thumbnailurl, "w=400");
1191
+ delete options.thumbnailurl;
1192
+ // Fetch the thumbnail
1193
+ thumbDef = common__namespace.getBlobAsFile(thumbnailurl, thumbFilename, storageAuthentication, [400]);
1194
+ }
1195
+ _replaceParamVariables(solutionTemplateData, templateDictionary);
1196
+ // Get information about deployment environment
1197
+ Promise.all([
1198
+ common__namespace.getPortal("", authentication),
1199
+ common__namespace.getUser(authentication),
1200
+ common__namespace.getFoldersAndGroups(authentication),
1201
+ thumbDef
1202
+ ])
1203
+ .then(responses => {
1204
+ const [portalResponse, userResponse, foldersAndGroupsResponse, thumbnailFile] = responses;
1205
+ if (!options.thumbnail && thumbnailFile) {
1206
+ options.thumbnail = thumbnailFile;
1207
+ }
1208
+ // update template items with source-itemId type keyword
1209
+ solutionTemplateData.templates = solutionTemplateData.templates.map((template) => {
1210
+ const sourceId = "source-" + template.itemId;
1211
+ /* istanbul ignore else */
1212
+ if (template.item) {
1213
+ /* istanbul ignore else */
1214
+ if (template.item.typeKeywords) {
1215
+ template.item.typeKeywords.push(sourceId);
1216
+ }
1217
+ /* istanbul ignore else */
1218
+ if (template.item.tags &&
1219
+ common__namespace.getProp(template, "item.type") === "Group") {
1220
+ template.item.tags.push(sourceId);
1221
+ }
1222
+ }
1223
+ return template;
1224
+ });
1225
+ templateDictionary.isPortal = portalResponse.isPortal;
1226
+ templateDictionary.organization = Object.assign(templateDictionary.organization || {}, portalResponse);
1227
+ // TODO: Add more computed properties here
1228
+ // portal: portalResponse
1229
+ // orgextent as bbox for assignment onto items
1230
+ // more info in #266 https://github.com/Esri/solution.js/issues/266
1231
+ templateDictionary.portalBaseUrl = _getPortalBaseUrl(portalResponse, authentication);
1232
+ templateDictionary.user = userResponse;
1233
+ templateDictionary.user.folders = foldersAndGroupsResponse.folders;
1234
+ templateDictionary.user.groups = foldersAndGroupsResponse.groups.filter((group) => group.owner === templateDictionary.user.username);
1235
+ // if we have tracking views and the user is not admin or the org doesn't support tracking an error is thrown
1236
+ common__namespace.setLocationTrackingEnabled(portalResponse, userResponse, templateDictionary, solutionTemplateData.templates);
1237
+ const trackingOwnerPromise = common__namespace.getTackingServiceOwner(templateDictionary, authentication);
1238
+ // Create a folder to hold the deployed solution. We use the solution name, appending a sequential
1239
+ // suffix if the folder exists, e.g.,
1240
+ // * Manage Right of Way Activities
1241
+ // * Manage Right of Way Activities 1
1242
+ // * Manage Right of Way Activities 2
1243
+ const folderPromise = common__namespace.createUniqueFolder(solutionTemplateBase.title, templateDictionary, authentication);
1244
+ // Apply the portal extents to the solution
1245
+ const portalExtent = portalResponse.defaultExtent;
1246
+ const extentsPromise = common__namespace.convertExtentWithFallback(portalExtent, undefined, { wkid: 4326 }, portalResponse.helperServices.geometry.url, authentication);
1247
+ // Await completion of async actions: folder creation & extents conversion
1248
+ return Promise.all([folderPromise, extentsPromise, trackingOwnerPromise]);
1249
+ })
1250
+ .then(responses => {
1251
+ const [folderResponse, wgs84Extent, trackingOwnerResponse] = responses;
1252
+ deployedFolderId = folderResponse.folder.id;
1253
+ templateDictionary.folderId = deployedFolderId;
1254
+ templateDictionary.solutionItemExtent =
1255
+ wgs84Extent.xmin +
1256
+ "," +
1257
+ wgs84Extent.ymin +
1258
+ "," +
1259
+ wgs84Extent.xmax +
1260
+ "," +
1261
+ wgs84Extent.ymax;
1262
+ // Hub Solutions depend on organization defaultExtentBBox as a nested array not a string
1263
+ templateDictionary.organization.defaultExtentBBox = [
1264
+ [wgs84Extent.xmin, wgs84Extent.ymin],
1265
+ [wgs84Extent.xmax, wgs84Extent.ymax]
1266
+ ];
1267
+ // update templateDictionary to indicate if the user owns the tracking service
1268
+ // this will affect how we handle group sharing
1269
+ /* istanbul ignore else */
1270
+ if (templateDictionary.locationTrackingEnabled) {
1271
+ common.setCreateProp(templateDictionary, "locationTracking.userIsOwner", trackingOwnerResponse);
1272
+ }
1273
+ // Create a deployed Solution item
1274
+ const createSolutionItemBase = {
1275
+ ...common__namespace.sanitizeJSONAndReportChanges(solutionTemplateBase),
1276
+ type: "Solution",
1277
+ typeKeywords: ["Solution"]
1278
+ };
1279
+ if (options.additionalTypeKeywords) {
1280
+ createSolutionItemBase.typeKeywords = ["Solution"].concat(options.additionalTypeKeywords);
1281
+ }
1282
+ // Create deployed solution item
1283
+ createSolutionItemBase.thumbnail = options.thumbnail;
1284
+ return common__namespace.createItemWithData(createSolutionItemBase, {}, authentication, deployedFolderId);
1285
+ })
1286
+ .then(createSolutionResponse => {
1287
+ deployedSolutionId = createSolutionResponse.id;
1288
+ // Protect the solution item
1289
+ const protectOptions = {
1290
+ id: deployedSolutionId,
1291
+ authentication
1292
+ };
1293
+ return portal__namespace.protectItem(protectOptions);
1294
+ })
1295
+ .then(() => {
1296
+ // TODO: Attach the whole solution model so we can
1297
+ // have stuff like `{{solution.item.title}}
1298
+ templateDictionary.solutionItemId = deployedSolutionId;
1299
+ solutionTemplateBase.id = deployedSolutionId;
1300
+ solutionTemplateBase.tryitUrl = _checkedReplaceAll(solutionTemplateBase.tryitUrl, templateSolutionId, deployedSolutionId);
1301
+ solutionTemplateBase.url = _checkedReplaceAll(solutionTemplateBase.url, templateSolutionId, deployedSolutionId);
1302
+ // Handle the contained item templates
1303
+ return deploySolutionItems(storageAuthentication.portal, templateSolutionId, solutionTemplateData.templates, storageAuthentication, templateDictionary, deployedSolutionId, authentication, options);
1304
+ })
1305
+ .then((clonedSolutionsResponse) => {
1306
+ solutionTemplateData.templates = solutionTemplateData.templates.map((itemTemplate) => {
1307
+ // Update ids present in template dictionary
1308
+ itemTemplate.itemId = common__namespace.getProp(templateDictionary, `${itemTemplate.itemId}.itemId`);
1309
+ // Update the dependencies hash to point to the new item ids
1310
+ itemTemplate.dependencies = itemTemplate.dependencies.map((id) => hubCommon.getWithDefault(templateDictionary, `${id}.itemId`, id));
1311
+ return itemTemplate;
1312
+ });
1313
+ // Sort the templates into build order, which is provided by clonedSolutionsResponse
1314
+ sortTemplates(solutionTemplateData.templates, clonedSolutionsResponse.map(response => response.id));
1315
+ // Wrap up with post-processing, in which we deal with groups and cycle remnants
1316
+ return postProcess(deployedSolutionId, solutionTemplateData.templates, clonedSolutionsResponse, authentication, templateDictionary);
1317
+ })
1318
+ .then(() => {
1319
+ // Update solution item using internal representation & and the updated data JSON
1320
+ solutionTemplateBase.typeKeywords = [].concat(solutionTemplateBase.typeKeywords, ["Deployed"]);
1321
+ const iTemplateKeyword = solutionTemplateBase.typeKeywords.indexOf("Template");
1322
+ /* istanbul ignore else */
1323
+ if (iTemplateKeyword >= 0) {
1324
+ solutionTemplateBase.typeKeywords.splice(iTemplateKeyword, 1);
1325
+ }
1326
+ solutionTemplateData.templates = solutionTemplateData.templates.map((itemTemplate) => _purgeTemplateProperties(itemTemplate));
1327
+ solutionTemplateData.templates = _updateGroupReferences(solutionTemplateData.templates, templateDictionary);
1328
+ // Update solution items data using template dictionary, and then update the
1329
+ // itemId & dependencies in each item template
1330
+ solutionTemplateBase.data = common__namespace.replaceInTemplate(solutionTemplateData, templateDictionary);
1331
+ // Write any user defined params to the solution
1332
+ /* istanbul ignore else */
1333
+ if (templateDictionary.params) {
1334
+ solutionTemplateBase.data.params = templateDictionary.params;
1335
+ }
1336
+ return common__namespace.updateItem(solutionTemplateBase, authentication, deployedFolderId);
1337
+ })
1338
+ .then(() => resolve(solutionTemplateBase.id), reject);
1339
+ });
1340
+ }
1341
+ /**
1342
+ * Update the deployOptions with the group properties
1343
+ *
1344
+ * @param deployOptions
1345
+ * @param sourceInfo
1346
+ * @param authentication
1347
+ * @param isGroup Boolean to indicate if the files are associated with a group or item
1348
+ * @internal
1349
+ */
1350
+ function _applySourceToDeployOptions(deployOptions, solutionTemplateBase, templateDictionary, authentication) {
1351
+ // Deploy a solution from the template's contents,
1352
+ // using the template's information as defaults for the deployed solution item
1353
+ ["title", "snippet", "description", "tags"].forEach(prop => {
1354
+ deployOptions[prop] = deployOptions[prop] ?? solutionTemplateBase[prop];
1355
+ if (deployOptions[prop]) {
1356
+ solutionTemplateBase[prop] = deployOptions[prop];
1357
+ // carry these options forward on the templateDict
1358
+ templateDictionary[prop] = deployOptions[prop];
1359
+ }
1360
+ });
1361
+ if (!deployOptions.thumbnailurl && solutionTemplateBase.thumbnail) {
1362
+ // Get the full path to the thumbnail
1363
+ deployOptions.thumbnailurl = common__namespace.generateSourceThumbnailUrl(authentication.portal, solutionTemplateBase.id, solutionTemplateBase.thumbnail);
1364
+ delete solutionTemplateBase.thumbnail;
1365
+ }
1366
+ return deployOptions;
1367
+ }
1368
+ function _replaceParamVariables(solutionTemplateData, templateDictionary) {
1369
+ // a custom params object can be passed in with the options to deploy a solution
1370
+ // in most cases we can defer to the item type handlers to use these values
1371
+ // for variable replacement
1372
+ // for spatial reference specifically we need to replace up front so the default extent
1373
+ // logic can execute as expected
1374
+ solutionTemplateData.templates = solutionTemplateData.templates.map((template) => {
1375
+ // can't do this as it causes other values that don't exist in the dict yet to revert to defaults they may have defined
1376
+ // return common.replaceInTemplate(template, templateDictionary);
1377
+ /* istanbul ignore else */
1378
+ if (template.type === "Feature Service") {
1379
+ const paramsLookup = "params.";
1380
+ const wkidItemPath = "item.spatialReference.wkid";
1381
+ template = _updateProp(template, wkidItemPath, paramsLookup, templateDictionary);
1382
+ const wkidServicePath = "properties.service.spatialReference.wkid";
1383
+ template = _updateProp(template, wkidServicePath, paramsLookup, templateDictionary);
1384
+ }
1385
+ return template;
1386
+ });
1387
+ }
1388
+ function _updateProp(template, path, lookup, templateDictionary) {
1389
+ const wkid = common__namespace.getProp(template, path);
1390
+ /* istanbul ignore else */
1391
+ if (wkid && typeof wkid === "string" && wkid.indexOf(lookup) > -1) {
1392
+ common__namespace.setProp(template, path, common__namespace.replaceInTemplate(wkid, templateDictionary));
1393
+ }
1394
+ return template;
1395
+ }
1396
+ function _checkedReplaceAll(template, oldValue, newValue) {
1397
+ let newTemplate;
1398
+ if (template && template.indexOf(oldValue) > -1) {
1399
+ const re = new RegExp(oldValue, "g");
1400
+ newTemplate = template.replace(re, newValue);
1401
+ }
1402
+ else {
1403
+ newTemplate = template;
1404
+ }
1405
+ return newTemplate;
1406
+ }
1407
+ function _getPortalBaseUrl(portalResponse, authentication) {
1408
+ // As of Spring 2020, only HTTPS (see
1409
+ // https://www.esri.com/arcgis-blog/products/product/administration/2019-arcgis-transport-security-improvements/)
1410
+ const scheme = "https"; // portalResponse.allSSL ? "https" : "http";
1411
+ const urlKey = common__namespace.getProp(portalResponse, "urlKey");
1412
+ const customBaseUrl = common__namespace.getProp(portalResponse, "customBaseUrl");
1413
+ const enterpriseBaseUrl = common__namespace.getProp(portalResponse, "portalHostname");
1414
+ return urlKey && customBaseUrl
1415
+ ? `${scheme}://${urlKey}.${customBaseUrl}`
1416
+ : enterpriseBaseUrl
1417
+ ? `${scheme}://${enterpriseBaseUrl}`
1418
+ : authentication.portal.replace("/sharing/rest", "");
1419
+ }
1420
+ function _updateGroupReferences(itemTemplates, templateDictionary) {
1421
+ const groupIds = itemTemplates.reduce((result, t) => {
1422
+ if (t.type === "Group") {
1423
+ result.push(t.itemId);
1424
+ }
1425
+ return result;
1426
+ }, []);
1427
+ Object.keys(templateDictionary).forEach(k => {
1428
+ const newId = templateDictionary[k].itemId;
1429
+ if (groupIds.indexOf(newId) > -1) {
1430
+ itemTemplates.forEach(t => {
1431
+ t.groups = t.groups.map((id) => (id === k ? newId : id));
1432
+ });
1433
+ }
1434
+ });
1435
+ return itemTemplates;
1436
+ }
1437
+ function _purgeTemplateProperties(itemTemplate) {
1438
+ const retainProps = ["itemId", "type", "dependencies", "groups"];
1439
+ const deleteProps = Object.keys(itemTemplate).filter(k => retainProps.indexOf(k) < 0);
1440
+ common__namespace.deleteProps(itemTemplate, deleteProps);
1441
+ return itemTemplate;
1442
+ }
1561
1443
 
1562
- /** @license
1563
- * Copyright 2018 Esri
1564
- *
1565
- * Licensed under the Apache License, Version 2.0 (the "License");
1566
- * you may not use this file except in compliance with the License.
1567
- * You may obtain a copy of the License at
1568
- *
1569
- * http://www.apache.org/licenses/LICENSE-2.0
1570
- *
1571
- * Unless required by applicable law or agreed to in writing, software
1572
- * distributed under the License is distributed on an "AS IS" BASIS,
1573
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1574
- * See the License for the specific language governing permissions and
1575
- * limitations under the License.
1576
- */
1577
- /**
1578
- * Deploy a Solution
1579
- *
1580
- * Pass in either the item id or an IModel (`{item:{}, model:{}}`)
1581
- * of a Solution Template, and this will generate the Solution
1582
- *
1583
- * @param maybeModel Item Id or IModel
1584
- * @param authentication Credentials for the destination organization
1585
- * @param options Options to override deployed information and to provide additional credentials
1586
- * @return The id of the created deployed solution item
1587
- */
1588
- function deploySolution(maybeModel, authentication, options) {
1589
- // if we are not passed the maybeModel, reject
1590
- if (!maybeModel) {
1591
- return Promise.reject(common.fail("The Solution Template id is missing"));
1592
- }
1593
- var deployOptions = options || {};
1594
- /* istanbul ignore else */
1595
- if (deployOptions.progressCallback) {
1596
- deployOptions.progressCallback(1, deployOptions.jobId); // let the caller know that we've started
1597
- }
1598
- // It is possible to provide a separate authentication for the source
1599
- var storageAuthentication = deployOptions.storageAuthentication
1600
- ? deployOptions.storageAuthentication
1601
- : authentication;
1602
- // deal with maybe getting an item or an id
1603
- return getSolutionTemplateItem(maybeModel, storageAuthentication)
1604
- .then(function (model) {
1605
- if (!isSolutionTemplateItem(model.item)) {
1606
- return Promise.reject(common.fail(model.item.id + " is not a Solution Template"));
1607
- }
1608
- else {
1609
- // fetch the metadata if the model's id is a GUID and pass the item & data forward
1610
- return Promise.all([
1611
- Promise.resolve(model.item),
1612
- Promise.resolve(model.data)
1613
- ]);
1614
- }
1615
- })
1616
- .then(function (responses) {
1617
- // extract responses
1618
- var _a = __read(responses, 2), itemBase = _a[0], itemData = _a[1];
1619
- // sanitize all the things
1620
- var sanitizer = new common.Sanitizer();
1621
- var item = common.sanitizeJSONAndReportChanges(itemBase, sanitizer);
1622
- // TODO: we should delegate data sanization to the type-specific modules
1623
- var data = itemData;
1624
- // get the item id before it is deleted
1625
- var itemId = item.id;
1626
- // apply item props to deployOptions
1627
- deployOptions = updateDeployOptions(deployOptions, item, storageAuthentication);
1628
- // Clone before mutating? This was messing me up in some testing...
1629
- common.deleteItemProps(item);
1630
- return deploySolutionFromTemplate(itemId, item, data, authentication, deployOptions);
1631
- })
1632
- .then(function (createdSolutionId) {
1633
- /* istanbul ignore else */
1634
- if (deployOptions.progressCallback) {
1635
- deployOptions.progressCallback(100, deployOptions.jobId); // we're done
1636
- }
1637
- return createdSolutionId;
1638
- }, function (error) {
1639
- // Error deploying solution
1640
- /* istanbul ignore else */
1641
- if (deployOptions.progressCallback) {
1642
- deployOptions.progressCallback(1, deployOptions.jobId);
1643
- }
1644
- return Promise.reject(error);
1645
- })
1646
- .catch(function (ex) {
1647
- throw ex;
1648
- });
1649
- }
1444
+ /** @license
1445
+ * Copyright 2018 Esri
1446
+ *
1447
+ * Licensed under the Apache License, Version 2.0 (the "License");
1448
+ * you may not use this file except in compliance with the License.
1449
+ * You may obtain a copy of the License at
1450
+ *
1451
+ * http://www.apache.org/licenses/LICENSE-2.0
1452
+ *
1453
+ * Unless required by applicable law or agreed to in writing, software
1454
+ * distributed under the License is distributed on an "AS IS" BASIS,
1455
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1456
+ * See the License for the specific language governing permissions and
1457
+ * limitations under the License.
1458
+ */
1459
+ /**
1460
+ * Given an itemId or an object, either fetch the item or
1461
+ * resolve using the object, if it is structured as expected
1462
+ *
1463
+ * @param idOrObject string || object like `{item:{...}, data: {...}}`
1464
+ * @param authentication UserSession
1465
+ */
1466
+ function getSolutionTemplateItem(idOrObject, authentication) {
1467
+ if (typeof idOrObject === "string") {
1468
+ // get the item + data
1469
+ return Promise.all([
1470
+ common__namespace.getItemBase(idOrObject, authentication),
1471
+ common__namespace.getItemDataAsJson(idOrObject, authentication)
1472
+ ]).then(([item, data]) => {
1473
+ // format into a model and migrate the schema
1474
+ return common__namespace.migrateSchema({
1475
+ item,
1476
+ data
1477
+ });
1478
+ });
1479
+ }
1480
+ else {
1481
+ // check if it is a "Model"
1482
+ if (_isModel(idOrObject)) {
1483
+ // run migrations
1484
+ return common__namespace.migrateSchema(idOrObject);
1485
+ }
1486
+ else {
1487
+ return Promise.reject(common__namespace.fail(`getSolutionTemplateItem must be passed an item id or a model object`));
1488
+ }
1489
+ }
1490
+ }
1491
+ /**
1492
+ * Update the Deploy Options with information from the
1493
+ * Solution Template item
1494
+ *
1495
+ * @param deployOptions
1496
+ * @param item
1497
+ * @param authentication
1498
+ */
1499
+ function updateDeployOptions(deployOptions, item, authentication) {
1500
+ deployOptions.jobId = deployOptions.jobId ?? item.id;
1501
+ deployOptions.title = deployOptions.title ?? item.title;
1502
+ deployOptions.snippet = deployOptions.snippet ?? item.snippet;
1503
+ deployOptions.description = deployOptions.description ?? item.description;
1504
+ deployOptions.tags = deployOptions.tags ?? item.tags;
1505
+ // add the thumbnail url
1506
+ deployOptions.thumbnailurl = item.thumbnail
1507
+ ? common__namespace.getItemThumbnailUrl(item.id, item.thumbnail, false, authentication)
1508
+ : null;
1509
+ return deployOptions;
1510
+ }
1511
+ /**
1512
+ * Check if an object is an Model
1513
+ *
1514
+ * @param obj any object
1515
+ */
1516
+ function _isModel(obj) {
1517
+ let result = false;
1518
+ // TODO Hoist into common?
1519
+ const isNotStringOrArray = (v) => v != null &&
1520
+ typeof v !== "string" &&
1521
+ !Array.isArray(v) &&
1522
+ typeof v === "object";
1523
+ if (isNotStringOrArray(obj)) {
1524
+ result = ["item", "data"].reduce((acc, prop) => {
1525
+ if (acc) {
1526
+ acc = isNotStringOrArray(obj[prop]);
1527
+ }
1528
+ return acc;
1529
+ }, true);
1530
+ }
1531
+ return result;
1532
+ }
1533
+ /**
1534
+ * Does the item have the correct type and keywords
1535
+ * to be a Solution Template item?
1536
+ *
1537
+ * @param item IItem
1538
+ */
1539
+ function isSolutionTemplateItem(item) {
1540
+ const kwds = item.typeKeywords;
1541
+ // Solution items
1542
+ let result = false;
1543
+ if (item.type === "Solution") {
1544
+ if (kwds.indexOf("Solution") > -1 &&
1545
+ (kwds.indexOf("Template") > -1 || kwds.indexOf("solutionTemplate") > -1)) {
1546
+ result = true;
1547
+ }
1548
+ }
1549
+ // Older Hub Solutions used Web Mapping Application items
1550
+ if (item.type === "Web Mapping Application") {
1551
+ if (kwds.indexOf("hubSolutionTemplate") > -1) {
1552
+ result = true;
1553
+ }
1554
+ }
1555
+ return result;
1556
+ }
1557
+
1558
+ /** @license
1559
+ * Copyright 2018 Esri
1560
+ *
1561
+ * Licensed under the Apache License, Version 2.0 (the "License");
1562
+ * you may not use this file except in compliance with the License.
1563
+ * You may obtain a copy of the License at
1564
+ *
1565
+ * http://www.apache.org/licenses/LICENSE-2.0
1566
+ *
1567
+ * Unless required by applicable law or agreed to in writing, software
1568
+ * distributed under the License is distributed on an "AS IS" BASIS,
1569
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1570
+ * See the License for the specific language governing permissions and
1571
+ * limitations under the License.
1572
+ */
1573
+ /**
1574
+ * Deploy a Solution
1575
+ *
1576
+ * Pass in either the item id or an IModel (`{item:{}, model:{}}`)
1577
+ * of a Solution Template, and this will generate the Solution
1578
+ *
1579
+ * @param maybeModel Item Id or IModel
1580
+ * @param authentication Credentials for the destination organization
1581
+ * @param options Options to override deployed information and to provide additional credentials
1582
+ * @return The id of the created deployed solution item
1583
+ */
1584
+ function deploySolution(maybeModel, authentication, options) {
1585
+ // if we are not passed the maybeModel, reject
1586
+ if (!maybeModel) {
1587
+ return Promise.reject(common__namespace.fail("The Solution Template id is missing"));
1588
+ }
1589
+ let deployOptions = options || {};
1590
+ /* istanbul ignore else */
1591
+ if (deployOptions.progressCallback) {
1592
+ deployOptions.progressCallback(1, deployOptions.jobId); // let the caller know that we've started
1593
+ }
1594
+ // It is possible to provide a separate authentication for the source
1595
+ const storageAuthentication = deployOptions.storageAuthentication
1596
+ ? deployOptions.storageAuthentication
1597
+ : authentication;
1598
+ // deal with maybe getting an item or an id
1599
+ return getSolutionTemplateItem(maybeModel, storageAuthentication)
1600
+ .then(model => {
1601
+ if (!isSolutionTemplateItem(model.item)) {
1602
+ return Promise.reject(common__namespace.fail(`${model.item.id} is not a Solution Template`));
1603
+ }
1604
+ else {
1605
+ // fetch the metadata if the model's id is a GUID and pass the item & data forward
1606
+ return Promise.all([
1607
+ Promise.resolve(model.item),
1608
+ Promise.resolve(model.data)
1609
+ ]);
1610
+ }
1611
+ })
1612
+ .then(responses => {
1613
+ // extract responses
1614
+ const [itemBase, itemData] = responses;
1615
+ // sanitize all the things
1616
+ const sanitizer = new common__namespace.Sanitizer();
1617
+ const item = common__namespace.sanitizeJSONAndReportChanges(itemBase, sanitizer);
1618
+ // TODO: we should delegate data sanization to the type-specific modules
1619
+ const data = itemData;
1620
+ // get the item id before it is deleted
1621
+ const itemId = item.id;
1622
+ // apply item props to deployOptions
1623
+ deployOptions = updateDeployOptions(deployOptions, item, storageAuthentication);
1624
+ // Clone before mutating? This was messing me up in some testing...
1625
+ common__namespace.deleteItemProps(item);
1626
+ return deploySolutionFromTemplate(itemId, item, data, authentication, deployOptions);
1627
+ })
1628
+ .then(createdSolutionId => {
1629
+ /* istanbul ignore else */
1630
+ if (deployOptions.progressCallback) {
1631
+ deployOptions.progressCallback(100, deployOptions.jobId); // we're done
1632
+ }
1633
+ return createdSolutionId;
1634
+ }, error => {
1635
+ // Error deploying solution
1636
+ /* istanbul ignore else */
1637
+ if (deployOptions.progressCallback) {
1638
+ deployOptions.progressCallback(1, deployOptions.jobId);
1639
+ }
1640
+ return Promise.reject(error);
1641
+ })
1642
+ .catch(ex => {
1643
+ throw ex;
1644
+ });
1645
+ }
1650
1646
 
1651
- exports.UNSUPPORTED = UNSUPPORTED;
1652
- exports._createItemFromTemplateWhenReady = _createItemFromTemplateWhenReady;
1653
- exports._estimateDeploymentCost = _estimateDeploymentCost;
1654
- exports._evaluateSharedViewSources = _evaluateSharedViewSources;
1655
- exports._findExistingItem = _findExistingItem;
1656
- exports._findExistingItemByKeyword = _findExistingItemByKeyword;
1657
- exports._flagPatchItemsForPostProcessing = _flagPatchItemsForPostProcessing;
1658
- exports._getGroupUpdates = _getGroupUpdates;
1659
- exports._getViewHash = _getViewHash;
1660
- exports._getViews = _getViews;
1661
- exports._handleExistingItems = _handleExistingItems;
1662
- exports._isModel = _isModel;
1663
- exports._reuseDeployedItems = _reuseDeployedItems;
1664
- exports._setFields = _setFields;
1665
- exports._setTypekeywordForExisting = _setTypekeywordForExisting;
1666
- exports._updateTemplateDictionary = _updateTemplateDictionary;
1667
- exports._updateTemplateDictionaryById = _updateTemplateDictionaryById;
1668
- exports._updateTemplateDictionaryForError = _updateTemplateDictionaryForError;
1669
- exports._updateViewTemplates = _updateViewTemplates;
1670
- exports._useExistingItems = _useExistingItems;
1671
- exports.deploySolution = deploySolution;
1672
- exports.deploySolutionItems = deploySolutionItems;
1673
- exports.getSolutionTemplateItem = getSolutionTemplateItem;
1674
- exports.isSolutionTemplateItem = isSolutionTemplateItem;
1675
- exports.moduleMap = moduleMap;
1676
- exports.updateDeployOptions = updateDeployOptions;
1647
+ exports.UNSUPPORTED = UNSUPPORTED$1;
1648
+ exports._createItemFromTemplateWhenReady = _createItemFromTemplateWhenReady;
1649
+ exports._estimateDeploymentCost = _estimateDeploymentCost;
1650
+ exports._evaluateSharedViewSources = _evaluateSharedViewSources;
1651
+ exports._findExistingItem = _findExistingItem;
1652
+ exports._findExistingItemByKeyword = _findExistingItemByKeyword;
1653
+ exports._flagPatchItemsForPostProcessing = _flagPatchItemsForPostProcessing;
1654
+ exports._getGroupUpdates = _getGroupUpdates;
1655
+ exports._getViewHash = _getViewHash;
1656
+ exports._getViews = _getViews;
1657
+ exports._handleExistingItems = _handleExistingItems;
1658
+ exports._isModel = _isModel;
1659
+ exports._reuseDeployedItems = _reuseDeployedItems;
1660
+ exports._setFields = _setFields;
1661
+ exports._setTypekeywordForExisting = _setTypekeywordForExisting;
1662
+ exports._updateTemplateDictionary = _updateTemplateDictionary;
1663
+ exports._updateTemplateDictionaryById = _updateTemplateDictionaryById;
1664
+ exports._updateTemplateDictionaryForError = _updateTemplateDictionaryForError;
1665
+ exports._updateViewTemplates = _updateViewTemplates;
1666
+ exports._useExistingItems = _useExistingItems;
1667
+ exports.deploySolution = deploySolution;
1668
+ exports.deploySolutionItems = deploySolutionItems;
1669
+ exports.getSolutionTemplateItem = getSolutionTemplateItem;
1670
+ exports.isSolutionTemplateItem = isSolutionTemplateItem;
1671
+ exports.moduleMap = moduleMap;
1672
+ exports.updateDeployOptions = updateDeployOptions;
1677
1673
 
1678
- Object.defineProperty(exports, '__esModule', { value: true });
1674
+ Object.defineProperty(exports, '__esModule', { value: true });
1679
1675
 
1680
- })));
1676
+ }));
1681
1677
  //# sourceMappingURL=deployer.umd.js.map