@esri/solutions-components 0.7.30 → 0.7.31

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 (60) hide show
  1. package/dist/assets/t9n/crowdsource-reporter/resources.json +7 -5
  2. package/dist/assets/t9n/crowdsource-reporter/resources_en.json +7 -5
  3. package/dist/assets/t9n/feature-list/resources.json +1 -1
  4. package/dist/assets/t9n/feature-list/resources_en.json +1 -1
  5. package/dist/assets/t9n/layer-list/resources.json +1 -1
  6. package/dist/assets/t9n/layer-list/resources_en.json +1 -1
  7. package/dist/cjs/{calcite-flow_4.cjs.entry.js → calcite-flow_5.cjs.entry.js} +235 -19
  8. package/dist/cjs/card-manager_3.cjs.entry.js +1 -1
  9. package/dist/cjs/crowdsource-reporter.cjs.entry.js +221 -32
  10. package/dist/cjs/{downloadUtils-83c6d3c3.js → downloadUtils-10e0de31.js} +2 -2
  11. package/dist/cjs/{index.es-bd1a93b2.js → index.es-72dc7ab9.js} +1 -1
  12. package/dist/cjs/loader.cjs.js +1 -1
  13. package/dist/cjs/map-select-tools_3.cjs.entry.js +1 -1
  14. package/dist/cjs/public-notification.cjs.entry.js +1 -1
  15. package/dist/cjs/solutions-components.cjs.js +1 -1
  16. package/dist/collection/collection-manifest.json +1 -0
  17. package/dist/collection/components/create-feature/create-feature.css +23 -0
  18. package/dist/collection/components/create-feature/create-feature.js +361 -0
  19. package/dist/collection/components/crowdsource-reporter/crowdsource-reporter.css +10 -1
  20. package/dist/collection/components/crowdsource-reporter/crowdsource-reporter.js +260 -33
  21. package/dist/collection/components/feature-list/feature-list.js +1 -0
  22. package/dist/collection/components/layer-list/layer-list.js +60 -16
  23. package/dist/collection/demos/crowdsource-reporter.html +26 -11
  24. package/dist/collection/utils/downloadUtils.js +1 -1
  25. package/dist/collection/utils/downloadUtils.ts +1 -1
  26. package/dist/components/create-feature.d.ts +11 -0
  27. package/dist/components/create-feature.js +11 -0
  28. package/dist/components/create-feature2.js +226 -0
  29. package/dist/components/crowdsource-reporter.js +297 -90
  30. package/dist/components/downloadUtils.js +1 -1
  31. package/dist/components/feature-list2.js +1 -0
  32. package/dist/components/layer-list2.js +38 -17
  33. package/dist/esm/{calcite-flow_4.entry.js → calcite-flow_5.entry.js} +235 -20
  34. package/dist/esm/card-manager_3.entry.js +1 -1
  35. package/dist/esm/crowdsource-reporter.entry.js +222 -33
  36. package/dist/esm/{downloadUtils-d070a467.js → downloadUtils-d297078f.js} +2 -2
  37. package/dist/esm/{index.es-d48535a2.js → index.es-3b4fa9d0.js} +1 -1
  38. package/dist/esm/loader.js +1 -1
  39. package/dist/esm/map-select-tools_3.entry.js +1 -1
  40. package/dist/esm/public-notification.entry.js +1 -1
  41. package/dist/esm/solutions-components.js +1 -1
  42. package/dist/solutions-components/demos/crowdsource-reporter.html +26 -11
  43. package/dist/solutions-components/{p-f120ff40.entry.js → p-09ec8c8f.entry.js} +1 -1
  44. package/dist/solutions-components/{p-55b835a1.js → p-103c5318.js} +2 -2
  45. package/dist/solutions-components/{p-309cdea1.entry.js → p-57d49d15.entry.js} +1 -1
  46. package/dist/solutions-components/{p-b913a4fd.js → p-8ec25bf4.js} +1 -1
  47. package/dist/solutions-components/{p-f22ff57e.entry.js → p-921f21d5.entry.js} +1 -1
  48. package/dist/solutions-components/p-b4e2cac4.entry.js +17 -0
  49. package/dist/solutions-components/p-bb6562ab.entry.js +6 -0
  50. package/dist/solutions-components/solutions-components.esm.js +1 -1
  51. package/dist/solutions-components/utils/downloadUtils.ts +1 -1
  52. package/dist/types/components/create-feature/create-feature.d.ts +107 -0
  53. package/dist/types/components/crowdsource-reporter/crowdsource-reporter.d.ts +132 -12
  54. package/dist/types/components/feature-list/feature-list.d.ts +1 -0
  55. package/dist/types/components/layer-list/layer-list.d.ts +6 -0
  56. package/dist/types/components.d.ts +89 -0
  57. package/dist/types/preact.d.ts +6 -0
  58. package/package.json +1 -1
  59. package/dist/solutions-components/p-2f162664.entry.js +0 -6
  60. package/dist/solutions-components/p-94ee3ef7.entry.js +0 -17
@@ -21,7 +21,8 @@
21
21
  import { Host, h } from "@stencil/core";
22
22
  import { getLocaleComponentStrings } from "../../utils/locale";
23
23
  import { loadModules } from "../../utils/loadModules";
24
- import { getAllLayers } from "../../utils/mapViewUtils";
24
+ import { getAllLayers, getLayerOrTable } from "../../utils/mapViewUtils";
25
+ import { queryFeaturesByID } from "../../utils/queryUtils";
25
26
  export class CrowdsourceReporter {
26
27
  constructor() {
27
28
  this.description = undefined;
@@ -34,6 +35,8 @@ export class CrowdsourceReporter {
34
35
  this.layers = undefined;
35
36
  this.loginTitle = undefined;
36
37
  this.mapView = undefined;
38
+ this.layerId = undefined;
39
+ this.objectId = undefined;
37
40
  this.reportButtonText = undefined;
38
41
  this.reportsHeader = undefined;
39
42
  this.reportSubmittedMessage = undefined;
@@ -51,6 +54,9 @@ export class CrowdsourceReporter {
51
54
  this._translations = undefined;
52
55
  this._hasValidLayers = false;
53
56
  this._selectedLayerName = undefined;
57
+ this._reportSubmitted = false;
58
+ this._showSubmitCancelButton = false;
59
+ this._featureCreationFailedErrorMsg = undefined;
54
60
  }
55
61
  //--------------------------------------------------------------------------
56
62
  //
@@ -89,7 +95,8 @@ export class CrowdsourceReporter {
89
95
  * Renders the component.
90
96
  */
91
97
  render() {
92
- return (h(Host, null, h("div", null, h("calcite-shell", { "content-behind": true }, this._getReporter()))));
98
+ const themeClass = this.theme === "dark" ? "calcite-mode-dark" : "calcite-mode-light";
99
+ return (h(Host, null, this._reportSubmitted && h("calcite-alert", { "auto-close": true, class: themeClass, closable: true, icon: "check-circle", kind: "success", onCalciteAlertClose: () => { this._reportSubmitted = false; }, open: true, placement: "top" }, h("div", { slot: "title" }, this._translations.reportSubmit), h("div", { slot: "message" }, this._translations.submitMsg)), this._featureCreationFailedErrorMsg && h("calcite-alert", { "auto-close": true, class: themeClass, closable: true, icon: "x-octagon", kind: "danger", onCalciteAlertClose: () => { this._featureCreationFailedErrorMsg = ""; }, open: true, placement: "top" }, h("div", { slot: "title" }, this._translations.error), h("div", { slot: "message" }, this._featureCreationFailedErrorMsg)), h("div", null, h("calcite-shell", { "content-behind": true }, this._getReporter()))));
93
100
  }
94
101
  //--------------------------------------------------------------------------
95
102
  //
@@ -109,6 +116,15 @@ export class CrowdsourceReporter {
109
116
  ]);
110
117
  this.reactiveUtils = reactiveUtils;
111
118
  }
119
+ /**
120
+ * Set the selected layer id and layer name
121
+ * @param layerId string layerId of the selected layer
122
+ * @param layerName string layerName of the selected layer
123
+ */
124
+ setSelectedLayer(layerId, layerName) {
125
+ this._selectedLayerId = layerId;
126
+ this._selectedLayerName = layerName;
127
+ }
112
128
  /**
113
129
  * Get the reporter app functionality
114
130
  * @protected
@@ -126,6 +142,12 @@ export class CrowdsourceReporter {
126
142
  case "feature-details":
127
143
  renderLists.push(this.getFeatureDetailsFlowItem());
128
144
  break;
145
+ case "reporting-layer-list":
146
+ renderLists.push(this.getChooseCategoryFlowItem());
147
+ break;
148
+ case "feature-create":
149
+ renderLists.push(this.getFeatureCreateFlowItem());
150
+ break;
129
151
  }
130
152
  });
131
153
  const themeClass = this.theme === "dark" ? "calcite-mode-dark" : "calcite-mode-light";
@@ -142,34 +164,135 @@ export class CrowdsourceReporter {
142
164
  return (h("calcite-flow-item", { collapsed: this.isMobile && this._sidePanelCollapsed, heading: this.reportsHeader }, this._hasValidLayers &&
143
165
  h("calcite-action", { icon: "sort-ascending-arrow", slot: this.isMobile ? "header-menu-actions" : "header-actions-end", text: this._translations.sort, "text-enabled": this.isMobile }), this._hasValidLayers &&
144
166
  h("calcite-action", { icon: "filter", slot: this.isMobile ? "header-menu-actions" : "header-actions-end", text: this._translations.filter, "text-enabled": this.isMobile }), this.isMobile && this.getActionToExpandCollapsePanel(), this._hasValidLayers && this.enableNewReports &&
145
- h("calcite-button", { appearance: "secondary", slot: "footer", width: "full" }, this.reportButtonText), h("calcite-panel", { "full-height": true, "full-width": true }, h("layer-list", { class: "height-full", layers: this.layers, mapView: this.mapView, noLayerErrorMsg: this._translations.noLayerToDisplayErrorMsg, onLayerSelect: this.displayFeaturesList.bind(this), onLayersListLoaded: this.layerListLoaded.bind(this), showFeatureCount: true, showNextIcon: true }))));
167
+ h("calcite-button", { appearance: "secondary", onClick: this.navigateToChooseCategory.bind(this), slot: "footer", width: "full" }, this.reportButtonText), h("calcite-panel", { "full-height": true, "full-width": true }, h("layer-list", { class: "height-full", layers: this.layers, mapView: this.mapView, noLayerErrorMsg: this._translations.noLayerToDisplayErrorMsg, onLayerSelect: this.displayFeaturesList.bind(this), onLayersListLoaded: this.layerListLoaded.bind(this), ref: el => this._layerList = el, showFeatureCount: true, showNextIcon: true }))));
168
+ }
169
+ /**
170
+ * Get the layer list for creating a report
171
+ * @returns Choose category flow item
172
+ * @protected
173
+ */
174
+ getChooseCategoryFlowItem() {
175
+ return (h("calcite-flow-item", { collapsed: this.isMobile && this._sidePanelCollapsed, heading: this._translations.createReportHeader, onCalciteFlowItemBack: this.backFromSelectedPanel.bind(this) }, this.isMobile && this.getActionToExpandCollapsePanel(), h("div", { class: "width-full", slot: "footer" }, h("calcite-button", { appearance: "secondary", class: "footer-top-button footer-button", disabled: !this._selectedLayerId, onClick: this.navigateToCreateFeature.bind(this), width: "full" }, this._translations.next), h("calcite-button", { appearance: "outline", class: "footer-button", onClick: this.backFromSelectedPanel.bind(this), width: "full" }, this._translations.cancel)), h("calcite-panel", { "full-height": true, "full-width": true }, h("calcite-notice", { class: "notice-msg", icon: "lightbulb", kind: "success", open: true }, h("div", { slot: "message" }, this._translations.chooseCategoryMsg)), h("layer-list", { class: "height-full", layers: this.layers, mapView: this.mapView, noLayerErrorMsg: this._translations.noLayerToDisplayErrorMsg, onLayerSelect: this.highlightSelectedLayer.bind(this), showFeatureCount: false, showNextIcon: false }))));
176
+ }
177
+ /**
178
+ * Get Feature create form of the selected feature layer
179
+ * @returns feature create form
180
+ * @protected
181
+ */
182
+ getFeatureCreateFlowItem() {
183
+ return (h("calcite-flow-item", { collapsed: this.isMobile && this._sidePanelCollapsed, heading: this._selectedLayerName, onCalciteFlowItemBack: this.backFromCreateFeaturePanel.bind(this) }, this.isMobile && this.getActionToExpandCollapsePanel(), this._showSubmitCancelButton && h("div", { class: "width-full", slot: "footer" }, h("calcite-button", { appearance: "secondary", class: "footer-top-button footer-button", onClick: this.onSubmitButtonClick.bind(this), width: "full" }, this._translations.submit), h("calcite-button", { appearance: "outline", class: "footer-button", onClick: this.backFromCreateFeaturePanel.bind(this), width: "full" }, this._translations.cancel)), h("calcite-panel", { "full-height": true, "full-width": true }, h("calcite-notice", { class: "notice-msg", icon: "lightbulb", kind: "success", open: true }, h("div", { slot: "message" }, this._translations.featureEditFormInfoMsg)), h("create-feature", { mapView: this.mapView, onDrawComplete: this.showSubmitCancelButton.bind(this), onFail: this.createFeatureFailed.bind(this), onSuccess: this.navigateHomePage.bind(this), ref: el => this._createFeature = el, selectedLayerId: this._selectedLayerId }))));
184
+ }
185
+ /**
186
+ * When drawing of incident location completed on map show the submit and cancel button
187
+ * @protected
188
+ */
189
+ showSubmitCancelButton() {
190
+ this._showSubmitCancelButton = true;
191
+ }
192
+ /**
193
+ * On back from create feature, call submit editor to destroy the Editor widget instance
194
+ * @protected
195
+ */
196
+ onSubmitButtonClick() {
197
+ if (this._createFeature) {
198
+ this._createFeature.submit();
199
+ }
200
+ }
201
+ /**
202
+ * On back from create feature, call close editor to destroy the Editor widget instance
203
+ * @protected
204
+ */
205
+ backFromCreateFeaturePanel() {
206
+ if (this._createFeature) {
207
+ this._createFeature.close();
208
+ }
209
+ this.backFromSelectedPanel();
210
+ }
211
+ /**
212
+ * On creating the feature is failed, show the error message
213
+ * @param evt Event which has feature failed message
214
+ * @protected
215
+ */
216
+ createFeatureFailed(evt) {
217
+ console.error(evt.detail);
218
+ this._featureCreationFailedErrorMsg = evt.detail.message;
219
+ }
220
+ /**
221
+ * On submit report navigate to the layer list home page and refresh the layer list
222
+ * @protected
223
+ */
224
+ navigateHomePage() {
225
+ this._reportSubmitted = true;
226
+ if (this._layerList) {
227
+ this._layerList.refresh();
228
+ }
229
+ this._flowItems = ["layer-list"];
230
+ }
231
+ /**
232
+ * Update the selected layer id and name
233
+ * @param evt Event which has details of selected layerId and layerName
234
+ * @protected
235
+ */
236
+ highlightSelectedLayer(evt) {
237
+ this.setSelectedLayer(evt.detail.layerId, evt.detail.layerName);
238
+ }
239
+ /**
240
+ * On next button click open the feature create flow item
241
+ * @protected
242
+ */
243
+ async navigateToCreateFeature() {
244
+ this._showSubmitCancelButton = false;
245
+ this._flowItems = [...this._flowItems, "feature-create"];
246
+ }
247
+ /**
248
+ * On report an incident button click open the create a report panel with the layer list
249
+ * @protected
250
+ */
251
+ navigateToChooseCategory() {
252
+ this._flowItems = [...this._flowItems, "reporting-layer-list"];
146
253
  }
147
254
  /**
148
255
  * When layer list is loaded, we will receive the list of layers, if its means we don't have any valid layer to be listed
149
256
  * @param evt Event which has list of layers
150
257
  * @protected
151
258
  */
152
- layerListLoaded(evt) {
259
+ async layerListLoaded(evt) {
153
260
  const layersListed = evt.detail;
154
- this.handleMapClick(layersListed);
261
+ //consider only the layers listed in the layer-list component
262
+ const allMapLayers = await getAllLayers(this.mapView);
263
+ this._validLayers = [];
264
+ allMapLayers.forEach((eachLayer) => {
265
+ if (layersListed.includes(eachLayer.id)) {
266
+ this._validLayers.push(eachLayer);
267
+ }
268
+ });
269
+ //handleMap click on layer list loaded
270
+ this.handleMapClick();
271
+ //update the has valid layer state
155
272
  this._hasValidLayers = layersListed.length > 0;
273
+ //navigate to the feature details if URL params found
274
+ await this.loadFeatureFromURLParams();
156
275
  }
157
276
  /**On click of layer list item show feature list
158
277
  * @param evt Event which has details of selected layerId and layerName
159
278
  * @protected
160
279
  */
161
280
  displayFeaturesList(evt) {
162
- this._selectedLayerId = evt.detail.layerId;
163
- this._selectedLayerName = evt.detail.layerName;
281
+ this.setSelectedLayer(evt.detail.layerId, evt.detail.layerName);
164
282
  this._flowItems = [...this._flowItems, "feature-list"];
165
283
  }
166
284
  /**
167
- * On back from feature list navigate to the Layer list panel
285
+ * On back from selected panel navigate to the previous panel
168
286
  * @protected
169
287
  */
170
- backFromFeatureList() {
288
+ backFromSelectedPanel() {
171
289
  const updatedFlowItems = [...this._flowItems];
172
290
  updatedFlowItems.pop();
291
+ //clear the selected layer and feature when back to layer list
292
+ if (updatedFlowItems.length === 1) {
293
+ this.setSelectedLayer('', '');
294
+ this.setSelectedFeatures([]);
295
+ }
173
296
  this._flowItems = [...updatedFlowItems];
174
297
  }
175
298
  /**
@@ -185,7 +308,7 @@ export class CrowdsourceReporter {
185
308
  * @param evt Event which has details of selected feature
186
309
  */
187
310
  async onFeatureSelectFromList(evt) {
188
- this._selectedFeature = [evt.detail];
311
+ this.setSelectedFeatures([evt.detail]);
189
312
  this._flowItems = [...this._flowItems, "feature-details"];
190
313
  }
191
314
  /**
@@ -196,26 +319,50 @@ export class CrowdsourceReporter {
196
319
  * @protected
197
320
  */
198
321
  getFeatureListFlowItem(layerId, layerName) {
199
- return (h("calcite-flow-item", { collapsed: this.isMobile && this._sidePanelCollapsed, heading: layerName, onCalciteFlowItemBack: this.backFromFeatureList.bind(this) }, h("calcite-action", { icon: "sort-ascending-arrow", slot: this.isMobile ? "header-menu-actions" : "header-actions-end", text: this._translations.sort, "text-enabled": this.isMobile }), h("calcite-action", { icon: "filter", slot: this.isMobile ? "header-menu-actions" : "header-actions-end", text: this._translations.filter, "text-enabled": this.isMobile }), this.isMobile && this.getActionToExpandCollapsePanel(), this.enableNewReports &&
200
- h("calcite-button", { appearance: "secondary", slot: "footer", width: "full" }, this.reportButtonText), h("calcite-panel", { "full-height": true }, h("feature-list", { class: "height-full", highlightOnMap: true, mapView: this.mapView, noFeaturesFoundMsg: this._translations.featureErrorMsg, onFeatureSelect: this.onFeatureSelectFromList.bind(this), pageSize: 30, selectedLayerId: layerId }))));
322
+ return (h("calcite-flow-item", { collapsed: this.isMobile && this._sidePanelCollapsed, heading: layerName, onCalciteFlowItemBack: this.backFromSelectedPanel.bind(this) }, h("calcite-action", { icon: "sort-ascending-arrow", slot: this.isMobile ? "header-menu-actions" : "header-actions-end", text: this._translations.sort, "text-enabled": this.isMobile }), h("calcite-action", { icon: "filter", slot: this.isMobile ? "header-menu-actions" : "header-actions-end", text: this._translations.filter, "text-enabled": this.isMobile }), this.isMobile && this.getActionToExpandCollapsePanel(), this.enableNewReports &&
323
+ h("calcite-button", { appearance: "secondary", onClick: this.navigateToCreateFeature.bind(this), slot: "footer", width: "full" }, this.reportButtonText), h("calcite-panel", { "full-height": true }, h("feature-list", { class: "height-full", highlightOnMap: true, mapView: this.mapView, noFeaturesFoundMsg: this._translations.featureErrorMsg, onFeatureSelect: this.onFeatureSelectFromList.bind(this), pageSize: 30, selectedLayerId: layerId }))));
201
324
  }
202
325
  /**
203
326
  * Returns the calcite-flow item for feature details
204
327
  * @returns Node
205
328
  */
206
329
  getFeatureDetailsFlowItem() {
207
- return (h("calcite-flow-item", { collapsed: this.isMobile && this._sidePanelCollapsed, heading: this._selectedLayerName, onCalciteFlowItemBack: this.backFromFeatureList.bind(this) }, this.isMobile && this.getActionToExpandCollapsePanel(), h("calcite-action", { icon: "share", slot: "header-actions-end", text: this._translations.share }), h("calcite-panel", { "full-height": true }, h("info-card", { allowEditing: false, graphics: this._selectedFeature, isLoading: false, isMobile: false, mapView: this.mapView, onSelectionChanged: this.featureDetailsChanged.bind(this), zoomAndScrollToSelected: true }))));
330
+ return (h("calcite-flow-item", { collapsed: this.isMobile && this._sidePanelCollapsed, heading: this._selectedLayerName, onCalciteFlowItemBack: this.backFromSelectedPanel.bind(this) }, this.isMobile && this.getActionToExpandCollapsePanel(), h("instant-apps-social-share", { autoUpdateShareUrl: false, embed: false, popoverButtonIconScale: "s", ref: el => this._shareNode = el, scale: "m", shareButtonColor: "neutral", shareButtonType: "action", slot: "header-actions-end", socialMedia: true, view: this.mapView }), h("calcite-panel", { "full-height": true }, h("info-card", { allowEditing: false, graphics: this._selectedFeature, isLoading: false, isMobile: false, mapView: this.mapView, onSelectionChanged: this.featureDetailsChanged.bind(this), zoomAndScrollToSelected: true }))));
331
+ }
332
+ /**
333
+ * Sets the selected features and updates the first feature as the current selected feature
334
+ * @param features Graphics array of the features selected
335
+ */
336
+ setSelectedFeatures(features) {
337
+ this._selectedFeature = features;
338
+ this.setCurrentFeature(this._selectedFeature.length ? this._selectedFeature[0] : null);
339
+ }
340
+ /**
341
+ * Set the object id of the current selected feature, and also updates the current selected layer details
342
+ * @param selectedFeature Graphic currently shown in feature details
343
+ */
344
+ setCurrentFeature(selectedFeature) {
345
+ if (selectedFeature && selectedFeature.layer) {
346
+ const layer = selectedFeature.layer;
347
+ this.setSelectedLayer(layer.id, layer.title);
348
+ this._currentFeatureId = selectedFeature.attributes[layer.objectIdField];
349
+ }
350
+ else {
351
+ this.setSelectedLayer('', '');
352
+ this._currentFeatureId = '';
353
+ }
354
+ this._updateShareURL();
208
355
  }
209
356
  /**
210
357
  * On Feature details change update the Layer title and the current selected layer id
211
358
  * @param evt Event hold the details of current feature graphic in the info-card
212
359
  */
213
360
  featureDetailsChanged(evt) {
214
- this._selectedLayerId = evt.detail[0].layer.id;
215
- this._selectedLayerName = evt.detail[0].layer.title;
361
+ this.setCurrentFeature(evt.detail[0]);
216
362
  }
217
363
  /**
218
364
  * Returns the action button to Expand/Collapse side panel in mobile mode
365
+ * @protected
219
366
  */
220
367
  getActionToExpandCollapsePanel() {
221
368
  return (h("calcite-action", { icon: this._sidePanelCollapsed ? "chevrons-up" : "chevrons-down", onClick: this.toggleSidePanel.bind(this), slot: "header-actions-end", text: this._sidePanelCollapsed ? this._translations.expand : this._translations.collapse }));
@@ -239,36 +386,26 @@ export class CrowdsourceReporter {
239
386
  * Handle map click event
240
387
  * @param layers Array of layerIds
241
388
  *
242
- * @protected
389
+ * @protected
243
390
  */
244
- handleMapClick(layers) {
391
+ handleMapClick() {
245
392
  if (this._mapClickHandle) {
246
393
  this._mapClickHandle.remove();
247
394
  }
248
- this._mapClickHandle = this.reactiveUtils.on(() => this.mapView, "click", (event) => {
249
- void this.onMapClick(event, layers);
250
- });
395
+ this._mapClickHandle = this.reactiveUtils.on(() => this.mapView, "click", this.onMapClick.bind(this));
251
396
  }
252
397
  /**
253
398
  * On map click do hitTest and get the clicked graphics of valid layers and show feature details
254
- * @param event
255
- * @param layers
399
+ * @param event IMapClick map click event details
256
400
  *
257
401
  * @protected
258
402
  */
259
- async onMapClick(event, layers) {
403
+ async onMapClick(event) {
260
404
  //disable map popup
261
405
  this.mapView.popupEnabled = false;
262
406
  // only include graphics from valid layers listed in the layer list widget
263
- const allMapLayers = await getAllLayers(this.mapView);
264
- const validLayers = [];
265
- allMapLayers.forEach((eachLayer) => {
266
- if (layers.includes(eachLayer.id)) {
267
- validLayers.push(eachLayer);
268
- }
269
- });
270
407
  const opts = {
271
- include: validLayers
408
+ include: this._validLayers
272
409
  };
273
410
  // Perform a hitTest on the View
274
411
  const hitTest = await this.mapView.hitTest(event, opts);
@@ -281,7 +418,7 @@ export class CrowdsourceReporter {
281
418
  }
282
419
  });
283
420
  //update the selectedFeature
284
- this._selectedFeature = clickedGraphics;
421
+ this.setSelectedFeatures(clickedGraphics);
285
422
  //if featureDetails not open then add it to the list else just reInit flowItems which will update details with newly selected features
286
423
  // eslint-disable-next-line unicorn/prefer-ternary
287
424
  if (this._flowItems.length && this._flowItems[this._flowItems.length - 1] !== "feature-details") {
@@ -301,6 +438,59 @@ export class CrowdsourceReporter {
301
438
  const messages = await getLocaleComponentStrings(this.el);
302
439
  this._translations = messages[0];
303
440
  }
441
+ /**
442
+ * Updates the share url for current selected feature
443
+ * @returns
444
+ * @protected
445
+ */
446
+ _updateShareURL() {
447
+ var _a, _b;
448
+ const url = (_a = this._shareNode) === null || _a === void 0 ? void 0 : _a.shareUrl;
449
+ if (!url) {
450
+ return;
451
+ }
452
+ const urlObj = new URL(url);
453
+ //set the selected layers id
454
+ if (this._selectedLayerId) {
455
+ urlObj.searchParams.set("layerid", this._selectedLayerId);
456
+ }
457
+ else {
458
+ urlObj.searchParams.delete("layerid");
459
+ }
460
+ //Set the selected features objectid
461
+ if ((_b = this._selectedFeature) === null || _b === void 0 ? void 0 : _b.length) {
462
+ urlObj.searchParams.set("oid", this._currentFeatureId);
463
+ }
464
+ else {
465
+ urlObj.searchParams.delete("oid");
466
+ }
467
+ //update the url in share component
468
+ this._shareNode.shareUrl = urlObj.href;
469
+ }
470
+ /**
471
+ * Navigates to selected features detail based on the URL params
472
+ */
473
+ async loadFeatureFromURLParams() {
474
+ if (this.layerId && this.objectId) {
475
+ const layer = await getLayerOrTable(this.mapView, this.layerId);
476
+ if (layer) {
477
+ // only query if we have some ids...query with no ids will result in all features being returned
478
+ const featureSet = await queryFeaturesByID([Number(this.objectId)], layer, [], false, this.mapView.spatialReference);
479
+ if (featureSet.length) {
480
+ //update the selectedFeature
481
+ this._selectedFeature = featureSet;
482
+ //if featureDetails not open then add it to the list else just reInit flowItems which will update details with newly selected features
483
+ // eslint-disable-next-line unicorn/prefer-ternary
484
+ if (this._flowItems.length && this._flowItems[this._flowItems.length - 1] !== "feature-details") {
485
+ this._flowItems = [...this._flowItems, "feature-details"];
486
+ }
487
+ else {
488
+ this._flowItems = [...this._flowItems];
489
+ }
490
+ }
491
+ }
492
+ }
493
+ }
304
494
  static get is() { return "crowdsource-reporter"; }
305
495
  static get originalStyleUrls() {
306
496
  return {
@@ -485,6 +675,40 @@ export class CrowdsourceReporter {
485
675
  "text": "esri/views/MapView: https://developers.arcgis.com/javascript/latest/api-reference/esri-views-MapView.html"
486
676
  }
487
677
  },
678
+ "layerId": {
679
+ "type": "string",
680
+ "mutable": false,
681
+ "complexType": {
682
+ "original": "string",
683
+ "resolved": "string",
684
+ "references": {}
685
+ },
686
+ "required": false,
687
+ "optional": false,
688
+ "docs": {
689
+ "tags": [],
690
+ "text": "string: Layer id of the feature from URL params"
691
+ },
692
+ "attribute": "layer-id",
693
+ "reflect": false
694
+ },
695
+ "objectId": {
696
+ "type": "string",
697
+ "mutable": false,
698
+ "complexType": {
699
+ "original": "string",
700
+ "resolved": "string",
701
+ "references": {}
702
+ },
703
+ "required": false,
704
+ "optional": false,
705
+ "docs": {
706
+ "tags": [],
707
+ "text": "string: Object id of the feature from URL params"
708
+ },
709
+ "attribute": "object-id",
710
+ "reflect": false
711
+ },
488
712
  "reportButtonText": {
489
713
  "type": "string",
490
714
  "mutable": false,
@@ -701,7 +925,10 @@ export class CrowdsourceReporter {
701
925
  "_sidePanelCollapsed": {},
702
926
  "_translations": {},
703
927
  "_hasValidLayers": {},
704
- "_selectedLayerName": {}
928
+ "_selectedLayerName": {},
929
+ "_reportSubmitted": {},
930
+ "_showSubmitCancelButton": {},
931
+ "_featureCreationFailedErrorMsg": {}
705
932
  };
706
933
  }
707
934
  static get events() {
@@ -84,6 +84,7 @@ export class FeatureList {
84
84
  //--------------------------------------------------------------------------
85
85
  /**
86
86
  * Initialize the features list using the selected layer
87
+ * @protected
87
88
  */
88
89
  async initializeFeatureItems() {
89
90
  if (this._selectedLayer) {
@@ -36,6 +36,23 @@ export class LayerList {
36
36
  }
37
37
  //--------------------------------------------------------------------------
38
38
  //
39
+ // Watch handlers
40
+ //
41
+ //--------------------------------------------------------------------------
42
+ //--------------------------------------------------------------------------
43
+ //
44
+ // Methods (public)
45
+ //
46
+ //--------------------------------------------------------------------------
47
+ /**
48
+ * Refresh the layer list which will fetch the latest layer count and update the list
49
+ * @returns Promise that resolves when the operation is complete
50
+ */
51
+ async refresh() {
52
+ await this.setLayers();
53
+ }
54
+ //--------------------------------------------------------------------------
55
+ //
39
56
  // Functions (lifecycle)
40
57
  //
41
58
  //--------------------------------------------------------------------------
@@ -60,7 +77,7 @@ export class LayerList {
60
77
  render() {
61
78
  return (h(Fragment, null, this._isLoading && h("calcite-loader", { scale: "m" }), !this._isLoading && this.mapView && this._noLayersToDisplay &&
62
79
  h("calcite-notice", { class: "error-msg", icon: "layers-reference", kind: "danger", open: true }, h("div", { slot: "title" }, this._translations.error), h("div", { slot: "message" }, this.noLayerErrorMsg ? this.noLayerErrorMsg : this._translations.noLayerToDisplayErrorMsg)), !this._isLoading && this.mapView &&
63
- h("calcite-list", { "selection-appearance": "border", "selection-mode": this.showNextIcon ? "none" : "single" }, this.renderLayerList())));
80
+ h("calcite-list", { "selection-appearance": "border", "selection-mode": this.showNextIcon ? "none" : "single-persist" }, this.renderLayerList())));
64
81
  }
65
82
  //--------------------------------------------------------------------------
66
83
  //
@@ -87,21 +104,24 @@ export class LayerList {
87
104
  this._layerItemsHash = await getMapLayerHash(this.mapView, true);
88
105
  const allMapLayers = await getAllLayers(this.mapView);
89
106
  // eslint-disable-next-line @typescript-eslint/no-misused-promises
90
- this.showFeatureCount && allMapLayers.forEach(async (eachLayer) => {
107
+ allMapLayers.forEach(async (eachLayer) => {
91
108
  var _a, _b;
92
109
  //TODO: checking editable condition could be configurable
93
- if ((eachLayer === null || eachLayer === void 0 ? void 0 : eachLayer.type) === "feature" && (eachLayer === null || eachLayer === void 0 ? void 0 : eachLayer.editingEnabled) && ((_b = (_a = eachLayer === null || eachLayer === void 0 ? void 0 : eachLayer.capabilities) === null || _a === void 0 ? void 0 : _a.operations) === null || _b === void 0 ? void 0 : _b.supportsUpdate)) {
94
- const q = eachLayer.createQuery();
95
- const result = eachLayer.queryFeatureCount(q);
96
- def.push(result);
97
- void result.then(async (resCount) => {
98
- const formattedCount = !isNaN(resCount) ? await formatNumber(resCount, {
99
- places: 0,
100
- api: 4,
101
- type: "decimal"
102
- }) : "";
103
- this._layerItemsHash[eachLayer.id].formattedFeatureCount = formattedCount;
104
- });
110
+ if ((eachLayer === null || eachLayer === void 0 ? void 0 : eachLayer.type) === "feature" && (eachLayer === null || eachLayer === void 0 ? void 0 : eachLayer.editingEnabled) && ((_b = (_a = eachLayer === null || eachLayer === void 0 ? void 0 : eachLayer.capabilities) === null || _a === void 0 ? void 0 : _a.operations) === null || _b === void 0 ? void 0 : _b.supportsAdd)) {
111
+ this._layerItemsHash[eachLayer.id].supportsAdd = true;
112
+ if (this.showFeatureCount) {
113
+ const q = eachLayer.createQuery();
114
+ const result = eachLayer.queryFeatureCount(q);
115
+ def.push(result);
116
+ void result.then(async (resCount) => {
117
+ const formattedCount = !isNaN(resCount) ? await formatNumber(resCount, {
118
+ places: 0,
119
+ api: 4,
120
+ type: "decimal"
121
+ }) : "";
122
+ this._layerItemsHash[eachLayer.id].formattedFeatureCount = formattedCount;
123
+ });
124
+ }
105
125
  }
106
126
  });
107
127
  await Promise.all(def).then(() => {
@@ -129,9 +149,9 @@ export class LayerList {
129
149
  var _a;
130
150
  const configuredLayers = ((_a = this.layers) === null || _a === void 0 ? void 0 : _a.length) > 0 ? this.layers : [];
131
151
  return Object.keys(hash).reduce((prev, cur) => {
132
- let showLayer = hash[cur].supportsUpdate;
152
+ let showLayer = hash[cur].supportsAdd;
133
153
  if ((configuredLayers === null || configuredLayers === void 0 ? void 0 : configuredLayers.length) > 0) {
134
- showLayer = configuredLayers.indexOf(cur) > -1 ? hash[cur].supportsUpdate : false;
154
+ showLayer = configuredLayers.indexOf(cur) > -1 ? hash[cur].supportsAdd : false;
135
155
  }
136
156
  if (showLayer) {
137
157
  prev.push(cur);
@@ -323,5 +343,29 @@ export class LayerList {
323
343
  }
324
344
  }];
325
345
  }
346
+ static get methods() {
347
+ return {
348
+ "refresh": {
349
+ "complexType": {
350
+ "signature": "() => Promise<void>",
351
+ "parameters": [],
352
+ "references": {
353
+ "Promise": {
354
+ "location": "global",
355
+ "id": "global::Promise"
356
+ }
357
+ },
358
+ "return": "Promise<void>"
359
+ },
360
+ "docs": {
361
+ "text": "Refresh the layer list which will fetch the latest layer count and update the list",
362
+ "tags": [{
363
+ "name": "returns",
364
+ "text": "Promise that resolves when the operation is complete"
365
+ }]
366
+ }
367
+ }
368
+ };
369
+ }
326
370
  static get elementRef() { return "el"; }
327
371
  }
@@ -93,23 +93,38 @@
93
93
  const demo = document.getElementById("demo");
94
94
  let custom = null;
95
95
  let portal;
96
- //Support webmap and portal URL parameter
97
- var vars = window.location.search.substring(1).split("&");
98
- vars.forEach((param) => {
99
- let vals = param.split("=");
100
- const v = vals[1];
101
- switch (vals[0]) {
96
+ let locale = 'en'
97
+ //Support webmap, portal and locale URL parameter
98
+ //Also, set search params to reporter component - layerId, objectId, center, level etc.
99
+ let urlObj = new URL(window.location)
100
+ for (const [key, value] of urlObj.searchParams.entries()) {
101
+ switch (key) {
102
102
  case "webmap":
103
103
  custom = {
104
- id: v
104
+ id: value
105
105
  };
106
106
  break;
107
107
  case "portal":
108
- portal = v;
109
- default:
108
+ portal = value;
109
+ break;
110
+ case "locale":
111
+ locale = value;
112
+ break;
113
+ case 'layerid':
114
+ demo.layerId = value;
115
+ break;
116
+ case 'oid':
117
+ demo.objectId = value;
118
+ case 'center' || 'level':
119
+ demo[key] = value;
110
120
  break;
111
121
  }
112
- });
122
+ }
123
+
124
+ // Set the locale before the JSAPI loads
125
+ esriConfig.locale = locale;
126
+ demo.lang = locale;
127
+
113
128
  //update the portalUrl if found in urlParams
114
129
  //esriConfig.portalUrl = "https://solutions.mapsdevext.arcgis.com";
115
130
  if (portal) {
@@ -117,7 +132,6 @@
117
132
  }
118
133
 
119
134
  let portalItem = {
120
- //id: "b5bdcb1e5d684dd3b21a2d44b8e4f928"
121
135
  //id: "f8c4d99deb3c483cac296cc261e18a25", //blank no layers
122
136
  //id: "a7e880f7afbb471991d43c8c4f1438ac" // Se mapping
123
137
  //id: "c720e337ff814fe4a83bc244c46f8e43" //15 Layers
@@ -125,6 +139,7 @@
125
139
  //id: "dda88d905a6748a5ab46bea5be795f33" // screening layers
126
140
  id: "b5bdcb1e5d684dd3b21a2d44b8e4f928" //Popup content
127
141
  //id: "d399ec39959a4aac8617ae4f05dd6785" //Arcade
142
+ //id: "024e8a5e73a34c5aade9632d651c5750" //Attachments
128
143
  }
129
144
  const webMap = new WebMap({
130
145
  portalItem: custom ?? portalItem
@@ -540,7 +540,7 @@ export function _prepareAttributeValue(attributeValue, attributeType, attributeD
540
540
  if (attributeDomain && attributeDomain.type === "coded-value") {
541
541
  // "coded-value" domain field
542
542
  const value = attributeDomain.getName(attributeValue);
543
- return value.toString();
543
+ return value === null || value === void 0 ? void 0 : value.toString();
544
544
  }
545
545
  else {
546
546
  // Non-domain field or unsupported domain type
@@ -769,7 +769,7 @@ export function _prepareAttributeValue(
769
769
  if (attributeDomain && (attributeDomain as __esri.CodedValueDomain).type === "coded-value") {
770
770
  // "coded-value" domain field
771
771
  const value = (attributeDomain as __esri.CodedValueDomain).getName(attributeValue);
772
- return value.toString();
772
+ return value?.toString();
773
773
  } else {
774
774
  // Non-domain field or unsupported domain type
775
775
  let value = attributeValue;