@esri/solutions-components 0.7.30 → 0.7.31

Sign up to get free protection for your applications and to get access to all the features.
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;