@esri/solutions-components 0.6.16 → 0.6.18

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 (216) hide show
  1. package/README.md +1 -1
  2. package/dist/assets/t9n/map-tools/resources.json +2 -1
  3. package/dist/assets/t9n/map-tools/resources_en.json +2 -1
  4. package/dist/assets/t9n/solution-spatial-ref/resources.json +0 -1
  5. package/dist/assets/t9n/solution-spatial-ref/resources_en.json +0 -1
  6. package/dist/assets/t9n/solution-spatial-ref/resources_fr.json +6 -0
  7. package/dist/assets/t9n/solution-spatial-ref/resources_he.json +6 -0
  8. package/dist/assets/t9n/spatial-ref/resources.json +3 -0
  9. package/dist/assets/t9n/spatial-ref/resources_en.json +3 -0
  10. package/dist/assets/t9n/spatial-ref/resources_fr.json +3 -0
  11. package/dist/assets/t9n/spatial-ref/resources_he.json +3 -0
  12. package/dist/cjs/{basemap-gallery_6.cjs.entry.js → basemap-gallery_7.cjs.entry.js} +124 -3
  13. package/dist/cjs/{calcite-tree_3.cjs.entry.js → calcite-checkbox_3.cjs.entry.js} +123 -319
  14. package/dist/cjs/calcite-combobox_6.cjs.entry.js +1 -1
  15. package/dist/cjs/calcite-shell-panel_14.cjs.entry.js +4 -3
  16. package/dist/cjs/card-manager_3.cjs.entry.js +10 -7
  17. package/dist/{collection/components/basemap-gallery/test/basemap-gallery.e2e.js → cjs/common-13719149.js} +17 -9
  18. package/dist/cjs/crowdsource-manager.cjs.entry.js +12 -7
  19. package/dist/cjs/{downloadUtils-34a515ad.js → downloadUtils-121fd7ff.js} +2 -2
  20. package/dist/cjs/edit-card_2.cjs.entry.js +4 -3
  21. package/dist/cjs/{index.es-0ba11065.js → index.es-5c0c137a.js} +2 -2
  22. package/dist/cjs/loader.cjs.js +1 -1
  23. package/dist/cjs/map-select-tools_3.cjs.entry.js +2 -2
  24. package/dist/cjs/{mapViewUtils-a2884698.js → mapViewUtils-786a219b.js} +32 -19
  25. package/dist/cjs/public-notification.cjs.entry.js +2 -2
  26. package/dist/cjs/solution-configuration.cjs.entry.js +2 -1
  27. package/dist/cjs/solution-contents_3.cjs.entry.js +21 -21256
  28. package/dist/cjs/solution-item-icon.cjs.entry.js +327 -0
  29. package/dist/cjs/{solution-store-c443e657.js → solution-resource-f9e3b289.js} +2 -1698
  30. package/dist/cjs/solution-store-2414dd8a.js +1707 -0
  31. package/dist/cjs/solutions-components.cjs.js +1 -1
  32. package/dist/cjs/spatial-ref.cjs.entry.js +21293 -0
  33. package/dist/collection/collection-manifest.json +2 -0
  34. package/dist/collection/components/card-manager/card-manager.js +1 -1
  35. package/dist/collection/components/crowdsource-manager/crowdsource-manager.css +17 -2
  36. package/dist/collection/components/crowdsource-manager/crowdsource-manager.js +47 -6
  37. package/dist/collection/components/edit-card/edit-card.css +0 -8
  38. package/dist/collection/components/floor-filter/floor-filter.css +19 -0
  39. package/dist/collection/components/floor-filter/floor-filter.js +163 -0
  40. package/dist/collection/components/info-card/info-card.js +3 -2
  41. package/dist/collection/components/layer-table/layer-table.css +8 -0
  42. package/dist/collection/components/layer-table/layer-table.js +18 -2
  43. package/dist/collection/components/map-card/map-card.js +19 -1
  44. package/dist/collection/components/map-picker/map-picker.css +0 -4
  45. package/dist/collection/components/map-picker/map-picker.js +1 -1
  46. package/dist/collection/components/map-tools/map-tools.js +54 -1
  47. package/dist/collection/components/solution-spatial-ref/solution-spatial-ref.css +1 -7
  48. package/dist/collection/components/solution-spatial-ref/solution-spatial-ref.js +37 -291
  49. package/dist/collection/components/solution-spatial-ref/test/solution-spatial-ref.e2e.js +24 -12
  50. package/dist/collection/components/solution-spatial-ref/test/solution-spatial-ref.spec.js +32 -128
  51. package/dist/collection/components/spatial-ref/spatial-ref.css +20 -0
  52. package/dist/collection/components/spatial-ref/spatial-ref.js +445 -0
  53. package/dist/collection/components/spatial-ref/test/spatial-ref.e2e.js +71 -0
  54. package/dist/collection/components/spatial-ref/test/spatial-ref.spec.js +158 -0
  55. package/dist/collection/demos/crowdsource-manager.html +4 -0
  56. package/dist/collection/demos/solution-spatial-ref.html +9 -16
  57. package/dist/collection/demos/spatial-ref.html +53 -0
  58. package/dist/collection/utils/mapViewUtils.js +32 -19
  59. package/dist/collection/utils/mapViewUtils.ts +43 -20
  60. package/dist/collection/utils/{templates.e2e.js → test/templates.e2e.js} +2 -2
  61. package/dist/collection/utils/{templates.e2e.ts → test/templates.e2e.ts} +2 -2
  62. package/dist/components/card-manager2.js +1 -1
  63. package/dist/components/crowdsource-manager.js +86 -73
  64. package/dist/components/edit-card2.js +1 -1
  65. package/dist/components/floor-filter.d.ts +11 -0
  66. package/dist/components/floor-filter.js +11 -0
  67. package/dist/components/floor-filter2.js +115 -0
  68. package/dist/components/info-card2.js +3 -2
  69. package/dist/components/layer-table2.js +5 -3
  70. package/dist/components/map-card2.js +45 -37
  71. package/dist/components/map-picker2.js +2 -2
  72. package/dist/components/map-tools2.js +52 -11
  73. package/dist/components/mapViewUtils.js +32 -19
  74. package/dist/components/solution-configuration.js +79 -72
  75. package/dist/components/solution-resource-item2.js +2 -1
  76. package/dist/components/solution-resource.js +1836 -0
  77. package/dist/components/solution-spatial-ref2.js +41 -21277
  78. package/dist/components/solution-store.js +2 -1830
  79. package/dist/components/spatial-ref.d.ts +11 -0
  80. package/dist/components/spatial-ref.js +11 -0
  81. package/dist/components/spatial-ref2.js +21374 -0
  82. package/dist/esm/{basemap-gallery_6.entry.js → basemap-gallery_7.entry.js} +124 -4
  83. package/dist/esm/{calcite-tree_3.entry.js → calcite-checkbox_3.entry.js} +125 -321
  84. package/dist/esm/calcite-combobox_6.entry.js +1 -1
  85. package/dist/esm/calcite-shell-panel_14.entry.js +2 -1
  86. package/dist/esm/card-manager_3.entry.js +10 -7
  87. package/dist/{collection/components/layer-table/test/layer-table.e2e.js → esm/common-e4a8e353.js} +15 -9
  88. package/dist/esm/crowdsource-manager.entry.js +12 -7
  89. package/dist/esm/{downloadUtils-ac67a786.js → downloadUtils-287994b1.js} +2 -2
  90. package/dist/esm/edit-card_2.entry.js +4 -3
  91. package/dist/esm/{index.es-f553598f.js → index.es-a3f8409f.js} +2 -2
  92. package/dist/esm/loader.js +1 -1
  93. package/dist/esm/map-select-tools_3.entry.js +2 -2
  94. package/dist/esm/{mapViewUtils-8141d8c1.js → mapViewUtils-8bfabd80.js} +32 -19
  95. package/dist/esm/public-notification.entry.js +2 -2
  96. package/dist/esm/solution-configuration.entry.js +2 -1
  97. package/dist/esm/solution-contents_3.entry.js +20 -21255
  98. package/dist/esm/solution-item-icon.entry.js +323 -0
  99. package/dist/esm/{solution-store-b29d50f7.js → solution-resource-be35d35b.js} +1 -1697
  100. package/dist/esm/solution-store-e734626a.js +1704 -0
  101. package/dist/esm/solutions-components.js +1 -1
  102. package/dist/esm/spatial-ref.entry.js +21289 -0
  103. package/dist/solutions-components/demos/crowdsource-manager.html +4 -0
  104. package/dist/solutions-components/demos/solution-spatial-ref.html +9 -16
  105. package/dist/solutions-components/demos/spatial-ref.html +53 -0
  106. package/dist/solutions-components/{p-64d29ba2.entry.js → p-0bc27ba7.entry.js} +2 -2
  107. package/dist/{collection/components/map-card/test/map-card.e2e.js → solutions-components/p-1b228f97.js} +2 -10
  108. package/dist/solutions-components/{p-9f11a403.entry.js → p-3c5c1487.entry.js} +1 -1
  109. package/dist/solutions-components/{p-a26711e8.js → p-469c8f8a.js} +1 -1
  110. package/dist/solutions-components/p-53bc5fc1.js +36 -0
  111. package/dist/solutions-components/p-5b8c8942.entry.js +21 -0
  112. package/dist/solutions-components/p-63c6fc29.entry.js +6 -0
  113. package/dist/solutions-components/p-64945b43.entry.js +18 -0
  114. package/dist/solutions-components/{p-c8d0ce92.js → p-698c6a56.js} +2 -2
  115. package/dist/solutions-components/{p-b9d29f30.entry.js → p-734cb206.entry.js} +1 -1
  116. package/dist/solutions-components/p-770bff06.entry.js +6 -0
  117. package/dist/solutions-components/p-7741dbab.entry.js +6 -0
  118. package/dist/solutions-components/p-80465067.entry.js +6 -0
  119. package/dist/solutions-components/p-846df994.entry.js +6 -0
  120. package/dist/solutions-components/p-b3f8d2cb.js +192 -0
  121. package/dist/solutions-components/p-c26d8b36.entry.js +6 -0
  122. package/dist/solutions-components/{p-57cf6784.entry.js → p-d22be647.entry.js} +1 -1
  123. package/dist/solutions-components/{p-4d942b0f.entry.js → p-f35147d5.entry.js} +1 -1
  124. package/dist/solutions-components/p-ff0d7712.js +44 -0
  125. package/dist/solutions-components/solutions-components.esm.js +1 -1
  126. package/dist/solutions-components/utils/mapViewUtils.ts +43 -20
  127. package/dist/solutions-components/utils/{templates.e2e.ts → test/templates.e2e.ts} +2 -2
  128. package/dist/types/components/crowdsource-manager/crowdsource-manager.d.ts +9 -1
  129. package/dist/types/components/floor-filter/floor-filter.d.ts +61 -0
  130. package/dist/types/components/layer-table/layer-table.d.ts +4 -0
  131. package/dist/types/components/map-card/map-card.d.ts +4 -0
  132. package/dist/types/components/map-tools/map-tools.d.ts +24 -0
  133. package/dist/types/components/solution-spatial-ref/solution-spatial-ref.d.ts +11 -93
  134. package/dist/types/components/spatial-ref/spatial-ref.d.ts +142 -0
  135. package/dist/types/components.d.ts +123 -16
  136. package/dist/types/preact.d.ts +8 -1
  137. package/package.json +6 -6
  138. package/dist/cjs/calcite-checkbox.cjs.entry.js +0 -136
  139. package/dist/collection/components/basemap-gallery/test/basemap-gallery.spec.js +0 -37
  140. package/dist/collection/components/buffer-tools/test/buffer-tools.e2e.js +0 -29
  141. package/dist/collection/components/buffer-tools/test/buffer-tools.spec.js +0 -160
  142. package/dist/collection/components/card-manager/test/card-manager.e2e.js +0 -29
  143. package/dist/collection/components/card-manager/test/card-manager.spec.js +0 -37
  144. package/dist/collection/components/crowdsource-manager/test/crowdsource-manager.e2e.js +0 -29
  145. package/dist/collection/components/crowdsource-manager/test/crowdsource-manager.spec.js +0 -37
  146. package/dist/collection/components/crowdsource-reporter/test/crowdsource-reporter.e2e.js +0 -29
  147. package/dist/collection/components/crowdsource-reporter/test/crowdsource-reporter.spec.js +0 -37
  148. package/dist/collection/components/deduct-calculator/test/deduct-calculator.e2e.js +0 -29
  149. package/dist/collection/components/deduct-calculator/test/deduct-calculator.spec.js +0 -37
  150. package/dist/collection/components/edit-card/test/edit-card.e2e.js +0 -14
  151. package/dist/collection/components/edit-card/test/edit-card.spec.js +0 -22
  152. package/dist/collection/components/info-card/test/info-card.e2e.js +0 -29
  153. package/dist/collection/components/info-card/test/info-card.spec.js +0 -37
  154. package/dist/collection/components/json-editor/test/json-editor.e2e.js +0 -36
  155. package/dist/collection/components/json-editor/test/json-editor.spec.js +0 -65
  156. package/dist/collection/components/layer-table/test/layer-table.spec.js +0 -37
  157. package/dist/collection/components/layout-manager/test/layout-manager.e2e.js +0 -29
  158. package/dist/collection/components/layout-manager/test/layout-manager.spec.js +0 -37
  159. package/dist/collection/components/list-item/test/list-item.e2e.js +0 -29
  160. package/dist/collection/components/list-item/test/list-item.spec.js +0 -37
  161. package/dist/collection/components/map-card/test/map-card.spec.js +0 -37
  162. package/dist/collection/components/map-draw-tools/test/map-draw-tools.e2e.js +0 -29
  163. package/dist/collection/components/map-draw-tools/test/map-draw-tools.spec.js +0 -37
  164. package/dist/collection/components/map-fullscreen/test/map-fullscreen.e2e.js +0 -29
  165. package/dist/collection/components/map-fullscreen/test/map-fullscreen.spec.js +0 -37
  166. package/dist/collection/components/map-layer-picker/test/map-layer-picker.e2e.js +0 -29
  167. package/dist/collection/components/map-layer-picker/test/map-layer-picker.spec.js +0 -114
  168. package/dist/collection/components/map-legend/test/map-legend.e2e.js +0 -14
  169. package/dist/collection/components/map-legend/test/map-legend.spec.js +0 -22
  170. package/dist/collection/components/map-picker/test/map-picker.e2e.js +0 -29
  171. package/dist/collection/components/map-picker/test/map-picker.spec.js +0 -37
  172. package/dist/collection/components/map-search/test/map-search.e2e.js +0 -29
  173. package/dist/collection/components/map-search/test/map-search.spec.js +0 -37
  174. package/dist/collection/components/map-select-tools/test/map-select-tools.e2e.js +0 -29
  175. package/dist/collection/components/map-select-tools/test/map-select-tools.spec.js +0 -366
  176. package/dist/collection/components/map-tools/test/map-tools.e2e.js +0 -29
  177. package/dist/collection/components/map-tools/test/map-tools.spec.js +0 -37
  178. package/dist/collection/components/pci-calculator/test/pci-calculator.e2e.js +0 -29
  179. package/dist/collection/components/pci-calculator/test/pci-calculator.spec.js +0 -37
  180. package/dist/collection/components/pdf-download/test/pdf-download.e2e.js +0 -76
  181. package/dist/collection/components/pdf-download/test/pdf-download.spec.js +0 -107
  182. package/dist/collection/components/public-notification/test/public-notification.spec.js +0 -161
  183. package/dist/collection/components/refine-selection/test/refine-selection.e2e.js +0 -14
  184. package/dist/collection/components/refine-selection/test/refine-selection.spec.js +0 -22
  185. package/dist/collection/components/solution-configuration/test/solution-configuration.e2e.js +0 -36
  186. package/dist/collection/components/solution-configuration/test/solution-configuration.spec.js +0 -119
  187. package/dist/collection/components/solution-contents/test/solution-contents.e2e.js +0 -94
  188. package/dist/collection/components/solution-contents/test/solution-contents.spec.js +0 -143
  189. package/dist/collection/components/solution-item/test/solution-item.e2e.js +0 -36
  190. package/dist/collection/components/solution-item/test/solution-item.spec.js +0 -77
  191. package/dist/collection/components/solution-item-details/test/solution-item-details.e2e.js +0 -36
  192. package/dist/collection/components/solution-item-details/test/solution-item-details.spec.js +0 -142
  193. package/dist/collection/components/solution-item-icon/test/solution-item-icon.e2e.js +0 -29
  194. package/dist/collection/components/solution-item-icon/test/solution-item-icon.spec.js +0 -39
  195. package/dist/collection/components/solution-item-sharing/test/solution-item-sharing.e2e.js +0 -36
  196. package/dist/collection/components/solution-item-sharing/test/solution-item-sharing.spec.js +0 -54
  197. package/dist/collection/components/solution-organization-variables/test/solution-organization-variables.e2e.js +0 -36
  198. package/dist/collection/components/solution-organization-variables/test/solution-organization-variables.spec.js +0 -65
  199. package/dist/collection/components/solution-resource-item/test/solution-resource-item.e2e.js +0 -36
  200. package/dist/collection/components/solution-resource-item/test/solution-resource-item.spec.js +0 -55
  201. package/dist/collection/components/solution-template-data/test/solution-template-data.e2e.js +0 -36
  202. package/dist/collection/components/solution-template-data/test/solution-template-data.spec.js +0 -60
  203. package/dist/collection/components/solution-variables/test/solution-variables.e2e.js +0 -36
  204. package/dist/collection/components/solution-variables/test/solution-variables.spec.js +0 -131
  205. package/dist/esm/calcite-checkbox.entry.js +0 -132
  206. package/dist/solutions-components/p-07d7e11f.entry.js +0 -6
  207. package/dist/solutions-components/p-16362eb4.js +0 -36
  208. package/dist/solutions-components/p-17d176b5.js +0 -230
  209. package/dist/solutions-components/p-1d9a5198.entry.js +0 -37
  210. package/dist/solutions-components/p-3707d9bd.entry.js +0 -6
  211. package/dist/solutions-components/p-4dbe8337.entry.js +0 -6
  212. package/dist/solutions-components/p-5ffaaaf4.entry.js +0 -6
  213. package/dist/solutions-components/p-736e76fb.entry.js +0 -17
  214. package/dist/solutions-components/p-99f1a767.entry.js +0 -6
  215. /package/dist/collection/components/{solution-spatial-ref → spatial-ref}/spatialreferences.js +0 -0
  216. /package/dist/types/components/{solution-spatial-ref → spatial-ref}/spatialreferences.d.ts +0 -0
@@ -0,0 +1,1704 @@
1
+ /*!
2
+ * Copyright 2022 Esri
3
+ * Licensed under the Apache License, Version 2.0
4
+ * http://www.apache.org/licenses/LICENSE-2.0
5
+ */
6
+ import { c as createStore } from './index-f4bd5aa3.js';
7
+ import { d as EUpdateType } from './interfaces-7470d906.js';
8
+ import { E as EFileType, j as jszip_min, S as SolutionTemplateFormatVersion } from './solution-resource-be35d35b.js';
9
+ import { c as cleanUrl, r as request } from './clean-url-bce022e6.js';
10
+
11
+ /* Copyright (c) 2018-2019 Environmental Systems Research Institute, Inc.
12
+ * Apache-2.0 */
13
+ /**
14
+ * Returns an array with arrays of the given size.
15
+ *
16
+ * @param arr Array to split
17
+ * @param size Size of every group
18
+ */
19
+ function chunkArray(arr, size) {
20
+ const results = [];
21
+ let index = 0;
22
+ while (index < arr.length) {
23
+ results.push(arr.slice(index, index + size));
24
+ index += size;
25
+ }
26
+ return results;
27
+ }
28
+
29
+ /*! *****************************************************************************
30
+ Copyright (c) Microsoft Corporation.
31
+
32
+ Permission to use, copy, modify, and/or distribute this software for any
33
+ purpose with or without fee is hereby granted.
34
+
35
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
36
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
37
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
38
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
39
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
40
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
41
+ PERFORMANCE OF THIS SOFTWARE.
42
+ ***************************************************************************** */
43
+
44
+ var __assign = function() {
45
+ __assign = Object.assign || function __assign(t) {
46
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
47
+ s = arguments[i];
48
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
49
+ }
50
+ return t;
51
+ };
52
+ return __assign.apply(this, arguments);
53
+ };
54
+
55
+ /* Copyright (c) 2017 Environmental Systems Research Institute, Inc.
56
+ * Apache-2.0 */
57
+ /**
58
+ * Helper that returns the appropriate portal url for a given request. `requestOptions.portal` is given
59
+ * precedence over `authentication.portal`. If neither `portal` nor `authentication` is present,
60
+ * `www.arcgis.com/sharing/rest` is returned.
61
+ *
62
+ * @param requestOptions - Request options that may have authentication manager
63
+ * @returns Portal url to be used in API requests
64
+ */
65
+ function getPortalUrl(requestOptions) {
66
+ if (requestOptions === void 0) { requestOptions = {}; }
67
+ // use portal in options if specified
68
+ if (requestOptions.portal) {
69
+ return cleanUrl(requestOptions.portal);
70
+ }
71
+ // if auth was passed, use that portal
72
+ if (requestOptions.authentication) {
73
+ // the portal url is already scrubbed in the auth package
74
+ return requestOptions.authentication.portal;
75
+ }
76
+ // default to arcgis.com
77
+ return "https://www.arcgis.com/sharing/rest";
78
+ }
79
+
80
+ /* Copyright (c) 2017-2018 Environmental Systems Research Institute, Inc.
81
+ * Apache-2.0 */
82
+ /**
83
+ * Serialize an item and its data into a json format accepted by the Portal API for create and update operations
84
+ *
85
+ * @param item Item to be serialized
86
+ * @returns a formatted json object to be sent to Portal
87
+ */
88
+ function serializeItem(item) {
89
+ // create a clone so we're not messing with the original
90
+ var clone = JSON.parse(JSON.stringify(item));
91
+ // binary data needs POSTed as a `file`
92
+ // JSON object literals should be passed as `text`.
93
+ if (clone.data) {
94
+ (typeof Blob !== "undefined" && item.data instanceof Blob) ||
95
+ // Node.js doesn't implement Blob
96
+ item.data.constructor.name === "ReadStream"
97
+ ? (clone.file = item.data)
98
+ : (clone.text = item.data);
99
+ delete clone.data;
100
+ }
101
+ return clone;
102
+ }
103
+ /**
104
+ * `requestOptions.owner` is given priority, `requestOptions.item.owner` will be checked next. If neither are present, `authentication.getUserName()` will be used instead.
105
+ */
106
+ function determineOwner(requestOptions) {
107
+ if (requestOptions.owner) {
108
+ return Promise.resolve(requestOptions.owner);
109
+ }
110
+ else if (requestOptions.item && requestOptions.item.owner) {
111
+ return Promise.resolve(requestOptions.item.owner);
112
+ }
113
+ else if (requestOptions.authentication &&
114
+ requestOptions.authentication.getUsername) {
115
+ return requestOptions.authentication.getUsername();
116
+ }
117
+ else {
118
+ return Promise.reject(new Error("Could not determine the owner of this item. Pass the `owner`, `item.owner`, or `authentication` option."));
119
+ }
120
+ }
121
+ /**
122
+ * checks if the extent is a valid BBox (2 element array of coordinate pair arrays)
123
+ * @param extent
124
+ * @returns
125
+ */
126
+ function isBBox(extent) {
127
+ return (Array.isArray(extent) &&
128
+ Array.isArray(extent[0]) &&
129
+ Array.isArray(extent[1]));
130
+ }
131
+ /**
132
+ * Given a Bbox, convert it to a string. Some api endpoints expect a string
133
+ *
134
+ * @param {BBox} extent
135
+ * @return {*} {string}
136
+ */
137
+ function bboxToString(extent) {
138
+ return extent.join(",");
139
+ }
140
+
141
+ /* Copyright (c) 2018 Environmental Systems Research Institute, Inc.
142
+ * Apache-2.0 */
143
+ /**
144
+ * ```js
145
+ * import { updateItem } from "@esri/arcgis-rest-portal";
146
+ * //
147
+ * updateItem({
148
+ * item: {
149
+ * id: "3ef",
150
+ * description: "A three hour tour"
151
+ * },
152
+ * authentication
153
+ * })
154
+ * .then(response)
155
+ * ```
156
+ * Update an Item. See the [REST Documentation](https://developers.arcgis.com/rest/users-groups-and-items/update-item.htm) for more information.
157
+ *
158
+ * @param requestOptions - Options for the request.
159
+ * @returns A Promise that updates an item.
160
+ */
161
+ function updateItem$1(requestOptions) {
162
+ return determineOwner(requestOptions).then(function (owner) {
163
+ var url = requestOptions.folderId
164
+ ? getPortalUrl(requestOptions) + "/content/users/" + owner + "/" + requestOptions.folderId + "/items/" + requestOptions.item.id + "/update"
165
+ : getPortalUrl(requestOptions) + "/content/users/" + owner + "/items/" + requestOptions.item.id + "/update";
166
+ // serialize the item into something Portal will accept
167
+ requestOptions.params = __assign(__assign({}, requestOptions.params), serializeItem(requestOptions.item));
168
+ // convert extent, if present, into a string from bbox
169
+ // processParams was previously doing this sort of work,
170
+ // however now we need to let array of arrays through
171
+ // Thus for extents we need to move this logic here
172
+ if (requestOptions.params.extent && isBBox(requestOptions.params.extent)) {
173
+ requestOptions.params.extent = bboxToString(requestOptions.params.extent);
174
+ }
175
+ return request(url, requestOptions);
176
+ });
177
+ }
178
+ /**
179
+ * ```js
180
+ * import { updateItemResource } from "@esri/arcgis-rest-portal";
181
+ * //
182
+ * updateItemResource({
183
+ * id: '3ef',
184
+ * resource: file,
185
+ * name: 'bigkahuna.jpg',
186
+ * authentication
187
+ * })
188
+ * .then(response)
189
+ * ```
190
+ * Update a resource associated with an item. See the [REST Documentation](https://developers.arcgis.com/rest/users-groups-and-items/update-resources.htm) for more information.
191
+ *
192
+ * @param requestOptions - Options for the request
193
+ * @returns A Promise that updates an item resource.
194
+ */
195
+ function updateItemResource(requestOptions) {
196
+ return determineOwner(requestOptions).then(function (owner) {
197
+ var url = getPortalUrl(requestOptions) + "/content/users/" + owner + "/items/" + requestOptions.id + "/updateResources";
198
+ // mix in user supplied params
199
+ requestOptions.params = __assign({ file: requestOptions.resource, fileName: requestOptions.name, resourcesPrefix: requestOptions.prefix, text: requestOptions.content }, requestOptions.params);
200
+ // only override the access specified previously if 'private' is passed explicitly
201
+ if (typeof requestOptions.private !== "undefined") {
202
+ requestOptions.params.access = requestOptions.private
203
+ ? "private"
204
+ : "inherit";
205
+ }
206
+ return request(url, requestOptions);
207
+ });
208
+ }
209
+
210
+ /* Copyright (c) 2018 Environmental Systems Research Institute, Inc.
211
+ * Apache-2.0 */
212
+ /**
213
+ * ```js
214
+ * import { addItemResource } from "@esri/arcgis-rest-portal";
215
+ * //
216
+ * // Add a file resource
217
+ * addItemResource({
218
+ * id: '3ef',
219
+ * resource: file,
220
+ * name: 'bigkahuna.jpg',
221
+ * authentication
222
+ * })
223
+ * .then(response)
224
+ * //
225
+ * // Add a text resource
226
+ * addItemResource({
227
+ * id: '4fg',
228
+ * content: "Text content",
229
+ * name: 'bigkahuna.txt',
230
+ * authentication
231
+ * })
232
+ * .then(response)
233
+ * ```
234
+ * Add a resource associated with an item. See the [REST Documentation](https://developers.arcgis.com/rest/users-groups-and-items/add-resources.htm) for more information.
235
+ *
236
+ * @param requestOptions - Options for the request
237
+ * @returns A Promise to add item resources.
238
+ */
239
+ function addItemResource(requestOptions) {
240
+ return determineOwner(requestOptions).then(function (owner) {
241
+ var url = getPortalUrl(requestOptions) + "/content/users/" + owner + "/items/" + requestOptions.id + "/addResources";
242
+ requestOptions.params = __assign({ file: requestOptions.resource, fileName: requestOptions.name, resourcesPrefix: requestOptions.prefix, text: requestOptions.content, access: requestOptions.private ? "private" : "inherit" }, requestOptions.params);
243
+ return request(url, requestOptions);
244
+ });
245
+ }
246
+
247
+ /* Copyright (c) 2018 Environmental Systems Research Institute, Inc.
248
+ * Apache-2.0 */
249
+ /**
250
+ * Remove a resource associated with an item
251
+ *
252
+ * @param requestOptions - Options for the request
253
+ * @returns A Promise that deletes an item resource.
254
+ */
255
+ function removeItemResource(requestOptions) {
256
+ return determineOwner(requestOptions).then(function (owner) {
257
+ var url = getPortalUrl(requestOptions) + "/content/users/" + owner + "/items/" + requestOptions.id + "/removeResources";
258
+ // mix in user supplied params
259
+ requestOptions.params = __assign(__assign({}, requestOptions.params), { resource: requestOptions.resource });
260
+ // only override the deleteAll param specified previously if it is passed explicitly
261
+ if (typeof requestOptions.deleteAll !== "undefined") {
262
+ requestOptions.params.deleteAll = requestOptions.deleteAll;
263
+ }
264
+ return request(url, requestOptions);
265
+ });
266
+ }
267
+
268
+ /** @license
269
+ * Copyright 2020 Esri
270
+ *
271
+ * Licensed under the Apache License, Version 2.0 (the "License");
272
+ * you may not use this file except in compliance with the License.
273
+ * You may obtain a copy of the License at
274
+ *
275
+ * http://www.apache.org/licenses/LICENSE-2.0
276
+ *
277
+ * Unless required by applicable law or agreed to in writing, software
278
+ * distributed under the License is distributed on an "AS IS" BASIS,
279
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
280
+ * See the License for the specific language governing permissions and
281
+ * limitations under the License.
282
+ */
283
+ /**
284
+ * Supplies the File constructor for Microsoft Legacy Edge.
285
+ *
286
+ * @param fileBits Contents for file
287
+ * @param fileName Name for file
288
+ * @param options Bucket of options, euch as `type` for the MIME type; defaults to empty string for `type`
289
+ * @returns File or, for Microsoft Legacy Edge, Blob
290
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/File/File
291
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/Blob/Blob
292
+ */
293
+ function new_File(fileBits, fileName, options) {
294
+ let file;
295
+ try {
296
+ // Modern browser
297
+ file = new File(fileBits, fileName, options);
298
+ }
299
+ catch (error) {
300
+ // Microsoft Legacy Edge
301
+ /* istanbul ignore next */
302
+ file = (function () {
303
+ if (typeof options === "undefined") {
304
+ // Microsoft Legacy Edge fails in karma if options is not defined
305
+ options = {
306
+ type: ""
307
+ };
308
+ }
309
+ const blob = new Blob(fileBits, options);
310
+ blob.lastModified = new Date();
311
+ blob.name = fileName;
312
+ return blob;
313
+ })();
314
+ }
315
+ return file;
316
+ }
317
+
318
+ /** @license
319
+ * Copyright 2018 Esri
320
+ *
321
+ * Licensed under the Apache License, Version 2.0 (the "License");
322
+ * you may not use this file except in compliance with the License.
323
+ * You may obtain a copy of the License at
324
+ *
325
+ * http://www.apache.org/licenses/LICENSE-2.0
326
+ *
327
+ * Unless required by applicable law or agreed to in writing, software
328
+ * distributed under the License is distributed on an "AS IS" BASIS,
329
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
330
+ * See the License for the specific language governing permissions and
331
+ * limitations under the License.
332
+ */
333
+ /**
334
+ * Extracts JSON from a Blob.
335
+ *
336
+ * @param blob Blob to use as source
337
+ * @returns A promise that will resolve with JSON or null
338
+ */
339
+ function blobToJson(blob) {
340
+ return new Promise(resolve => {
341
+ blobToText(blob).then(blobContents => {
342
+ try {
343
+ resolve(JSON.parse(blobContents));
344
+ }
345
+ catch (err) {
346
+ resolve(null);
347
+ }
348
+ }, () => resolve(null));
349
+ });
350
+ }
351
+ /**
352
+ * Converts a Blob to a File.
353
+ *
354
+ * @param blob Blob to use as source
355
+ * @param filename Name to use for file
356
+ * @param mimeType MIME type to override blob's MIME type
357
+ * @returns File created out of Blob and filename
358
+ */
359
+ function blobToFile(blob, filename, mimeType) {
360
+ return blob
361
+ ? new_File([blob], filename ? filename : "", {
362
+ type: mimeType || blob.type
363
+ })
364
+ : null;
365
+ }
366
+ /**
367
+ * Extracts text from a Blob.
368
+ *
369
+ * @param blob Blob to use as source
370
+ * @returns A promise that will resolve with text read from blob
371
+ */
372
+ function blobToText(blob) {
373
+ return new Promise(resolve => {
374
+ const reader = new FileReader();
375
+ reader.onload = function (evt) {
376
+ // Disable needed because Node requires cast
377
+ // tslint:disable-next-line: no-unnecessary-type-assertion
378
+ const blobContents = evt.target.result;
379
+ resolve(blobContents ? blobContents : ""); // not handling ArrayContents variant
380
+ };
381
+ reader.readAsText(blob);
382
+ });
383
+ }
384
+ /**
385
+ * Checks that a URL path ends with a slash.
386
+ *
387
+ * @param url URL to check
388
+ * @returns URL, appended with slash if missing
389
+ */
390
+ function checkUrlPathTermination(url) {
391
+ return url ? (url.endsWith("/") ? url : url + "/") : url;
392
+ }
393
+ /**
394
+ * Gets a property out of a deeply nested object.
395
+ * Does not handle anything but nested object graph
396
+ *
397
+ * @param obj Object to retrieve value from
398
+ * @param path Path into an object, e.g., "data.values.webmap", where "data" is a top-level property
399
+ * in obj
400
+ * @returns Value at end of path
401
+ */
402
+ function getProp(obj, path) {
403
+ return path.split(".").reduce(function (prev, curr) {
404
+ /* istanbul ignore next no need to test undefined scenario */
405
+ return prev ? prev[curr] : undefined;
406
+ }, obj);
407
+ }
408
+ /**
409
+ * Sets a deeply nested property of an object.
410
+ * Creates the full path if it does not exist.
411
+ *
412
+ * @param obj Object to set value of
413
+ * @param path Path into an object, e.g., "data.values.webmap", where "data" is a top-level property in obj
414
+ * @param value The value to set at the end of the path
415
+ */
416
+ function setCreateProp(obj, path, value) {
417
+ const pathParts = path.split(".");
418
+ pathParts.reduce((a, b, c) => {
419
+ if (c === pathParts.length - 1) {
420
+ a[b] = value;
421
+ return value;
422
+ }
423
+ else {
424
+ if (!a[b]) {
425
+ a[b] = {};
426
+ }
427
+ return a[b];
428
+ }
429
+ }, obj);
430
+ }
431
+
432
+ /**
433
+ * Gets a Blob from a web site.
434
+ *
435
+ * @param url Address of Blob
436
+ * @param authentication Credentials for the request
437
+ * @param requestOptions - Options for the request, including parameters relevant to the endpoint.
438
+ * @returns Promise that will resolve with Blob or an AGO-style JSON failure response
439
+ */
440
+ function getBlob(url, authentication, requestOptions = {}) {
441
+ if (!url) {
442
+ return Promise.reject("Url must be provided");
443
+ }
444
+ const blobRequestOptions = {
445
+ authentication: authentication,
446
+ rawResponse: true,
447
+ ...requestOptions
448
+ };
449
+ return request(url, blobRequestOptions).then(response => {
450
+ return response.blob();
451
+ });
452
+ }
453
+
454
+ /** @license
455
+ * Copyright 2018 Esri
456
+ *
457
+ * Licensed under the Apache License, Version 2.0 (the "License");
458
+ * you may not use this file except in compliance with the License.
459
+ * You may obtain a copy of the License at
460
+ *
461
+ * http://www.apache.org/licenses/LICENSE-2.0
462
+ *
463
+ * Unless required by applicable law or agreed to in writing, software
464
+ * distributed under the License is distributed on an "AS IS" BASIS,
465
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
466
+ * See the License for the specific language governing permissions and
467
+ * limitations under the License.
468
+ */
469
+ // ------------------------------------------------------------------------------------------------------------------ //
470
+ const ZIP_FILE_HEADER_SIGNATURE = "PK";
471
+ /**
472
+ * Gets a Blob from a web site and casts it as a file using the supplied name.
473
+ *
474
+ * @param url Address of Blob
475
+ * @param filename Name to use for file
476
+ * @param authentication Credentials for the request
477
+ * @returns Promise that will resolve with a File, undefined if the Blob is null, or an AGO-style JSON failure response
478
+ */
479
+ function getBlobAsFile(url, filename, authentication, ignoreErrors = [], mimeType) {
480
+ return new Promise((resolve, reject) => {
481
+ // Get the blob from the URL
482
+ getBlobCheckForError(url, authentication, ignoreErrors).then(blob => !blob ? resolve(null) : resolve(blobToFile(blob, filename, mimeType)), reject);
483
+ });
484
+ }
485
+ /**
486
+ * Gets a Blob from a web site and checks for a JSON error packet in the Blob.
487
+ *
488
+ * @param url Address of Blob
489
+ * @param authentication Credentials for the request
490
+ * @param ignoreErrors List of HTTP error codes that should be ignored
491
+ * @returns Promise that will resolve with Blob or an AGO-REST JSON failure response
492
+ */
493
+ function getBlobCheckForError(url, authentication, ignoreErrors = []) {
494
+ return new Promise((resolve, reject) => {
495
+ // Get the blob from the URL
496
+ getBlob(url, authentication).then(blob => {
497
+ // Reclassify text/plain blobs as needed
498
+ _fixTextBlobType(blob).then(adjustedBlob => {
499
+ if (adjustedBlob.type === "application/json") {
500
+ // Blob may be an error
501
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
502
+ blobToJson(adjustedBlob).then((json) => {
503
+ // Check for valid JSON with an error
504
+ if (json?.error) {
505
+ const code = json.error.code;
506
+ if (code !== undefined && ignoreErrors.indexOf(code) >= 0) {
507
+ resolve(null); // Error, but ignored
508
+ }
509
+ else {
510
+ reject(json); // Other error; fail with error
511
+ }
512
+ }
513
+ else {
514
+ resolve(adjustedBlob);
515
+ }
516
+ });
517
+ }
518
+ else {
519
+ resolve(adjustedBlob);
520
+ }
521
+ }, reject);
522
+ }, reject);
523
+ });
524
+ }
525
+ /**
526
+ * Gets the data information of an AGO item in its JSON form.
527
+ *
528
+ * @param itemId Id of an item whose data information is sought
529
+ * @param filename Name to use for file
530
+ * @param authentication Credentials for the request to AGO
531
+ * @returns Promise that will resolve with JSON, or an AGO-style JSON failure response
532
+ */
533
+ function getItemDataAsJson(itemId, authentication) {
534
+ return new Promise(resolve => {
535
+ getItemDataBlob(itemId, authentication).then(blob => resolve(blobToJson(blob)), () => resolve(null));
536
+ });
537
+ }
538
+ /**
539
+ * Gets the data information of an AGO item in its raw (Blob) form.
540
+ *
541
+ * @param itemId Id of an item whose data information is sought
542
+ * @param authentication Credentials for the request to AGO
543
+ * @returns A promise that will resolve with the data Blob or null if the item doesn't have a data section
544
+ */
545
+ function getItemDataBlob(itemId, authentication) {
546
+ return new Promise(resolve => {
547
+ const url = getItemDataBlobUrl(itemId, authentication);
548
+ getBlobCheckForError(url, authentication, [400, 500]).then(blob => resolve(_fixTextBlobType(blob)), () => resolve(null));
549
+ });
550
+ }
551
+ /**
552
+ * Gets the URL to the data information of an AGO item in its raw (Blob) form.
553
+ *
554
+ * @param itemId Id of an item whose data information is sought
555
+ * @param authentication Credentials for the request to AGO
556
+ * @returns URL string
557
+ */
558
+ function getItemDataBlobUrl(itemId, authentication) {
559
+ return `${getPortalSharingUrlFromAuth(authentication)}/content/items/${itemId}/data`;
560
+ }
561
+ /**
562
+ * Extracts the portal sharing url from a supplied authentication.
563
+ *
564
+ * @param authentication Credentials for the request to AGO
565
+ * @returns Portal sharing url to be used in API requests, defaulting to `https://www.arcgis.com/sharing/rest`
566
+ */
567
+ function getPortalSharingUrlFromAuth(authentication) {
568
+ // If auth was passed, use that portal
569
+ return getProp(authentication, "portal") || "https://www.arcgis.com/sharing/rest";
570
+ }
571
+ function getThumbnailFile(url, filename, authentication) {
572
+ return new Promise(resolve => {
573
+ getBlobAsFile(url, filename, authentication, [500]).then(resolve, () => resolve(null));
574
+ });
575
+ }
576
+ // ------------------------------------------------------------------------------------------------------------------ //
577
+ /**
578
+ * Fixes the types of Blobs incorrectly typed as text/plain.
579
+ *
580
+ * @param blob Blob to check
581
+ * @returns Promise resolving to original Blob, unless it's originally typed as text/plain but is
582
+ * really JSON, ZIP, or XML
583
+ * @private
584
+ */
585
+ function _fixTextBlobType(blob) {
586
+ return new Promise((resolve, reject) => {
587
+ if (blob &&
588
+ blob.size > 0 &&
589
+ (blob.type.startsWith("text/plain") ||
590
+ blob.type.startsWith("application/json"))) {
591
+ blobToText(blob).then(blobText => {
592
+ // Convertible to JSON?
593
+ try {
594
+ JSON.parse(blobText);
595
+ // Yes; reclassify as JSON
596
+ resolve(new Blob([blob], { type: "application/json" }));
597
+ }
598
+ catch (ignored) {
599
+ // Nope; test for ZIP file
600
+ if (blobText.length > 4 &&
601
+ blobText.substr(0, 4) === ZIP_FILE_HEADER_SIGNATURE) {
602
+ // Yes; reclassify as ZIP
603
+ resolve(new Blob([blob], { type: "application/zip" }));
604
+ }
605
+ else if (blobText.startsWith("<")) {
606
+ // Reclassify as XML; since the blob started out as text/plain, it's more likely that is
607
+ // meant to be human-readable, so we'll use text/xml instead of application/xml
608
+ resolve(new Blob([blob], { type: "text/xml" }));
609
+ }
610
+ else {
611
+ // Leave as text
612
+ resolve(blob);
613
+ }
614
+ }
615
+ },
616
+ // Faulty blob
617
+ reject);
618
+ }
619
+ else {
620
+ // Empty or not typed as plain text, so simply return
621
+ if (blob) {
622
+ resolve(blob);
623
+ }
624
+ else {
625
+ reject();
626
+ }
627
+ }
628
+ });
629
+ }
630
+
631
+ /** @license
632
+ * Copyright 2018 Esri
633
+ *
634
+ * Licensed under the Apache License, Version 2.0 (the "License");
635
+ * you may not use this file except in compliance with the License.
636
+ * You may obtain a copy of the License at
637
+ *
638
+ * http://www.apache.org/licenses/LICENSE-2.0
639
+ *
640
+ * Unless required by applicable law or agreed to in writing, software
641
+ * distributed under the License is distributed on an "AS IS" BASIS,
642
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
643
+ * See the License for the specific language governing permissions and
644
+ * limitations under the License.
645
+ */
646
+ /**
647
+ * Updates an item.
648
+ *
649
+ * @param itemInfo The base info of an item; note that this content will be serialized, which doesn't work
650
+ * for binary content
651
+ * @param authentication Credentials for request
652
+ * @param folderId Item's folder
653
+ * @param additionalParams Updates that are put under the `params` property, which is not serialized
654
+ * @return
655
+ */
656
+ function updateItem(itemInfo, authentication, folderId, additionalParams) {
657
+ return new Promise((resolve, reject) => {
658
+ const updateOptions = {
659
+ item: itemInfo,
660
+ folderId: folderId,
661
+ authentication: authentication,
662
+ params: {
663
+ ...(additionalParams ?? {})
664
+ }
665
+ };
666
+ updateItem$1(updateOptions).then(response => (response.success ? resolve(response) : reject(response)), err => reject(err));
667
+ });
668
+ }
669
+
670
+ /** @license
671
+ * Copyright 2020 Esri
672
+ *
673
+ * Licensed under the Apache License, Version 2.0 (the "License");
674
+ * you may not use this file except in compliance with the License.
675
+ * You may obtain a copy of the License at
676
+ *
677
+ * http://www.apache.org/licenses/LICENSE-2.0
678
+ *
679
+ * Unless required by applicable law or agreed to in writing, software
680
+ * distributed under the License is distributed on an "AS IS" BASIS,
681
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
682
+ * See the License for the specific language governing permissions and
683
+ * limitations under the License.
684
+ */
685
+ /**
686
+ * Extracts an item's resource folder and filename from the filename used to store a copy in a storage item.
687
+ *
688
+ * @param storageResourceFilename Filename used to store the resource, metadata, or thumbnail of an item
689
+ * @param storageVersion Version of the Solution template
690
+ * @returns Folder and filename for storing information in an item, as well as the type (resource, metadata,
691
+ * or thumbnail) of the information; the folder property is only meaningful for the resource type
692
+ * @see generateResourceStorageFilename
693
+ * @see generateMetadataStorageFilename
694
+ * @see generateThumbnailStorageFilename
695
+ * @see convertItemResourceToStorageResource
696
+ */
697
+ function convertStorageResourceToItemResource(storageResourceFilename, storageVersion = 0) {
698
+ const nameParts = storageResourceFilename.split("/");
699
+ let filename = nameParts.pop();
700
+ let folder = "";
701
+ const firstPrefixPart = nameParts.shift(); // undefined if there's no folder
702
+ // Handle special "folders"
703
+ let type = EFileType.Resource;
704
+ if (firstPrefixPart) {
705
+ if (firstPrefixPart.endsWith("_info_thumbnail")) {
706
+ type = EFileType.Thumbnail;
707
+ }
708
+ else if (firstPrefixPart.endsWith("_info_metadata")) {
709
+ type = EFileType.Metadata;
710
+ filename = "metadata.xml";
711
+ }
712
+ else if (firstPrefixPart.endsWith("_info_data")) {
713
+ type = EFileType.Data;
714
+ }
715
+ else if (firstPrefixPart.endsWith("_info_dataz")) {
716
+ filename = filename.replace(/\.zip$/, "");
717
+ type = EFileType.Data;
718
+ // Otherwise, strip off item id
719
+ }
720
+ else if (storageVersion < 1) {
721
+ // Version 0
722
+ const folderStart = firstPrefixPart.indexOf("_");
723
+ if (folderStart > 0) {
724
+ folder = firstPrefixPart.substr(folderStart + 1);
725
+ }
726
+ }
727
+ else {
728
+ // Version ≥ 1
729
+ folder = nameParts.join("/"); // folder is optional, in which case this will be ""
730
+ }
731
+ }
732
+ return { type, folder, filename };
733
+ }
734
+
735
+ /** @license
736
+ * Copyright 2021 Esri
737
+ *
738
+ * Licensed under the Apache License, Version 2.0 (the "License");
739
+ * you may not use this file except in compliance with the License.
740
+ * You may obtain a copy of the License at
741
+ *
742
+ * http://www.apache.org/licenses/LICENSE-2.0
743
+ *
744
+ * Unless required by applicable law or agreed to in writing, software
745
+ * distributed under the License is distributed on an "AS IS" BASIS,
746
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
747
+ * See the License for the specific language governing permissions and
748
+ * limitations under the License.
749
+ */
750
+ // ------------------------------------------------------------------------------------------------------------------ //
751
+ /**
752
+ * Generates IAssociatedFileCopyResults object.
753
+ *
754
+ * @param fileInfo Info about item that was to be copied
755
+ * @param fetchedFromSource Status of fetching item from source
756
+ * @param copiedToDestination Status of copying item to destination
757
+ * @returns IAssociatedFileCopyResults object
758
+ */
759
+ function createCopyResults(fileInfo, fetchedFromSource, copiedToDestination) {
760
+ return {
761
+ ...fileInfo,
762
+ fetchedFromSource,
763
+ copiedToDestination
764
+ };
765
+ }
766
+
767
+ /** @license
768
+ * Copyright 2021 Esri
769
+ *
770
+ * Licensed under the Apache License, Version 2.0 (the "License");
771
+ * you may not use this file except in compliance with the License.
772
+ * You may obtain a copy of the License at
773
+ *
774
+ * http://www.apache.org/licenses/LICENSE-2.0
775
+ *
776
+ * Unless required by applicable law or agreed to in writing, software
777
+ * distributed under the License is distributed on an "AS IS" BASIS,
778
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
779
+ * See the License for the specific language governing permissions and
780
+ * limitations under the License.
781
+ */
782
+ // ------------------------------------------------------------------------------------------------------------------ //
783
+ /**
784
+ * Copies a resource into a zipfile.
785
+ *
786
+ * @param file Information about the source and destination of the file such as its URL, folder, filename
787
+ * @param zipInfo Information about a zipfile such as its name and its zip object
788
+ * @returns The result of the copy
789
+ */
790
+ function copyResourceIntoZip(file, zipInfo) {
791
+ // Add it to the zip
792
+ if (file.folder) {
793
+ zipInfo.zip
794
+ .folder(file.folder)
795
+ .file(file.filename, file.file, { binary: true });
796
+ }
797
+ else {
798
+ zipInfo.zip.file(file.filename, file.file, { binary: true });
799
+ }
800
+ zipInfo.filelist.push(file);
801
+ return createCopyResults(file, true);
802
+ }
803
+
804
+ /** @license
805
+ * Copyright 2021 Esri
806
+ *
807
+ * Licensed under the Apache License, Version 2.0 (the "License");
808
+ * you may not use this file except in compliance with the License.
809
+ * You may obtain a copy of the License at
810
+ *
811
+ * http://www.apache.org/licenses/LICENSE-2.0
812
+ *
813
+ * Unless required by applicable law or agreed to in writing, software
814
+ * distributed under the License is distributed on an "AS IS" BASIS,
815
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
816
+ * See the License for the specific language governing permissions and
817
+ * limitations under the License.
818
+ */
819
+ // ------------------------------------------------------------------------------------------------------------------ //
820
+ /**
821
+ * Copies a zipfile into an AGO item.
822
+ *
823
+ * @param zipInfo Information about a zipfile such as its name and its zip object
824
+ * @param destinationItemId Id of item to receive copy of resource/metadata/thumbnail
825
+ * @param destinationAuthentication Credentials for the request to the storage
826
+ * @returns A promise which resolves to the result of the copy
827
+ */
828
+ function copyZipIntoItem(zipInfo, destinationItemId, destinationAuthentication) {
829
+ return new Promise(resolve => {
830
+ zipInfo.zip
831
+ .generateAsync({ type: "blob" })
832
+ .then((content) => {
833
+ return blobToFile(content, zipInfo.filename, "application/zip");
834
+ })
835
+ .then((zipfile) => {
836
+ const addResourceOptions = {
837
+ id: destinationItemId,
838
+ resource: zipfile,
839
+ authentication: destinationAuthentication,
840
+ params: {
841
+ archive: true
842
+ }
843
+ };
844
+ return addItemResource(addResourceOptions);
845
+ })
846
+ .then(() => resolve(createCopyResults(zipInfo, true, true)), () => resolve(createCopyResults(zipInfo, true, false)) // unable to add resource
847
+ );
848
+ });
849
+ }
850
+
851
+ /** @license
852
+ * Copyright 2021 Esri
853
+ *
854
+ * Licensed under the Apache License, Version 2.0 (the "License");
855
+ * you may not use this file except in compliance with the License.
856
+ * You may obtain a copy of the License at
857
+ *
858
+ * http://www.apache.org/licenses/LICENSE-2.0
859
+ *
860
+ * Unless required by applicable law or agreed to in writing, software
861
+ * distributed under the License is distributed on an "AS IS" BASIS,
862
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
863
+ * See the License for the specific language governing permissions and
864
+ * limitations under the License.
865
+ */
866
+ // ------------------------------------------------------------------------------------------------------------------ //
867
+ /**
868
+ * Copies the files for storing the resources, metadata, and thumbnail of an item or group to a storage item
869
+ * with a specified path by collecting files into zip files.
870
+ *
871
+ * @param files List of item files' URLs and folder/filenames for storing the files
872
+ * @param destinationItemId Id of item to receive copy of resource/metadata/thumbnail
873
+ * @param destinationAuthentication Credentials for the request to the storage
874
+ * @param filesPerZip Number of files to include per zip file; AGO limits zips to 50 files
875
+ * @returns A promise which resolves to a list of the result of the copies
876
+ */
877
+ function copyFilesAsResources(files, destinationItemId, destinationAuthentication, filesPerZip = 40) {
878
+ return new Promise(resolve => {
879
+ let awaitAllItems = [];
880
+ const zipInfos = [];
881
+ if (files.length > 0) {
882
+ // Bundle the resources into chunked zip updates because AGO tends to have problems with
883
+ // many updates in a row to the same item: it claims success despite randomly failing.
884
+ // Note that AGO imposes a limit of 50 files per zip, so we break the list of resource
885
+ // file info into chunks below this threshold and start a zip for each
886
+ // https://developers.arcgis.com/rest/users-groups-and-items/add-resources.htm
887
+ const chunkedResourceFiles = chunkArray(files, filesPerZip);
888
+ chunkedResourceFiles.forEach((chunk, index) => {
889
+ // Create a zip for this chunk
890
+ const zipInfo = {
891
+ filename: `resources${index}.zip`,
892
+ zip: new jszip_min(),
893
+ filelist: []
894
+ };
895
+ awaitAllItems = awaitAllItems.concat(chunk.map(file => copyResourceIntoZip(file, zipInfo)));
896
+ zipInfos.push(zipInfo);
897
+ });
898
+ }
899
+ if (awaitAllItems.length > 0) {
900
+ // Wait until the Resource zip file(s) are prepared
901
+ void Promise.all(awaitAllItems).then((results) => {
902
+ // We have three types of results:
903
+ // | fetchedFromSource | copiedToDestination | interpretation | |
904
+ // +-------------------+---------------------+------------------------------------------------+
905
+ // | false | * | could not fetch file from source |
906
+ // | true | true | file has been fetched and sent to AGO |
907
+ // | true | undefined | file has been fetched and will be sent via zip |
908
+ // Filter out copiedToDestination===undefined; we'll get their status when we send their zip
909
+ results = results.filter((result) => !(result.fetchedFromSource &&
910
+ typeof result.copiedToDestination === "undefined"));
911
+ // Now send the resources to AGO
912
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
913
+ _copyAssociatedFileZips(zipInfos, destinationItemId, destinationAuthentication).then((zipResults) => {
914
+ resolve(results.concat(zipResults));
915
+ });
916
+ });
917
+ }
918
+ else {
919
+ // No data, metadata, or resources to send; we're done
920
+ resolve([]);
921
+ }
922
+ });
923
+ }
924
+ /**
925
+ * Copies one or more zipfiles to a storage item.
926
+ *
927
+ * @param zipInfos List of zip files containing files to store
928
+ * @param destinationItemId Id of item to receive copy of resource/metadata/thumbnail
929
+ * @param destinationAuthentication Credentials for the request to the storage
930
+ * @returns A promise which resolves to a list of the result of the copies
931
+ * @private
932
+ */
933
+ function _copyAssociatedFileZips(zipInfos, destinationItemId, destinationAuthentication) {
934
+ return new Promise(resolve => {
935
+ const results = [];
936
+ // Filter out empty zips, which can happen when none of the files in the chunk going into a zip
937
+ // can be fetched; e.g., the only file is metadata.xml, and the source item doesn't have metadata
938
+ const nonEmptyZipInfos = zipInfos.filter((zipInfo) => Object.keys(zipInfo.zip.files).length > 0);
939
+ if (nonEmptyZipInfos.length > 0) {
940
+ // Send the zip(s) to AGO
941
+ void _sendZipsSeriallyToItem(nonEmptyZipInfos, destinationItemId, destinationAuthentication).then((zipResults) => {
942
+ resolve(zipResults);
943
+ });
944
+ }
945
+ else {
946
+ // No resources to send; we're done
947
+ resolve(results);
948
+ }
949
+ });
950
+ }
951
+ /**
952
+ * Copies one or more zipfiles to a storage item in a serial fashion, waiting a bit between sends.
953
+ *
954
+ * @param zipInfos List of zip files containing files to store
955
+ * @param destinationItemId Id of item to receive copy of resource/metadata/thumbnail
956
+ * @param destinationAuthentication Credentials for the request to the storage
957
+ * @returns A promise which resolves to a list of the result of the copies
958
+ */
959
+ function _sendZipsSeriallyToItem(zipInfos, destinationItemId, destinationAuthentication) {
960
+ return new Promise(resolve => {
961
+ let allResults = [];
962
+ // Remove zip from bottom of list
963
+ const zipInfoToSend = zipInfos.pop();
964
+ // Send predecessors in list
965
+ let sendOthersPromise = Promise.resolve([]);
966
+ if (zipInfos.length > 0) {
967
+ sendOthersPromise = _sendZipsSeriallyToItem(zipInfos, destinationItemId, destinationAuthentication);
968
+ }
969
+ void sendOthersPromise
970
+ .then((response) => {
971
+ allResults = response;
972
+ // Stall a little to give AGO time to catch up
973
+ return new Promise(resolveSleep => {
974
+ setTimeout(() => resolveSleep(), 1000);
975
+ });
976
+ })
977
+ .then(() => {
978
+ // Now send the zip removed from bottom of the input list
979
+ return copyZipIntoItem(zipInfoToSend, destinationItemId, destinationAuthentication);
980
+ })
981
+ .then((zipResult) => {
982
+ // Save the result of copying this zip as a status for each of the files that it contains
983
+ zipResult.filelist.forEach((fileInfo) => {
984
+ allResults.push(createCopyResults(fileInfo, true, zipResult.copiedToDestination));
985
+ });
986
+ resolve(allResults);
987
+ });
988
+ });
989
+ }
990
+
991
+ /** @license
992
+ * Copyright 2018 Esri
993
+ *
994
+ * Licensed under the Apache License, Version 2.0 (the "License");
995
+ * you may not use this file except in compliance with the License.
996
+ * You may obtain a copy of the License at
997
+ *
998
+ * http://www.apache.org/licenses/LICENSE-2.0
999
+ *
1000
+ * Unless required by applicable law or agreed to in writing, software
1001
+ * distributed under the License is distributed on an "AS IS" BASIS,
1002
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1003
+ * See the License for the specific language governing permissions and
1004
+ * limitations under the License.
1005
+ */
1006
+ /**
1007
+ * Copies the files for storing the resources, metadata, and thumbnail of an item or group to a storage item
1008
+ * with a specified path.
1009
+ *
1010
+ * @param files List of item files and paths for storing the files
1011
+ * @param storageItemId Id of item to receive copy of resource/metadata
1012
+ * @param storageAuthentication Credentials for the request to the storage
1013
+ * @returns A promise which resolves to a list of the filenames under which the resource/metadata are stored
1014
+ */
1015
+ function copyFilesToStorageItem(files, storageItemId, storageAuthentication) {
1016
+ return new Promise(resolve => {
1017
+ // tslint:disable-next-line: no-floating-promises
1018
+ void copyFilesAsResources(files, storageItemId, storageAuthentication).then((results) => {
1019
+ resolve(results
1020
+ // Filter out failures
1021
+ .filter((result) => result.fetchedFromSource && result.copiedToDestination)
1022
+ // Return folder and filename in storage item's resources
1023
+ .map((result) => result.folder + "/" + result.filename));
1024
+ });
1025
+ });
1026
+ }
1027
+ /**
1028
+ * Generates the URL for reading an item's resource given the filename of the resource.
1029
+ *
1030
+ * @param sourcePortalSharingUrl Server/sharing
1031
+ * @param itemId Id of item
1032
+ * @param sourceResourceFilename Either filename or folder/filename to resource
1033
+ * @returns URL string
1034
+ */
1035
+ function generateSourceResourceUrl(sourcePortalSharingUrl, itemId, sourceResourceFilename) {
1036
+ return (checkUrlPathTermination(sourcePortalSharingUrl) +
1037
+ "content/items/" +
1038
+ itemId +
1039
+ "/resources/" +
1040
+ sourceResourceFilename);
1041
+ }
1042
+ /**
1043
+ * Generates a list of full URLs and folder/filename combinations used to store the resources, metadata,
1044
+ * and thumbnail of an item.
1045
+ *
1046
+ * @param portalSharingUrl Server/sharing
1047
+ * @param storageItemId Id of storage item
1048
+ * @param resourceFilenames List of resource filenames for an item, e.g., ["file1", "myFolder/file2"]
1049
+ * @param storageVersion Version of the Solution template
1050
+ * @returns List of item files' URLs and folder/filenames for storing the files
1051
+ */
1052
+ function generateStorageFilePaths(portalSharingUrl, storageItemId, resourceFilenames = [], storageVersion = 0) {
1053
+ return resourceFilenames.map(resourceFilename => {
1054
+ return {
1055
+ url: generateSourceResourceUrl(portalSharingUrl, storageItemId, resourceFilename),
1056
+ ...convertStorageResourceToItemResource(resourceFilename, storageVersion)
1057
+ };
1058
+ });
1059
+ }
1060
+ function isSupportedFileType(filename) {
1061
+ // Supported file formats are: .json, .xml, .txt, .png, .pbf, .zip, .jpeg, .jpg, .gif, .bmp, .gz, .svg,
1062
+ // .svgz, .geodatabase (https://developers.arcgis.com/rest/users-groups-and-items/add-resources.htm)
1063
+ const filenameExtension = filename.match(/\.([a-z]+)$/i);
1064
+ const supportedExtensions = "|.json|.xml|.txt|.png|.pbf|.zip|.jpeg|.jpg|.gif|.bmp|.gz|.svg|.svgz|.geodatabase|";
1065
+ return (!!filenameExtension &&
1066
+ supportedExtensions.indexOf("|" + filenameExtension[0] + "|") >= 0);
1067
+ }
1068
+ /**
1069
+ * Gets the thumbnail of an item or group.
1070
+ *
1071
+ * @param authentication Credentials for the request to the storage
1072
+ * @param filePaths List of item files' URLs and folder/filenames for storing the files
1073
+ * @returns A promise which resolves to a boolean indicating if the copies were successful
1074
+ */
1075
+ function getThumbnailFromStorageItem(authentication, filePaths) {
1076
+ let thumbnailUrl;
1077
+ let thumbnailFilename;
1078
+ filePaths.forEach(path => {
1079
+ if (path.type === EFileType.Thumbnail) {
1080
+ thumbnailUrl = path.url;
1081
+ thumbnailFilename = path.filename;
1082
+ }
1083
+ });
1084
+ if (!thumbnailUrl) {
1085
+ return Promise.resolve(null);
1086
+ }
1087
+ return getThumbnailFile(thumbnailUrl, thumbnailFilename, authentication);
1088
+ }
1089
+ /**
1090
+ * Removes the item's resource that matches the filename with new content
1091
+ *
1092
+ * @param itemId Id of the item to remove
1093
+ * @param filename Name of the resource file to remove
1094
+ * @param authentication Credentials for the request to the storage
1095
+ * @returns A promise which resolves with a success true/false response
1096
+ */
1097
+ function removeItemResourceFile(itemId, filename, authentication) {
1098
+ return removeItemResource({
1099
+ id: itemId,
1100
+ resource: filename,
1101
+ authentication: authentication
1102
+ });
1103
+ }
1104
+ /**
1105
+ * Updates the item's resource that matches the filename with new content
1106
+ *
1107
+ * @param itemId Id of the item to update
1108
+ * @param filename Name of the resource file to update; prefix optional (e.g., a/b/file.txt)
1109
+ * @param resource The new content to update the resource with
1110
+ * @param authentication Credentials for the request to the storage
1111
+ * @returns A promise which resolves with a success true/false response
1112
+ */
1113
+ function updateItemResourceFile(itemId, filename, resource, authentication) {
1114
+ // Prefix has to be specified separately
1115
+ const prefixedFilenameParts = filename.split("/");
1116
+ const prefix = prefixedFilenameParts.length > 1 ? prefixedFilenameParts.slice(0, prefixedFilenameParts.length - 1).join("/") : undefined;
1117
+ const suffix = prefixedFilenameParts[prefixedFilenameParts.length - 1];
1118
+ return updateItemResource({
1119
+ id: itemId,
1120
+ prefix: prefix,
1121
+ name: suffix,
1122
+ resource,
1123
+ authentication: authentication
1124
+ });
1125
+ }
1126
+
1127
+ /** @license
1128
+ * Copyright 2022 Esri
1129
+ *
1130
+ * Licensed under the Apache License, Version 2.0 (the "License");
1131
+ * you may not use this file except in compliance with the License.
1132
+ * You may obtain a copy of the License at
1133
+ *
1134
+ * http://www.apache.org/licenses/LICENSE-2.0
1135
+ *
1136
+ * Unless required by applicable law or agreed to in writing, software
1137
+ * distributed under the License is distributed on an "AS IS" BASIS,
1138
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1139
+ * See the License for the specific language governing permissions and
1140
+ * limitations under the License.
1141
+ */
1142
+ const EmptySolutionStore = {
1143
+ solutionItemId: "",
1144
+ defaultWkid: undefined,
1145
+ solutionData: { metadata: {}, templates: [] },
1146
+ templateEdits: {},
1147
+ featureServices: [],
1148
+ spatialReferenceInfo: {
1149
+ enabled: false,
1150
+ services: {},
1151
+ spatialReference: undefined
1152
+ }
1153
+ };
1154
+ class SolutionStore {
1155
+ /**
1156
+ * Creates singleton instance when accessed; default export from module.
1157
+ *
1158
+ * @returns Static instance of the class
1159
+ */
1160
+ static get Store() {
1161
+ return this._instance || (this._instance = new this());
1162
+ }
1163
+ /**
1164
+ * Creates an empty store.
1165
+ *
1166
+ * @protected
1167
+ */
1168
+ constructor() {
1169
+ this._hasChanges = false;
1170
+ this._store = createStore(Object.assign({}, EmptySolutionStore));
1171
+ }
1172
+ /**
1173
+ * Returns the stored information of an item.
1174
+ *
1175
+ * @param itemId Id of item to fetch
1176
+ *
1177
+ * @returns Item information or `undefined` if not found
1178
+ */
1179
+ getItemInfo(itemId) {
1180
+ const templates = this._store.get("solutionData").templates;
1181
+ let template;
1182
+ templates.some((t) => {
1183
+ if (itemId == t.itemId) {
1184
+ template = t;
1185
+ return true;
1186
+ }
1187
+ return false;
1188
+ });
1189
+ return template;
1190
+ }
1191
+ /**
1192
+ * Returns a top-level store property: solutionItemId, defaultWkid, etc.
1193
+ *
1194
+ * @param propName Name of property
1195
+ *
1196
+ * @returns Value of property
1197
+ */
1198
+ getStoreInfo(propName) {
1199
+ return this._store.get(propName);
1200
+ }
1201
+ /**
1202
+ * Loads a Solution into the store from AGO.
1203
+ *
1204
+ * @param solutionItemId Id of the solution represented in the store
1205
+ * @param authentication Credentials for fetching information to be loaded into the store
1206
+ *
1207
+ * @returns Promise that resolves when task is done
1208
+ */
1209
+ async loadSolution(solutionItemId, authentication) {
1210
+ this._authentication = authentication;
1211
+ const solutionData = await getItemDataAsJson(solutionItemId, authentication);
1212
+ if (solutionData) {
1213
+ const defaultWkid = getProp(solutionData, "params.wkid.default");
1214
+ await this._prepareSolutionItemsForEditing(solutionItemId, solutionData.templates, authentication);
1215
+ const featureServices = this._getFeatureServices(solutionData.templates);
1216
+ const spatialReferenceInfo = this._getSpatialReferenceInfo(featureServices, defaultWkid);
1217
+ this._store.set("solutionItemId", solutionItemId);
1218
+ this._store.set("defaultWkid", defaultWkid);
1219
+ this._store.set("solutionData", solutionData);
1220
+ this._store.set("featureServices", featureServices);
1221
+ this._store.set("spatialReferenceInfo", spatialReferenceInfo);
1222
+ }
1223
+ this._flagStoreHasChanges(false);
1224
+ }
1225
+ /**
1226
+ * Queues the replacement of the thumbnail associated with a template item in the store.
1227
+ *
1228
+ * @param itemEdit Details of the template to modify, containing the new thumbnail in the `thumbnail`
1229
+ * property
1230
+ */
1231
+ replaceItemThumbnail(itemEdit) {
1232
+ // Flag the current thumbnail and any replacements for removal
1233
+ itemEdit.resourceFilePaths.forEach((path) => {
1234
+ if (path.type === EFileType.Thumbnail) {
1235
+ if (path.updateType === EUpdateType.None) {
1236
+ // Existing thumbnail not yet flagged for removal
1237
+ path.updateType = EUpdateType.Remove;
1238
+ }
1239
+ else if (path.updateType === EUpdateType.Add || path.updateType === EUpdateType.Update) {
1240
+ // An earlier replacement
1241
+ path.updateType = EUpdateType.Obsolete;
1242
+ }
1243
+ }
1244
+ });
1245
+ // Remove any replacements already queued
1246
+ itemEdit.resourceFilePaths =
1247
+ itemEdit.resourceFilePaths.filter((path) => path.updateType != EUpdateType.Obsolete);
1248
+ // Add the new thumbnail to the store item
1249
+ itemEdit.resourceFilePaths.push({
1250
+ blob: itemEdit.thumbnail,
1251
+ filename: itemEdit.thumbnail.name,
1252
+ type: EFileType.Thumbnail,
1253
+ updateType: EUpdateType.Add
1254
+ });
1255
+ // Update the store
1256
+ this.setItemInfo(itemEdit);
1257
+ }
1258
+ /**
1259
+ * Writes a Solution into AGO from the store. Must use `loadSolution` to continue with solution.
1260
+ *
1261
+ * @returns Promise that resolves when task is done
1262
+ */
1263
+ async saveSolution() {
1264
+ // Update the templates in the original solution item data
1265
+ const solutionItemId = this._store.get("solutionItemId");
1266
+ const solutionData = this._store.get("solutionData");
1267
+ const spatialReferenceInfo = this._store.get("spatialReferenceInfo");
1268
+ await this._prepareSolutionItemsForStorage(solutionItemId, solutionData.templates, this._authentication);
1269
+ const updatedDefaultWkid = this._setSpatialReferenceInfo(spatialReferenceInfo, solutionData.templates);
1270
+ if (updatedDefaultWkid) {
1271
+ setCreateProp(solutionData, "params.wkid", {
1272
+ "label": "Spatial Reference",
1273
+ "default": updatedDefaultWkid,
1274
+ "valueType": "spatialReference",
1275
+ "attributes": {
1276
+ "required": "true"
1277
+ }
1278
+ });
1279
+ }
1280
+ else {
1281
+ setCreateProp(solutionData, "params.wkid", {});
1282
+ }
1283
+ const itemInfo = {
1284
+ id: solutionItemId,
1285
+ text: solutionData
1286
+ };
1287
+ await updateItem(itemInfo, this._authentication);
1288
+ }
1289
+ /**
1290
+ * Stores information for item.
1291
+ *
1292
+ * @param itemEdit Item information
1293
+ */
1294
+ setItemInfo(itemEdit) {
1295
+ const solutionData = this._store.get("solutionData");
1296
+ const templates = solutionData.templates;
1297
+ templates.some((t) => {
1298
+ if (itemEdit.itemId == t.itemId) {
1299
+ t = itemEdit;
1300
+ this._store.set("solutionData", solutionData);
1301
+ this._flagStoreHasChanges(true);
1302
+ return true;
1303
+ }
1304
+ return false;
1305
+ });
1306
+ }
1307
+ /**
1308
+ * Sets a top-level store property: solutionItemId, defaultWkid, etc.
1309
+ *
1310
+ * @param propName Name of property
1311
+ * @param value Value of property
1312
+ */
1313
+ setStoreInfo(propName, value) {
1314
+ this._store.set(propName, value);
1315
+ this._flagStoreHasChanges(true);
1316
+ }
1317
+ //------------------------------------------------------------------------------------------------------------------//
1318
+ /** Provides access to protected methods for unit testing.
1319
+ *
1320
+ * @param methodName Name of protected method to run
1321
+ * @param arg1 First argument to forward to method, e.g., for "_prepareSolutionItemsForEditing", `solutionItemId`
1322
+ * @param arg2 Second argument to forward to method, e.g., for "_prepareSolutionItemsForEditing", `templates`
1323
+ * @param arg3 Third argument to forward to method, e.g., for "_prepareSolutionItemsForEditing", `authentication`
1324
+ *
1325
+ * @returns
1326
+ */
1327
+ _testAccess(methodName, arg1, arg2, arg3) {
1328
+ switch (methodName) {
1329
+ case "_emptyTheStore":
1330
+ this._emptyTheStore();
1331
+ break;
1332
+ case "_getFeatureServices":
1333
+ return this._getFeatureServices(arg1);
1334
+ case "_getItemsSharedWithThisGroup":
1335
+ return this._getItemsSharedWithThisGroup(arg1, arg2);
1336
+ case "_getResourceFilePaths":
1337
+ return this._getResourceFilePaths(arg1, arg2, arg3);
1338
+ case "_getResourceStorageName":
1339
+ return this._getResourceStorageName(arg1, arg2);
1340
+ case "_getSpatialReferenceInfo":
1341
+ return this._getSpatialReferenceInfo(arg1, arg2);
1342
+ case "_prepareSolutionItemsForEditing":
1343
+ return this._prepareSolutionItemsForEditing(arg1, arg2, arg3);
1344
+ case "_prepareSolutionItemsForStorage":
1345
+ return this._prepareSolutionItemsForStorage(arg1, arg2, arg3);
1346
+ case "_setSpatialReferenceInfo":
1347
+ return this._setSpatialReferenceInfo(arg1, arg2);
1348
+ case "_splitFilename":
1349
+ return this._splitFilename(arg1);
1350
+ }
1351
+ return null;
1352
+ }
1353
+ /**
1354
+ * Returns the store to the empty state.
1355
+ *
1356
+ * @protected
1357
+ */
1358
+ _emptyTheStore() {
1359
+ this._store.set("solutionItemId", EmptySolutionStore.solutionItemId);
1360
+ this._store.set("defaultWkid", EmptySolutionStore.defaultWkid);
1361
+ this._store.set("solutionData", EmptySolutionStore.solutionData);
1362
+ this._store.set("templateEdits", EmptySolutionStore.templateEdits);
1363
+ this._store.set("featureServices", EmptySolutionStore.featureServices);
1364
+ this._store.set("spatialReferenceInfo", EmptySolutionStore.spatialReferenceInfo);
1365
+ }
1366
+ /**
1367
+ * Sets the store's flag indicating if it has changes and dispatches an event when
1368
+ * the flag value changes.
1369
+ *
1370
+ * @param flagHasChanges Current state of change in the store; if it doesn't match the value saved in this
1371
+ * object, an event is dispatched with the new value and the saved value is updated
1372
+ *
1373
+ * @protected
1374
+ */
1375
+ _flagStoreHasChanges(flagHasChanges) {
1376
+ // Event for notifying if the store has changes or not
1377
+ if (this._hasChanges !== flagHasChanges) {
1378
+ window.dispatchEvent(new CustomEvent("solutionStoreHasChanges", {
1379
+ detail: flagHasChanges,
1380
+ bubbles: true,
1381
+ cancelable: false,
1382
+ composed: true
1383
+ }));
1384
+ }
1385
+ this._hasChanges = flagHasChanges;
1386
+ }
1387
+ /**
1388
+ * Gets a list of Feature Services that are not views.
1389
+ *
1390
+ * @param templates A list of item templates from the solution
1391
+ *
1392
+ * @returns a list of feature services
1393
+ *
1394
+ * @protected
1395
+ */
1396
+ _getCustomizableFeatureServices(templates) {
1397
+ return templates.reduce((prev, cur) => {
1398
+ if (cur.type === "Feature Service" && cur.item.typeKeywords.indexOf("View Service") < 0) {
1399
+ prev.push(cur);
1400
+ }
1401
+ return prev;
1402
+ }, []);
1403
+ }
1404
+ /**
1405
+ * Gets a list of Feature Services that are not views along with an enabled property that indicates
1406
+ * if the service currently uses a spatial reference variable.
1407
+ *
1408
+ * @param templates A list of item templates from the solution
1409
+ *
1410
+ * @returns a list of feature service names and an enabled property to indicate
1411
+ * if they currently use a spatial reference variable.
1412
+ *
1413
+ * @protected
1414
+ */
1415
+ _getFeatureServices(templates) {
1416
+ const customizeableFeatureServices = this._getCustomizableFeatureServices(templates);
1417
+ return customizeableFeatureServices.map((fs) => {
1418
+ const name = fs.item.title || fs.item.name;
1419
+ const wkid = getProp(fs, "properties.service.spatialReference.wkid");
1420
+ return { name, enabled: wkid.toString().startsWith("{{params.wkid||") };
1421
+ });
1422
+ }
1423
+ /**
1424
+ * Capture the key item details for a given group template
1425
+ *
1426
+ * @param template one of the templates from the current solution
1427
+ * @param templates full list of templates
1428
+ *
1429
+ * @returns a list of IItemShare objects
1430
+ *
1431
+ * @protected
1432
+ */
1433
+ _getItemsSharedWithThisGroup(template, templates) {
1434
+ return templates.reduce((prev, cur) => {
1435
+ if (cur.itemId !== template.itemId && cur.type !== "Group") {
1436
+ prev.push({
1437
+ id: cur.itemId,
1438
+ title: cur.item.name || cur.item.title,
1439
+ isShared: (cur.groups || []).indexOf(template.itemId) > -1,
1440
+ shareItem: (cur.groups || []).indexOf(template.itemId) > -1,
1441
+ type: cur.type,
1442
+ typeKeywords: cur.item.typeKeywords
1443
+ });
1444
+ }
1445
+ return prev;
1446
+ }, []);
1447
+ }
1448
+ /**
1449
+ * Generate storage file paths from the solution template
1450
+ *
1451
+ * @param solutionId the id of the current solution
1452
+ * @param template the current template from the solution
1453
+ * @param portal Portal where file is to be found
1454
+ *
1455
+ * @returns a list of resource file infos
1456
+ *
1457
+ * @protected
1458
+ */
1459
+ _getResourceFilePaths(solutionId, template, portal) {
1460
+ const resourceFilePaths = generateStorageFilePaths(portal, solutionId, template.resources, SolutionTemplateFormatVersion);
1461
+ return resourceFilePaths.map((fp) => {
1462
+ fp.updateType = EUpdateType.None;
1463
+ return fp;
1464
+ });
1465
+ }
1466
+ /**
1467
+ * Generates a resource name from a storage file path.
1468
+ *
1469
+ * @param templateItemId The id of the template item whose resource this is; used as a prefix in the resource name
1470
+ * @param resourcePath Resource file infos
1471
+ *
1472
+ * @returns The resource name to use when attaching a resource to the item.
1473
+ *
1474
+ * @protected
1475
+ */
1476
+ _getResourceStorageName(templateItemId, resourcePath) {
1477
+ /* Converts
1478
+ {
1479
+ "url": "https://myorg.maps.arcgis.com/sharing/rest/content/items/ca924c6db7d247b9a31fa30532fb5913/resources/79036430a6274e17ae915d0278b8569c_info_metadata/metadata.xml",
1480
+ "type": 2,
1481
+ "folder": "",
1482
+ "filename": "metadata.xml",
1483
+ "updateType": 3
1484
+ }
1485
+ to
1486
+ ca924c6db7d247b9a31fa30532fb5913_info_metadata/metadata.xml
1487
+ */
1488
+ let prefix = templateItemId;
1489
+ switch (resourcePath.type) {
1490
+ case EFileType.Data:
1491
+ prefix = `${prefix}_info_data`;
1492
+ break;
1493
+ case EFileType.Info:
1494
+ prefix = `${prefix}_info`;
1495
+ break;
1496
+ case EFileType.Metadata:
1497
+ prefix = `${prefix}_info_metadata`;
1498
+ break;
1499
+ case EFileType.Resource:
1500
+ break;
1501
+ case EFileType.Thumbnail:
1502
+ prefix = `${prefix}_info_thumbnail`;
1503
+ break;
1504
+ }
1505
+ let filenameToUse = resourcePath.filename;
1506
+ if (resourcePath.type == EFileType.Data && filenameToUse && !isSupportedFileType(filenameToUse)) {
1507
+ filenameToUse = filenameToUse + ".zip";
1508
+ prefix += "z";
1509
+ }
1510
+ const filename = resourcePath.folder ? resourcePath.folder + "/" + filenameToUse : filenameToUse;
1511
+ return prefix + "/" + filename;
1512
+ }
1513
+ /**
1514
+ * Extracts basic spatial reference information that is used to determine if a custom spatial reference parameter will
1515
+ * be exposed while deploying this solution and if so what feature services will support it and what will the default wkid be
1516
+ *
1517
+ * @param services a list of objects with service name and enabled property (indicates if they currently use a spatial reference var)
1518
+ * @param data the data object of a solution item
1519
+ *
1520
+ * @returns an object that stores if a custom spatial reference parameter is enabled/disabled,
1521
+ * a list of services and if they are enabled/disabled, and the default wkid
1522
+ *
1523
+ * @protected
1524
+ */
1525
+ _getSpatialReferenceInfo(services, defaultWkid) {
1526
+ const defaultServices = {};
1527
+ services.forEach(service => {
1528
+ defaultServices[service.name] = service.enabled;
1529
+ });
1530
+ return {
1531
+ enabled: defaultWkid !== undefined,
1532
+ services: defaultServices,
1533
+ spatialReference: defaultWkid ? defaultWkid : undefined
1534
+ };
1535
+ }
1536
+ /**
1537
+ * Create and store template items for the editor.
1538
+ *
1539
+ * @param solutionItemId Id of the solution represented in the store
1540
+ * @param templates A list of item templates from the solution
1541
+ * @param authentication Credentials for fetching information to be loaded into the store
1542
+ *
1543
+ * @returns a promise that resolves when the templates are ready
1544
+ *
1545
+ * @protected
1546
+ */
1547
+ async _prepareSolutionItemsForEditing(solutionItemId, templates, authentication) {
1548
+ const thumbnailPromises = [];
1549
+ // Augment the template with paths to resources and group information, if relevant
1550
+ templates.forEach((t) => {
1551
+ t.resourceFilePaths = this._getResourceFilePaths(solutionItemId, t, authentication.portal);
1552
+ thumbnailPromises.push(t.resourceFilePaths.length > 0 ?
1553
+ getThumbnailFromStorageItem(authentication, t.resourceFilePaths) :
1554
+ Promise.resolve());
1555
+ t.groupDetails = t.type === "Group" ? this._getItemsSharedWithThisGroup(t, templates) : [];
1556
+ });
1557
+ // Augment the template with its thumbnail file
1558
+ const thumbnails = await Promise.all(thumbnailPromises);
1559
+ templates.forEach((t, i) => {
1560
+ t.thumbnail = thumbnails[i] ? thumbnails[i] : undefined;
1561
+ });
1562
+ return Promise.resolve();
1563
+ }
1564
+ /**
1565
+ * Prepares template items for sending to AGO by updating the resources held by the solution item.
1566
+ *
1567
+ * @param solutionItemId Id of the solution represented in the store
1568
+ * @param templates A list of item templates from the solution
1569
+ * @param authentication Credentials for fetching information to be loaded into the store
1570
+ *
1571
+ * @returns a promise that resolves when the templates are ready
1572
+ *
1573
+ * @protected
1574
+ */
1575
+ async _prepareSolutionItemsForStorage(solutionItemId, templates, authentication) {
1576
+ const resourceAdds = [];
1577
+ // Update the resources and remove the augmentation from a template
1578
+ const pendingTasks = [];
1579
+ templates.forEach((t) => {
1580
+ // Run through the resourceFilePaths for the item seeking modifications to be made to the solution item's
1581
+ // collection of resources; queue them for batching
1582
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
1583
+ t.resourceFilePaths.forEach(async (path) => {
1584
+ const storageName = this._getResourceStorageName(t.itemId, path);
1585
+ switch (path.updateType) {
1586
+ case EUpdateType.Add:
1587
+ const { prefix, suffix } = this._splitFilename(storageName);
1588
+ t.resources.push(storageName);
1589
+ resourceAdds.push({
1590
+ itemId: t.itemId,
1591
+ file: path.blob,
1592
+ folder: prefix,
1593
+ filename: suffix
1594
+ });
1595
+ break;
1596
+ case EUpdateType.Update:
1597
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
1598
+ pendingTasks.push(new Promise(async (resolve) => {
1599
+ try {
1600
+ await updateItemResourceFile(solutionItemId, storageName, path.blob, authentication);
1601
+ }
1602
+ catch (err) {
1603
+ console.log("Unable to update " + storageName + " for item " + t.itemId + ": " + JSON.stringify(err));
1604
+ }
1605
+ resolve();
1606
+ }));
1607
+ break;
1608
+ case EUpdateType.Remove:
1609
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
1610
+ pendingTasks.push(new Promise(async (resolve) => {
1611
+ try {
1612
+ await removeItemResourceFile(solutionItemId, storageName, authentication);
1613
+ t.resources = t.resources.filter((path) => path !== storageName);
1614
+ }
1615
+ catch (err) {
1616
+ console.log("Unable to remove " + storageName + " for item " + t.itemId + ": " + JSON.stringify(err));
1617
+ }
1618
+ resolve();
1619
+ }));
1620
+ break;
1621
+ }
1622
+ return Promise.resolve();
1623
+ });
1624
+ delete t.resourceFilePaths;
1625
+ delete t.thumbnail;
1626
+ delete t.groupDetails;
1627
+ });
1628
+ // Update the resources
1629
+ return Promise.all(pendingTasks)
1630
+ .then(async () => {
1631
+ if (resourceAdds.length > 0) {
1632
+ await copyFilesToStorageItem(resourceAdds, solutionItemId, authentication);
1633
+ }
1634
+ return Promise.resolve();
1635
+ });
1636
+ }
1637
+ /**
1638
+ * Stores basic spatial reference information that is used to determine if a custom spatial reference parameter will
1639
+ * be exposed while deploying this solution and if so what feature services will support it and what will the default wkid be
1640
+ *
1641
+ * @param spatialReferenceInfo The configuration settings for a custom spatial reference
1642
+ * @param templates The templates in the current solution, which will be updated in place if
1643
+ * `spatialReferenceInfo.enabled` is true
1644
+ *
1645
+ * @returns The new default wkid
1646
+ *
1647
+ * @protected
1648
+ */
1649
+ _setSpatialReferenceInfo(spatialReferenceInfo, templates) {
1650
+ const customizingPrefix = "{{params.wkid||";
1651
+ const customizeableFeatureServices = this._getCustomizableFeatureServices(templates);
1652
+ if (spatialReferenceInfo.enabled) {
1653
+ // Enable or disable this feature in each service
1654
+ customizeableFeatureServices.forEach((fs) => {
1655
+ const name = fs.item.title || fs.item.name;
1656
+ let wkid;
1657
+ if (spatialReferenceInfo.services[name]) { // enabled
1658
+ wkid = `{{params.wkid||${spatialReferenceInfo.spatialReference}}}`;
1659
+ setCreateProp(fs, "properties.service.spatialReference.wkid", wkid);
1660
+ }
1661
+ else { // disabled
1662
+ wkid = getProp(fs, "properties.service.spatialReference.wkid");
1663
+ // Remove customizing prefix if present
1664
+ if (wkid.toString().startsWith(customizingPrefix)) {
1665
+ wkid = wkid.toString().substring(customizingPrefix.length, wkid.length - 2);
1666
+ setCreateProp(fs, "properties.service.spatialReference.wkid", wkid);
1667
+ }
1668
+ }
1669
+ });
1670
+ return spatialReferenceInfo.spatialReference;
1671
+ }
1672
+ else {
1673
+ // Disable this feature in each service
1674
+ customizeableFeatureServices.forEach((fs) => {
1675
+ const wkid = getProp(fs, "properties.service.spatialReference.wkid");
1676
+ // Remove customizing prefix if present
1677
+ if (wkid.toString().startsWith(customizingPrefix)) {
1678
+ setCreateProp(fs, "properties.service.spatialReference.wkid", wkid.toString().substring(customizingPrefix.length, wkid.length - 2));
1679
+ }
1680
+ });
1681
+ return undefined;
1682
+ }
1683
+ }
1684
+ /**
1685
+ * Splits a pathed filename into a last term and a prefix; e.g., "a/b/c" returns "c" with a prefix of "a/b".
1686
+ *
1687
+ * @param filename Filename with optional path
1688
+ *
1689
+ * @returns An object consisting of a `prefix` (undefined if `filename` does not contain a path) and a `suffix`--the
1690
+ * filename at the end of a path
1691
+ *
1692
+ * @protected
1693
+ */
1694
+ _splitFilename(filename) {
1695
+ const filenameParts = filename.split("/");
1696
+ return {
1697
+ prefix: filenameParts.length > 1 ? filenameParts.slice(0, filenameParts.length - 1).join("/") : undefined,
1698
+ suffix: filenameParts[filenameParts.length - 1]
1699
+ };
1700
+ }
1701
+ }
1702
+ const state = SolutionStore.Store;
1703
+
1704
+ export { getProp as g, state as s };