UNPKG

@arcgis/map-components

Version:
499 lines (498 loc) • 23.7 kB
/* COPYRIGHT Esri - https://js.arcgis.com/5.1/LICENSE.txt */ import { c as S } from "../../chunks/runtime.js"; import { css as M, html as m } from "lit"; import { keyed as C } from "lit/directives/keyed.js"; import { i as k, q as D } from "../../chunks/layer-utils.js"; import { createReactiveMap as I, findUtilityNetwork as V, getOrCreateMapValue as j } from "@arcgis/core/applications/Components/featureUtils.js"; import { stripHTML as v } from "@arcgis/core/applications/Components/stringUtils.js"; import w from "@arcgis/core/core/Collection.js"; import { ignoreAbortErrors as E } from "@arcgis/core/core/promiseUtils.js"; import { watch as A } from "@arcgis/core/core/reactiveUtils.js"; import * as x from "@arcgis/core/core/sql.js"; import P from "@arcgis/core/rest/networks/support/NetworkElement.js"; import U from "@arcgis/core/rest/networks/support/QueryAssociationsParameters.js"; import { LitElement as Q, renderElement as q } from "@arcgis/lumina"; import { debounce as T } from "@arcgis/toolkit/function"; import G from "@arcgis/core/popup/Feature.js"; const B = M`.list-container{min-height:var(--calcite-spacing-xxxl)}.loading-container{display:flex;justify-content:center;padding:var(--calcite-spacing-md) 0;width:100%}.sticky-loading-container{display:flex;position:sticky;bottom:var(--calcite-spacing-sm);align-items:center;justify-content:center;z-index:2;margin:0;padding:0;height:var(--calcite-spacing-xxxl);pointer-events:none;height:500px}`, L = 100, $ = { assetGroup: "assetgroup", assetType: "assettype" }, N = "{00000000-0000-0000-0000-000000000000}"; class R extends Q { constructor() { super(...arguments), this._addFlowItem = (t) => { t && this.flowItems?.push(t); }, this._attachmentAssociations = new w(), this._attachmentFeatureCount = 0, this._cancelQuery = () => { const { _queryAbortController: t } = this; t && t.abort(), this._queryAbortController = null; }, this._cancelQueryFeatureCount = () => { const { _queryFeatureCountAbortController: t } = this; t && t.abort(), this._queryFeatureCountAbortController = null; }, this._connectivityAssociations = new w(), this._connectivityFeatureCount = 0, this._containerAssociations = new w(), this._containerFeatureCount = 0, this._contentAssociations = new w(), this._contentFeatureCount = 0, this._networkSourceIdsInUse = /* @__PURE__ */ new Set(), this._query = async (t) => { if (!t) return; await this._loadUtiltyNetworks(); const { _queryAbortController: e } = this; this._destroyAssociatedFeatureViewModels(), this._clearFeatures(), this._featureCount && await this._queryAssociatedFeatures(t, { signal: e?.signal }); }, this._queryController = async (t) => { this._cancelQuery(); const e = new AbortController(); this._queryAbortController = e, await E(this._query(t)), this._queryAbortController === e && (this._queryAbortController = null); }, this._queryFeatureCountController = async () => { this._loaded = !1, this._cancelQueryFeatureCount(); const t = new AbortController(); this._queryFeatureCountAbortController = t, await E(this._queryFeatureCount()), this._queryFeatureCountAbortController === t && (this._queryFeatureCountAbortController = null), this._loaded = !0; }, this._queryDebounced = T(this._queryController, L), this._queryFeatureCountDebounced = T(this._queryFeatureCountController, L), this._structureAssociations = new w(), this._structureFeatureCount = 0, this._queryAssociationType = async () => { this._activeAssociationType && this._queryDebounced(this._activeAssociationType); }, this._associationFeatures = I(), this._associationViewModels = I(), this._featureCount = 0, this._loaded = !1, this._queryAbortController = null, this._queryFeatureCountAbortController = null, this._queryPageAbortController = null, this.associationTypes = null, this.autoDestroyDisabled = !1, this.useFeatureNextFlowItem = !1, this.flowType = "feature-utility-network-associations", this.headingLevel = 2, this.source = "popup"; } static { this.properties = { _activeAssociationType: 16, _associationFeatures: 16, _associationViewModels: 16, _canLoad: 16, _canQuery: 16, _featureCount: 16, _loaded: 16, _queryAbortController: 16, _queryFeatureCountAbortController: 16, _queryPageAbortController: 16, _state: 16, associationTypes: 0, autoDestroyDisabled: 5, description: 1, flowItems: 0, useFeatureNextFlowItem: 5, flowType: 1, graphic: 0, heading: 1, headingLevel: 9, layer: 0, map: 0, messages: 0, parentFeatureViewModel: 0, referenceElement: 1, source: 1, spatialReference: 0, timeZone: 1, view: 0 }; } static { this.styles = B; } get _globalId() { return (this._globalIdField && this.graphic?.attributes?.[this._globalIdField]) ?? null; } get _globalIdField() { return this.layer?.globalIdField; } get _objectId() { return (this._objectIdField && this.graphic?.attributes?.[this._objectIdField]) ?? null; } get _objectIdField() { return this.layer?.objectIdField; } get _supportsCacheHint() { return !!this.layer?.capabilities?.queryRelated?.supportsCacheHint; } get _utilityNetwork() { const { layer: t, map: e } = this; if (!t?.loaded || !e) return null; const s = k(t) ? t.parent : t; return V(e, s); } get _canLoad() { return !!this.map; } get _canQuery() { return !!this.layer?.capabilities?.query?.supportsPagination; } get _state() { const { _canLoad: t, _canQuery: e, _featureCount: s, _loaded: o, _queryAbortController: i, _queryFeatureCountAbortController: a, _queryPageAbortController: r, associationTypes: c } = this; return a || t && !o ? "loading" : i || r ? "querying" : !this._globalId || !c || !e || !s ? "disabled" : "ready"; } get heading() { return this._heading; } set heading(t) { this._heading = t; } async destroy() { await this.manager.destroy(); } loaded() { this.manager.onLifecycle(() => [ A(() => [ this.graphic, this.layer, this.map, this.associationTypes, this._canQuery, this._objectId, this._globalId ], () => { this._queryFeatureCountDebounced(), this._queryAssociationType(); }, { initial: !0 }), A(() => this._activeAssociationType, (t) => { this._queryDebounced(t); }), A(() => this._associationFeatures.values(), () => { this._setUpUtilityNetworkAssociationsViewModels(); }) ]), this.manager.onDestroy(() => { this._cancelQuery(), this._cancelQueryFeatureCount(); }); } _addAssociationTypeFlowItem(t) { const e = this.useFeatureNextFlowItem ? q(m`<arcgis-feature-utility-network-association-list .autoDestroyDisabled=${this.autoDestroyDisabled} .associationViewModels=${this._associationViewModels} .description=${this._getParentFeatureDescription()} .flowItems=${this.flowItems} .flowType=${this.flowType} .heading=${this._getAssociationTypeTitle(t)} .messages=${this.messages} .map=${this.map} .parentFeatureViewModel=${this.parentFeatureViewModel} .referenceElement=${this.referenceElement} .state=${this._state} .spatialReference=${this.spatialReference} .timeZone=${this.timeZone} use-feature-next-flow-item .view=${this.view}></arcgis-feature-utility-network-association-list>`) : q(m`<arcgis-feature-utility-network-association-list .autoDestroyDisabled=${this.autoDestroyDisabled} .associationViewModels=${this._associationViewModels} .description=${this._getParentFeatureDescription()} .flowItems=${this.flowItems} .flowType=${this.flowType} .heading=${this._getAssociationTypeTitle(t)} .messages=${this.messages} .map=${this.map} .parentFeatureViewModel=${this.parentFeatureViewModel} .referenceElement=${this.referenceElement} .state=${this._state} .spatialReference=${this.spatialReference} .timeZone=${this.timeZone} .view=${this.view}></arcgis-feature-utility-network-association-list>`); this._addFlowItem(e); } _clearAssociations() { this._attachmentAssociations.removeAll(), this._connectivityAssociations.removeAll(), this._containerAssociations.removeAll(), this._contentAssociations.removeAll(), this._structureAssociations.removeAll(); } _clearFeatures() { this._associationFeatures.forEach((t) => t.removeAll()), this._associationFeatures.clear(); } _compareByFeatureTitle(t, e) { return t.title.localeCompare(e.title, void 0, { numeric: !0 }); } async _countAssociatedFeatureCount(t, e, s, o, i) { const a = this._getFeatureQueryWhereClause(t, e, s, o), r = t.createQuery(); return r.where = a, r.outFields = ["*"], r.returnGeometry = !1, await t.queryFeatureCount(r, { signal: i?.signal }); } async _countAssociatedFeatures(t, e, s, o, i) { if (!e.length) return 0; const a = await this._findLayersBySourceId(t); await this._loadLayers(a); const r = a.map((l) => this._countAssociatedFeatureCount(l, e, s, o, i)); return (await Promise.all(r)).reduce((l, d) => l + d, 0); } async _createAssociationFeatureObjects(t, e, s, o, i) { if (!t.length) return []; const a = /* @__PURE__ */ new Map(), r = Array.from(e.entries()).map(async ([l, d]) => { const u = await this._findLayersBySourceId(l); await this._loadLayers(u); const y = u.map((n) => this._queryLayer(n, d, s, o, i)); (await Promise.all(y)).forEach((n) => { n.forEach((h) => { if (this.source === "popup" ? h.sourceLayer && h.getEffectivePopupTemplate() : !!h.sourceLayer) { const f = h.layer.globalIdField ?? "", g = h.getAttribute(f), F = a.get(g) ?? []; F.push(h), a.set(g, F); } }); }); }); await Promise.all(r); const c = []; return await Promise.all(t.toArray().map(async (l) => { const { fromNetworkElement: d, toNetworkElement: u } = l, y = d.globalId === this._globalId ? u : d, p = a.get(y.globalId) ?? []; await Promise.all(p.map(async (n) => { const h = this._utilityNetwork?.getTerminalById(y?.terminalId ?? void 0)?.name, _ = await n.sourceLayer.getFeatureTitle(n) || this._getFeatureTitle(n); c.push({ title: _, feature: n, association: l, terminalName: h }); })); })), c; } _destroyAssociatedFeatureViewModels() { this._associationViewModels.forEach((t) => t.destroyAll()); } _equals(t, e) { if (t.globalId === N && e.globalId === N) { let s = function(d, u) { return d.networkSourceId === u.networkSourceId && d.globalId === u.globalId && d.terminalId === u.terminalId && d.firstUnit === u.firstUnit && d.numUnits === u.numUnits; }; const o = t.fromNetworkElement, i = t.toNetworkElement, a = e.fromNetworkElement, r = e.toNetworkElement, c = s(o, a), l = s(i, r); return c && l && t.associationType === e.associationType; } return t.globalId != null && e.globalId != null && t.globalId === e.globalId; } async _findLayersBySourceId(t) { const { _utilityNetwork: e, map: s } = this; e?.loaded || await e?.load(); const o = e.getLayerIdBySourceId(t), i = s.allLayers.filter((c) => !!e?.isUtilityLayer(c) && c.layerId === o), a = s.allTables.filter((c) => !!e?.isUtilityLayer(c) && c.layerId === o); return i.concat(a).toArray(); } _getAssociationsByType(t) { switch (t) { case "attachment": return this._attachmentAssociations; case "structure": return this._structureAssociations; case "connectivity": return this._connectivityAssociations; case "container": return this._containerAssociations; case "content": return this._contentAssociations; } } _getAssociationTypeTitle(t) { const { messages: e } = this; if (t.title) return t.title; switch (t.type) { case "attachment": return e?.associationsAttachments ?? this.messages?.noTitle ?? ""; case "connectivity": return e?.associationsConnectivity ?? this.messages?.noTitle ?? ""; case "structure": return e?.associationsStructure ?? this.messages?.noTitle ?? ""; case "content": return e?.associationsContents ?? this.messages?.noTitle ?? ""; case "container": return e?.associationsContainer ?? this.messages?.noTitle ?? ""; } } _getFeatureCountForAssociationType(t) { switch (t) { case "attachment": return this._attachmentFeatureCount; case "structure": return this._structureFeatureCount; case "content": return this._contentFeatureCount; case "container": return this._containerFeatureCount; case "connectivity": return this._connectivityFeatureCount; } } _getFeatureQueryWhereClause(t, e, s, o) { const i = t.globalIdField, a = t.fieldsIndex.get($.assetGroup), r = t.fieldsIndex.get($.assetType), c = s != null, l = o != null, d = i ? x.sqlIn(i, e) : null, u = c ? `(${a?.name} = ${s})` : null, y = c && l ? `(${r?.name} = ${o})` : null; return [d, u, y].filter(Boolean).join(" AND "); } _getFeatureTitle(t) { const e = t.attributes, s = t.sourceLayer; if (!e || !s) return ""; const o = "displayField" in s ? s.displayField : null, i = o != null ? e[o.toString()] : null, a = i != null ? i.toString() : null, r = t.getObjectId()?.toString(); return a || r || ""; } _getParentFeatureDescription() { const { parentFeatureViewModel: t } = this; if (t) { if ("heading" in t) return t.heading; if ("title" in t) return t.title; } } async _loadUtiltyNetworks() { const t = this.map; if (!t) return; t.utilityNetworks && await Promise.allSettled(t.utilityNetworks.map((s) => s.load())); const e = this._utilityNetwork; if (e) { const s = (o) => { if ("layerId" in o && e.isUtilityLayer(o)) { const i = o.layerId != null ? e.getSourceIdByLayerId(o.layerId) : null; i != null && this._networkSourceIdsInUse.add(i); } }; this._networkSourceIdsInUse = /* @__PURE__ */ new Set(), t.allLayers.forEach(s), t.allTables.forEach(s); } } async _loadLayers(t) { const e = t.filter((s) => !s.loaded).map((s) => s.load()); e.length && await Promise.allSettled(e); } _matchesGlobalFeature(t, e) { return this._equals(t.association, e.association); } async _queryAssociatedFeatures(t, e) { const { layer: s, _globalId: o, associationTypes: i, _utilityNetwork: a, _canQuery: r, _associationFeatures: c } = this; if (await Promise.allSettled([s?.load(), a?.load()]), !r || !s || !i || !a) return; const l = this._getAssociationsByType(t.type), { associatedAssetGroup: d, associatedAssetType: u } = t, y = /* @__PURE__ */ new Map(); l.forEach((n) => { const { fromNetworkElement: h, toNetworkElement: _ } = n, { networkSourceId: f, elementGlobalId: g } = h.globalId === o ? { networkSourceId: _.networkSourceId, elementGlobalId: _.globalId } : { networkSourceId: h.networkSourceId, elementGlobalId: h.globalId }, F = y.get(f) || []; F.push(g), y.set(f, F); }); const p = await this._createAssociationFeatureObjects(l, y, d, u, e); this._parseFeatureObjects(p, c); } async _queryAssociations(t) { const { layer: e, _globalId: s, associationTypes: o, _utilityNetwork: i, _canQuery: a } = this; if (await Promise.allSettled([e?.load(), i?.load()]), this._clearAssociations(), !a || !e || !o || !i || !s) return; const r = k(e) ? e.parent : e, c = new P({ globalId: s, networkSourceId: i.getSourceIdByLayerId(r.layerId) }), l = /* @__PURE__ */ new Set(); o.forEach((n) => { switch (n.type) { case "attachment": case "structure": l.add("attachment"); break; case "container": case "content": l.add("containment"); break; case "connectivity": l.add("connectivity"), l.add("junction-junction-connectivity"), l.add("junction-edge-from-connectivity"), l.add("junction-edge-midspan-connectivity"), l.add("junction-edge-to-connectivity"); break; } }); const d = await i?.queryAssociations(new U({ elements: [c], types: Array.from(l) }), { signal: t?.signal }), u = /* @__PURE__ */ new Map(), y = /* @__PURE__ */ new Map(); o.forEach((n) => { y.set(n.type, n), u.set(n.type, []); }), d.forEach((n) => { const { toNetworkElement: h, fromNetworkElement: _ } = n; switch (n.associationType) { case "attachment": if (_?.globalId === s) { if (this._shouldDiscardNetworkElement(h, "attachment", y)) break; u.get("attachment")?.push(h.globalId), this._attachmentAssociations.add(n); } else { if (this._shouldDiscardNetworkElement(_, "structure", y)) break; u.get("structure")?.push(_.globalId), this._structureAssociations.add(n); } break; case "connectivity": case "junction-edge-from-connectivity": case "junction-edge-midspan-connectivity": case "junction-edge-to-connectivity": case "junction-junction-connectivity": if (_?.globalId === s) { if (this._shouldDiscardNetworkElement(h, "connectivity", y)) break; u.get("connectivity")?.push(h.globalId); } else { if (this._shouldDiscardNetworkElement(_, "connectivity", y)) break; u.get("connectivity")?.push(_.globalId); } this._connectivityAssociations.add(n); break; case "containment": if (_?.globalId === s) { if (this._shouldDiscardNetworkElement(h, "content", y)) break; u.get("content")?.push(h.globalId), this._contentAssociations.add(n); } else { if (this._shouldDiscardNetworkElement(_, "container", y)) break; u.get("container")?.push(_.globalId), this._containerAssociations.add(n); } break; } }); const p = o.map(async (n) => { const { associatedNetworkSourceId: h, associatedAssetGroup: _, associatedAssetType: f } = n, g = u.get(n.type), b = _ != null ? await this._countAssociatedFeatures(h, g, _, f, t) : g.length; switch (n.type) { case "attachment": this._attachmentFeatureCount = b; break; case "connectivity": this._connectivityFeatureCount = b; break; case "container": this._containerFeatureCount = b; break; case "content": this._contentFeatureCount = b; break; case "structure": this._structureFeatureCount = b; break; } }); await Promise.allSettled(p); } async _queryFeatureCount() { await this._loadUtiltyNetworks(); const { _queryFeatureCountAbortController: t, _canQuery: e } = this; if (!e) { this._featureCount = 0; return; } await this._queryAssociations(t), this._featureCount = this._attachmentFeatureCount + this._connectivityFeatureCount + this._containerFeatureCount + this._contentFeatureCount + this._structureFeatureCount; } async _queryLayer(t, e, s, o, i) { const a = this._getFeatureQueryWhereClause(t, e, s, o), r = t.createQuery(); r.where = a, r.outFields = ["*"], r.returnGeometry = !1, r.cacheHint = this._supportsCacheHint; const { features: c } = await D(t, r, i); return c; } _parseFeatureObjects(t, e) { const s = I(); t.forEach((o) => { const a = (o?.feature).sourceLayer; j(s, a, () => new w()).add(o); }); for (const [o, i] of s) this._sortFeatureObjectsByTitle(i), e.set(o, i); } _selectAssociationType(t) { const { flowItems: e } = this; e && (this._activeAssociationType = t, this._setUpUtilityNetworkAssociationsViewModels(), this._addAssociationTypeFlowItem(t)); } _setUpUtilityNetworkAssociationsViewModels() { this._associationViewModels.forEach((i, a) => { const r = this._associationFeatures.get(a); r ? i.forEach((c) => { r.find((d) => this._matchesGlobalFeature(c, d)) || (i.remove(c), i.length || this._associationViewModels.delete(a)); }) : (i.removeAll(), this._associationViewModels.delete(a)); }); const { map: t, view: e, spatialReference: s, timeZone: o } = this; this._associationFeatures.forEach((i, a) => { const r = this._associationViewModels.get(a) || new w(); i?.filter(Boolean).forEach((c, l) => { if (!r.some((u) => this._matchesGlobalFeature(u, c))) { const { association: u, feature: y, terminalName: p, title: n } = c; r.add({ title: n, association: u, featureViewModel: new G({ abilities: { utilityNetworkAssociationsContent: !1 }, map: t, view: e, spatialReference: s, timeZone: o, graphic: y }), terminalName: p }, l); } }), this._associationViewModels.set(a, r); }); } _shouldDiscardNetworkElement(t, e, s) { if (!t) return !1; const { networkSourceId: o } = t, i = s.get(e)?.associatedNetworkSourceId, a = this._networkSourceIdsInUse.has(o); return i != null && i !== o || !a; } _sortFeatureObjectsByTitle(t) { t.sort(this._compareByFeatureTitle); } render() { const { _state: t } = this; return m`<div class="root"><arcgis-feature-element-info .heading=${this.heading} .headingLevel=${this.headingLevel} .description=${this.description}></arcgis-feature-element-info>${t === "loading" ? this._renderLoading() : t === "disabled" ? this._renderAssociationNotFound() : this._renderContent()}</div>`; } _renderAssociationNotFound() { return m`<calcite-notice icon=information kind=info open scale=s width=full><div slot=message>${this.messages?.noAssociations}</div></calcite-notice>`; } _renderAssociationTypeList(t) { return this._getFeatureCountForAssociationType(t.type) > 0 ? this._renderAssociationTypeListItem(t) : null; } _renderAssociationTypeListItem(t) { const e = this._getAssociationTypeTitle(t); return C(`association-type-${t.type}`, m`<calcite-list-item .description=${v(t.description)} .label=${v(e)} .value=${t.type} @calciteListItemSelect=${() => this._selectAssociationType(t)}><calcite-icon flip-rtl icon=chevron-right scale=s slot=content-end></calcite-icon></calcite-list-item>`); } _renderContent() { const { _state: t, associationTypes: e, messages: s } = this, o = s?.associationsList ?? s?.noTitle ?? ""; return C("list-container", m`<div class="list-container">${t === "ready" ? m`<div><calcite-list display-mode=flat .label=${o}>${e.map((i) => this._renderAssociationTypeList(i))}</calcite-list></div>` : null}${this._renderStickyLoading()}</div>`); } _renderLoading() { return m`<div class="loading-container">${this._renderLoadingIcon()}${this._renderStickyLoading()}</div>`; } _renderLoadingIcon() { return m`<calcite-loader inline label></calcite-loader>`; } _renderStickyLoading() { return this._state === "querying" ? m`<div class="sticky-loading-container">${this._renderLoadingIcon()}</div>` : null; } } S("arcgis-feature-utility-network-associations", R); export { R as ArcgisFeatureUtilityNetworkAssociations };