@esri/solutions-components 0.7.30 → 0.7.32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) 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} +286 -19
  8. package/dist/cjs/card-manager_3.cjs.entry.js +1 -1
  9. package/dist/cjs/crowdsource-reporter.cjs.entry.js +248 -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 +50 -0
  18. package/dist/collection/components/create-feature/create-feature.js +444 -0
  19. package/dist/collection/components/crowdsource-reporter/crowdsource-reporter.css +10 -1
  20. package/dist/collection/components/crowdsource-reporter/crowdsource-reporter.js +287 -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/create-feature.html +90 -0
  24. package/dist/collection/demos/crowdsource-reporter.html +26 -11
  25. package/dist/collection/utils/downloadUtils.js +1 -1
  26. package/dist/collection/utils/downloadUtils.ts +1 -1
  27. package/dist/components/create-feature.d.ts +11 -0
  28. package/dist/components/create-feature.js +11 -0
  29. package/dist/components/create-feature2.js +278 -0
  30. package/dist/components/crowdsource-reporter.js +324 -90
  31. package/dist/components/downloadUtils.js +1 -1
  32. package/dist/components/feature-list2.js +1 -0
  33. package/dist/components/layer-list2.js +38 -17
  34. package/dist/esm/{calcite-flow_4.entry.js → calcite-flow_5.entry.js} +286 -20
  35. package/dist/esm/card-manager_3.entry.js +1 -1
  36. package/dist/esm/crowdsource-reporter.entry.js +249 -33
  37. package/dist/esm/{downloadUtils-d070a467.js → downloadUtils-d297078f.js} +2 -2
  38. package/dist/esm/{index.es-d48535a2.js → index.es-3b4fa9d0.js} +1 -1
  39. package/dist/esm/loader.js +1 -1
  40. package/dist/esm/map-select-tools_3.entry.js +1 -1
  41. package/dist/esm/public-notification.entry.js +1 -1
  42. package/dist/esm/solutions-components.js +1 -1
  43. package/dist/solutions-components/demos/create-feature.html +90 -0
  44. package/dist/solutions-components/demos/crowdsource-reporter.html +26 -11
  45. package/dist/solutions-components/{p-f120ff40.entry.js → p-09ec8c8f.entry.js} +1 -1
  46. package/dist/solutions-components/{p-55b835a1.js → p-103c5318.js} +2 -2
  47. package/dist/solutions-components/{p-309cdea1.entry.js → p-57d49d15.entry.js} +1 -1
  48. package/dist/solutions-components/{p-b913a4fd.js → p-8ec25bf4.js} +1 -1
  49. package/dist/solutions-components/{p-f22ff57e.entry.js → p-921f21d5.entry.js} +1 -1
  50. package/dist/solutions-components/p-d5263cb9.entry.js +17 -0
  51. package/dist/solutions-components/p-ea17cefb.entry.js +6 -0
  52. package/dist/solutions-components/solutions-components.esm.js +1 -1
  53. package/dist/solutions-components/utils/downloadUtils.ts +1 -1
  54. package/dist/types/components/create-feature/create-feature.d.ts +125 -0
  55. package/dist/types/components/crowdsource-reporter/crowdsource-reporter.d.ts +146 -12
  56. package/dist/types/components/feature-list/feature-list.d.ts +1 -0
  57. package/dist/types/components/layer-list/layer-list.d.ts +6 -0
  58. package/dist/types/components.d.ts +102 -0
  59. package/dist/types/preact.d.ts +7 -0
  60. package/package.json +1 -1
  61. package/dist/solutions-components/p-2f162664.entry.js +0 -6
  62. 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
  //
@@ -82,6 +88,7 @@ export class CrowdsourceReporter {
82
88
  * @returns Promise when complete
83
89
  */
84
90
  async componentWillLoad() {
91
+ this._urlParamsLoaded = false;
85
92
  await this._initModules();
86
93
  await this._getTranslations();
87
94
  }
@@ -89,7 +96,8 @@ export class CrowdsourceReporter {
89
96
  * Renders the component.
90
97
  */
91
98
  render() {
92
- return (h(Host, null, h("div", null, h("calcite-shell", { "content-behind": true }, this._getReporter()))));
99
+ const themeClass = this.theme === "dark" ? "calcite-mode-dark" : "calcite-mode-light";
100
+ 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
101
  }
94
102
  //--------------------------------------------------------------------------
95
103
  //
@@ -109,6 +117,20 @@ export class CrowdsourceReporter {
109
117
  ]);
110
118
  this.reactiveUtils = reactiveUtils;
111
119
  }
120
+ /**
121
+ * Set the selected layer id and layer name
122
+ * @param layerId string layerId of the selected layer
123
+ * @param layerName string layerName of the selected layer
124
+ */
125
+ setSelectedLayer(layerId, layerName) {
126
+ this._selectedLayerId = layerId;
127
+ this._selectedLayerName = layerName;
128
+ //show only current layer on map and hide other valid editable layers
129
+ //if layerId is empty then show all the layers on map
130
+ this._validLayers.forEach(layer => {
131
+ layer.set('visible', !layerId || (layer.id === layerId));
132
+ });
133
+ }
112
134
  /**
113
135
  * Get the reporter app functionality
114
136
  * @protected
@@ -126,6 +148,12 @@ export class CrowdsourceReporter {
126
148
  case "feature-details":
127
149
  renderLists.push(this.getFeatureDetailsFlowItem());
128
150
  break;
151
+ case "reporting-layer-list":
152
+ renderLists.push(this.getChooseCategoryFlowItem());
153
+ break;
154
+ case "feature-create":
155
+ renderLists.push(this.getFeatureCreateFlowItem());
156
+ break;
129
157
  }
130
158
  });
131
159
  const themeClass = this.theme === "dark" ? "calcite-mode-dark" : "calcite-mode-light";
@@ -142,34 +170,156 @@ export class CrowdsourceReporter {
142
170
  return (h("calcite-flow-item", { collapsed: this.isMobile && this._sidePanelCollapsed, heading: this.reportsHeader }, this._hasValidLayers &&
143
171
  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
172
  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 }))));
173
+ 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 }))));
174
+ }
175
+ /**
176
+ * Get the layer list for creating a report
177
+ * @returns Choose category flow item
178
+ * @protected
179
+ */
180
+ getChooseCategoryFlowItem() {
181
+ 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 }))));
182
+ }
183
+ /**
184
+ * Get Feature create form of the selected feature layer
185
+ * @returns feature create form
186
+ * @protected
187
+ */
188
+ getFeatureCreateFlowItem() {
189
+ 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", { customizeSubmit: true, mapView: this.mapView, onDrawComplete: this.onDrawComplete.bind(this), onEditingAttachment: this.showSubmitCancelButton.bind(this), onFail: this.createFeatureFailed.bind(this), onSuccess: this.onReportSubmitted.bind(this), ref: el => this._createFeature = el, selectedLayerId: this._selectedLayerId }))));
190
+ }
191
+ /**
192
+ * When drawing of incident location completed on map show the submit and cancel button
193
+ * @protected
194
+ */
195
+ onDrawComplete() {
196
+ this._showSubmitCancelButton = true;
197
+ }
198
+ /**
199
+ * When Add attachment panel is enabled hide the submit and cancel button
200
+ * @protected
201
+ */
202
+ showSubmitCancelButton(evt) {
203
+ this._showSubmitCancelButton = !evt.detail;
204
+ }
205
+ /**
206
+ * On back from create feature, call submit editor to destroy the Editor widget instance
207
+ * @protected
208
+ */
209
+ onSubmitButtonClick() {
210
+ if (this._createFeature) {
211
+ this._createFeature.submit();
212
+ }
213
+ }
214
+ /**
215
+ * On back from create feature, call close editor to destroy the Editor widget instance
216
+ * @protected
217
+ */
218
+ backFromCreateFeaturePanel() {
219
+ if (this._createFeature) {
220
+ this._createFeature.close();
221
+ }
222
+ this.backFromSelectedPanel();
223
+ }
224
+ /**
225
+ * On creating the feature is failed, show the error message
226
+ * @param evt Event which has feature failed message
227
+ * @protected
228
+ */
229
+ createFeatureFailed(evt) {
230
+ console.error(evt.detail);
231
+ this._featureCreationFailedErrorMsg = evt.detail.message;
232
+ }
233
+ /**
234
+ * On submit report navigate to the layer list home page and refresh the layer list
235
+ * @protected
236
+ */
237
+ onReportSubmitted() {
238
+ this._reportSubmitted = true;
239
+ this.navigateToHomePage();
240
+ }
241
+ /**
242
+ * Navigates to layer-list
243
+ * @protected
244
+ */
245
+ navigateToHomePage() {
246
+ if (this._createFeature) {
247
+ this._createFeature.close();
248
+ }
249
+ if (this._layerList) {
250
+ this._layerList.refresh();
251
+ }
252
+ this.setSelectedFeatures([]);
253
+ this._flowItems = ["layer-list"];
254
+ }
255
+ /**
256
+ * Update the selected layer id and name
257
+ * @param evt Event which has details of selected layerId and layerName
258
+ * @protected
259
+ */
260
+ highlightSelectedLayer(evt) {
261
+ this.setSelectedLayer(evt.detail.layerId, evt.detail.layerName);
262
+ }
263
+ /**
264
+ * On next button click open the feature create flow item
265
+ * @protected
266
+ */
267
+ async navigateToCreateFeature() {
268
+ this._showSubmitCancelButton = false;
269
+ this._flowItems = [...this._flowItems, "feature-create"];
270
+ }
271
+ /**
272
+ * On report an incident button click open the create a report panel with the layer list
273
+ * @protected
274
+ */
275
+ navigateToChooseCategory() {
276
+ this._flowItems = [...this._flowItems, "reporting-layer-list"];
146
277
  }
147
278
  /**
148
279
  * 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
280
  * @param evt Event which has list of layers
150
281
  * @protected
151
282
  */
152
- layerListLoaded(evt) {
283
+ async layerListLoaded(evt) {
153
284
  const layersListed = evt.detail;
154
- this.handleMapClick(layersListed);
285
+ //consider only the layers listed in the layer-list component
286
+ const allMapLayers = await getAllLayers(this.mapView);
287
+ this._validLayers = [];
288
+ allMapLayers.forEach((eachLayer) => {
289
+ if (layersListed.includes(eachLayer.id)) {
290
+ this._validLayers.push(eachLayer);
291
+ }
292
+ });
293
+ //handleMap click on layer list loaded
294
+ this.handleMapClick();
295
+ //update the has valid layer state
155
296
  this._hasValidLayers = layersListed.length > 0;
297
+ //navigate to the feature details if URL params found
298
+ if (!this._urlParamsLoaded) {
299
+ this._urlParamsLoaded = true;
300
+ await this.loadFeatureFromURLParams();
301
+ }
156
302
  }
157
303
  /**On click of layer list item show feature list
158
304
  * @param evt Event which has details of selected layerId and layerName
159
305
  * @protected
160
306
  */
161
307
  displayFeaturesList(evt) {
162
- this._selectedLayerId = evt.detail.layerId;
163
- this._selectedLayerName = evt.detail.layerName;
308
+ this.setSelectedLayer(evt.detail.layerId, evt.detail.layerName);
164
309
  this._flowItems = [...this._flowItems, "feature-list"];
165
310
  }
166
311
  /**
167
- * On back from feature list navigate to the Layer list panel
312
+ * On back from selected panel navigate to the previous panel
168
313
  * @protected
169
314
  */
170
- backFromFeatureList() {
315
+ backFromSelectedPanel() {
171
316
  const updatedFlowItems = [...this._flowItems];
172
317
  updatedFlowItems.pop();
318
+ //Back to layer list, and return as the flowItems will be reset in navigateToHomePage
319
+ if (updatedFlowItems.length === 1) {
320
+ this.navigateToHomePage();
321
+ return;
322
+ }
173
323
  this._flowItems = [...updatedFlowItems];
174
324
  }
175
325
  /**
@@ -185,7 +335,7 @@ export class CrowdsourceReporter {
185
335
  * @param evt Event which has details of selected feature
186
336
  */
187
337
  async onFeatureSelectFromList(evt) {
188
- this._selectedFeature = [evt.detail];
338
+ this.setSelectedFeatures([evt.detail]);
189
339
  this._flowItems = [...this._flowItems, "feature-details"];
190
340
  }
191
341
  /**
@@ -196,26 +346,50 @@ export class CrowdsourceReporter {
196
346
  * @protected
197
347
  */
198
348
  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 }))));
349
+ 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 &&
350
+ 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
351
  }
202
352
  /**
203
353
  * Returns the calcite-flow item for feature details
204
354
  * @returns Node
205
355
  */
206
356
  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 }))));
357
+ 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 }))));
358
+ }
359
+ /**
360
+ * Sets the selected features and updates the first feature as the current selected feature
361
+ * @param features Graphics array of the features selected
362
+ */
363
+ setSelectedFeatures(features) {
364
+ this._selectedFeature = features;
365
+ this.setCurrentFeature(this._selectedFeature.length ? this._selectedFeature[0] : null);
366
+ }
367
+ /**
368
+ * Set the object id of the current selected feature, and also updates the current selected layer details
369
+ * @param selectedFeature Graphic currently shown in feature details
370
+ */
371
+ setCurrentFeature(selectedFeature) {
372
+ if (selectedFeature && selectedFeature.layer) {
373
+ const layer = selectedFeature.layer;
374
+ this.setSelectedLayer(layer.id, layer.title);
375
+ this._currentFeatureId = selectedFeature.attributes[layer.objectIdField];
376
+ }
377
+ else {
378
+ this.setSelectedLayer('', '');
379
+ this._currentFeatureId = '';
380
+ }
381
+ this._updateShareURL();
208
382
  }
209
383
  /**
210
384
  * On Feature details change update the Layer title and the current selected layer id
211
385
  * @param evt Event hold the details of current feature graphic in the info-card
212
386
  */
213
387
  featureDetailsChanged(evt) {
214
- this._selectedLayerId = evt.detail[0].layer.id;
215
- this._selectedLayerName = evt.detail[0].layer.title;
388
+ this.setCurrentFeature(evt.detail[0]);
216
389
  }
217
390
  /**
218
391
  * Returns the action button to Expand/Collapse side panel in mobile mode
392
+ * @protected
219
393
  */
220
394
  getActionToExpandCollapsePanel() {
221
395
  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 +413,26 @@ export class CrowdsourceReporter {
239
413
  * Handle map click event
240
414
  * @param layers Array of layerIds
241
415
  *
242
- * @protected
416
+ * @protected
243
417
  */
244
- handleMapClick(layers) {
418
+ handleMapClick() {
245
419
  if (this._mapClickHandle) {
246
420
  this._mapClickHandle.remove();
247
421
  }
248
- this._mapClickHandle = this.reactiveUtils.on(() => this.mapView, "click", (event) => {
249
- void this.onMapClick(event, layers);
250
- });
422
+ this._mapClickHandle = this.reactiveUtils.on(() => this.mapView, "click", this.onMapClick.bind(this));
251
423
  }
252
424
  /**
253
425
  * On map click do hitTest and get the clicked graphics of valid layers and show feature details
254
- * @param event
255
- * @param layers
426
+ * @param event IMapClick map click event details
256
427
  *
257
428
  * @protected
258
429
  */
259
- async onMapClick(event, layers) {
430
+ async onMapClick(event) {
260
431
  //disable map popup
261
432
  this.mapView.popupEnabled = false;
262
433
  // 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
434
  const opts = {
271
- include: validLayers
435
+ include: this._validLayers
272
436
  };
273
437
  // Perform a hitTest on the View
274
438
  const hitTest = await this.mapView.hitTest(event, opts);
@@ -281,7 +445,7 @@ export class CrowdsourceReporter {
281
445
  }
282
446
  });
283
447
  //update the selectedFeature
284
- this._selectedFeature = clickedGraphics;
448
+ this.setSelectedFeatures(clickedGraphics);
285
449
  //if featureDetails not open then add it to the list else just reInit flowItems which will update details with newly selected features
286
450
  // eslint-disable-next-line unicorn/prefer-ternary
287
451
  if (this._flowItems.length && this._flowItems[this._flowItems.length - 1] !== "feature-details") {
@@ -301,6 +465,59 @@ export class CrowdsourceReporter {
301
465
  const messages = await getLocaleComponentStrings(this.el);
302
466
  this._translations = messages[0];
303
467
  }
468
+ /**
469
+ * Updates the share url for current selected feature
470
+ * @protected
471
+ */
472
+ _updateShareURL() {
473
+ var _a, _b;
474
+ const url = (_a = this._shareNode) === null || _a === void 0 ? void 0 : _a.shareUrl;
475
+ if (!url) {
476
+ return;
477
+ }
478
+ const urlObj = new URL(url);
479
+ //set the selected layers id
480
+ if (this._selectedLayerId) {
481
+ urlObj.searchParams.set("layerid", this._selectedLayerId);
482
+ }
483
+ else {
484
+ urlObj.searchParams.delete("layerid");
485
+ }
486
+ //Set the selected features objectid
487
+ if ((_b = this._selectedFeature) === null || _b === void 0 ? void 0 : _b.length) {
488
+ urlObj.searchParams.set("oid", this._currentFeatureId);
489
+ }
490
+ else {
491
+ urlObj.searchParams.delete("oid");
492
+ }
493
+ //update the url in share component
494
+ this._shareNode.shareUrl = urlObj.href;
495
+ }
496
+ /**
497
+ * Navigates to selected features detail based on the URL params
498
+ * @protected
499
+ */
500
+ async loadFeatureFromURLParams() {
501
+ if (this.layerId && this.objectId) {
502
+ const layer = await getLayerOrTable(this.mapView, this.layerId);
503
+ if (layer) {
504
+ // only query if we have some ids...query with no ids will result in all features being returned
505
+ const featureSet = await queryFeaturesByID([Number(this.objectId)], layer, [], false, this.mapView.spatialReference);
506
+ if (featureSet.length) {
507
+ //update the selectedFeature
508
+ this._selectedFeature = featureSet;
509
+ //if featureDetails not open then add it to the list else just reInit flowItems which will update details with newly selected features
510
+ // eslint-disable-next-line unicorn/prefer-ternary
511
+ if (this._flowItems.length && this._flowItems[this._flowItems.length - 1] !== "feature-details") {
512
+ this._flowItems = [...this._flowItems, "feature-details"];
513
+ }
514
+ else {
515
+ this._flowItems = [...this._flowItems];
516
+ }
517
+ }
518
+ }
519
+ }
520
+ }
304
521
  static get is() { return "crowdsource-reporter"; }
305
522
  static get originalStyleUrls() {
306
523
  return {
@@ -485,6 +702,40 @@ export class CrowdsourceReporter {
485
702
  "text": "esri/views/MapView: https://developers.arcgis.com/javascript/latest/api-reference/esri-views-MapView.html"
486
703
  }
487
704
  },
705
+ "layerId": {
706
+ "type": "string",
707
+ "mutable": false,
708
+ "complexType": {
709
+ "original": "string",
710
+ "resolved": "string",
711
+ "references": {}
712
+ },
713
+ "required": false,
714
+ "optional": false,
715
+ "docs": {
716
+ "tags": [],
717
+ "text": "string: Layer id of the feature from URL params"
718
+ },
719
+ "attribute": "layer-id",
720
+ "reflect": false
721
+ },
722
+ "objectId": {
723
+ "type": "string",
724
+ "mutable": false,
725
+ "complexType": {
726
+ "original": "string",
727
+ "resolved": "string",
728
+ "references": {}
729
+ },
730
+ "required": false,
731
+ "optional": false,
732
+ "docs": {
733
+ "tags": [],
734
+ "text": "string: Object id of the feature from URL params"
735
+ },
736
+ "attribute": "object-id",
737
+ "reflect": false
738
+ },
488
739
  "reportButtonText": {
489
740
  "type": "string",
490
741
  "mutable": false,
@@ -701,7 +952,10 @@ export class CrowdsourceReporter {
701
952
  "_sidePanelCollapsed": {},
702
953
  "_translations": {},
703
954
  "_hasValidLayers": {},
704
- "_selectedLayerName": {}
955
+ "_selectedLayerName": {},
956
+ "_reportSubmitted": {},
957
+ "_showSubmitCancelButton": {},
958
+ "_featureCreationFailedErrorMsg": {}
705
959
  };
706
960
  }
707
961
  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
  }