@esri/solutions-components 0.5.6 → 0.5.8

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 (47) hide show
  1. package/dist/assets/t9n/map-select-tools/resources.json +2 -2
  2. package/dist/assets/t9n/map-select-tools/resources_en.json +2 -2
  3. package/dist/assets/t9n/public-notification/resources.json +1 -1
  4. package/dist/assets/t9n/public-notification/resources_en.json +1 -1
  5. package/dist/cjs/calcite-input-text_5.cjs.entry.js +4 -4
  6. package/dist/cjs/calcite-shell-panel_14.cjs.entry.js +1 -1
  7. package/dist/cjs/{downloadUtils-06876768.js → downloadUtils-8d66f03e.js} +95 -21
  8. package/dist/cjs/{index.es-d07646b4.js → index.es-4f5dfcc6.js} +1 -1
  9. package/dist/cjs/layer-table_2.cjs.entry.js +1 -1
  10. package/dist/cjs/public-notification.cjs.entry.js +12 -1
  11. package/dist/cjs/solution-configuration.cjs.entry.js +1 -1
  12. package/dist/cjs/solution-contents_3.cjs.entry.js +1 -1
  13. package/dist/cjs/{solution-store-70002b57.js → solution-store-ca4639d5.js} +3 -3
  14. package/dist/collection/components/map-select-tools/map-select-tools.css +7 -2
  15. package/dist/collection/components/map-select-tools/map-select-tools.js +2 -2
  16. package/dist/collection/components/public-notification/public-notification.js +12 -1
  17. package/dist/collection/components/refine-selection/refine-selection.css +85 -85
  18. package/dist/collection/utils/downloadUtils.js +94 -20
  19. package/dist/collection/utils/downloadUtils.ts +147 -27
  20. package/dist/components/downloadUtils.js +94 -20
  21. package/dist/components/map-select-tools2.js +14 -14
  22. package/dist/components/public-notification.js +12 -1
  23. package/dist/components/solution-store.js +3 -3
  24. package/dist/esm/calcite-input-text_5.entry.js +4 -4
  25. package/dist/esm/calcite-shell-panel_14.entry.js +1 -1
  26. package/dist/esm/{downloadUtils-046ce0aa.js → downloadUtils-b9785635.js} +95 -21
  27. package/dist/esm/{index.es-3fd0e8f6.js → index.es-70994c40.js} +1 -1
  28. package/dist/esm/layer-table_2.entry.js +1 -1
  29. package/dist/esm/public-notification.entry.js +12 -1
  30. package/dist/esm/solution-configuration.entry.js +1 -1
  31. package/dist/esm/solution-contents_3.entry.js +1 -1
  32. package/dist/esm/{solution-store-5d068b07.js → solution-store-70f874f8.js} +3 -3
  33. package/dist/solutions-components/{p-1850a763.entry.js → p-10336554.entry.js} +1 -1
  34. package/dist/solutions-components/{p-41802f6b.entry.js → p-16dfb254.entry.js} +1 -1
  35. package/dist/solutions-components/{p-99aec087.js → p-5d5e10d4.js} +1 -1
  36. package/dist/solutions-components/{p-4769a2a5.entry.js → p-5ed755a2.entry.js} +1 -1
  37. package/dist/solutions-components/{p-826a814d.js → p-78719506.js} +2 -2
  38. package/dist/solutions-components/{p-9f620303.entry.js → p-b4b19fd3.entry.js} +1 -1
  39. package/dist/solutions-components/{p-2e0db581.js → p-be943993.js} +11 -11
  40. package/dist/solutions-components/{p-7e409786.entry.js → p-c3e3d0bb.entry.js} +3 -3
  41. package/dist/solutions-components/p-f66a7ea7.entry.js +6 -0
  42. package/dist/solutions-components/solutions-components.esm.js +1 -1
  43. package/dist/solutions-components/utils/downloadUtils.ts +147 -27
  44. package/dist/solutions-components_commit.txt +8 -0
  45. package/dist/types/utils/downloadUtils.d.ts +21 -0
  46. package/package.json +1 -1
  47. package/dist/solutions-components/p-6e87198f.entry.js +0 -6
@@ -196,6 +196,38 @@ export function _createFilename(selectionSetNames) {
196
196
  const title = selectionSetNames.length > 0 ? selectionSetNames.join(", ") : "download";
197
197
  return title;
198
198
  }
199
+ /**
200
+ * Creates relationship queries for each relationship flag in a popup.
201
+ * @param layer Layer whose popup is to be examined
202
+ * @return Hash of relationships by their id, or null if there are no relationship flags in the
203
+ * popup; each relationship has the properties layer and relatedQuery for the related layer
204
+ * and the query for that layer
205
+ */
206
+ export function _createRelationshipQueries(layer) {
207
+ const relationships = {};
208
+ const relationshipFieldPattern = /\{relationships\/\d+\//gm;
209
+ const relationshipIdPattern = /\d+/;
210
+ // Test if this popup has any relationship references
211
+ const matches = layer.popupTemplate.content[0].text.match(relationshipFieldPattern);
212
+ if (matches) {
213
+ matches.forEach(match => {
214
+ // Add a query to a found relationship if we don't already have one
215
+ const id = match.match(relationshipIdPattern)[0];
216
+ if (!relationships.hasOwnProperty(id)) {
217
+ const relatedQuery = {
218
+ outFields: ['*'],
219
+ relationshipId: id,
220
+ returnGeometry: false
221
+ };
222
+ relationships[id] = {
223
+ layer,
224
+ relatedQuery
225
+ };
226
+ }
227
+ });
228
+ }
229
+ return relationships;
230
+ }
199
231
  /**
200
232
  * Prepares an attribute's value by applying domain and type information.
201
233
  *
@@ -256,7 +288,7 @@ function _prepareAttributeValue(attributeValue, attributeType, attributeDomain,
256
288
  * @returns Promise resolving when function is done
257
289
  */
258
290
  async function _prepareLabels(layer, ids, removeDuplicates = true, formatUsingLayerPopup = true, includeHeaderNames = false) {
259
- var _a, _b, _c, _d;
291
+ var _a, _b, _c, _d, _e, _f;
260
292
  const [intl] = await loadModules(["esri/intl"]);
261
293
  // Get the features to export
262
294
  const featureSet = await queryFeaturesByID(ids, layer);
@@ -270,6 +302,7 @@ async function _prepareLabels(layer, ids, removeDuplicates = true, formatUsingLa
270
302
  const attributeFormats = {};
271
303
  // Get the label formatting, if any
272
304
  let labelFormat;
305
+ let relationshipQueries = {};
273
306
  let arcadeExecutors = {};
274
307
  if (layer.popupEnabled) {
275
308
  layer.popupTemplate.fieldInfos.forEach(
@@ -298,6 +331,8 @@ async function _prepareLabels(layer, ids, removeDuplicates = true, formatUsingLa
298
331
  }
299
332
  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") {
300
333
  labelFormat = _convertPopupTextToLabelSpec(layer.popupTemplate.content[0].text);
334
+ // Do we need any relationship queries?
335
+ relationshipQueries = _createRelationshipQueries(layer);
301
336
  // Do we need any Arcade executors?
302
337
  arcadeExecutors = await _createArcadeExecutors(labelFormat, layer);
303
338
  }
@@ -306,36 +341,75 @@ async function _prepareLabels(layer, ids, removeDuplicates = true, formatUsingLa
306
341
  let labels;
307
342
  // eslint-disable-next-line unicorn/prefer-ternary
308
343
  if (labelFormat) {
344
+ console.log("labelFormat", labelFormat); //???
309
345
  const arcadeExpressionRegExp = /\{expression\/\w+\}/g;
310
346
  const attributeRegExp = /\{\w+\}/g;
311
347
  // Find the label fields that we need to replace with values
312
- const arcadeExpressionMatches = labelFormat.match(arcadeExpressionRegExp);
313
- const attributeMatches = labelFormat.match(attributeRegExp);
348
+ const arcadeExpressionMatches = (_e = labelFormat.match(arcadeExpressionRegExp)) !== null && _e !== void 0 ? _e : [];
349
+ const attributeMatches = (_f = labelFormat.match(attributeRegExp)) !== null && _f !== void 0 ? _f : [];
314
350
  // Convert feature attributes into an array of labels
315
- labels = featureSet.features.map(feature => {
351
+ const relationshipKeys = Object.keys(relationshipQueries);
352
+ labels = await Promise.all(featureSet.features.map(async (feature) => {
316
353
  let labelPrep = labelFormat;
317
- // Replace Arcade expressions
318
- if (arcadeExpressionMatches) {
319
- arcadeExpressionMatches.forEach((match) => {
320
- const expressionName = match.substring(match.indexOf("/") + 1, match.length - 1);
321
- const value = arcadeExecutors[expressionName].execute({ "$feature": feature });
322
- labelPrep = labelPrep.replace(match, value);
323
- });
324
- }
325
- // Replace non-Arcade fields
326
- if (attributeMatches) {
327
- attributeMatches.forEach((match) => {
328
- const attributeName = match.substring(1, match.length - 1);
329
- const value = _prepareAttributeValue(feature.attributes[attributeName], attributeTypes[attributeName], attributeDomains[attributeName], attributeFormats[attributeName], intl);
330
- labelPrep = labelPrep.replace(match, value);
354
+ // Replace Arcade expressions in this feature
355
+ arcadeExpressionMatches.forEach((match) => {
356
+ const expressionName = match.substring(match.indexOf("/") + 1, match.length - 1);
357
+ const value = arcadeExecutors[expressionName].execute({ "$feature": feature });
358
+ labelPrep = labelPrep.replace(match, value);
359
+ });
360
+ // Replace relationship expressions in this feature
361
+ const relatedFeatureQueries = [];
362
+ const relationshipIds = [];
363
+ relationshipKeys.forEach((relationshipId) => {
364
+ const relationship = relationshipQueries[relationshipId];
365
+ const objectId = feature.attributes[relationship.layer.objectIdField];
366
+ const relatedQuery = Object.assign(Object.assign({}, relationship.relatedQuery), { objectIds: [objectId] });
367
+ relatedFeatureQueries.push(relationship.layer.queryRelatedFeatures(relatedQuery));
368
+ relationshipIds.push(relationshipId);
369
+ });
370
+ // Wait for all of the queries for related records for this label
371
+ const relatedFeatureQueryResults = await Promise.all(relatedFeatureQueries);
372
+ console.log("relatedFeatureQueryResults", relatedFeatureQueryResults); //???
373
+ relatedFeatureQueryResults.forEach((relatedFeatureQueryResult, i) => {
374
+ // We have an object with FeatureSets grouped by source layer or table objectIds
375
+ const relationshipId = relationshipIds[i];
376
+ console.log("relationshipId", relationshipId); //???
377
+ console.log("relatedFeatureQueryResult", relatedFeatureQueryResult); //???
378
+ // Run through the source layer or table objectIds
379
+ Object.keys(relatedFeatureQueryResult).forEach(relatedFeatureSetId => {
380
+ console.log("relatedFeatureSetId", relatedFeatureSetId); //???
381
+ // We have a feature set
382
+ const relatedFeatures = relatedFeatureQueryResult[relatedFeatureSetId].features;
383
+ console.log("relatedFeatures", relatedFeatures); //???
384
+ // Get the values from each feature and replace them in the label
385
+ relatedFeatures.forEach(feature => {
386
+ // Merge the base and related feature attributes and create the label
387
+ // Prefix related feature's attributes with "relationships/<id>/" to match popup
388
+ const rePrefix = "\{relationships/" + relationshipId + "/";
389
+ const reSuffix = "\}";
390
+ console.log("/rePrefix + attributeName + reSuffix/g", rePrefix + "attributeName" + reSuffix); //???
391
+ const attributes = feature.attributes;
392
+ Object.keys(attributes).forEach(attributeName => {
393
+ console.log("/rePrefix + attributeName + reSuffix/g", rePrefix + attributeName + reSuffix); //???
394
+ // Replace the value using the attribute name as a relationship
395
+ const attributeRelationshipRegExp = new RegExp(rePrefix + attributeName + reSuffix, "g");
396
+ labelPrep = labelPrep.replaceAll(attributeRelationshipRegExp, attributes[attributeName]);
397
+ });
398
+ });
331
399
  });
332
- }
400
+ });
401
+ // Replace non-Arcade fields in this feature
402
+ attributeMatches.forEach((match) => {
403
+ const attributeName = match.substring(1, match.length - 1);
404
+ const value = _prepareAttributeValue(feature.attributes[attributeName], attributeTypes[attributeName], attributeDomains[attributeName], attributeFormats[attributeName], intl);
405
+ labelPrep = labelPrep.replace(match, value);
406
+ });
333
407
  // Split label into lines
334
408
  let label = labelPrep.split(lineSeparatorChar);
335
409
  // Trim lines
336
410
  label = label.map(line => line.trim());
337
411
  return label;
338
- });
412
+ }));
339
413
  }
340
414
  else {
341
415
  // Export all attributes
@@ -43,6 +43,25 @@ interface IAttributeTypes {
43
43
  [attributeName: string]: string;
44
44
  }
45
45
 
46
+ interface ILayerRelationshipQuery {
47
+ layer: __esri.FeatureLayer;
48
+ relatedQuery: IRelatedFeaturesQuery;
49
+ }
50
+
51
+ interface ILayerRelationshipQueryHash {
52
+ [relationshipId: string]: ILayerRelationshipQuery;
53
+ }
54
+
55
+ // Class RelationshipQuery doesn't appear to work, and so since
56
+ // https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-FeatureLayer.html#queryRelatedFeatures
57
+ // says that the relationshipQuery argument is autocast, we'll set up a variant for the class
58
+ interface IRelatedFeaturesQuery {
59
+ outFields: string[];
60
+ relationshipId: string;
61
+ returnGeometry: boolean;
62
+ objectIds?: number;
63
+ }
64
+
46
65
  const lineSeparatorChar = "|";
47
66
 
48
67
  //#endregion
@@ -278,6 +297,44 @@ export function _createFilename(
278
297
  return title;
279
298
  }
280
299
 
300
+ /**
301
+ * Creates relationship queries for each relationship flag in a popup.
302
+ * @param layer Layer whose popup is to be examined
303
+ * @return Hash of relationships by their id, or null if there are no relationship flags in the
304
+ * popup; each relationship has the properties layer and relatedQuery for the related layer
305
+ * and the query for that layer
306
+ */
307
+ export function _createRelationshipQueries(
308
+ layer: __esri.FeatureLayer,
309
+ ): ILayerRelationshipQueryHash {
310
+
311
+ const relationships: ILayerRelationshipQueryHash = {};
312
+ const relationshipFieldPattern = /\{relationships\/\d+\//gm;
313
+ const relationshipIdPattern = /\d+/;
314
+
315
+ // Test if this popup has any relationship references
316
+ const matches = layer.popupTemplate.content[0].text.match(relationshipFieldPattern);
317
+ if (matches) {
318
+ matches.forEach(match => {
319
+ // Add a query to a found relationship if we don't already have one
320
+ const id = match.match(relationshipIdPattern)[0];
321
+ if (!relationships.hasOwnProperty(id)) {
322
+ const relatedQuery: IRelatedFeaturesQuery = {
323
+ outFields: ['*'],
324
+ relationshipId: id,
325
+ returnGeometry: false
326
+ };
327
+ relationships[id] = {
328
+ layer,
329
+ relatedQuery
330
+ } as ILayerRelationshipQuery;
331
+ }
332
+ });
333
+ }
334
+
335
+ return relationships;
336
+ }
337
+
281
338
  /**
282
339
  * Prepares an attribute's value by applying domain and type information.
283
340
  *
@@ -369,6 +426,7 @@ async function _prepareLabels(
369
426
 
370
427
  // Get the label formatting, if any
371
428
  let labelFormat: string;
429
+ let relationshipQueries: ILayerRelationshipQueryHash = {};
372
430
  let arcadeExecutors: IArcadeExecutors = {};
373
431
  if (layer.popupEnabled) {
374
432
  layer.popupTemplate.fieldInfos.forEach(
@@ -401,6 +459,9 @@ async function _prepareLabels(
401
459
  } else if (formatUsingLayerPopup && layer.popupTemplate?.content[0]?.type === "text") {
402
460
  labelFormat = _convertPopupTextToLabelSpec(layer.popupTemplate.content[0].text);
403
461
 
462
+ // Do we need any relationship queries?
463
+ relationshipQueries = _createRelationshipQueries(layer);
464
+
404
465
  // Do we need any Arcade executors?
405
466
  arcadeExecutors = await _createArcadeExecutors(labelFormat, layer);
406
467
  }
@@ -410,41 +471,100 @@ async function _prepareLabels(
410
471
  let labels: string[][];
411
472
  // eslint-disable-next-line unicorn/prefer-ternary
412
473
  if (labelFormat) {
474
+ console.log("labelFormat", labelFormat);//???
413
475
  const arcadeExpressionRegExp = /\{expression\/\w+\}/g;
414
476
  const attributeRegExp = /\{\w+\}/g;
415
477
 
416
478
  // Find the label fields that we need to replace with values
417
- const arcadeExpressionMatches = labelFormat.match(arcadeExpressionRegExp);
418
- const attributeMatches = labelFormat.match(attributeRegExp);
479
+ const arcadeExpressionMatches = labelFormat.match(arcadeExpressionRegExp) ?? [];
480
+ const attributeMatches = labelFormat.match(attributeRegExp) ?? [];
419
481
 
420
482
  // Convert feature attributes into an array of labels
421
- labels = featureSet.features.map(
422
- feature => {
483
+ const relationshipKeys = Object.keys(relationshipQueries);
484
+ labels = await Promise.all(featureSet.features.map(
485
+ async feature => {
423
486
  let labelPrep = labelFormat;
424
487
 
425
- // Replace Arcade expressions
426
- if (arcadeExpressionMatches) {
427
- arcadeExpressionMatches.forEach(
428
- (match: string) => {
429
- const expressionName = match.substring(match.indexOf("/") + 1, match.length - 1);
430
- const value = arcadeExecutors[expressionName].execute({"$feature": feature});
431
- labelPrep = labelPrep.replace(match, value);
432
- }
433
- )
434
- }
488
+ // Replace Arcade expressions in this feature
489
+ arcadeExpressionMatches.forEach(
490
+ (match: string) => {
491
+ const expressionName = match.substring(match.indexOf("/") + 1, match.length - 1);
492
+ const value = arcadeExecutors[expressionName].execute({"$feature": feature});
493
+ labelPrep = labelPrep.replace(match, value);
494
+ }
495
+ )
496
+
497
+ // Replace relationship expressions in this feature
498
+ const relatedFeatureQueries = [] as Promise<__esri.FeatureSet>[];
499
+ const relationshipIds = [] as string[];
500
+ relationshipKeys.forEach(
501
+ (relationshipId) => {
502
+ const relationship = relationshipQueries[relationshipId];
503
+ const objectId = feature.attributes[relationship.layer.objectIdField];
504
+ const relatedQuery = {
505
+ ...relationship.relatedQuery,
506
+ objectIds: [objectId]
507
+ };
508
+ relatedFeatureQueries.push(relationship.layer.queryRelatedFeatures(relatedQuery as any));
509
+ relationshipIds.push(relationshipId);
510
+ }
511
+ );
435
512
 
436
- // Replace non-Arcade fields
437
- if (attributeMatches) {
438
- attributeMatches.forEach(
439
- (match: string) => {
440
- const attributeName = match.substring(1, match.length - 1);
441
- const value = _prepareAttributeValue(feature.attributes[attributeName],
442
- attributeTypes[attributeName], attributeDomains[attributeName],
443
- attributeFormats[attributeName], intl);
444
- labelPrep = labelPrep.replace(match, value);
445
- }
446
- )
447
- }
513
+ // Wait for all of the queries for related records for this label
514
+ const relatedFeatureQueryResults = await Promise.all(relatedFeatureQueries);
515
+ console.log("relatedFeatureQueryResults", relatedFeatureQueryResults);//???
516
+ relatedFeatureQueryResults.forEach(
517
+ (relatedFeatureQueryResult, i) => {
518
+ // We have an object with FeatureSets grouped by source layer or table objectIds
519
+ const relationshipId = relationshipIds[i];
520
+ console.log("relationshipId", relationshipId);//???
521
+ console.log("relatedFeatureQueryResult", relatedFeatureQueryResult);//???
522
+
523
+ // Run through the source layer or table objectIds
524
+ Object.keys(relatedFeatureQueryResult).forEach(
525
+ relatedFeatureSetId => {
526
+ console.log("relatedFeatureSetId", relatedFeatureSetId);//???
527
+ // We have a feature set
528
+ const relatedFeatures = relatedFeatureQueryResult[relatedFeatureSetId].features;
529
+ console.log("relatedFeatures", relatedFeatures);//???
530
+
531
+ // Get the values from each feature and replace them in the label
532
+ relatedFeatures.forEach(
533
+ feature => {
534
+ // Merge the base and related feature attributes and create the label
535
+ // Prefix related feature's attributes with "relationships/<id>/" to match popup
536
+ const rePrefix = "\{relationships/" + relationshipId + "/";
537
+ const reSuffix = "\}";
538
+ console.log("/rePrefix + attributeName + reSuffix/g", rePrefix + "attributeName" + reSuffix);//???
539
+
540
+ const attributes = feature.attributes;
541
+ Object.keys(attributes).forEach(
542
+ attributeName => {
543
+ console.log("/rePrefix + attributeName + reSuffix/g", rePrefix + attributeName + reSuffix);//???
544
+ // Replace the value using the attribute name as a relationship
545
+ const attributeRelationshipRegExp = new RegExp(rePrefix + attributeName + reSuffix, "g");
546
+ labelPrep = labelPrep.replaceAll(attributeRelationshipRegExp, attributes[attributeName]);
547
+ }
548
+ );
549
+ }
550
+ );
551
+ }
552
+ );
553
+ }
554
+ );
555
+
556
+ // Replace non-Arcade fields in this feature
557
+ attributeMatches.forEach(
558
+ (match: string) => {
559
+ const attributeName = match.substring(1, match.length - 1);
560
+
561
+ const value = _prepareAttributeValue(feature.attributes[attributeName],
562
+ attributeTypes[attributeName], attributeDomains[attributeName],
563
+ attributeFormats[attributeName], intl);
564
+ labelPrep = labelPrep.replace(match, value);
565
+
566
+ }
567
+ )
448
568
 
449
569
  // Split label into lines
450
570
  let label = labelPrep.split(lineSeparatorChar);
@@ -454,7 +574,7 @@ async function _prepareLabels(
454
574
 
455
575
  return label;
456
576
  }
457
- );
577
+ ));
458
578
 
459
579
  } else {
460
580
  // Export all attributes
@@ -2425,6 +2425,38 @@ function _createFilename(selectionSetNames) {
2425
2425
  const title = selectionSetNames.length > 0 ? selectionSetNames.join(", ") : "download";
2426
2426
  return title;
2427
2427
  }
2428
+ /**
2429
+ * Creates relationship queries for each relationship flag in a popup.
2430
+ * @param layer Layer whose popup is to be examined
2431
+ * @return Hash of relationships by their id, or null if there are no relationship flags in the
2432
+ * popup; each relationship has the properties layer and relatedQuery for the related layer
2433
+ * and the query for that layer
2434
+ */
2435
+ function _createRelationshipQueries(layer) {
2436
+ const relationships = {};
2437
+ const relationshipFieldPattern = /\{relationships\/\d+\//gm;
2438
+ const relationshipIdPattern = /\d+/;
2439
+ // Test if this popup has any relationship references
2440
+ const matches = layer.popupTemplate.content[0].text.match(relationshipFieldPattern);
2441
+ if (matches) {
2442
+ matches.forEach(match => {
2443
+ // Add a query to a found relationship if we don't already have one
2444
+ const id = match.match(relationshipIdPattern)[0];
2445
+ if (!relationships.hasOwnProperty(id)) {
2446
+ const relatedQuery = {
2447
+ outFields: ['*'],
2448
+ relationshipId: id,
2449
+ returnGeometry: false
2450
+ };
2451
+ relationships[id] = {
2452
+ layer,
2453
+ relatedQuery
2454
+ };
2455
+ }
2456
+ });
2457
+ }
2458
+ return relationships;
2459
+ }
2428
2460
  /**
2429
2461
  * Prepares an attribute's value by applying domain and type information.
2430
2462
  *
@@ -2485,7 +2517,7 @@ function _prepareAttributeValue(attributeValue, attributeType, attributeDomain,
2485
2517
  * @returns Promise resolving when function is done
2486
2518
  */
2487
2519
  async function _prepareLabels(layer, ids, removeDuplicates = true, formatUsingLayerPopup = true, includeHeaderNames = false) {
2488
- var _a, _b, _c, _d;
2520
+ var _a, _b, _c, _d, _e, _f;
2489
2521
  const [intl] = await loadModules(["esri/intl"]);
2490
2522
  // Get the features to export
2491
2523
  const featureSet = await queryFeaturesByID(ids, layer);
@@ -2499,6 +2531,7 @@ async function _prepareLabels(layer, ids, removeDuplicates = true, formatUsingLa
2499
2531
  const attributeFormats = {};
2500
2532
  // Get the label formatting, if any
2501
2533
  let labelFormat;
2534
+ let relationshipQueries = {};
2502
2535
  let arcadeExecutors = {};
2503
2536
  if (layer.popupEnabled) {
2504
2537
  layer.popupTemplate.fieldInfos.forEach(
@@ -2527,6 +2560,8 @@ async function _prepareLabels(layer, ids, removeDuplicates = true, formatUsingLa
2527
2560
  }
2528
2561
  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") {
2529
2562
  labelFormat = _convertPopupTextToLabelSpec(layer.popupTemplate.content[0].text);
2563
+ // Do we need any relationship queries?
2564
+ relationshipQueries = _createRelationshipQueries(layer);
2530
2565
  // Do we need any Arcade executors?
2531
2566
  arcadeExecutors = await _createArcadeExecutors(labelFormat, layer);
2532
2567
  }
@@ -2535,36 +2570,75 @@ async function _prepareLabels(layer, ids, removeDuplicates = true, formatUsingLa
2535
2570
  let labels;
2536
2571
  // eslint-disable-next-line unicorn/prefer-ternary
2537
2572
  if (labelFormat) {
2573
+ console.log("labelFormat", labelFormat); //???
2538
2574
  const arcadeExpressionRegExp = /\{expression\/\w+\}/g;
2539
2575
  const attributeRegExp = /\{\w+\}/g;
2540
2576
  // Find the label fields that we need to replace with values
2541
- const arcadeExpressionMatches = labelFormat.match(arcadeExpressionRegExp);
2542
- const attributeMatches = labelFormat.match(attributeRegExp);
2577
+ const arcadeExpressionMatches = (_e = labelFormat.match(arcadeExpressionRegExp)) !== null && _e !== void 0 ? _e : [];
2578
+ const attributeMatches = (_f = labelFormat.match(attributeRegExp)) !== null && _f !== void 0 ? _f : [];
2543
2579
  // Convert feature attributes into an array of labels
2544
- labels = featureSet.features.map(feature => {
2580
+ const relationshipKeys = Object.keys(relationshipQueries);
2581
+ labels = await Promise.all(featureSet.features.map(async (feature) => {
2545
2582
  let labelPrep = labelFormat;
2546
- // Replace Arcade expressions
2547
- if (arcadeExpressionMatches) {
2548
- arcadeExpressionMatches.forEach((match) => {
2549
- const expressionName = match.substring(match.indexOf("/") + 1, match.length - 1);
2550
- const value = arcadeExecutors[expressionName].execute({ "$feature": feature });
2551
- labelPrep = labelPrep.replace(match, value);
2552
- });
2553
- }
2554
- // Replace non-Arcade fields
2555
- if (attributeMatches) {
2556
- attributeMatches.forEach((match) => {
2557
- const attributeName = match.substring(1, match.length - 1);
2558
- const value = _prepareAttributeValue(feature.attributes[attributeName], attributeTypes[attributeName], attributeDomains[attributeName], attributeFormats[attributeName], intl);
2559
- labelPrep = labelPrep.replace(match, value);
2583
+ // Replace Arcade expressions in this feature
2584
+ arcadeExpressionMatches.forEach((match) => {
2585
+ const expressionName = match.substring(match.indexOf("/") + 1, match.length - 1);
2586
+ const value = arcadeExecutors[expressionName].execute({ "$feature": feature });
2587
+ labelPrep = labelPrep.replace(match, value);
2588
+ });
2589
+ // Replace relationship expressions in this feature
2590
+ const relatedFeatureQueries = [];
2591
+ const relationshipIds = [];
2592
+ relationshipKeys.forEach((relationshipId) => {
2593
+ const relationship = relationshipQueries[relationshipId];
2594
+ const objectId = feature.attributes[relationship.layer.objectIdField];
2595
+ const relatedQuery = Object.assign(Object.assign({}, relationship.relatedQuery), { objectIds: [objectId] });
2596
+ relatedFeatureQueries.push(relationship.layer.queryRelatedFeatures(relatedQuery));
2597
+ relationshipIds.push(relationshipId);
2598
+ });
2599
+ // Wait for all of the queries for related records for this label
2600
+ const relatedFeatureQueryResults = await Promise.all(relatedFeatureQueries);
2601
+ console.log("relatedFeatureQueryResults", relatedFeatureQueryResults); //???
2602
+ relatedFeatureQueryResults.forEach((relatedFeatureQueryResult, i) => {
2603
+ // We have an object with FeatureSets grouped by source layer or table objectIds
2604
+ const relationshipId = relationshipIds[i];
2605
+ console.log("relationshipId", relationshipId); //???
2606
+ console.log("relatedFeatureQueryResult", relatedFeatureQueryResult); //???
2607
+ // Run through the source layer or table objectIds
2608
+ Object.keys(relatedFeatureQueryResult).forEach(relatedFeatureSetId => {
2609
+ console.log("relatedFeatureSetId", relatedFeatureSetId); //???
2610
+ // We have a feature set
2611
+ const relatedFeatures = relatedFeatureQueryResult[relatedFeatureSetId].features;
2612
+ console.log("relatedFeatures", relatedFeatures); //???
2613
+ // Get the values from each feature and replace them in the label
2614
+ relatedFeatures.forEach(feature => {
2615
+ // Merge the base and related feature attributes and create the label
2616
+ // Prefix related feature's attributes with "relationships/<id>/" to match popup
2617
+ const rePrefix = "\{relationships/" + relationshipId + "/";
2618
+ const reSuffix = "\}";
2619
+ console.log("/rePrefix + attributeName + reSuffix/g", rePrefix + "attributeName" + reSuffix); //???
2620
+ const attributes = feature.attributes;
2621
+ Object.keys(attributes).forEach(attributeName => {
2622
+ console.log("/rePrefix + attributeName + reSuffix/g", rePrefix + attributeName + reSuffix); //???
2623
+ // Replace the value using the attribute name as a relationship
2624
+ const attributeRelationshipRegExp = new RegExp(rePrefix + attributeName + reSuffix, "g");
2625
+ labelPrep = labelPrep.replaceAll(attributeRelationshipRegExp, attributes[attributeName]);
2626
+ });
2627
+ });
2560
2628
  });
2561
- }
2629
+ });
2630
+ // Replace non-Arcade fields in this feature
2631
+ attributeMatches.forEach((match) => {
2632
+ const attributeName = match.substring(1, match.length - 1);
2633
+ const value = _prepareAttributeValue(feature.attributes[attributeName], attributeTypes[attributeName], attributeDomains[attributeName], attributeFormats[attributeName], intl);
2634
+ labelPrep = labelPrep.replace(match, value);
2635
+ });
2562
2636
  // Split label into lines
2563
2637
  let label = labelPrep.split(lineSeparatorChar);
2564
2638
  // Trim lines
2565
2639
  label = label.map(line => line.trim());
2566
2640
  return label;
2567
- });
2641
+ }));
2568
2642
  }
2569
2643
  else {
2570
2644
  // Export all attributes
@@ -22,14 +22,14 @@ import { d as defineCustomElement$b } from './input-message.js';
22
22
  import { d as defineCustomElement$a } from './label.js';
23
23
  import { d as defineCustomElement$9 } from './loader.js';
24
24
  import { d as defineCustomElement$8 } from './option.js';
25
- import { d as defineCustomElement$7 } from './progress.js';
26
- import { d as defineCustomElement$6 } from './select.js';
27
- import { d as defineCustomElement$5 } from './slider.js';
28
- import { d as defineCustomElement$4 } from './switch.js';
29
- import { d as defineCustomElement$3 } from './tooltip.js';
25
+ import { d as defineCustomElement$7 } from './popover.js';
26
+ import { d as defineCustomElement$6 } from './progress.js';
27
+ import { d as defineCustomElement$5 } from './select.js';
28
+ import { d as defineCustomElement$4 } from './slider.js';
29
+ import { d as defineCustomElement$3 } from './switch.js';
30
30
  import { d as defineCustomElement$2 } from './map-draw-tools2.js';
31
31
 
32
- const mapSelectToolsCss = ":host{display:block}.div-visible{display:inherit}.div-visible-search{display:flex;height:44px;align-items:center;padding-bottom:0}.div-not-visible{display:none}.padding-bottom-1{padding-bottom:1rem}.padding-top-1{padding-top:1rem}.search-widget{width:100% !important;border:1px solid var(--calcite-ui-border-input)}.w-100{width:100%}.w-50{width:50%}.search-distance-container{padding-top:\"1rem\" !important}.end-border{-webkit-border-end:1px solid var(--calcite-ui-border-2);border-inline-end:1px solid var(--calcite-ui-border-2)}.search-distance{display:flex;padding-top:1rem}.font-bold{font:bold}.border-bottom{border-bottom:1px solid var(--calcite-ui-border-2)}.tooltip-container{justify-content:center;display:flex}.padding-start-1-2{-webkit-padding-start:0.5rem;padding-inline-start:0.5rem}.icon{--calcite-ui-icon-color:var(--calcite-ui-brand)}";
32
+ const mapSelectToolsCss = ":host{display:block}.div-visible{display:inherit}.div-visible-search{display:flex;height:44px;align-items:center;padding-bottom:0}.div-not-visible{display:none}.padding-bottom-1{padding-bottom:1rem}.padding-top-1{padding-top:1rem}.search-widget{width:100% !important;border:1px solid var(--calcite-ui-border-input)}.w-100{width:100%}.w-50{width:50%}.search-distance-container{padding-top:\"1rem\" !important}.end-border{-webkit-border-end:1px solid var(--calcite-ui-border-2);border-inline-end:1px solid var(--calcite-ui-border-2)}.search-distance{display:flex;padding-top:1rem}.font-bold{font:bold}.border-bottom{border-bottom:1px solid var(--calcite-ui-border-2)}.tooltip-container{display:flex}.padding-start-1-2{-webkit-padding-start:0.5rem;padding-inline-start:0.5rem}.icon{--calcite-ui-icon-color:var(--calcite-ui-brand)}.tooltip-message{padding:5px 8px;font-weight:var(--calcite-font-weight-normal);color:var(--calcite-ui-text-2)}";
33
33
 
34
34
  const MapSelectTools = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
35
35
  constructor() {
@@ -200,14 +200,14 @@ const MapSelectTools = /*@__PURE__*/ proxyCustomElement(class extends HTMLElemen
200
200
  var _a, _b;
201
201
  const showBufferToolsClass = this._searchDistanceEnabled ? "search-distance" : "div-not-visible";
202
202
  const bufferDistance = typeof ((_a = this.selectionSet) === null || _a === void 0 ? void 0 : _a.distance) === "number" ? this.selectionSet.distance : this.defaultBufferDistance;
203
- return (h("div", null, h("div", { class: "padding-top-1 display-flex" }, h("calcite-label", { class: "label-margin-0 w-100", layout: "inline-space-between" }, h("div", { class: "tooltip-container" }, this._translations.searchDistance, h("calcite-icon", { class: "padding-start-1-2 icon", icon: "question", id: "search-distance-icon", scale: "s" }), h("calcite-tooltip", { label: "Data disclaimer", placement: "auto", "reference-element": "search-distance-icon" }, h("span", null, this._translations.useSearchDistanceTootip))), h("calcite-switch", { checked: this._searchDistanceEnabled, onCalciteSwitchChange: () => this._searchDistanceEnabled = !this._searchDistanceEnabled }))), h("div", { class: showBufferToolsClass }, h("buffer-tools", { disabled: !this._searchDistanceEnabled, distance: bufferDistance, geometries: this.geometries, onBufferComplete: (evt) => this._bufferComplete(evt), ref: (el) => this._bufferTools = el, unit: ((_b = this.selectionSet) === null || _b === void 0 ? void 0 : _b.unit) || this.defaultBufferUnit }))));
203
+ return (h("div", null, h("div", { class: "padding-top-1 display-flex" }, h("calcite-label", { class: "label-margin-0 w-100", layout: "inline-space-between" }, h("div", { class: "tooltip-container" }, this._translations.searchDistance, h("calcite-icon", { class: "padding-start-1-2 icon", icon: "question", id: "search-distance-icon", scale: "s" }))), h("calcite-popover", { closable: true, label: "", referenceElement: "search-distance-icon" }, h("span", { class: "tooltip-message" }, this._translations.useSearchDistanceTootip)), h("calcite-switch", { checked: this._searchDistanceEnabled, onCalciteSwitchChange: () => this._searchDistanceEnabled = !this._searchDistanceEnabled })), h("div", { class: showBufferToolsClass }, h("buffer-tools", { disabled: !this._searchDistanceEnabled, distance: bufferDistance, geometries: this.geometries, onBufferComplete: (evt) => this._bufferComplete(evt), ref: (el) => this._bufferTools = el, unit: ((_b = this.selectionSet) === null || _b === void 0 ? void 0 : _b.unit) || this.defaultBufferUnit }))));
204
204
  }
205
205
  /**
206
206
  * Renders the map layer picker component.
207
207
  */
208
208
  _getUseLayerFeaturesOptions() {
209
209
  const useLayerFeaturesClass = this._useLayerFeaturesEnabled ? "div-visible" : "div-not-visible";
210
- return (h("div", null, h("div", { class: "padding-top-1 display-flex" }, h("calcite-label", { class: "label-margin-0 w-100", layout: "inline-space-between" }, h("div", { class: "tooltip-container" }, this._translations.useLayerFeatures, h("calcite-icon", { class: "padding-start-1-2 icon", icon: "question", id: "use-layer-features-icon", scale: "s" }), h("calcite-tooltip", { label: "Data disclaimer", placement: "auto", "reference-element": "use-layer-features-icon" }, h("span", null, this._translations.useLayerFeaturesTooltip))), h("calcite-switch", { checked: this._useLayerFeaturesEnabled, onCalciteSwitchChange: () => { this._useLayerFeaturesEnabledChanged(); } }))), h("div", { class: useLayerFeaturesClass + " padding-top-1" }, h("map-layer-picker", { enabledLayerIds: this.enabledLayerIds, mapView: this.mapView, onLayerSelectionChange: (evt) => { void this._layerSelectionChange(evt); }, selectedLayerIds: this.layerViews.map(l => l.layer.id), selectionMode: "single" }))));
210
+ return (h("div", null, h("div", { class: "padding-top-1 display-flex" }, h("calcite-label", { class: "label-margin-0 w-100", layout: "inline-space-between" }, h("div", { class: "tooltip-container" }, this._translations.useLayerFeatures, h("calcite-icon", { class: "padding-start-1-2 icon", icon: "question", id: "use-layer-features-icon", scale: "s" }))), h("calcite-popover", { closable: true, label: "", referenceElement: "use-layer-features-icon" }, h("span", { class: "tooltip-message" }, this._translations.useLayerFeaturesTooltip)), h("calcite-switch", { checked: this._useLayerFeaturesEnabled, onCalciteSwitchChange: () => { this._useLayerFeaturesEnabledChanged(); } })), h("div", { class: useLayerFeaturesClass + " padding-top-1" }, h("map-layer-picker", { enabledLayerIds: this.enabledLayerIds, mapView: this.mapView, onLayerSelectionChange: (evt) => { void this._layerSelectionChange(evt); }, selectedLayerIds: this.layerViews.map(l => l.layer.id), selectionMode: "single" }))));
211
211
  }
212
212
  /**
213
213
  * Renders the number of selected features
@@ -809,7 +809,7 @@ function defineCustomElement() {
809
809
  if (typeof customElements === "undefined") {
810
810
  return;
811
811
  }
812
- const components = ["map-select-tools", "buffer-tools", "calcite-action", "calcite-chip", "calcite-combobox", "calcite-combobox-item", "calcite-graph", "calcite-icon", "calcite-input", "calcite-input-message", "calcite-label", "calcite-loader", "calcite-option", "calcite-progress", "calcite-select", "calcite-slider", "calcite-switch", "calcite-tooltip", "map-draw-tools", "map-layer-picker"];
812
+ const components = ["map-select-tools", "buffer-tools", "calcite-action", "calcite-chip", "calcite-combobox", "calcite-combobox-item", "calcite-graph", "calcite-icon", "calcite-input", "calcite-input-message", "calcite-label", "calcite-loader", "calcite-option", "calcite-popover", "calcite-progress", "calcite-select", "calcite-slider", "calcite-switch", "map-draw-tools", "map-layer-picker"];
813
813
  components.forEach(tagName => { switch (tagName) {
814
814
  case "map-select-tools":
815
815
  if (!customElements.get(tagName)) {
@@ -876,27 +876,27 @@ function defineCustomElement() {
876
876
  defineCustomElement$8();
877
877
  }
878
878
  break;
879
- case "calcite-progress":
879
+ case "calcite-popover":
880
880
  if (!customElements.get(tagName)) {
881
881
  defineCustomElement$7();
882
882
  }
883
883
  break;
884
- case "calcite-select":
884
+ case "calcite-progress":
885
885
  if (!customElements.get(tagName)) {
886
886
  defineCustomElement$6();
887
887
  }
888
888
  break;
889
- case "calcite-slider":
889
+ case "calcite-select":
890
890
  if (!customElements.get(tagName)) {
891
891
  defineCustomElement$5();
892
892
  }
893
893
  break;
894
- case "calcite-switch":
894
+ case "calcite-slider":
895
895
  if (!customElements.get(tagName)) {
896
896
  defineCustomElement$4();
897
897
  }
898
898
  break;
899
- case "calcite-tooltip":
899
+ case "calcite-switch":
900
900
  if (!customElements.get(tagName)) {
901
901
  defineCustomElement$3();
902
902
  }