@esri/solutions-components 0.4.1 → 0.4.3

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 (92) hide show
  1. package/dist/assets/t9n/map-select-tools/resources.json +1 -1
  2. package/dist/assets/t9n/map-select-tools/resources_en.json +1 -1
  3. package/dist/assets/t9n/public-notification/resources.json +6 -3
  4. package/dist/assets/t9n/public-notification/resources_en.json +6 -3
  5. package/dist/assets/t9n/refine-selection/resources.json +3 -3
  6. package/dist/assets/t9n/refine-selection/resources_en.json +3 -3
  7. package/dist/cjs/add-record-modal.cjs.entry.js +1 -1
  8. package/dist/cjs/buffer-tools_6.cjs.entry.js +5 -2
  9. package/dist/cjs/calcite-dropdown-group_4.cjs.entry.js +1 -1
  10. package/dist/cjs/calcite-input-message_5.cjs.entry.js +16 -12
  11. package/dist/cjs/calcite-shell-panel_14.cjs.entry.js +1 -1
  12. package/dist/cjs/card-manager.cjs.entry.js +1 -1
  13. package/dist/cjs/{downloadUtils-27dbd8b9.js → downloadUtils-ae182e3a.js} +89 -16
  14. package/dist/cjs/{index.es-40d341ed.js → index.es-b71e9071.js} +3 -3
  15. package/dist/cjs/info-card_2.cjs.entry.js +1 -1
  16. package/dist/cjs/layer-table.cjs.entry.js +4 -4
  17. package/dist/cjs/{loadModules-918ff3e7.js → loadModules-0806a34f.js} +1 -1
  18. package/dist/cjs/loader.cjs.js +1 -1
  19. package/dist/cjs/{locale-db1db902.js → locale-04da9a8c.js} +1 -0
  20. package/dist/cjs/map-card.cjs.entry.js +2 -2
  21. package/dist/cjs/map-search.cjs.entry.js +2 -2
  22. package/dist/cjs/public-notification.cjs.entry.js +40 -13
  23. package/dist/cjs/solution-configuration.cjs.entry.js +1 -1
  24. package/dist/cjs/solution-contents_3.cjs.entry.js +1 -1
  25. package/dist/cjs/solutions-components.cjs.js +1 -1
  26. package/dist/collection/components/layer-table/layer-table.js +1 -1
  27. package/dist/collection/components/map-select-tools/map-select-tools.js +21 -5
  28. package/dist/collection/components/pdf-download/pdf-download.js +26 -6
  29. package/dist/collection/components/public-notification/public-notification.js +46 -12
  30. package/dist/collection/components/refine-selection-tools/refine-selection-tools.js +17 -0
  31. package/dist/collection/utils/downloadUtils.js +87 -14
  32. package/dist/collection/utils/downloadUtils.ts +123 -14
  33. package/dist/collection/utils/locale.js +1 -1
  34. package/dist/collection/utils/locale.ts +1 -1
  35. package/dist/components/downloadUtils.js +87 -14
  36. package/dist/components/layer-table.js +1 -1
  37. package/dist/components/locale.js +1 -1
  38. package/dist/components/map-select-tools2.js +7 -5
  39. package/dist/components/pdf-download2.js +6 -4
  40. package/dist/components/public-notification.js +41 -13
  41. package/dist/components/refine-selection-tools2.js +3 -0
  42. package/dist/esm/add-record-modal.entry.js +1 -1
  43. package/dist/esm/buffer-tools_6.entry.js +5 -2
  44. package/dist/esm/calcite-dropdown-group_4.entry.js +1 -1
  45. package/dist/esm/calcite-input-message_5.entry.js +16 -12
  46. package/dist/esm/calcite-shell-panel_14.entry.js +1 -1
  47. package/dist/esm/card-manager.entry.js +1 -1
  48. package/dist/esm/{downloadUtils-76e38a94.js → downloadUtils-8d64719e.js} +89 -16
  49. package/dist/esm/{index.es-489f4f08.js → index.es-1d777745.js} +3 -3
  50. package/dist/esm/info-card_2.entry.js +1 -1
  51. package/dist/esm/layer-table.entry.js +4 -4
  52. package/dist/esm/{loadModules-649aedac.js → loadModules-b299cd43.js} +1 -1
  53. package/dist/esm/loader.js +1 -1
  54. package/dist/esm/{locale-4a87aff1.js → locale-7bf10e0a.js} +1 -1
  55. package/dist/esm/map-card.entry.js +2 -2
  56. package/dist/esm/map-search.entry.js +2 -2
  57. package/dist/esm/public-notification.entry.js +40 -13
  58. package/dist/esm/solution-configuration.entry.js +1 -1
  59. package/dist/esm/solution-contents_3.entry.js +1 -1
  60. package/dist/esm/solutions-components.js +1 -1
  61. package/dist/solutions-components/{p-caa7e7a7.js → p-01215468.js} +11 -11
  62. package/dist/solutions-components/{p-92cb569a.entry.js → p-048a4c91.entry.js} +1 -1
  63. package/dist/solutions-components/{p-8eeb8faa.entry.js → p-0e459cc7.entry.js} +1 -1
  64. package/dist/solutions-components/{p-4ef269be.entry.js → p-43d4ceda.entry.js} +1 -1
  65. package/dist/solutions-components/{p-eea93a37.js → p-4aa3ba60.js} +1 -1
  66. package/dist/solutions-components/p-4bfcd9ea.entry.js +17 -0
  67. package/dist/solutions-components/{p-13b4fb80.entry.js → p-4cbaf0f1.entry.js} +1 -1
  68. package/dist/solutions-components/{p-ebd3f353.entry.js → p-6f012424.entry.js} +1 -1
  69. package/dist/solutions-components/{p-bff8aa4e.js → p-702e1915.js} +1 -1
  70. package/dist/solutions-components/{p-0a4c2213.entry.js → p-74cfd344.entry.js} +1 -1
  71. package/dist/solutions-components/{p-a3b60bc9.entry.js → p-773918c0.entry.js} +2 -2
  72. package/dist/solutions-components/{p-9260d75a.js → p-829e6d4f.js} +2 -2
  73. package/dist/solutions-components/{p-7a411772.entry.js → p-9e8a371f.entry.js} +1 -1
  74. package/dist/solutions-components/p-a99ca396.entry.js +6 -0
  75. package/dist/solutions-components/{p-b342e3ff.entry.js → p-af9c7482.entry.js} +1 -1
  76. package/dist/solutions-components/{p-05e26a56.entry.js → p-d5a76fb0.entry.js} +1 -1
  77. package/dist/solutions-components/{p-bf45dbae.entry.js → p-dd0241fb.entry.js} +1 -1
  78. package/dist/solutions-components/solutions-components.esm.js +1 -1
  79. package/dist/solutions-components/utils/downloadUtils.ts +123 -14
  80. package/dist/solutions-components/utils/locale.ts +1 -1
  81. package/dist/types/components/map-select-tools/map-select-tools.d.ts +5 -1
  82. package/dist/types/components/pdf-download/pdf-download.d.ts +4 -2
  83. package/dist/types/components/public-notification/public-notification.d.ts +21 -1
  84. package/dist/types/components/refine-selection-tools/refine-selection-tools.d.ts +4 -0
  85. package/dist/types/components.d.ts +12 -2
  86. package/dist/types/preact.d.ts +4 -2
  87. package/dist/types/utils/downloadUtils.d.ts +4 -2
  88. package/dist/types/utils/locale.d.ts +1 -0
  89. package/package.json +1 -1
  90. package/dist/solutions-components/p-4ef94c6b.entry.js +0 -6
  91. package/dist/solutions-components/p-5d27b47d.entry.js +0 -17
  92. package/dist/types/components/json-editor/assets/monaco-editor/monaco.d.ts +0 -8262
@@ -24,7 +24,7 @@ import { loadModules } from "../../utils/loadModules";
24
24
  import { goToSelection, getMapLayerView, highlightFeatures } from "../../utils/mapViewUtils";
25
25
  import { getSelectionSetQuery } from "../../utils/queryUtils";
26
26
  import state from "../../utils/publicNotificationStore";
27
- import { getLocaleComponentStrings } from "../../utils/locale";
27
+ import { getComponentClosestLanguage, getLocaleComponentStrings } from "../../utils/locale";
28
28
  import * as utils from "../../utils/publicNotificationUtils";
29
29
  export class PublicNotification {
30
30
  constructor() {
@@ -47,6 +47,7 @@ export class PublicNotification {
47
47
  this._numSelected = 0;
48
48
  this._pageType = EPageType.LIST;
49
49
  this._saveEnabled = false;
50
+ this._selectionLoading = false;
50
51
  this._selectionSets = [];
51
52
  this._sketchType = ESketchType.INTERACTIVE;
52
53
  this._selectionWorkflowType = EWorkflowType.SEARCH;
@@ -82,7 +83,8 @@ export class PublicNotification {
82
83
  console.log(oldValue);
83
84
  if (JSON.stringify(newValue) !== JSON.stringify(oldValue)) {
84
85
  console.log("Emit event from parent");
85
- this.searchConfigurationChange.emit(newValue);
86
+ this._searchConfiguration = Object.assign({}, newValue);
87
+ this.searchConfigurationChange.emit(this._searchConfiguration);
86
88
  }
87
89
  }
88
90
  /**
@@ -117,6 +119,12 @@ export class PublicNotification {
117
119
  this._updateLabel(event, "distance");
118
120
  this._distance = event.detail.newValue;
119
121
  }
122
+ /**
123
+ * Handle changes when selection is loading
124
+ */
125
+ selectionLoadingChange(event) {
126
+ this._selectionLoading = event.detail;
127
+ }
120
128
  /**
121
129
  * Handle changes to the selection sets
122
130
  */
@@ -152,8 +160,7 @@ export class PublicNotification {
152
160
  * Renders the component.
153
161
  */
154
162
  render() {
155
- const hasSelections = this._selectionSets.length > 0;
156
- return (h(Host, null, h("calcite-shell", null, h("calcite-action-bar", { class: "border-bottom-1 action-bar-size", "expand-disabled": true, layout: "horizontal", slot: "header" }, this._getActionGroup("list-check", false, EPageType.LIST, this._translations.myLists), this.showRefineSelection ? this._getActionGroup("test-data", !hasSelections, EPageType.REFINE, this._translations.refineSelection) : undefined, this._getActionGroup("file-pdf", !hasSelections, EPageType.PDF, this._translations.downloadPDF), this._getActionGroup("file-csv", !hasSelections, EPageType.CSV, this._translations.downloadCSV)), this._getPage(this._pageType))));
163
+ return (h(Host, null, h("calcite-shell", null, h("calcite-action-bar", { class: "border-bottom-1 action-bar-size", "expand-disabled": true, layout: "horizontal", slot: "header" }, this._getActionGroup("list-check", EPageType.LIST, this._translations.myLists), this.showRefineSelection ? this._getActionGroup("test-data", EPageType.REFINE, this._translations.refineSelection) : undefined, this._getActionGroup("file-pdf", EPageType.PDF, this._translations.downloadPDF), this._getActionGroup("file-csv", EPageType.CSV, this._translations.downloadCSV)), this._getPage(this._pageType))));
157
164
  }
158
165
  //--------------------------------------------------------------------------
159
166
  //
@@ -183,9 +190,9 @@ export class PublicNotification {
183
190
  *
184
191
  * @protected
185
192
  */
186
- _getActionGroup(icon, disabled, pageType, tip) {
193
+ _getActionGroup(icon, pageType, tip) {
187
194
  const groupClass = this.showRefineSelection ? "action-center w-1-4" : "action-center w-1-3";
188
- return (h("calcite-action-group", { class: groupClass, layout: "horizontal" }, h("calcite-action", { active: this._pageType === pageType, alignment: "center", class: "width-full height-full", compact: false, disabled: disabled, icon: icon, id: icon, onClick: () => { this._setPageType(pageType); }, text: "" }), h("calcite-tooltip", { label: "", placement: "bottom", "reference-element": icon }, h("span", null, tip))));
195
+ return (h("calcite-action-group", { class: groupClass, layout: "horizontal" }, h("calcite-action", { active: this._pageType === pageType, alignment: "center", class: "width-full height-full", compact: false, icon: icon, id: icon, onClick: () => { this._setPageType(pageType); }, text: "" }), h("calcite-tooltip", { label: "", placement: "bottom", "reference-element": icon }, h("span", null, tip))));
189
196
  }
190
197
  /**
191
198
  * Navigate to the defined page type
@@ -299,6 +306,16 @@ export class PublicNotification {
299
306
  this._layerSelectionChangeEvt.detail[0] : "";
300
307
  await this._updateAddresseeLayer(id);
301
308
  }
309
+ /**
310
+ * Check if any selection sets exist.
311
+ *
312
+ * @returns true if selection sets exist
313
+ *
314
+ * @protected
315
+ */
316
+ _hasSelections() {
317
+ return this._selectionSets.length > 0;
318
+ }
302
319
  /**
303
320
  * Create the Select page that shows the selection workflows
304
321
  *
@@ -315,8 +332,13 @@ export class PublicNotification {
315
332
  const noticeText = this._selectionWorkflowType === EWorkflowType.SELECT ? selectTip :
316
333
  this._selectionWorkflowType === EWorkflowType.SKETCH ? sketchTip : searchTip;
317
334
  const nameLabelClass = this.customLabelEnabled ? "" : "display-none";
318
- return (h("calcite-panel", null, this._getLabel(this._translations.stepTwoFull.replace("{{layer}}", (_a = this.addresseeLayer) === null || _a === void 0 ? void 0 : _a.layer.title)), this._getNotice(noticeText), h("div", { class: "padding-top-sides-1" }, h("map-select-tools", { bufferColor: this.bufferColor, bufferOutlineColor: this.bufferOutlineColor, class: "font-bold", defaultBufferDistance: this.defaultBufferDistance, defaultBufferUnit: this.defaultBufferUnit, enabledLayerIds: this.selectionLayerIds, isUpdate: !!this._activeSelection, mapView: this.mapView, onSelectionSetChange: (evt) => this._updateForSelection(evt), onWorkflowTypeChange: (evt) => this._updateForWorkflowType(evt), ref: (el) => { this._selectTools = el; }, searchConfiguration: this.searchConfiguration, selectLayerView: this.addresseeLayer, selectionSet: this._activeSelection, showBufferTools: this.showSearchSettings })), h("div", { class: "padding-sides-1 padding-bottom-1", style: { "align-items": "end", "display": "flex" } }, h("calcite-icon", { class: "info-blue padding-end-1-2", icon: "feature-layer", scale: "s" }), h("calcite-input-message", { active: true, class: "info-blue", scale: "m" }, this.noResultText && this._numSelected === 0 ? this.noResultText :
319
- this._translations.selectedAddresses.replace("{{n}}", this._numSelected.toString()).replace("{{layer}}", ((_b = this.addresseeLayer) === null || _b === void 0 ? void 0 : _b.layer.title) || ""))), h("div", { class: "padding-sides-1 " + nameLabelClass }, h("calcite-label", { class: "font-bold" }, "List name", h("calcite-input", { onInput: () => {
335
+ // TODO find out if ... is appropriate for other languages
336
+ const locale = getComponentClosestLanguage(this.el);
337
+ const selectionLoading = locale && locale === "en" ?
338
+ `${this._translations.selectionLoading}...` : this._translations.selectionLoading;
339
+ return (h("calcite-panel", null, this._getLabel(this._translations.stepTwoFull.replace("{{layer}}", (_a = this.addresseeLayer) === null || _a === void 0 ? void 0 : _a.layer.title)), this._getNotice(noticeText), h("div", { class: "padding-top-sides-1" }, h("map-select-tools", { bufferColor: this.bufferColor, bufferOutlineColor: this.bufferOutlineColor, class: "font-bold", defaultBufferDistance: this.defaultBufferDistance, defaultBufferUnit: this.defaultBufferUnit, enabledLayerIds: this.selectionLayerIds, isUpdate: !!this._activeSelection, mapView: this.mapView, onSelectionSetChange: (evt) => this._updateForSelection(evt), onWorkflowTypeChange: (evt) => this._updateForWorkflowType(evt), ref: (el) => { this._selectTools = el; }, searchConfiguration: this._searchConfiguration, selectLayerView: this.addresseeLayer, selectionSet: this._activeSelection, showBufferTools: this.showSearchSettings })), h("div", { class: "padding-sides-1 padding-bottom-1", style: { "align-items": "end", "display": "flex" } }, this._selectionLoading ? (h("div", null, h("calcite-loader", { active: true, class: "info-blue", inline: true, label: selectionLoading, scale: "m", type: "indeterminate" }))) : (h("calcite-icon", { class: "info-blue padding-end-1-2", icon: "feature-layer", scale: "s" })), h("calcite-input-message", { active: true, class: "info-blue", scale: "m" }, this._selectionLoading ? selectionLoading :
340
+ this.noResultText && this._numSelected === 0 ? this.noResultText :
341
+ this._translations.selectedAddresses.replace("{{n}}", this._numSelected.toString()).replace("{{layer}}", ((_b = this.addresseeLayer) === null || _b === void 0 ? void 0 : _b.layer.title) || ""))), h("div", { class: "padding-sides-1 " + nameLabelClass }, h("calcite-label", { class: "font-bold" }, "List name", h("calcite-input", { onInput: () => {
320
342
  this.labelChange.emit(this._labelName.value);
321
343
  }, placeholder: "Insert label here...", ref: (el) => { this._labelName = el; }, value: this._customLabel || "" }))), this._getPageNavButtons(this._translations.done, this._numSelected === 0, () => { void this._saveSelection(); }, this._translations.cancel, false, () => { void this._home(); })));
322
344
  }
@@ -327,7 +349,9 @@ export class PublicNotification {
327
349
  * @protected
328
350
  */
329
351
  _getRefinePage() {
330
- return (h("calcite-panel", null, this._getLabel(this._translations.refineSelection), this._getNotice(this._translations.refineTip, "padding-sides-1"), h("refine-selection", { addresseeLayer: this.addresseeLayer, enabledLayerIds: this.selectionLayerIds, mapView: this.mapView, selectionSets: this._selectionSets })));
352
+ const hasSelections = this._hasSelections();
353
+ return (h("calcite-panel", null, this._getLabel(this._translations.refineSelection), hasSelections ? (h("div", null, this._getNotice(this._translations.refineTip, "padding-sides-1"), h("refine-selection", { addresseeLayer: this.addresseeLayer, enabledLayerIds: this.selectionLayerIds, mapView: this.mapView, selectionSets: this._selectionSets }))) :
354
+ this._getNotice(this._translations.refineTipNoSelections, "padding-sides-1")));
331
355
  }
332
356
  /**
333
357
  * Create the PDF download page that shows the download options
@@ -358,7 +382,8 @@ export class PublicNotification {
358
382
  */
359
383
  _getDownloadPage(type) {
360
384
  const isPdf = type === EExportType.PDF;
361
- return (h("calcite-panel", null, h("div", null, h("div", { class: "padding-top-sides-1" }, h("calcite-label", { class: "font-bold" }, isPdf ? this._translations.downloadPDF : this._translations.downloadCSV), h("calcite-label", null, this._translations.notifications)), this._getSelectionLists(), h("div", { class: "margin-side-1 padding-top-1 border-bottom" }), h("div", { class: "padding-top-sides-1" }, h("calcite-label", { layout: "inline" }, h("calcite-checkbox", { disabled: !this._downloadActive, ref: (el) => { this._removeDuplicates = el; } }), this._translations.removeDuplicate)), h("div", { class: isPdf ? "" : "display-none" }, this._getLabel(this._translations.selectPDFLabelOption, false), h("div", { class: "padding-sides-1" }, h("pdf-download", { disabled: !this._downloadActive, layerView: this.addresseeLayer, ref: (el) => { this._downloadTools = el; } }))), h("div", { class: "padding-1 display-flex" }, h("calcite-button", { disabled: !this._downloadActive, onClick: isPdf ? () => this._downloadPDF() : () => this._downloadCSV(), width: "full" }, isPdf ? this._translations.downloadPDF : this._translations.downloadCSV)))));
385
+ const hasSelections = this._hasSelections();
386
+ return (h("calcite-panel", null, h("div", null, h("div", { class: "padding-top-sides-1" }, h("calcite-label", { class: "font-bold" }, isPdf ? this._translations.downloadPDF : this._translations.downloadCSV)), hasSelections ? (h("div", null, h("calcite-label", null, this._translations.notifications), this._getSelectionLists(), h("div", { class: "margin-side-1 padding-top-1 border-bottom" }), h("div", { class: "padding-top-sides-1" }, h("calcite-label", { layout: "inline" }, h("calcite-checkbox", { disabled: !this._downloadActive, ref: (el) => { this._removeDuplicates = el; } }), this._translations.removeDuplicate)), h("div", { class: isPdf ? "" : "display-none" }, this._getLabel(this._translations.selectPDFLabelOption, false), h("div", { class: "padding-sides-1" }, h("pdf-download", { disabled: !this._downloadActive, layerView: this.addresseeLayer, ref: (el) => { this._downloadTools = el; } }))), h("div", { class: "padding-1 display-flex" }, h("calcite-button", { disabled: !this._downloadActive, onClick: isPdf ? () => this._downloadPDF() : () => this._downloadCSV(), width: "full" }, isPdf ? this._translations.downloadPDF : this._translations.downloadCSV)))) : (this._getNotice(this._translations.downloadNoLists, "padding-sides-1 padding-bottom-1")))));
362
387
  }
363
388
  /**
364
389
  * Create the stacked navigation buttons for a page
@@ -441,7 +466,8 @@ export class PublicNotification {
441
466
  */
442
467
  _downloadPDF() {
443
468
  const ids = utils.getSelectionIds(this._getDownloadSelectionSets());
444
- void this._downloadTools.downloadPDF(ids, this._removeDuplicates.checked);
469
+ const selectionSetNames = this._selectionSets.map(set => set.label);
470
+ void this._downloadTools.downloadPDF(selectionSetNames, ids, this._removeDuplicates.checked);
445
471
  }
446
472
  /**
447
473
  * Download all selection sets as CSV
@@ -450,7 +476,8 @@ export class PublicNotification {
450
476
  */
451
477
  _downloadCSV() {
452
478
  const ids = utils.getSelectionIds(this._getDownloadSelectionSets());
453
- void this._downloadTools.downloadCSV(ids, this._removeDuplicates.checked);
479
+ const selectionSetNames = this._selectionSets.map(set => set.label);
480
+ void this._downloadTools.downloadCSV(selectionSetNames, ids, this._removeDuplicates.checked);
454
481
  }
455
482
  /**
456
483
  * Get all enabled selection sets
@@ -976,6 +1003,7 @@ export class PublicNotification {
976
1003
  "_numSelected": {},
977
1004
  "_pageType": {},
978
1005
  "_saveEnabled": {},
1006
+ "_selectionLoading": {},
979
1007
  "_selectionSets": {},
980
1008
  "_sketchType": {},
981
1009
  "_selectionWorkflowType": {},
@@ -1044,6 +1072,12 @@ export class PublicNotification {
1044
1072
  "target": "window",
1045
1073
  "capture": false,
1046
1074
  "passive": false
1075
+ }, {
1076
+ "name": "selectionLoadingChange",
1077
+ "method": "selectionLoadingChange",
1078
+ "target": "window",
1079
+ "capture": false,
1080
+ "passive": false
1047
1081
  }, {
1048
1082
  "name": "selectionSetsChanged",
1049
1083
  "method": "selectionSetsChanged",
@@ -300,11 +300,13 @@ export class RefineSelectionTools {
300
300
  * @protected
301
301
  */
302
302
  async _selectFeatures(geom) {
303
+ this.selectionLoadingChange.emit(true);
303
304
  const queryFeaturePromises = this.layerViews.map(layerView => {
304
305
  this._featuresCollection[layerView.layer.id] = [];
305
306
  return queryFeaturesByGeometry(0, layerView.layer, geom, this._featuresCollection);
306
307
  });
307
308
  return Promise.all(queryFeaturePromises).then(async (response) => {
309
+ this.selectionLoadingChange.emit(false);
308
310
  let graphics = [];
309
311
  response.forEach(r => {
310
312
  Object.keys(r).forEach(k => {
@@ -660,6 +662,21 @@ export class RefineSelectionTools {
660
662
  }
661
663
  static get events() {
662
664
  return [{
665
+ "method": "selectionLoadingChange",
666
+ "name": "selectionLoadingChange",
667
+ "bubbles": true,
668
+ "cancelable": true,
669
+ "composed": true,
670
+ "docs": {
671
+ "tags": [],
672
+ "text": "Emitted on demand when selection starts or ends."
673
+ },
674
+ "complexType": {
675
+ "original": "boolean",
676
+ "resolved": "boolean",
677
+ "references": {}
678
+ }
679
+ }, {
663
680
  "method": "refineSelectionGraphicsChange",
664
681
  "name": "refineSelectionGraphicsChange",
665
682
  "bubbles": true,
@@ -29,6 +29,7 @@ export { ILabel } from "./pdfUtils";
29
29
  /**
30
30
  * Downloads csv of mailing labels for the provided list of ids
31
31
  *
32
+ * @param selectionSetNames Names of the selection sets used to provide ids
32
33
  * @param layer Layer providing features and attributes for download
33
34
  * @param ids List of ids to download
34
35
  * @param formatUsingLayerPopup When true, the layer's popup is used to choose attributes for each column; when false,
@@ -37,7 +38,8 @@ export { ILabel } from "./pdfUtils";
37
38
  * @param addColumnTitle Indicates if column headings should be included in output
38
39
  * @returns Promise resolving when function is done
39
40
  */
40
- export async function downloadCSV(layer, ids, formatUsingLayerPopup, removeDuplicates = false, addColumnTitle = false) {
41
+ export async function downloadCSV(selectionSetNames, layer, ids, formatUsingLayerPopup, removeDuplicates = false, addColumnTitle = false) {
42
+ console.log("downloadCSV using selectionSetNames " + JSON.stringify(selectionSetNames)); //???
41
43
  const labels = await _prepareLabels(layer, ids, removeDuplicates, formatUsingLayerPopup, addColumnTitle);
42
44
  exportCSV(labels);
43
45
  return Promise.resolve();
@@ -45,13 +47,15 @@ export async function downloadCSV(layer, ids, formatUsingLayerPopup, removeDupli
45
47
  /**
46
48
  * Downloads csv of mailing labels for the provided list of ids
47
49
  *
50
+ * @param selectionSetNames Names of the selection sets used to provide ids
48
51
  * @param layer Layer providing features and attributes for download
49
52
  * @param ids List of ids to download
50
53
  * @param removeDuplicates When true a single label is generated when multiple featues have a shared address value
51
54
  * @param labelPageDescription Provides PDF page layout info
52
55
  * @returns Promise resolving when function is done
53
56
  */
54
- export async function downloadPDF(layer, ids, removeDuplicates, labelPageDescription) {
57
+ export async function downloadPDF(selectionSetNames, layer, ids, removeDuplicates, labelPageDescription) {
58
+ console.log("downloadPDF using selectionSetNames " + JSON.stringify(selectionSetNames)); //???
55
59
  const labels = await _prepareLabels(layer, ids, removeDuplicates);
56
60
  exportPDF(labels, labelPageDescription);
57
61
  return Promise.resolve();
@@ -62,13 +66,14 @@ export async function downloadPDF(layer, ids, removeDuplicates, labelPageDescrip
62
66
  * Converts a set of fieldInfos into template lines.
63
67
  *
64
68
  * @param fieldInfos Layer's fieldInfos structure
69
+ * @param bypassFieldVisiblity Indicates if the configured fieldInfo visibility property should be ignored
65
70
  * @return Label spec
66
71
  */
67
- function _convertPopupFieldsToLabelSpec(fieldInfos) {
72
+ function _convertPopupFieldsToLabelSpec(fieldInfos, bypassFieldVisiblity = false) {
68
73
  const labelSpec = [];
69
74
  // Every visible attribute is used
70
75
  fieldInfos.forEach(fieldInfo => {
71
- if (fieldInfo.visible) {
76
+ if (fieldInfo.visible || bypassFieldVisiblity) {
72
77
  labelSpec.push(`{${fieldInfo.fieldName}}`);
73
78
  }
74
79
  });
@@ -100,6 +105,49 @@ function _convertPopupTextToLabelSpec(popupInfo) {
100
105
  return labelSpec;
101
106
  }
102
107
  ;
108
+ /**
109
+ * Extracts Arcade expressions from the lines of a label format and creates an Arcade executor for each
110
+ * referenced expression name.
111
+ *
112
+ * @param labelFormat Label to examine
113
+ * @param layer Layer from which to fetch features
114
+ * @return Promise resolving to a set of executors keyed using the expression name
115
+ */
116
+ async function _createArcadeExecutors(labelFormat, layer) {
117
+ const arcadeExecutors = {};
118
+ // Are any Arcade expressions in the layer?
119
+ if (!Array.isArray(layer.popupTemplate.expressionInfos) || layer.popupTemplate.expressionInfos.length === 0) {
120
+ return Promise.resolve(arcadeExecutors);
121
+ }
122
+ // Are there any Arcade expressions in the label format?
123
+ const arcadeExpressionRegExp = /\{expression\/\w+\}/g;
124
+ const arcadeExpressionsMatches = labelFormat.join("|").match(arcadeExpressionRegExp);
125
+ if (!arcadeExpressionsMatches) {
126
+ return Promise.resolve(arcadeExecutors);
127
+ }
128
+ // Generate an Arcade executor for each match
129
+ const [arcade] = await loadModules(["esri/arcade"]);
130
+ const labelingProfile = arcade.createArcadeProfile("popup");
131
+ const createArcadeExecutorPromises = {};
132
+ arcadeExpressionsMatches.forEach((match) => {
133
+ const expressionName = match.substring(match.indexOf("/") + 1, match.length - 1);
134
+ (layer.popupTemplate.expressionInfos || []).forEach(expressionInfo => {
135
+ if (expressionInfo.name === expressionName) {
136
+ createArcadeExecutorPromises[expressionName] =
137
+ arcade.createArcadeExecutor(expressionInfo.expression, labelingProfile);
138
+ }
139
+ });
140
+ });
141
+ const promises = Object.values(createArcadeExecutorPromises);
142
+ return Promise.all(promises)
143
+ .then(executors => {
144
+ const expressionNames = Object.keys(createArcadeExecutorPromises);
145
+ for (let i = 0; i < expressionNames.length; ++i) {
146
+ arcadeExecutors[expressionNames[i]] = executors[i].valueOf();
147
+ }
148
+ return arcadeExecutors;
149
+ });
150
+ }
103
151
  /**
104
152
  * Creates labels from items.
105
153
  *
@@ -113,33 +161,57 @@ function _convertPopupTextToLabelSpec(popupInfo) {
113
161
  */
114
162
  async function _prepareLabels(layer, ids, removeDuplicates = true, formatUsingLayerPopup = true, includeHeaderNames = false) {
115
163
  var _a, _b, _c, _d;
116
- const [intl] = await loadModules([
117
- "esri/intl"
118
- ]);
119
- // Get the attributes of the features to export
164
+ const [intl] = await loadModules(["esri/intl"]);
165
+ // Get the features to export
120
166
  const featureSet = await queryFeaturesByID(ids, layer);
121
- const featuresAttrs = featureSet.features.map(f => f.attributes);
122
167
  // Get the label formatting, if any
123
168
  let labelFormat;
169
+ let arcadeExecutors = {};
124
170
  if (layer.popupEnabled) {
125
171
  // What data fields are used in the labels?
126
172
  // Example labelFormat: ['{NAME}', '{STREET}', '{CITY}, {STATE} {ZIP}']
127
173
  if (formatUsingLayerPopup && ((_b = (_a = layer.popupTemplate) === null || _a === void 0 ? void 0 : _a.content[0]) === null || _b === void 0 ? void 0 : _b.type) === "fields") {
128
174
  labelFormat = _convertPopupFieldsToLabelSpec(layer.popupTemplate.fieldInfos);
175
+ // If popup is configured with "no attribute information", then no fields will visible
176
+ if (labelFormat.length === 0) {
177
+ // Can we use the popup title?
178
+ // eslint-disable-next-line unicorn/prefer-ternary
179
+ if (typeof layer.popupTemplate.title === "string") {
180
+ labelFormat = [layer.popupTemplate.title];
181
+ // Otherwise revert to using attributes
182
+ }
183
+ else {
184
+ labelFormat = _convertPopupFieldsToLabelSpec(layer.popupTemplate.fieldInfos, true);
185
+ }
186
+ }
129
187
  }
130
188
  else if (formatUsingLayerPopup && ((_d = (_c = layer.popupTemplate) === null || _c === void 0 ? void 0 : _c.content[0]) === null || _d === void 0 ? void 0 : _d.type) === "text") {
131
189
  labelFormat = _convertPopupTextToLabelSpec(layer.popupTemplate.content[0].text);
190
+ // Do we need any Arcade executors?
191
+ arcadeExecutors = await _createArcadeExecutors(labelFormat, layer);
132
192
  }
133
193
  }
134
194
  // Apply the label format
135
195
  let labels;
136
196
  // eslint-disable-next-line unicorn/prefer-ternary
137
197
  if (labelFormat) {
198
+ const arcadeExpressionRegExp = /\{expression\/\w+\}/g;
138
199
  // Convert attributes into an array of labels
139
- labels = featuresAttrs.map(featureAttributes => {
200
+ labels = featureSet.features.map(feature => {
140
201
  const label = [];
141
202
  labelFormat.forEach(labelLineTemplate => {
142
- const labelLine = intl.substitute(labelLineTemplate, featureAttributes).trim();
203
+ let labelLine = labelLineTemplate;
204
+ // Replace Arcade expressions
205
+ const arcadeExpressionsMatches = labelLine.match(arcadeExpressionRegExp);
206
+ if (arcadeExpressionsMatches) {
207
+ arcadeExpressionsMatches.forEach((match) => {
208
+ const expressionName = match.substring(match.indexOf("/") + 1, match.length - 1);
209
+ const replacement = arcadeExecutors[expressionName].execute({ "$feature": feature });
210
+ labelLine = labelLine.replace(match, replacement);
211
+ });
212
+ }
213
+ // Replace fields; must be done after Arcade check because `substitute` will discard Arcade expressions!
214
+ labelLine = intl.substitute(labelLine, feature.attributes).trim();
143
215
  if (labelLine.length > 0) {
144
216
  label.push(labelLine);
145
217
  }
@@ -151,8 +223,8 @@ async function _prepareLabels(layer, ids, removeDuplicates = true, formatUsingLa
151
223
  }
152
224
  else {
153
225
  // Export all attributes
154
- labels = featuresAttrs.map(featureAttributes => {
155
- return Object.values(featureAttributes).map(attribute => `${attribute}`);
226
+ labels = featureSet.features.map(feature => {
227
+ return Object.values(feature.attributes).map(attribute => `${attribute}`);
156
228
  });
157
229
  }
158
230
  // Remove duplicates
@@ -168,7 +240,8 @@ async function _prepareLabels(layer, ids, removeDuplicates = true, formatUsingLa
168
240
  headerNames = labelFormat.map(labelFormatLine => labelFormatLine.replace(/\{/g, "").replace(/\}/g, ""));
169
241
  }
170
242
  else {
171
- Object.keys(featuresAttrs[0]).forEach(k => {
243
+ const featuresAttrs = featureSet.features[0].attributes;
244
+ Object.keys(featuresAttrs).forEach(k => {
172
245
  if (featuresAttrs[0].hasOwnProperty(k)) {
173
246
  headerNames.push(k);
174
247
  }
@@ -23,12 +23,21 @@ import { queryFeaturesByID } from "./queryUtils";
23
23
 
24
24
  export { ILabel } from "./pdfUtils";
25
25
 
26
+ interface IArcadeExecutors {
27
+ [expressionName: string]: __esri.ArcadeExecutor;
28
+ }
29
+
30
+ interface IArcadeExecutorPromises {
31
+ [expressionName: string]: Promise<__esri.ArcadeExecutor>;
32
+ }
33
+
26
34
  //#endregion
27
35
  //#region Public functions
28
36
 
29
37
  /**
30
38
  * Downloads csv of mailing labels for the provided list of ids
31
39
  *
40
+ * @param selectionSetNames Names of the selection sets used to provide ids
32
41
  * @param layer Layer providing features and attributes for download
33
42
  * @param ids List of ids to download
34
43
  * @param formatUsingLayerPopup When true, the layer's popup is used to choose attributes for each column; when false,
@@ -38,12 +47,14 @@ export { ILabel } from "./pdfUtils";
38
47
  * @returns Promise resolving when function is done
39
48
  */
40
49
  export async function downloadCSV(
50
+ selectionSetNames: string[],
41
51
  layer: __esri.FeatureLayer,
42
52
  ids: number[],
43
53
  formatUsingLayerPopup: boolean,
44
54
  removeDuplicates = false,
45
55
  addColumnTitle = false
46
56
  ): Promise<void> {
57
+ console.log("downloadCSV using selectionSetNames " + JSON.stringify(selectionSetNames));//???
47
58
  const labels = await _prepareLabels(layer, ids, removeDuplicates, formatUsingLayerPopup, addColumnTitle);
48
59
 
49
60
  exportCSV(labels);
@@ -54,6 +65,7 @@ export async function downloadCSV(
54
65
  /**
55
66
  * Downloads csv of mailing labels for the provided list of ids
56
67
  *
68
+ * @param selectionSetNames Names of the selection sets used to provide ids
57
69
  * @param layer Layer providing features and attributes for download
58
70
  * @param ids List of ids to download
59
71
  * @param removeDuplicates When true a single label is generated when multiple featues have a shared address value
@@ -61,11 +73,13 @@ export async function downloadCSV(
61
73
  * @returns Promise resolving when function is done
62
74
  */
63
75
  export async function downloadPDF(
76
+ selectionSetNames: string[],
64
77
  layer: __esri.FeatureLayer,
65
78
  ids: number[],
66
79
  removeDuplicates: boolean,
67
80
  labelPageDescription: ILabel
68
81
  ): Promise<void> {
82
+ console.log("downloadPDF using selectionSetNames " + JSON.stringify(selectionSetNames));//???
69
83
  const labels = await _prepareLabels(layer, ids, removeDuplicates);
70
84
 
71
85
  exportPDF(labels, labelPageDescription);
@@ -80,17 +94,19 @@ export async function downloadPDF(
80
94
  * Converts a set of fieldInfos into template lines.
81
95
  *
82
96
  * @param fieldInfos Layer's fieldInfos structure
97
+ * @param bypassFieldVisiblity Indicates if the configured fieldInfo visibility property should be ignored
83
98
  * @return Label spec
84
99
  */
85
100
  function _convertPopupFieldsToLabelSpec(
86
- fieldInfos: __esri.FieldInfo[]
101
+ fieldInfos: __esri.FieldInfo[],
102
+ bypassFieldVisiblity = false
87
103
  ): string[] {
88
104
  const labelSpec: string[] = [];
89
105
 
90
106
  // Every visible attribute is used
91
107
  fieldInfos.forEach(
92
108
  fieldInfo => {
93
- if (fieldInfo.visible) {
109
+ if (fieldInfo.visible || bypassFieldVisiblity) {
94
110
  labelSpec.push(`{${fieldInfo.fieldName}}`);
95
111
  }
96
112
  }
@@ -129,6 +145,67 @@ function _convertPopupTextToLabelSpec(
129
145
  return labelSpec;
130
146
  };
131
147
 
148
+ /**
149
+ * Extracts Arcade expressions from the lines of a label format and creates an Arcade executor for each
150
+ * referenced expression name.
151
+ *
152
+ * @param labelFormat Label to examine
153
+ * @param layer Layer from which to fetch features
154
+ * @return Promise resolving to a set of executors keyed using the expression name
155
+ */
156
+ async function _createArcadeExecutors(
157
+ labelFormat: string[],
158
+ layer: __esri.FeatureLayer
159
+ ): Promise<IArcadeExecutors> {
160
+ const arcadeExecutors: IArcadeExecutors = {};
161
+
162
+ // Are any Arcade expressions in the layer?
163
+ if (!Array.isArray(layer.popupTemplate.expressionInfos) || layer.popupTemplate.expressionInfos.length === 0) {
164
+ return Promise.resolve(arcadeExecutors);
165
+ }
166
+
167
+ // Are there any Arcade expressions in the label format?
168
+ const arcadeExpressionRegExp = /\{expression\/\w+\}/g;
169
+ const arcadeExpressionsMatches = labelFormat.join("|").match(arcadeExpressionRegExp);
170
+ if (!arcadeExpressionsMatches) {
171
+ return Promise.resolve(arcadeExecutors);
172
+ }
173
+
174
+ // Generate an Arcade executor for each match
175
+ const [arcade] = await loadModules(["esri/arcade"]);
176
+ const labelingProfile: __esri.Profile = arcade.createArcadeProfile("popup");
177
+
178
+ const createArcadeExecutorPromises: IArcadeExecutorPromises = {};
179
+ arcadeExpressionsMatches.forEach(
180
+ (match: string) => {
181
+ const expressionName = match.substring(match.indexOf("/") + 1, match.length - 1);
182
+
183
+ (layer.popupTemplate.expressionInfos || []).forEach(
184
+ expressionInfo => {
185
+ if (expressionInfo.name === expressionName) {
186
+ createArcadeExecutorPromises[expressionName] =
187
+ arcade.createArcadeExecutor(expressionInfo.expression, labelingProfile);
188
+ }
189
+ }
190
+ );
191
+ }
192
+ );
193
+
194
+ const promises = Object.values(createArcadeExecutorPromises);
195
+ return Promise.all(promises)
196
+ .then(
197
+ executors => {
198
+ const expressionNames = Object.keys(createArcadeExecutorPromises);
199
+
200
+ for (let i = 0; i < expressionNames.length; ++i) {
201
+ arcadeExecutors[expressionNames[i]] = executors[i].valueOf() as __esri.ArcadeExecutor;
202
+ }
203
+
204
+ return arcadeExecutors;
205
+ }
206
+ );
207
+ }
208
+
132
209
  /**
133
210
  * Creates labels from items.
134
211
  *
@@ -147,25 +224,38 @@ async function _prepareLabels(
147
224
  formatUsingLayerPopup = true,
148
225
  includeHeaderNames = false
149
226
  ): Promise<string[][]> {
150
- const [intl] = await loadModules([
151
- "esri/intl"
152
- ]);
227
+ const [intl] = await loadModules(["esri/intl"]);
153
228
 
154
- // Get the attributes of the features to export
229
+ // Get the features to export
155
230
  const featureSet = await queryFeaturesByID(ids, layer);
156
- const featuresAttrs = featureSet.features.map(f => f.attributes);
157
231
 
158
232
  // Get the label formatting, if any
159
233
  let labelFormat: string[];
234
+ let arcadeExecutors: IArcadeExecutors = {};
160
235
  if (layer.popupEnabled) {
161
236
  // What data fields are used in the labels?
162
237
  // Example labelFormat: ['{NAME}', '{STREET}', '{CITY}, {STATE} {ZIP}']
163
238
  if (formatUsingLayerPopup && layer.popupTemplate?.content[0]?.type === "fields") {
164
239
  labelFormat = _convertPopupFieldsToLabelSpec(layer.popupTemplate.fieldInfos);
165
240
 
241
+ // If popup is configured with "no attribute information", then no fields will visible
242
+ if (labelFormat.length === 0) {
243
+ // Can we use the popup title?
244
+ // eslint-disable-next-line unicorn/prefer-ternary
245
+ if (typeof layer.popupTemplate.title === "string") {
246
+ labelFormat = [layer.popupTemplate.title];
247
+
248
+ // Otherwise revert to using attributes
249
+ } else {
250
+ labelFormat = _convertPopupFieldsToLabelSpec(layer.popupTemplate.fieldInfos, true);
251
+ }
252
+ }
253
+
166
254
  } else if (formatUsingLayerPopup && layer.popupTemplate?.content[0]?.type === "text") {
167
255
  labelFormat = _convertPopupTextToLabelSpec(layer.popupTemplate.content[0].text);
168
256
 
257
+ // Do we need any Arcade executors?
258
+ arcadeExecutors = await _createArcadeExecutors(labelFormat, layer);
169
259
  }
170
260
  }
171
261
 
@@ -173,13 +263,31 @@ async function _prepareLabels(
173
263
  let labels: string[][];
174
264
  // eslint-disable-next-line unicorn/prefer-ternary
175
265
  if (labelFormat) {
266
+ const arcadeExpressionRegExp = /\{expression\/\w+\}/g;
267
+
176
268
  // Convert attributes into an array of labels
177
- labels = featuresAttrs.map(
178
- featureAttributes => {
269
+ labels = featureSet.features.map(
270
+ feature => {
179
271
  const label: string[] = [];
180
272
  labelFormat.forEach(
181
273
  labelLineTemplate => {
182
- const labelLine = intl.substitute(labelLineTemplate, featureAttributes).trim();
274
+ let labelLine = labelLineTemplate;
275
+
276
+ // Replace Arcade expressions
277
+ const arcadeExpressionsMatches = labelLine.match(arcadeExpressionRegExp);
278
+ if (arcadeExpressionsMatches) {
279
+ arcadeExpressionsMatches.forEach(
280
+ (match: string) => {
281
+ const expressionName = match.substring(match.indexOf("/") + 1, match.length - 1);
282
+ const replacement = arcadeExecutors[expressionName].execute({"$feature": feature});
283
+ labelLine = labelLine.replace(match, replacement);
284
+ }
285
+ )
286
+ }
287
+
288
+ // Replace fields; must be done after Arcade check because `substitute` will discard Arcade expressions!
289
+ labelLine = intl.substitute(labelLine, feature.attributes).trim();
290
+
183
291
  if (labelLine.length > 0) {
184
292
  label.push(labelLine);
185
293
  }
@@ -193,9 +301,9 @@ async function _prepareLabels(
193
301
 
194
302
  } else {
195
303
  // Export all attributes
196
- labels = featuresAttrs.map(
197
- featureAttributes => {
198
- return Object.values(featureAttributes).map(
304
+ labels = featureSet.features.map(
305
+ feature => {
306
+ return Object.values(feature.attributes).map(
199
307
  attribute => `${attribute}`
200
308
  );
201
309
  }
@@ -219,7 +327,8 @@ async function _prepareLabels(
219
327
  headerNames = labelFormat.map(labelFormatLine => labelFormatLine.replace(/\{/g, "").replace(/\}/g, ""));
220
328
 
221
329
  } else {
222
- Object.keys(featuresAttrs[0]).forEach(k => {
330
+ const featuresAttrs = featureSet.features[0].attributes;
331
+ Object.keys(featuresAttrs).forEach(k => {
223
332
  if (featuresAttrs[0].hasOwnProperty(k)) {
224
333
  headerNames.push(k);
225
334
  }
@@ -21,7 +21,7 @@
21
21
  // https://medium.com/stencil-tricks/implementing-internationalisation-i18n-with-stencil-5e6559554117
22
22
  import { languageMap } from "./languageUtil";
23
23
  import { getAssetPath } from "@stencil/core";
24
- function getComponentClosestLanguage(element) {
24
+ export function getComponentClosestLanguage(element) {
25
25
  var _a, _b, _c;
26
26
  const closestElement = (_a = (element.closest("[lang]"))) !== null && _a !== void 0 ? _a : (_c = (_b = element.shadowRoot) === null || _b === void 0 ? void 0 : _b.ownerDocument) === null || _c === void 0 ? void 0 : _c.documentElement;
27
27
  // language set by the calling application or browser. defaults to english.
@@ -18,7 +18,7 @@
18
18
  import { languageMap } from "./languageUtil";
19
19
  import { getAssetPath } from "@stencil/core";
20
20
 
21
- function getComponentClosestLanguage(element: HTMLElement): string | undefined {
21
+ export function getComponentClosestLanguage(element: HTMLElement): string | undefined {
22
22
  const closestElement = (element.closest("[lang]") ) ?? element.shadowRoot?.ownerDocument?.documentElement as any;
23
23
  // language set by the calling application or browser. defaults to english.
24
24
  const lang = (closestElement?.lang || navigator?.language || "en").toLowerCase() ;