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