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