@esri/solutions-components 0.5.3 → 0.5.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. package/dist/cjs/calcite-input-text_5.cjs.entry.js +36 -36
  2. package/dist/cjs/calcite-shell-panel_14.cjs.entry.js +1 -1
  3. package/dist/cjs/solution-configuration.cjs.entry.js +1 -1
  4. package/dist/cjs/solution-contents_3.cjs.entry.js +1 -1
  5. package/dist/cjs/{solution-store-70002b57.js → solution-store-ca4639d5.js} +3 -3
  6. package/dist/collection/components/add-record-modal/test/add-record-modal.e2e.js +24 -0
  7. package/dist/collection/components/add-record-modal/test/add-record-modal.spec.js +32 -0
  8. package/dist/collection/components/buffer-tools/test/buffer-tools.e2e.js +24 -0
  9. package/dist/collection/components/buffer-tools/test/buffer-tools.spec.js +157 -0
  10. package/dist/collection/components/card-manager/test/card-manager.e2e.js +24 -0
  11. package/dist/collection/components/card-manager/test/card-manager.spec.js +32 -0
  12. package/dist/collection/components/comment-card/test/comment-card.e2e.js +24 -0
  13. package/dist/collection/components/comment-card/test/comment-card.spec.js +32 -0
  14. package/dist/collection/components/crowdsource-manager/test/crowdsource-manager.e2e.js +24 -0
  15. package/dist/collection/components/crowdsource-manager/test/crowdsource-manager.spec.js +32 -0
  16. package/dist/collection/components/crowdsource-reporter/test/crowdsource-reporter.e2e.js +24 -0
  17. package/dist/collection/components/crowdsource-reporter/test/crowdsource-reporter.spec.js +32 -0
  18. package/dist/collection/components/deduct-calculator/test/deduct-calculator.e2e.js +24 -0
  19. package/dist/collection/components/deduct-calculator/test/deduct-calculator.spec.js +32 -0
  20. package/dist/collection/components/edit-record-modal/test/edit-record-modal.e2e.js +24 -0
  21. package/dist/collection/components/edit-record-modal/test/edit-record-modal.spec.js +32 -0
  22. package/dist/collection/components/info-card/test/info-card.e2e.js +24 -0
  23. package/dist/collection/components/info-card/test/info-card.spec.js +32 -0
  24. package/dist/collection/components/json-editor/test/json-editor.e2e.js +31 -0
  25. package/dist/collection/components/json-editor/test/json-editor.spec.js +60 -0
  26. package/dist/collection/components/layer-table/test/layer-table.e2e.js +24 -0
  27. package/dist/collection/components/layer-table/test/layer-table.spec.js +32 -0
  28. package/dist/collection/components/list-item/test/list-item.e2e.js +24 -0
  29. package/dist/collection/components/list-item/test/list-item.spec.js +32 -0
  30. package/dist/collection/components/map-card/test/map-card.e2e.js +24 -0
  31. package/dist/collection/components/map-card/test/map-card.spec.js +32 -0
  32. package/dist/collection/components/map-draw-tools/test/map-draw-tools.e2e.js +24 -0
  33. package/dist/collection/components/map-draw-tools/test/map-draw-tools.spec.js +32 -0
  34. package/dist/collection/components/map-layer-picker/test/map-layer-picker.e2e.js +24 -0
  35. package/dist/collection/components/map-layer-picker/test/map-layer-picker.spec.js +109 -0
  36. package/dist/collection/components/map-search/test/map-search.e2e.js +24 -0
  37. package/dist/collection/components/map-search/test/map-search.spec.js +53 -0
  38. package/dist/collection/components/map-select-tools/map-select-tools.js +36 -36
  39. package/dist/collection/components/map-select-tools/test/map-select-tools.e2e.js +24 -0
  40. package/dist/collection/components/map-select-tools/test/map-select-tools.spec.js +349 -0
  41. package/dist/collection/components/media-card/test/media-card.e2e.js +24 -0
  42. package/dist/collection/components/media-card/test/media-card.spec.js +32 -0
  43. package/dist/collection/components/pci-calculator/test/pci-calculator.e2e.js +24 -0
  44. package/dist/collection/components/pci-calculator/test/pci-calculator.spec.js +32 -0
  45. package/dist/collection/components/pdf-download/test/pdf-download.e2e.js +71 -0
  46. package/dist/collection/components/pdf-download/test/pdf-download.spec.js +104 -0
  47. package/dist/collection/components/public-notification/test/public-notification.e2e.js +95 -0
  48. package/dist/collection/components/public-notification/test/public-notification.spec.js +149 -0
  49. package/dist/collection/components/refine-selection/refine-selection.css +85 -85
  50. package/dist/collection/components/solution-configuration/test/solution-configuration.e2e.js +31 -0
  51. package/dist/collection/components/solution-configuration/test/solution-configuration.spec.js +114 -0
  52. package/dist/collection/components/solution-contents/test/solution-contents.e2e.js +89 -0
  53. package/dist/collection/components/solution-contents/test/solution-contents.spec.js +138 -0
  54. package/dist/collection/components/solution-item/test/solution-item.e2e.js +31 -0
  55. package/dist/collection/components/solution-item/test/solution-item.spec.js +72 -0
  56. package/dist/collection/components/solution-item-details/test/solution-item-details.e2e.js +31 -0
  57. package/dist/collection/components/solution-item-details/test/solution-item-details.spec.js +137 -0
  58. package/dist/collection/components/solution-item-icon/test/solution-item-icon.e2e.js +24 -0
  59. package/dist/collection/components/solution-item-icon/test/solution-item-icon.spec.js +34 -0
  60. package/dist/collection/components/solution-item-sharing/test/solution-item-sharing.e2e.js +31 -0
  61. package/dist/collection/components/solution-item-sharing/test/solution-item-sharing.spec.js +49 -0
  62. package/dist/collection/components/solution-organization-variables/test/solution-organization-variables.e2e.js +31 -0
  63. package/dist/collection/components/solution-organization-variables/test/solution-organization-variables.spec.js +60 -0
  64. package/dist/collection/components/solution-resource-item/test/solution-resource-item.e2e.js +31 -0
  65. package/dist/collection/components/solution-resource-item/test/solution-resource-item.spec.js +50 -0
  66. package/dist/collection/components/solution-spatial-ref/test/solution-spatial-ref.e2e.js +31 -0
  67. package/dist/collection/components/solution-spatial-ref/test/solution-spatial-ref.spec.js +170 -0
  68. package/dist/collection/components/solution-template-data/test/solution-template-data.e2e.js +31 -0
  69. package/dist/collection/components/solution-template-data/test/solution-template-data.spec.js +55 -0
  70. package/dist/collection/components/solution-variables/test/solution-variables.e2e.js +31 -0
  71. package/dist/collection/components/solution-variables/test/solution-variables.spec.js +126 -0
  72. package/dist/collection/utils/publicNotificationUtils.js +45 -0
  73. package/dist/collection/utils/templates.e2e.js +25 -0
  74. package/dist/collection/utils/test/csvUtils.spec.js +46 -0
  75. package/dist/collection/utils/test/downloadUtils.spec.js +102 -0
  76. package/dist/collection/utils/test/pciUtils.spec.js +297 -0
  77. package/dist/collection/utils/test/solution-store.spec.js +439 -0
  78. package/dist/components/map-select-tools2.js +36 -36
  79. package/dist/components/solution-store.js +3 -3
  80. package/dist/esm/calcite-input-text_5.entry.js +36 -36
  81. package/dist/esm/calcite-shell-panel_14.entry.js +1 -1
  82. package/dist/esm/solution-configuration.entry.js +1 -1
  83. package/dist/esm/solution-contents_3.entry.js +1 -1
  84. package/dist/esm/{solution-store-5d068b07.js → solution-store-70f874f8.js} +3 -3
  85. package/dist/solutions-components/{p-41802f6b.entry.js → p-16dfb254.entry.js} +1 -1
  86. package/dist/solutions-components/{p-4769a2a5.entry.js → p-5ed755a2.entry.js} +1 -1
  87. package/dist/solutions-components/{p-826a814d.js → p-78719506.js} +2 -2
  88. package/dist/solutions-components/{p-9f620303.entry.js → p-b4b19fd3.entry.js} +1 -1
  89. package/dist/solutions-components/{p-24fe6e1c.entry.js → p-d5d5942d.entry.js} +1 -1
  90. package/dist/solutions-components/solutions-components.esm.js +1 -1
  91. package/dist/solutions-components/utils/common.js +291 -0
  92. package/dist/solutions-components/utils/csvDownload.js +36 -0
  93. package/dist/solutions-components/utils/csvUtils.js +32 -0
  94. package/dist/solutions-components/utils/downloadUtils.js +386 -0
  95. package/dist/solutions-components/utils/interfaces.js +56 -0
  96. package/dist/solutions-components/utils/languageUtil.js +85 -0
  97. package/dist/solutions-components/utils/loadModules.js +20 -0
  98. package/dist/solutions-components/utils/locale.js +56 -0
  99. package/dist/solutions-components/utils/mapViewUtils.js +140 -0
  100. package/dist/solutions-components/utils/pciUtils.js +837 -0
  101. package/dist/solutions-components/utils/pdfUtils.js +62 -0
  102. package/dist/solutions-components/utils/publicNotificationStore.js +38 -0
  103. package/dist/solutions-components/utils/publicNotificationUtils.js +45 -0
  104. package/dist/solutions-components/utils/queryUtils.js +148 -0
  105. package/dist/solutions-components/utils/solution-store.js +579 -0
  106. package/dist/solutions-components/utils/templates.e2e.js +25 -0
  107. package/dist/solutions-components/utils/templates.js +341 -0
  108. package/dist/solutions-components/utils/test/csvUtils.spec.js +46 -0
  109. package/dist/solutions-components/utils/test/downloadUtils.spec.js +102 -0
  110. package/dist/solutions-components/utils/test/mocks/jsApi.js +74 -0
  111. package/dist/solutions-components/utils/test/pciUtils.spec.js +297 -0
  112. package/dist/solutions-components/utils/test/solution-store.spec.js +439 -0
  113. package/dist/solutions-components/utils/test/testUtils.js +135 -0
  114. package/dist/solutions-components/utils/types.js +14 -0
  115. package/dist/solutions-components_commit.txt +7 -0
  116. package/package.json +7 -7
@@ -0,0 +1,579 @@
1
+ /** @license
2
+ * Copyright 2022 Esri
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import { createStore } from "@stencil/store";
17
+ import { EUpdateType } from './interfaces';
18
+ import { EFileType, SolutionTemplateFormatVersion, copyFilesToStorageItem, generateStorageFilePaths, getItemDataAsJson, getProp, getThumbnailFromStorageItem, isSupportedFileType, removeItemResourceFile, setCreateProp, updateItem, updateItemResourceFile } from '@esri/solution-common';
19
+ const EmptySolutionStore = {
20
+ solutionItemId: "",
21
+ defaultWkid: undefined,
22
+ solutionData: { metadata: {}, templates: [] },
23
+ templateEdits: {},
24
+ featureServices: [],
25
+ spatialReferenceInfo: {
26
+ enabled: false,
27
+ services: {},
28
+ spatialReference: undefined
29
+ }
30
+ };
31
+ class SolutionStore {
32
+ /**
33
+ * Creates singleton instance when accessed; default export from module.
34
+ *
35
+ * @returns Static instance of the class
36
+ */
37
+ static get Store() {
38
+ return this._instance || (this._instance = new this());
39
+ }
40
+ /**
41
+ * Creates an empty store.
42
+ *
43
+ * @protected
44
+ */
45
+ constructor() {
46
+ this._hasChanges = false;
47
+ this._store = createStore(Object.assign({}, EmptySolutionStore));
48
+ }
49
+ /**
50
+ * Returns the stored information of an item.
51
+ *
52
+ * @param itemId Id of item to fetch
53
+ *
54
+ * @returns Item information or `undefined` if not found
55
+ */
56
+ getItemInfo(itemId) {
57
+ const templates = this._store.get("solutionData").templates;
58
+ let template;
59
+ templates.some((t) => {
60
+ if (itemId == t.itemId) {
61
+ template = t;
62
+ return true;
63
+ }
64
+ return false;
65
+ });
66
+ return template;
67
+ }
68
+ /**
69
+ * Returns a top-level store property: solutionItemId, defaultWkid, etc.
70
+ *
71
+ * @param propName Name of property
72
+ *
73
+ * @returns Value of property
74
+ */
75
+ getStoreInfo(propName) {
76
+ return this._store.get(propName);
77
+ }
78
+ /**
79
+ * Loads a Solution into the store from AGO.
80
+ *
81
+ * @param solutionItemId Id of the solution represented in the store
82
+ * @param authentication Credentials for fetching information to be loaded into the store
83
+ *
84
+ * @returns Promise that resolves when task is done
85
+ */
86
+ async loadSolution(solutionItemId, authentication) {
87
+ this._authentication = authentication;
88
+ const solutionData = await getItemDataAsJson(solutionItemId, authentication);
89
+ if (solutionData) {
90
+ const defaultWkid = getProp(solutionData, "params.wkid.default");
91
+ await this._prepareSolutionItemsForEditing(solutionItemId, solutionData.templates, authentication);
92
+ const featureServices = this._getFeatureServices(solutionData.templates);
93
+ const spatialReferenceInfo = this._getSpatialReferenceInfo(featureServices, defaultWkid);
94
+ this._store.set("solutionItemId", solutionItemId);
95
+ this._store.set("defaultWkid", defaultWkid);
96
+ this._store.set("solutionData", solutionData);
97
+ this._store.set("featureServices", featureServices);
98
+ this._store.set("spatialReferenceInfo", spatialReferenceInfo);
99
+ }
100
+ this._flagStoreHasChanges(false);
101
+ }
102
+ /**
103
+ * Queues the replacement of the thumbnail associated with a template item in the store.
104
+ *
105
+ * @param itemEdit Details of the template to modify, containing the new thumbnail in the `thumbnail`
106
+ * property
107
+ */
108
+ replaceItemThumbnail(itemEdit) {
109
+ // Flag the current thumbnail and any replacements for removal
110
+ itemEdit.resourceFilePaths.forEach((path) => {
111
+ if (path.type === EFileType.Thumbnail) {
112
+ if (path.updateType === EUpdateType.None) {
113
+ // Existing thumbnail not yet flagged for removal
114
+ path.updateType = EUpdateType.Remove;
115
+ }
116
+ else if (path.updateType === EUpdateType.Add || path.updateType === EUpdateType.Update) {
117
+ // An earlier replacement
118
+ path.updateType = EUpdateType.Obsolete;
119
+ }
120
+ }
121
+ });
122
+ // Remove any replacements already queued
123
+ itemEdit.resourceFilePaths =
124
+ itemEdit.resourceFilePaths.filter((path) => path.updateType != EUpdateType.Obsolete);
125
+ // Add the new thumbnail to the store item
126
+ itemEdit.resourceFilePaths.push({
127
+ blob: itemEdit.thumbnail,
128
+ filename: itemEdit.thumbnail.name,
129
+ type: EFileType.Thumbnail,
130
+ updateType: EUpdateType.Add
131
+ });
132
+ // Update the store
133
+ this.setItemInfo(itemEdit);
134
+ }
135
+ /**
136
+ * Writes a Solution into AGO from the store. Must use `loadSolution` to continue with solution.
137
+ *
138
+ * @returns Promise that resolves when task is done
139
+ */
140
+ async saveSolution() {
141
+ // Update the templates in the original solution item data
142
+ const solutionItemId = this._store.get("solutionItemId");
143
+ const solutionData = this._store.get("solutionData");
144
+ const spatialReferenceInfo = this._store.get("spatialReferenceInfo");
145
+ await this._prepareSolutionItemsForStorage(solutionItemId, solutionData.templates, this._authentication);
146
+ const updatedDefaultWkid = this._setSpatialReferenceInfo(spatialReferenceInfo, solutionData.templates);
147
+ if (updatedDefaultWkid) {
148
+ setCreateProp(solutionData, "params.wkid", {
149
+ "label": "Spatial Reference",
150
+ "default": updatedDefaultWkid,
151
+ "valueType": "spatialReference",
152
+ "attributes": {
153
+ "required": "true"
154
+ }
155
+ });
156
+ }
157
+ else {
158
+ setCreateProp(solutionData, "params.wkid", {});
159
+ }
160
+ const itemInfo = {
161
+ id: solutionItemId,
162
+ text: solutionData
163
+ };
164
+ await updateItem(itemInfo, this._authentication);
165
+ }
166
+ /**
167
+ * Stores information for item.
168
+ *
169
+ * @param itemEdit Item information
170
+ */
171
+ setItemInfo(itemEdit) {
172
+ const solutionData = this._store.get("solutionData");
173
+ const templates = solutionData.templates;
174
+ templates.some((t) => {
175
+ if (itemEdit.itemId == t.itemId) {
176
+ t = itemEdit;
177
+ this._store.set("solutionData", solutionData);
178
+ this._flagStoreHasChanges(true);
179
+ return true;
180
+ }
181
+ return false;
182
+ });
183
+ }
184
+ /**
185
+ * Sets a top-level store property: solutionItemId, defaultWkid, etc.
186
+ *
187
+ * @param propName Name of property
188
+ * @param value Value of property
189
+ */
190
+ setStoreInfo(propName, value) {
191
+ this._store.set(propName, value);
192
+ this._flagStoreHasChanges(true);
193
+ }
194
+ //------------------------------------------------------------------------------------------------------------------//
195
+ /** Provides access to protected methods for unit testing.
196
+ *
197
+ * @param methodName Name of protected method to run
198
+ * @param arg1 First argument to forward to method, e.g., for "_prepareSolutionItemsForEditing", `solutionItemId`
199
+ * @param arg2 Second argument to forward to method, e.g., for "_prepareSolutionItemsForEditing", `templates`
200
+ * @param arg3 Third argument to forward to method, e.g., for "_prepareSolutionItemsForEditing", `authentication`
201
+ *
202
+ * @returns
203
+ */
204
+ _testAccess(methodName, arg1, arg2, arg3) {
205
+ switch (methodName) {
206
+ case "_emptyTheStore":
207
+ this._emptyTheStore();
208
+ break;
209
+ case "_getFeatureServices":
210
+ return this._getFeatureServices(arg1);
211
+ case "_getItemsSharedWithThisGroup":
212
+ return this._getItemsSharedWithThisGroup(arg1, arg2);
213
+ case "_getResourceFilePaths":
214
+ return this._getResourceFilePaths(arg1, arg2, arg3);
215
+ case "_getResourceStorageName":
216
+ return this._getResourceStorageName(arg1, arg2);
217
+ case "_getSpatialReferenceInfo":
218
+ return this._getSpatialReferenceInfo(arg1, arg2);
219
+ case "_prepareSolutionItemsForEditing":
220
+ return this._prepareSolutionItemsForEditing(arg1, arg2, arg3);
221
+ case "_prepareSolutionItemsForStorage":
222
+ return this._prepareSolutionItemsForStorage(arg1, arg2, arg3);
223
+ case "_setSpatialReferenceInfo":
224
+ return this._setSpatialReferenceInfo(arg1, arg2);
225
+ case "_splitFilename":
226
+ return this._splitFilename(arg1);
227
+ }
228
+ return null;
229
+ }
230
+ /**
231
+ * Returns the store to the empty state.
232
+ *
233
+ * @protected
234
+ */
235
+ _emptyTheStore() {
236
+ this._store.set("solutionItemId", EmptySolutionStore.solutionItemId);
237
+ this._store.set("defaultWkid", EmptySolutionStore.defaultWkid);
238
+ this._store.set("solutionData", EmptySolutionStore.solutionData);
239
+ this._store.set("templateEdits", EmptySolutionStore.templateEdits);
240
+ this._store.set("featureServices", EmptySolutionStore.featureServices);
241
+ this._store.set("spatialReferenceInfo", EmptySolutionStore.spatialReferenceInfo);
242
+ }
243
+ /**
244
+ * Sets the store's flag indicating if it has changes and dispatches an event when
245
+ * the flag value changes.
246
+ *
247
+ * @param flagHasChanges Current state of change in the store; if it doesn't match the value saved in this
248
+ * object, an event is dispatched with the new value and the saved value is updated
249
+ *
250
+ * @protected
251
+ */
252
+ _flagStoreHasChanges(flagHasChanges) {
253
+ // Event for notifying if the store has changes or not
254
+ if (this._hasChanges !== flagHasChanges) {
255
+ window.dispatchEvent(new CustomEvent("solutionStoreHasChanges", {
256
+ detail: flagHasChanges,
257
+ bubbles: true,
258
+ cancelable: false,
259
+ composed: true
260
+ }));
261
+ }
262
+ this._hasChanges = flagHasChanges;
263
+ }
264
+ /**
265
+ * Gets a list of Feature Services that are not views.
266
+ *
267
+ * @param templates A list of item templates from the solution
268
+ *
269
+ * @returns a list of feature services
270
+ *
271
+ * @protected
272
+ */
273
+ _getCustomizableFeatureServices(templates) {
274
+ return templates.reduce((prev, cur) => {
275
+ if (cur.type === "Feature Service" && cur.item.typeKeywords.indexOf("View Service") < 0) {
276
+ prev.push(cur);
277
+ }
278
+ return prev;
279
+ }, []);
280
+ }
281
+ /**
282
+ * Gets a list of Feature Services that are not views along with an enabled property that indicates
283
+ * if the service currently uses a spatial reference variable.
284
+ *
285
+ * @param templates A list of item templates from the solution
286
+ *
287
+ * @returns a list of feature service names and an enabled property to indicate
288
+ * if they currently use a spatial reference variable.
289
+ *
290
+ * @protected
291
+ */
292
+ _getFeatureServices(templates) {
293
+ const customizeableFeatureServices = this._getCustomizableFeatureServices(templates);
294
+ return customizeableFeatureServices.map((fs) => {
295
+ const name = fs.item.title || fs.item.name;
296
+ const wkid = getProp(fs, "properties.service.spatialReference.wkid");
297
+ return { name, enabled: wkid.toString().startsWith("{{params.wkid||") };
298
+ });
299
+ }
300
+ /**
301
+ * Capture the key item details for a given group template
302
+ *
303
+ * @param template one of the templates from the current solution
304
+ * @param templates full list of templates
305
+ *
306
+ * @returns a list of IItemShare objects
307
+ *
308
+ * @protected
309
+ */
310
+ _getItemsSharedWithThisGroup(template, templates) {
311
+ return templates.reduce((prev, cur) => {
312
+ if (cur.itemId !== template.itemId && cur.type !== "Group") {
313
+ prev.push({
314
+ id: cur.itemId,
315
+ title: cur.item.name || cur.item.title,
316
+ isShared: (cur.groups || []).indexOf(template.itemId) > -1,
317
+ shareItem: (cur.groups || []).indexOf(template.itemId) > -1,
318
+ type: cur.type,
319
+ typeKeywords: cur.item.typeKeywords
320
+ });
321
+ }
322
+ return prev;
323
+ }, []);
324
+ }
325
+ /**
326
+ * Generate storage file paths from the solution template
327
+ *
328
+ * @param solutionId the id of the current solution
329
+ * @param template the current template from the solution
330
+ * @param portal Portal where file is to be found
331
+ *
332
+ * @returns a list of resource file infos
333
+ *
334
+ * @protected
335
+ */
336
+ _getResourceFilePaths(solutionId, template, portal) {
337
+ const resourceFilePaths = generateStorageFilePaths(portal, solutionId, template.resources, SolutionTemplateFormatVersion);
338
+ return resourceFilePaths.map((fp) => {
339
+ fp.updateType = EUpdateType.None;
340
+ return fp;
341
+ });
342
+ }
343
+ /**
344
+ * Generates a resource name from a storage file path.
345
+ *
346
+ * @param templateItemId The id of the template item whose resource this is; used as a prefix in the resource name
347
+ * @param resourcePath Resource file infos
348
+ *
349
+ * @returns The resource name to use when attaching a resource to the item.
350
+ *
351
+ * @protected
352
+ */
353
+ _getResourceStorageName(templateItemId, resourcePath) {
354
+ /* Converts
355
+ {
356
+ "url": "https://myorg.maps.arcgis.com/sharing/rest/content/items/ca924c6db7d247b9a31fa30532fb5913/resources/79036430a6274e17ae915d0278b8569c_info_metadata/metadata.xml",
357
+ "type": 2,
358
+ "folder": "",
359
+ "filename": "metadata.xml",
360
+ "updateType": 3
361
+ }
362
+ to
363
+ ca924c6db7d247b9a31fa30532fb5913_info_metadata/metadata.xml
364
+ */
365
+ let prefix = templateItemId;
366
+ switch (resourcePath.type) {
367
+ case EFileType.Data:
368
+ prefix = `${prefix}_info_data`;
369
+ break;
370
+ case EFileType.Info:
371
+ prefix = `${prefix}_info`;
372
+ break;
373
+ case EFileType.Metadata:
374
+ prefix = `${prefix}_info_metadata`;
375
+ break;
376
+ case EFileType.Resource:
377
+ break;
378
+ case EFileType.Thumbnail:
379
+ prefix = `${prefix}_info_thumbnail`;
380
+ break;
381
+ }
382
+ let filenameToUse = resourcePath.filename;
383
+ if (resourcePath.type == EFileType.Data && filenameToUse && !isSupportedFileType(filenameToUse)) {
384
+ filenameToUse = filenameToUse + ".zip";
385
+ prefix += "z";
386
+ }
387
+ const filename = resourcePath.folder ? resourcePath.folder + "/" + filenameToUse : filenameToUse;
388
+ return prefix + "/" + filename;
389
+ }
390
+ /**
391
+ * Extracts basic spatial reference information that is used to determine if a custom spatial reference parameter will
392
+ * be exposed while deploying this solution and if so what feature services will support it and what will the default wkid be
393
+ *
394
+ * @param services a list of objects with service name and enabled property (indicates if they currently use a spatial reference var)
395
+ * @param data the data object of a solution item
396
+ *
397
+ * @returns an object that stores if a custom spatial reference parameter is enabled/disabled,
398
+ * a list of services and if they are enabled/disabled, and the default wkid
399
+ *
400
+ * @protected
401
+ */
402
+ _getSpatialReferenceInfo(services, defaultWkid) {
403
+ const defaultServices = {};
404
+ services.forEach(service => {
405
+ defaultServices[service.name] = service.enabled;
406
+ });
407
+ return {
408
+ enabled: defaultWkid !== undefined,
409
+ services: defaultServices,
410
+ spatialReference: defaultWkid ? defaultWkid : undefined
411
+ };
412
+ }
413
+ /**
414
+ * Create and store template items for the editor.
415
+ *
416
+ * @param solutionItemId Id of the solution represented in the store
417
+ * @param templates A list of item templates from the solution
418
+ * @param authentication Credentials for fetching information to be loaded into the store
419
+ *
420
+ * @returns a promise that resolves when the templates are ready
421
+ *
422
+ * @protected
423
+ */
424
+ async _prepareSolutionItemsForEditing(solutionItemId, templates, authentication) {
425
+ const thumbnailPromises = [];
426
+ // Augment the template with paths to resources and group information, if relevant
427
+ templates.forEach((t) => {
428
+ t.resourceFilePaths = this._getResourceFilePaths(solutionItemId, t, authentication.portal);
429
+ thumbnailPromises.push(t.resourceFilePaths.length > 0 ?
430
+ getThumbnailFromStorageItem(authentication, t.resourceFilePaths) :
431
+ Promise.resolve());
432
+ t.groupDetails = t.type === "Group" ? this._getItemsSharedWithThisGroup(t, templates) : [];
433
+ });
434
+ // Augment the template with its thumbnail file
435
+ const thumbnails = await Promise.all(thumbnailPromises);
436
+ templates.forEach((t, i) => {
437
+ t.thumbnail = thumbnails[i] ? thumbnails[i] : undefined;
438
+ });
439
+ return Promise.resolve();
440
+ }
441
+ /**
442
+ * Prepares template items for sending to AGO by updating the resources held by the solution item.
443
+ *
444
+ * @param solutionItemId Id of the solution represented in the store
445
+ * @param templates A list of item templates from the solution
446
+ * @param authentication Credentials for fetching information to be loaded into the store
447
+ *
448
+ * @returns a promise that resolves when the templates are ready
449
+ *
450
+ * @protected
451
+ */
452
+ async _prepareSolutionItemsForStorage(solutionItemId, templates, authentication) {
453
+ const resourceAdds = [];
454
+ // Update the resources and remove the augmentation from a template
455
+ const pendingTasks = [];
456
+ templates.forEach((t) => {
457
+ // Run through the resourceFilePaths for the item seeking modifications to be made to the solution item's
458
+ // collection of resources; queue them for batching
459
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
460
+ t.resourceFilePaths.forEach(async (path) => {
461
+ const storageName = this._getResourceStorageName(t.itemId, path);
462
+ switch (path.updateType) {
463
+ case EUpdateType.Add:
464
+ const { prefix, suffix } = this._splitFilename(storageName);
465
+ t.resources.push(storageName);
466
+ resourceAdds.push({
467
+ itemId: t.itemId,
468
+ file: path.blob,
469
+ folder: prefix,
470
+ filename: suffix
471
+ });
472
+ break;
473
+ case EUpdateType.Update:
474
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
475
+ pendingTasks.push(new Promise(async (resolve) => {
476
+ try {
477
+ await updateItemResourceFile(solutionItemId, storageName, path.blob, authentication);
478
+ }
479
+ catch (err) {
480
+ console.log("Unable to update " + storageName + " for item " + t.itemId + ": " + JSON.stringify(err));
481
+ }
482
+ resolve();
483
+ }));
484
+ break;
485
+ case EUpdateType.Remove:
486
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
487
+ pendingTasks.push(new Promise(async (resolve) => {
488
+ try {
489
+ await removeItemResourceFile(solutionItemId, storageName, authentication);
490
+ t.resources = t.resources.filter((path) => path !== storageName);
491
+ }
492
+ catch (err) {
493
+ console.log("Unable to remove " + storageName + " for item " + t.itemId + ": " + JSON.stringify(err));
494
+ }
495
+ resolve();
496
+ }));
497
+ break;
498
+ }
499
+ return Promise.resolve();
500
+ });
501
+ delete t.resourceFilePaths;
502
+ delete t.thumbnail;
503
+ delete t.groupDetails;
504
+ });
505
+ // Update the resources
506
+ return Promise.all(pendingTasks)
507
+ .then(async () => {
508
+ if (resourceAdds.length > 0) {
509
+ await copyFilesToStorageItem(resourceAdds, solutionItemId, authentication);
510
+ }
511
+ return Promise.resolve();
512
+ });
513
+ }
514
+ /**
515
+ * Stores basic spatial reference information that is used to determine if a custom spatial reference parameter will
516
+ * be exposed while deploying this solution and if so what feature services will support it and what will the default wkid be
517
+ *
518
+ * @param spatialReferenceInfo The configuration settings for a custom spatial reference
519
+ * @param templates The templates in the current solution, which will be updated in place if
520
+ * `spatialReferenceInfo.enabled` is true
521
+ *
522
+ * @returns The new default wkid
523
+ *
524
+ * @protected
525
+ */
526
+ _setSpatialReferenceInfo(spatialReferenceInfo, templates) {
527
+ const customizingPrefix = "{{params.wkid||";
528
+ const customizeableFeatureServices = this._getCustomizableFeatureServices(templates);
529
+ if (spatialReferenceInfo.enabled) {
530
+ // Enable or disable this feature in each service
531
+ customizeableFeatureServices.forEach((fs) => {
532
+ const name = fs.item.title || fs.item.name;
533
+ let wkid;
534
+ if (spatialReferenceInfo.services[name]) { // enabled
535
+ wkid = `{{params.wkid||${spatialReferenceInfo.spatialReference}}}`;
536
+ setCreateProp(fs, "properties.service.spatialReference.wkid", wkid);
537
+ }
538
+ else { // disabled
539
+ wkid = getProp(fs, "properties.service.spatialReference.wkid");
540
+ // Remove customizing prefix if present
541
+ if (wkid.toString().startsWith(customizingPrefix)) {
542
+ wkid = wkid.toString().substring(customizingPrefix.length, wkid.length - 2);
543
+ setCreateProp(fs, "properties.service.spatialReference.wkid", wkid);
544
+ }
545
+ }
546
+ });
547
+ return spatialReferenceInfo.spatialReference;
548
+ }
549
+ else {
550
+ // Disable this feature in each service
551
+ customizeableFeatureServices.forEach((fs) => {
552
+ const wkid = getProp(fs, "properties.service.spatialReference.wkid");
553
+ // Remove customizing prefix if present
554
+ if (wkid.toString().startsWith(customizingPrefix)) {
555
+ setCreateProp(fs, "properties.service.spatialReference.wkid", wkid.toString().substring(customizingPrefix.length, wkid.length - 2));
556
+ }
557
+ });
558
+ return undefined;
559
+ }
560
+ }
561
+ /**
562
+ * Splits a pathed filename into a last term and a prefix; e.g., "a/b/c" returns "c" with a prefix of "a/b".
563
+ *
564
+ * @param filename Filename with optional path
565
+ *
566
+ * @returns An object consisting of a `prefix` (undefined if `filename` does not contain a path) and a `suffix`--the
567
+ * filename at the end of a path
568
+ *
569
+ * @protected
570
+ */
571
+ _splitFilename(filename) {
572
+ const filenameParts = filename.split("/");
573
+ return {
574
+ prefix: filenameParts.length > 1 ? filenameParts.slice(0, filenameParts.length - 1).join("/") : undefined,
575
+ suffix: filenameParts[filenameParts.length - 1]
576
+ };
577
+ }
578
+ }
579
+ export default SolutionStore.Store;
@@ -0,0 +1,25 @@
1
+ /** @license
2
+ * Copyright 2022 Esri
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import { getInventoryItems } from "./templates";
17
+ import * as electionOutreach from '../demos/data/election-outreach.json';
18
+ describe("getInventoryItems", () => {
19
+ it("can get inventory items", () => {
20
+ const templates = electionOutreach.templates;
21
+ expect(templates.length).toEqual(11);
22
+ const actual = getInventoryItems(templates);
23
+ expect(actual.length).toEqual(5);
24
+ });
25
+ });