@itwin/map-layers 4.0.0-dev.7 → 4.0.0
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.
- package/CHANGELOG.md +746 -848
- package/README.md +32 -32
- package/lib/cjs/MapLayerPreferences.d.ts +88 -88
- package/lib/cjs/MapLayerPreferences.js +312 -312
- package/lib/cjs/MapLayerPreferences.js.map +1 -1
- package/lib/cjs/map-layers.d.ts +6 -6
- package/lib/cjs/map-layers.js +22 -22
- package/lib/cjs/mapLayers.d.ts +26 -44
- package/lib/cjs/mapLayers.d.ts.map +1 -1
- package/lib/cjs/mapLayers.js +34 -63
- package/lib/cjs/mapLayers.js.map +1 -1
- package/lib/cjs/ui/FeatureInfoUiItemsProvider.d.ts +16 -11
- package/lib/cjs/ui/FeatureInfoUiItemsProvider.d.ts.map +1 -1
- package/lib/cjs/ui/FeatureInfoUiItemsProvider.js +47 -52
- package/lib/cjs/ui/FeatureInfoUiItemsProvider.js.map +1 -1
- package/lib/cjs/ui/Interfaces.d.ts +50 -50
- package/lib/cjs/ui/Interfaces.js +2 -2
- package/lib/cjs/ui/Interfaces.js.map +1 -1
- package/lib/cjs/ui/MapFeatureInfoTool.d.ts +13 -13
- package/lib/cjs/ui/MapFeatureInfoTool.d.ts.map +1 -1
- package/lib/cjs/ui/MapFeatureInfoTool.js +50 -50
- package/lib/cjs/ui/MapFeatureInfoTool.js.map +1 -1
- package/lib/cjs/ui/MapLayersUiItemsProvider.d.ts +8 -8
- package/lib/cjs/ui/MapLayersUiItemsProvider.d.ts.map +1 -1
- package/lib/cjs/ui/MapLayersUiItemsProvider.js +35 -38
- package/lib/cjs/ui/MapLayersUiItemsProvider.js.map +1 -1
- package/lib/cjs/ui/widget/AttachLayerPopupButton.d.ts +13 -14
- package/lib/cjs/ui/widget/AttachLayerPopupButton.d.ts.map +1 -1
- package/lib/cjs/ui/widget/AttachLayerPopupButton.js +338 -338
- package/lib/cjs/ui/widget/AttachLayerPopupButton.js.map +1 -1
- package/lib/cjs/ui/widget/BasemapPanel.d.ts +7 -8
- package/lib/cjs/ui/widget/BasemapPanel.d.ts.map +1 -1
- package/lib/cjs/ui/widget/BasemapPanel.js +156 -156
- package/lib/cjs/ui/widget/BasemapPanel.js.map +1 -1
- package/lib/cjs/ui/widget/BasemapPanel.scss +87 -87
- package/lib/cjs/ui/widget/ConfirmMessageDialog.d.ts +20 -21
- package/lib/cjs/ui/widget/ConfirmMessageDialog.d.ts.map +1 -1
- package/lib/cjs/ui/widget/ConfirmMessageDialog.js +25 -25
- package/lib/cjs/ui/widget/ConfirmMessageDialog.js.map +1 -1
- package/lib/cjs/ui/widget/FeatureInfoDataProvider.d.ts +35 -40
- package/lib/cjs/ui/widget/FeatureInfoDataProvider.d.ts.map +1 -1
- package/lib/cjs/ui/widget/FeatureInfoDataProvider.js +140 -139
- package/lib/cjs/ui/widget/FeatureInfoDataProvider.js.map +1 -1
- package/lib/cjs/ui/widget/FeatureInfoWidget.d.ts +6 -7
- package/lib/cjs/ui/widget/FeatureInfoWidget.d.ts.map +1 -1
- package/lib/cjs/ui/widget/FeatureInfoWidget.js +76 -71
- package/lib/cjs/ui/widget/FeatureInfoWidget.js.map +1 -1
- package/lib/cjs/ui/widget/MapLayerDroppable.d.ts +18 -19
- package/lib/cjs/ui/widget/MapLayerDroppable.d.ts.map +1 -1
- package/lib/cjs/ui/widget/MapLayerDroppable.js +88 -88
- package/lib/cjs/ui/widget/MapLayerDroppable.js.map +1 -1
- package/lib/cjs/ui/widget/MapLayerManager.d.ts +26 -26
- package/lib/cjs/ui/widget/MapLayerManager.js +403 -403
- package/lib/cjs/ui/widget/MapLayerManager.js.map +1 -1
- package/lib/cjs/ui/widget/MapLayerManager.scss +409 -409
- package/lib/cjs/ui/widget/MapLayerSettingsMenu.d.ts +11 -12
- package/lib/cjs/ui/widget/MapLayerSettingsMenu.d.ts.map +1 -1
- package/lib/cjs/ui/widget/MapLayerSettingsMenu.js +83 -83
- package/lib/cjs/ui/widget/MapLayerSettingsMenu.js.map +1 -1
- package/lib/cjs/ui/widget/MapLayerSettingsPopupButton.d.ts +6 -7
- package/lib/cjs/ui/widget/MapLayerSettingsPopupButton.d.ts.map +1 -1
- package/lib/cjs/ui/widget/MapLayerSettingsPopupButton.js +65 -65
- package/lib/cjs/ui/widget/MapLayerSettingsPopupButton.js.map +1 -1
- package/lib/cjs/ui/widget/MapLayerSettingsPopupButton.scss +20 -20
- package/lib/cjs/ui/widget/MapLayersWidget.d.ts +10 -11
- package/lib/cjs/ui/widget/MapLayersWidget.d.ts.map +1 -1
- package/lib/cjs/ui/widget/MapLayersWidget.js +31 -31
- package/lib/cjs/ui/widget/MapLayersWidget.js.map +1 -1
- package/lib/cjs/ui/widget/MapManagerSettings.d.ts +2 -3
- package/lib/cjs/ui/widget/MapManagerSettings.d.ts.map +1 -1
- package/lib/cjs/ui/widget/MapManagerSettings.js +200 -200
- package/lib/cjs/ui/widget/MapManagerSettings.js.map +1 -1
- package/lib/cjs/ui/widget/MapManagerSettings.scss +29 -29
- package/lib/cjs/ui/widget/MapUrlDialog.d.ts +22 -23
- package/lib/cjs/ui/widget/MapUrlDialog.d.ts.map +1 -1
- package/lib/cjs/ui/widget/MapUrlDialog.js +533 -527
- package/lib/cjs/ui/widget/MapUrlDialog.js.map +1 -1
- package/lib/cjs/ui/widget/MapUrlDialog.scss +99 -100
- package/lib/cjs/ui/widget/SelectMapFormat.d.ts +17 -18
- package/lib/cjs/ui/widget/SelectMapFormat.d.ts.map +1 -1
- package/lib/cjs/ui/widget/SelectMapFormat.js +59 -59
- package/lib/cjs/ui/widget/SelectMapFormat.js.map +1 -1
- package/lib/cjs/ui/widget/SubLayersDataProvider.d.ts +18 -20
- package/lib/cjs/ui/widget/SubLayersDataProvider.d.ts.map +1 -1
- package/lib/cjs/ui/widget/SubLayersDataProvider.js +75 -76
- package/lib/cjs/ui/widget/SubLayersDataProvider.js.map +1 -1
- package/lib/cjs/ui/widget/SubLayersPopupButton.d.ts +9 -10
- package/lib/cjs/ui/widget/SubLayersPopupButton.d.ts.map +1 -1
- package/lib/cjs/ui/widget/SubLayersPopupButton.js +40 -40
- package/lib/cjs/ui/widget/SubLayersPopupButton.js.map +1 -1
- package/lib/cjs/ui/widget/SubLayersTree.d.ts +14 -15
- package/lib/cjs/ui/widget/SubLayersTree.d.ts.map +1 -1
- package/lib/cjs/ui/widget/SubLayersTree.js +419 -419
- package/lib/cjs/ui/widget/SubLayersTree.js.map +1 -1
- package/lib/cjs/ui/widget/SubLayersTree.scss +70 -69
- package/lib/cjs/ui/widget/TransparencyPopupButton.d.ts +13 -14
- package/lib/cjs/ui/widget/TransparencyPopupButton.d.ts.map +1 -1
- package/lib/cjs/ui/widget/TransparencyPopupButton.js +47 -47
- package/lib/cjs/ui/widget/TransparencyPopupButton.js.map +1 -1
- package/lib/cjs/ui/widget/TransparencyPopupButton.scss +35 -36
- package/lib/esm/MapLayerPreferences.d.ts +88 -88
- package/lib/esm/MapLayerPreferences.js +308 -308
- package/lib/esm/MapLayerPreferences.js.map +1 -1
- package/lib/esm/map-layers.d.ts +6 -6
- package/lib/esm/map-layers.js +10 -10
- package/lib/esm/mapLayers.d.ts +26 -44
- package/lib/esm/mapLayers.d.ts.map +1 -1
- package/lib/esm/mapLayers.js +30 -59
- package/lib/esm/mapLayers.js.map +1 -1
- package/lib/esm/ui/FeatureInfoUiItemsProvider.d.ts +16 -11
- package/lib/esm/ui/FeatureInfoUiItemsProvider.d.ts.map +1 -1
- package/lib/esm/ui/FeatureInfoUiItemsProvider.js +43 -48
- package/lib/esm/ui/FeatureInfoUiItemsProvider.js.map +1 -1
- package/lib/esm/ui/Interfaces.d.ts +50 -50
- package/lib/esm/ui/Interfaces.js +1 -1
- package/lib/esm/ui/Interfaces.js.map +1 -1
- package/lib/esm/ui/MapFeatureInfoTool.d.ts +13 -13
- package/lib/esm/ui/MapFeatureInfoTool.d.ts.map +1 -1
- package/lib/esm/ui/MapFeatureInfoTool.js +45 -45
- package/lib/esm/ui/MapFeatureInfoTool.js.map +1 -1
- package/lib/esm/ui/MapLayersUiItemsProvider.d.ts +8 -8
- package/lib/esm/ui/MapLayersUiItemsProvider.d.ts.map +1 -1
- package/lib/esm/ui/MapLayersUiItemsProvider.js +31 -34
- package/lib/esm/ui/MapLayersUiItemsProvider.js.map +1 -1
- package/lib/esm/ui/widget/AttachLayerPopupButton.d.ts +13 -14
- package/lib/esm/ui/widget/AttachLayerPopupButton.d.ts.map +1 -1
- package/lib/esm/ui/widget/AttachLayerPopupButton.js +334 -334
- package/lib/esm/ui/widget/AttachLayerPopupButton.js.map +1 -1
- package/lib/esm/ui/widget/BasemapPanel.d.ts +7 -8
- package/lib/esm/ui/widget/BasemapPanel.d.ts.map +1 -1
- package/lib/esm/ui/widget/BasemapPanel.js +152 -152
- package/lib/esm/ui/widget/BasemapPanel.js.map +1 -1
- package/lib/esm/ui/widget/BasemapPanel.scss +87 -87
- package/lib/esm/ui/widget/ConfirmMessageDialog.d.ts +20 -21
- package/lib/esm/ui/widget/ConfirmMessageDialog.d.ts.map +1 -1
- package/lib/esm/ui/widget/ConfirmMessageDialog.js +21 -21
- package/lib/esm/ui/widget/ConfirmMessageDialog.js.map +1 -1
- package/lib/esm/ui/widget/FeatureInfoDataProvider.d.ts +35 -40
- package/lib/esm/ui/widget/FeatureInfoDataProvider.d.ts.map +1 -1
- package/lib/esm/ui/widget/FeatureInfoDataProvider.js +136 -135
- package/lib/esm/ui/widget/FeatureInfoDataProvider.js.map +1 -1
- package/lib/esm/ui/widget/FeatureInfoWidget.d.ts +6 -7
- package/lib/esm/ui/widget/FeatureInfoWidget.d.ts.map +1 -1
- package/lib/esm/ui/widget/FeatureInfoWidget.js +72 -67
- package/lib/esm/ui/widget/FeatureInfoWidget.js.map +1 -1
- package/lib/esm/ui/widget/MapLayerDroppable.d.ts +18 -19
- package/lib/esm/ui/widget/MapLayerDroppable.d.ts.map +1 -1
- package/lib/esm/ui/widget/MapLayerDroppable.js +84 -84
- package/lib/esm/ui/widget/MapLayerDroppable.js.map +1 -1
- package/lib/esm/ui/widget/MapLayerManager.d.ts +26 -26
- package/lib/esm/ui/widget/MapLayerManager.js +398 -398
- package/lib/esm/ui/widget/MapLayerManager.js.map +1 -1
- package/lib/esm/ui/widget/MapLayerManager.scss +409 -409
- package/lib/esm/ui/widget/MapLayerSettingsMenu.d.ts +11 -12
- package/lib/esm/ui/widget/MapLayerSettingsMenu.d.ts.map +1 -1
- package/lib/esm/ui/widget/MapLayerSettingsMenu.js +79 -79
- package/lib/esm/ui/widget/MapLayerSettingsMenu.js.map +1 -1
- package/lib/esm/ui/widget/MapLayerSettingsPopupButton.d.ts +6 -7
- package/lib/esm/ui/widget/MapLayerSettingsPopupButton.d.ts.map +1 -1
- package/lib/esm/ui/widget/MapLayerSettingsPopupButton.js +61 -61
- package/lib/esm/ui/widget/MapLayerSettingsPopupButton.js.map +1 -1
- package/lib/esm/ui/widget/MapLayerSettingsPopupButton.scss +20 -20
- package/lib/esm/ui/widget/MapLayersWidget.d.ts +10 -11
- package/lib/esm/ui/widget/MapLayersWidget.d.ts.map +1 -1
- package/lib/esm/ui/widget/MapLayersWidget.js +27 -27
- package/lib/esm/ui/widget/MapLayersWidget.js.map +1 -1
- package/lib/esm/ui/widget/MapManagerSettings.d.ts +2 -3
- package/lib/esm/ui/widget/MapManagerSettings.d.ts.map +1 -1
- package/lib/esm/ui/widget/MapManagerSettings.js +196 -196
- package/lib/esm/ui/widget/MapManagerSettings.js.map +1 -1
- package/lib/esm/ui/widget/MapManagerSettings.scss +29 -29
- package/lib/esm/ui/widget/MapUrlDialog.d.ts +22 -23
- package/lib/esm/ui/widget/MapUrlDialog.d.ts.map +1 -1
- package/lib/esm/ui/widget/MapUrlDialog.js +529 -523
- package/lib/esm/ui/widget/MapUrlDialog.js.map +1 -1
- package/lib/esm/ui/widget/MapUrlDialog.scss +99 -100
- package/lib/esm/ui/widget/SelectMapFormat.d.ts +17 -18
- package/lib/esm/ui/widget/SelectMapFormat.d.ts.map +1 -1
- package/lib/esm/ui/widget/SelectMapFormat.js +55 -55
- package/lib/esm/ui/widget/SelectMapFormat.js.map +1 -1
- package/lib/esm/ui/widget/SubLayersDataProvider.d.ts +18 -20
- package/lib/esm/ui/widget/SubLayersDataProvider.d.ts.map +1 -1
- package/lib/esm/ui/widget/SubLayersDataProvider.js +71 -72
- package/lib/esm/ui/widget/SubLayersDataProvider.js.map +1 -1
- package/lib/esm/ui/widget/SubLayersPopupButton.d.ts +9 -10
- package/lib/esm/ui/widget/SubLayersPopupButton.d.ts.map +1 -1
- package/lib/esm/ui/widget/SubLayersPopupButton.js +36 -36
- package/lib/esm/ui/widget/SubLayersPopupButton.js.map +1 -1
- package/lib/esm/ui/widget/SubLayersTree.d.ts +14 -15
- package/lib/esm/ui/widget/SubLayersTree.d.ts.map +1 -1
- package/lib/esm/ui/widget/SubLayersTree.js +414 -414
- package/lib/esm/ui/widget/SubLayersTree.js.map +1 -1
- package/lib/esm/ui/widget/SubLayersTree.scss +70 -69
- package/lib/esm/ui/widget/TransparencyPopupButton.d.ts +13 -14
- package/lib/esm/ui/widget/TransparencyPopupButton.d.ts.map +1 -1
- package/lib/esm/ui/widget/TransparencyPopupButton.js +43 -43
- package/lib/esm/ui/widget/TransparencyPopupButton.js.map +1 -1
- package/lib/esm/ui/widget/TransparencyPopupButton.scss +35 -36
- package/package.json +39 -38
|
@@ -1,335 +1,335 @@
|
|
|
1
|
-
/*---------------------------------------------------------------------------------------------
|
|
2
|
-
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
|
|
3
|
-
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
4
|
-
*--------------------------------------------------------------------------------------------*/
|
|
5
|
-
import * as React from "react";
|
|
6
|
-
import { IModelApp, MapLayerSourceStatus, NotifyMessageDetails, OutputMessagePriority } from "@itwin/core-frontend";
|
|
7
|
-
import { RelativePosition } from "@itwin/appui-abstract";
|
|
8
|
-
import * as UiCore from "@itwin/core-react";
|
|
9
|
-
import {
|
|
10
|
-
import { useSourceMapContext } from "./MapLayerManager";
|
|
11
|
-
import { MapUrlDialog } from "./MapUrlDialog";
|
|
12
|
-
import { ConfirmMessageDialog } from "./ConfirmMessageDialog";
|
|
13
|
-
import { Button, Input } from "@itwin/itwinui-react";
|
|
14
|
-
import { MapLayerPreferences } from "../../MapLayerPreferences";
|
|
15
|
-
import { MapLayersUI } from "../../mapLayers";
|
|
16
|
-
// cSpell:ignore droppable Sublayer
|
|
17
|
-
var LayerAction;
|
|
18
|
-
(function (LayerAction) {
|
|
19
|
-
LayerAction[LayerAction["Attached"] = 0] = "Attached";
|
|
20
|
-
LayerAction[LayerAction["Edited"] = 1] = "Edited";
|
|
21
|
-
})(LayerAction || (LayerAction = {}));
|
|
22
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
23
|
-
function AttachLayerPanel({ isOverlay, onLayerAttached, onHandleOutsideClick }) {
|
|
24
|
-
var _a, _b;
|
|
25
|
-
const [layerNameToAdd, setLayerNameToAdd] = React.useState();
|
|
26
|
-
const [sourceFilterString, setSourceFilterString] = React.useState();
|
|
27
|
-
const { placeholderLabel, addCustomLayerLabel, addCustomLayerToolTip, loadingMapSources, removeLayerDefButtonTitle, editLayerDefButtonTitle, removeLayerDefDialogTitle } = React.useMemo(() => {
|
|
28
|
-
return {
|
|
29
|
-
placeholderLabel: MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.SearchPlaceholder"),
|
|
30
|
-
addCustomLayerLabel: MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.Custom"),
|
|
31
|
-
addCustomLayerToolTip: MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.AttachCustomLayer"),
|
|
32
|
-
loadingMapSources: MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.LoadingMapSources"),
|
|
33
|
-
removeLayerDefButtonTitle: MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.RemoveLayerDefButtonTitle"),
|
|
34
|
-
editLayerDefButtonTitle: MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.EditLayerDefButtonTitle"),
|
|
35
|
-
removeLayerDefDialogTitle: MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.RemoveLayerDefDialogTitle"),
|
|
36
|
-
};
|
|
37
|
-
}, []);
|
|
38
|
-
const [loading, setLoading] = React.useState(false);
|
|
39
|
-
const [layerNameUnderCursor, setLayerNameUnderCursor] = React.useState();
|
|
40
|
-
const resumeOutsideClick = React.useCallback(() => {
|
|
41
|
-
if (onHandleOutsideClick) {
|
|
42
|
-
onHandleOutsideClick(true);
|
|
43
|
-
}
|
|
44
|
-
}, [onHandleOutsideClick]);
|
|
45
|
-
// 'isMounted' is used to prevent any async operation once the hook has been
|
|
46
|
-
// unloaded. Otherwise we get a 'Can't perform a React state update on an unmounted component.' warning in the console.
|
|
47
|
-
const isMounted = React.useRef(false);
|
|
48
|
-
React.useEffect(() => {
|
|
49
|
-
isMounted.current = true;
|
|
50
|
-
return () => {
|
|
51
|
-
isMounted.current = false;
|
|
52
|
-
// We close any open dialogs that we might have opened
|
|
53
|
-
// This was added because the modal dialog remained remained displayed after the session expired.
|
|
54
|
-
|
|
55
|
-
};
|
|
56
|
-
}, []);
|
|
57
|
-
const handleFilterTextChanged = React.useCallback((event) => {
|
|
58
|
-
setSourceFilterString(event.target.value);
|
|
59
|
-
}, []);
|
|
60
|
-
const { loadingSources, sources, activeViewport, backgroundLayers, overlayLayers, mapLayerOptions } = useSourceMapContext();
|
|
61
|
-
const mapTypesOptions = mapLayerOptions === null || mapLayerOptions === void 0 ? void 0 : mapLayerOptions.mapTypeOptions;
|
|
62
|
-
const iTwinId = (_a = activeViewport === null || activeViewport === void 0 ? void 0 : activeViewport.iModel) === null || _a === void 0 ? void 0 : _a.iTwinId;
|
|
63
|
-
const iModelId = (_b = activeViewport === null || activeViewport === void 0 ? void 0 : activeViewport.iModel) === null || _b === void 0 ? void 0 : _b.iModelId;
|
|
64
|
-
const styleContainsLayer = React.useCallback((name) => {
|
|
65
|
-
if (backgroundLayers) {
|
|
66
|
-
if (-1 !== backgroundLayers.findIndex((layer) => layer.name === name))
|
|
67
|
-
return true;
|
|
68
|
-
}
|
|
69
|
-
if (overlayLayers) {
|
|
70
|
-
if (-1 !== overlayLayers.findIndex((layer) => layer.name === name))
|
|
71
|
-
return true;
|
|
72
|
-
}
|
|
73
|
-
return false;
|
|
74
|
-
}, [backgroundLayers, overlayLayers]);
|
|
75
|
-
const handleModalUrlDialogOk = React.useCallback((action) => {
|
|
76
|
-
if (LayerAction.Attached === action) {
|
|
77
|
-
// close popup and refresh UI
|
|
78
|
-
onLayerAttached();
|
|
79
|
-
}
|
|
80
|
-
resumeOutsideClick();
|
|
81
|
-
}, [onLayerAttached, resumeOutsideClick]);
|
|
82
|
-
const handleModalUrlDialogCancel = React.useCallback(() => {
|
|
83
|
-
// close popup and refresh UI
|
|
84
|
-
setLoading(false);
|
|
85
|
-
|
|
86
|
-
resumeOutsideClick();
|
|
87
|
-
}, [resumeOutsideClick]);
|
|
88
|
-
React.useEffect(() => {
|
|
89
|
-
async function attemptToAddLayer(layerName) {
|
|
90
|
-
if (layerName && activeViewport) {
|
|
91
|
-
// if the layer is not in the style add it now.
|
|
92
|
-
if (undefined === (backgroundLayers === null || backgroundLayers === void 0 ? void 0 : backgroundLayers.find((layer) => layerName === layer.name)) && undefined === (overlayLayers === null || overlayLayers === void 0 ? void 0 : overlayLayers.find((layer) => layerName === layer.name))) {
|
|
93
|
-
const mapLayerSettings = sources === null || sources === void 0 ? void 0 : sources.find((source) => source.name === layerName);
|
|
94
|
-
if (mapLayerSettings === undefined) {
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
try {
|
|
98
|
-
if (isMounted.current) {
|
|
99
|
-
setLoading(true);
|
|
100
|
-
}
|
|
101
|
-
const { status, subLayers } = await mapLayerSettings.validateSource();
|
|
102
|
-
if (status === MapLayerSourceStatus.Valid || status === MapLayerSourceStatus.RequireAuth) {
|
|
103
|
-
if (status === MapLayerSourceStatus.Valid) {
|
|
104
|
-
const settings = mapLayerSettings.toLayerSettings(subLayers);
|
|
105
|
-
if (settings) {
|
|
106
|
-
activeViewport.displayStyle.attachMapLayer({ settings, isOverlay });
|
|
107
|
-
activeViewport.invalidateRenderPlan();
|
|
108
|
-
const msg = IModelApp.localization.getLocalizedString("mapLayers:Messages.MapLayerAttached", { sourceName: settings.name, sourceUrl: settings.url });
|
|
109
|
-
IModelApp.notifications.outputMessage(new NotifyMessageDetails(OutputMessagePriority.Info, msg));
|
|
110
|
-
}
|
|
111
|
-
if (isMounted.current) {
|
|
112
|
-
setLoading(false);
|
|
113
|
-
}
|
|
114
|
-
if (onLayerAttached) {
|
|
115
|
-
onLayerAttached();
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
else if (status === MapLayerSourceStatus.RequireAuth && isMounted.current) {
|
|
119
|
-
|
|
120
|
-
if (onHandleOutsideClick) {
|
|
121
|
-
onHandleOutsideClick(false);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
else {
|
|
126
|
-
const msg = IModelApp.localization.getLocalizedString("mapLayers:Messages.MapLayerValidationFailed", { sourceUrl: mapLayerSettings.url });
|
|
127
|
-
IModelApp.notifications.outputMessage(new NotifyMessageDetails(OutputMessagePriority.Error, msg));
|
|
128
|
-
if (isMounted.current) {
|
|
129
|
-
setLoading(false);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
catch (err) {
|
|
134
|
-
if (isMounted.current) {
|
|
135
|
-
setLoading(false);
|
|
136
|
-
}
|
|
137
|
-
const msg = IModelApp.localization.getLocalizedString("mapLayers:Messages.MapLayerAttachError", { error: err, sourceUrl: mapLayerSettings.url });
|
|
138
|
-
IModelApp.notifications.outputMessage(new NotifyMessageDetails(OutputMessagePriority.Error, msg));
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
if (layerNameToAdd) {
|
|
145
|
-
attemptToAddLayer(layerNameToAdd); // eslint-disable-line @typescript-eslint/no-floating-promises
|
|
146
|
-
if (isMounted.current) {
|
|
147
|
-
setLayerNameToAdd(undefined);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}, [setLayerNameToAdd, layerNameToAdd, activeViewport, sources, backgroundLayers, isOverlay, overlayLayers, onLayerAttached, handleModalUrlDialogOk, mapTypesOptions, handleModalUrlDialogCancel, onHandleOutsideClick]);
|
|
151
|
-
const options = React.useMemo(() => sources === null || sources === void 0 ? void 0 : sources.filter((source) => !styleContainsLayer(source.name)), [sources, styleContainsLayer]);
|
|
152
|
-
const filteredOptions = React.useMemo(() => {
|
|
153
|
-
if (undefined === sourceFilterString || 0 === sourceFilterString.length) {
|
|
154
|
-
return options;
|
|
155
|
-
}
|
|
156
|
-
else {
|
|
157
|
-
return options === null || options === void 0 ? void 0 : options.filter((option) => option.name.toLowerCase().includes(sourceFilterString === null || sourceFilterString === void 0 ? void 0 : sourceFilterString.toLowerCase()));
|
|
158
|
-
}
|
|
159
|
-
}, [options, sourceFilterString]);
|
|
160
|
-
const handleAddNewMapSource = React.useCallback(() => {
|
|
161
|
-
|
|
162
|
-
if (onHandleOutsideClick) {
|
|
163
|
-
onHandleOutsideClick(false);
|
|
164
|
-
}
|
|
165
|
-
return;
|
|
166
|
-
}, [activeViewport, handleModalUrlDialogCancel, handleModalUrlDialogOk, isOverlay, mapTypesOptions, onHandleOutsideClick]);
|
|
167
|
-
const handleAttach = React.useCallback((mapName) => {
|
|
168
|
-
setLayerNameToAdd(mapName);
|
|
169
|
-
}, []);
|
|
170
|
-
const handleKeypressOnSourceList = React.useCallback((event) => {
|
|
171
|
-
var _a, _b;
|
|
172
|
-
const key = event.key;
|
|
173
|
-
if (key === "Enter") {
|
|
174
|
-
event.preventDefault();
|
|
175
|
-
const mapName = (_b = (_a = event.currentTarget) === null || _a === void 0 ? void 0 : _a.dataset) === null || _b === void 0 ? void 0 : _b.value;
|
|
176
|
-
if (mapName && mapName.length) {
|
|
177
|
-
handleAttach(mapName);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
}, [handleAttach]);
|
|
181
|
-
const onListboxValueChange = React.useCallback((mapName) => {
|
|
182
|
-
setLayerNameToAdd(mapName);
|
|
183
|
-
}, []);
|
|
184
|
-
const handleNoConfirmation = React.useCallback((_layerName) => {
|
|
185
|
-
|
|
186
|
-
resumeOutsideClick();
|
|
187
|
-
}, [resumeOutsideClick]);
|
|
188
|
-
const handleYesConfirmation = React.useCallback(async (source) => {
|
|
189
|
-
const layerName = source.name;
|
|
190
|
-
if (!!iTwinId) {
|
|
191
|
-
try {
|
|
192
|
-
await MapLayerPreferences.deleteByName(source, iTwinId, iModelId);
|
|
193
|
-
const msg = MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.RemoveLayerDefSuccess", { layerName });
|
|
194
|
-
IModelApp.notifications.outputMessage(new NotifyMessageDetails(OutputMessagePriority.Info, msg));
|
|
195
|
-
}
|
|
196
|
-
catch (err) {
|
|
197
|
-
const msg = MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.RemoveLayerDefError", { layerName });
|
|
198
|
-
IModelApp.notifications.outputMessage(new NotifyMessageDetails(OutputMessagePriority.Error, msg));
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
resumeOutsideClick();
|
|
203
|
-
}, [iTwinId, iModelId, resumeOutsideClick]);
|
|
204
|
-
/*
|
|
205
|
-
Handle Remove layer button clicked
|
|
206
|
-
*/
|
|
207
|
-
const onItemRemoveButtonClicked = React.useCallback((source, event) => {
|
|
208
|
-
event.stopPropagation(); // We don't want the owning ListBox to react on mouse click.
|
|
209
|
-
const layerName = source.name;
|
|
210
|
-
const msg = MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.RemoveLayerDefDialogMessage", { layerName });
|
|
211
|
-
|
|
212
|
-
if (onHandleOutsideClick) {
|
|
213
|
-
onHandleOutsideClick(false);
|
|
214
|
-
}
|
|
215
|
-
}, [handleNoConfirmation, handleYesConfirmation, onHandleOutsideClick, removeLayerDefDialogTitle]);
|
|
216
|
-
/*
|
|
217
|
-
Handle Edit layer button clicked
|
|
218
|
-
*/
|
|
219
|
-
const onItemEditButtonClicked = React.useCallback((event) => {
|
|
220
|
-
var _a, _b, _c;
|
|
221
|
-
event.stopPropagation(); // We don't want the owning ListBox to react on mouse click.
|
|
222
|
-
const targetLayerName = (_c = (_b = (_a = event === null || event === void 0 ? void 0 : event.currentTarget) === null || _a === void 0 ? void 0 : _a.parentNode) === null || _b === void 0 ? void 0 : _b.dataset) === null || _c === void 0 ? void 0 : _c.value;
|
|
223
|
-
const matchingSource = sources.find((layerSource) => layerSource.name === targetLayerName);
|
|
224
|
-
// we expect a single layer source matching this name
|
|
225
|
-
if (matchingSource === undefined) {
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
if (onHandleOutsideClick) {
|
|
230
|
-
onHandleOutsideClick(false);
|
|
231
|
-
}
|
|
232
|
-
}, [activeViewport, handleModalUrlDialogCancel, handleModalUrlDialogOk, isOverlay, mapTypesOptions, onHandleOutsideClick, sources]);
|
|
233
|
-
return (React.createElement("div", { className: "map-manager-header" },
|
|
234
|
-
(loading || loadingSources) && React.createElement(UiCore.LoadingSpinner, { message: loadingMapSources }),
|
|
235
|
-
React.createElement("div", { className: "map-manager-source-listbox-header" },
|
|
236
|
-
React.createElement(Input, { type: "text", className: "map-manager-source-list-filter", placeholder: placeholderLabel, value: sourceFilterString, onChange: handleFilterTextChanged, size: "small" }),
|
|
237
|
-
React.createElement(Button, { className: "map-manager-add-source-button", title: addCustomLayerToolTip, onClick: handleAddNewMapSource }, addCustomLayerLabel)),
|
|
238
|
-
React.createElement("div", { className: "map-manager-sources" },
|
|
239
|
-
React.createElement(UiCore.Listbox, { id: "map-sources", selectedValue: layerNameToAdd, className: "map-manager-source-list", onKeyPress: handleKeypressOnSourceList, onListboxValueChange: onListboxValueChange }, filteredOptions === null || filteredOptions === void 0 ? void 0 : filteredOptions.map((source) => React.createElement(UiCore.ListboxItem, { key: source.name, className: "map-source-list-entry", value: source.name, onMouseEnter: () => setLayerNameUnderCursor(source.name), onMouseLeave: () => setLayerNameUnderCursor(undefined) },
|
|
240
|
-
React.createElement("span", { className: "map-source-list-entry-name", title: source.name }, source.name),
|
|
241
|
-
// otherwise list feels cluttered.
|
|
242
|
-
(!!iTwinId && layerNameUnderCursor && layerNameUnderCursor === source.name) &&
|
|
243
|
-
React.createElement(React.Fragment, null,
|
|
244
|
-
React.createElement(Button, { size: "small", styleType: "borderless", className: "map-source-list-entry-button", title: editLayerDefButtonTitle, onClick: onItemEditButtonClicked },
|
|
245
|
-
React.createElement(UiCore.Icon, { iconSpec: "icon-edit" })),
|
|
246
|
-
React.createElement(Button, { size: "small", styleType: "borderless", className: "map-source-list-entry-button", title: removeLayerDefButtonTitle, onClick: (event) => { onItemRemoveButtonClicked(source, event); } },
|
|
247
|
-
React.createElement(UiCore.Icon, { iconSpec: "icon-delete" })))))))));
|
|
248
|
-
}
|
|
249
|
-
/** @internal */
|
|
250
|
-
export var AttachLayerButtonType;
|
|
251
|
-
(function (AttachLayerButtonType) {
|
|
252
|
-
AttachLayerButtonType[AttachLayerButtonType["Primary"] = 0] = "Primary";
|
|
253
|
-
AttachLayerButtonType[AttachLayerButtonType["Blue"] = 1] = "Blue";
|
|
254
|
-
AttachLayerButtonType[AttachLayerButtonType["Icon"] = 2] = "Icon";
|
|
255
|
-
})(AttachLayerButtonType || (AttachLayerButtonType = {}));
|
|
256
|
-
/** @internal */
|
|
257
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
258
|
-
export function AttachLayerPopupButton(props) {
|
|
259
|
-
const { showAttachLayerLabel, hideAttachLayerLabel, addCustomLayerButtonLabel } = React.useMemo(() => {
|
|
260
|
-
return {
|
|
261
|
-
showAttachLayerLabel: MapLayersUI.localization.getLocalizedString("mapLayers:AttachLayerPopup.Attach"),
|
|
262
|
-
hideAttachLayerLabel: MapLayersUI.localization.getLocalizedString("mapLayers:AttachLayerPopup.Close"),
|
|
263
|
-
addCustomLayerButtonLabel: MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.AddCustomLayerButtonLabel"),
|
|
264
|
-
};
|
|
265
|
-
}, []);
|
|
266
|
-
const [handleOutsideClick, setHandleOutsideClick] = React.useState(true);
|
|
267
|
-
const [popupOpen, setPopupOpen] = React.useState(false);
|
|
268
|
-
const buttonRef = React.useRef(null);
|
|
269
|
-
const panelRef = React.useRef(null);
|
|
270
|
-
// 'isMounted' is used to prevent any async operation once the hook has been
|
|
271
|
-
// unloaded. Otherwise we get a 'Can't perform a React state update on an unmounted component.' warning in the console.
|
|
272
|
-
const isMounted = React.useRef(false);
|
|
273
|
-
React.useEffect(() => {
|
|
274
|
-
isMounted.current = true;
|
|
275
|
-
return () => {
|
|
276
|
-
isMounted.current = false;
|
|
277
|
-
};
|
|
278
|
-
}, []);
|
|
279
|
-
const togglePopup = React.useCallback(() => {
|
|
280
|
-
setPopupOpen(!popupOpen);
|
|
281
|
-
}, [popupOpen]);
|
|
282
|
-
const handleClosePopup = React.useCallback(() => {
|
|
283
|
-
setPopupOpen(false);
|
|
284
|
-
}, []);
|
|
285
|
-
const onHandleOutsideClick = React.useCallback((event) => {
|
|
286
|
-
if (!handleOutsideClick) {
|
|
287
|
-
return;
|
|
288
|
-
}
|
|
289
|
-
// If clicking on button that open panel - don't trigger outside click processing
|
|
290
|
-
if ((buttonRef === null || buttonRef === void 0 ? void 0 : buttonRef.current) && (buttonRef === null || buttonRef === void 0 ? void 0 : buttonRef.current.contains(event.target))) {
|
|
291
|
-
return;
|
|
292
|
-
}
|
|
293
|
-
// If clicking the panel, this is not an outside clicked
|
|
294
|
-
if (panelRef.current && (panelRef === null || panelRef === void 0 ? void 0 : panelRef.current.contains(event.target))) {
|
|
295
|
-
return;
|
|
296
|
-
}
|
|
297
|
-
// If we reach this point, we got an outside clicked, no close the popup
|
|
298
|
-
setPopupOpen(false);
|
|
299
|
-
}, [handleOutsideClick]);
|
|
300
|
-
const { refreshFromStyle } = useSourceMapContext();
|
|
301
|
-
const handleLayerAttached = React.useCallback(() => {
|
|
302
|
-
if (!isMounted.current) {
|
|
303
|
-
return;
|
|
304
|
-
}
|
|
305
|
-
setPopupOpen(false);
|
|
306
|
-
refreshFromStyle();
|
|
307
|
-
}, [refreshFromStyle]);
|
|
308
|
-
function renderButton() {
|
|
309
|
-
let button;
|
|
310
|
-
if (props.buttonType === undefined || props.buttonType === AttachLayerButtonType.Icon) {
|
|
311
|
-
button = (React.createElement(Button, { disabled: props.disabled, size: "small", styleType: "borderless", ref: buttonRef, className: "map-manager-attach-layer-button", title: popupOpen ? hideAttachLayerLabel : showAttachLayerLabel, onClick: togglePopup },
|
|
312
|
-
React.createElement(UiCore.WebFontIcon, { iconName: "icon-add" })));
|
|
313
|
-
}
|
|
314
|
-
else {
|
|
315
|
-
const determineStyleType = () => {
|
|
316
|
-
switch (props.buttonType) {
|
|
317
|
-
case AttachLayerButtonType.Blue:
|
|
318
|
-
return "high-visibility";
|
|
319
|
-
case AttachLayerButtonType.Primary:
|
|
320
|
-
default:
|
|
321
|
-
return "cta";
|
|
322
|
-
}
|
|
323
|
-
};
|
|
324
|
-
const styleType = determineStyleType();
|
|
325
|
-
button = (React.createElement(Button, { disabled: props.disabled, ref: buttonRef, styleType: styleType, title: popupOpen ? hideAttachLayerLabel : showAttachLayerLabel, onClick: togglePopup }, addCustomLayerButtonLabel));
|
|
326
|
-
}
|
|
327
|
-
return button;
|
|
328
|
-
}
|
|
329
|
-
return (React.createElement(React.Fragment, null,
|
|
330
|
-
renderButton(),
|
|
331
|
-
React.createElement(UiCore.Popup, { isOpen: popupOpen, position: RelativePosition.BottomRight, onClose: handleClosePopup, onOutsideClick: onHandleOutsideClick, target: buttonRef.current, closeOnEnter: false, closeOnContextMenu: false },
|
|
332
|
-
React.createElement("div", { ref: panelRef, className: "map-sources-popup-panel" },
|
|
333
|
-
React.createElement(AttachLayerPanel, { isOverlay: props.isOverlay, onLayerAttached: handleLayerAttached, onHandleOutsideClick: setHandleOutsideClick })))));
|
|
334
|
-
}
|
|
1
|
+
/*---------------------------------------------------------------------------------------------
|
|
2
|
+
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
|
|
3
|
+
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
4
|
+
*--------------------------------------------------------------------------------------------*/
|
|
5
|
+
import * as React from "react";
|
|
6
|
+
import { IModelApp, MapLayerSourceStatus, NotifyMessageDetails, OutputMessagePriority } from "@itwin/core-frontend";
|
|
7
|
+
import { RelativePosition } from "@itwin/appui-abstract";
|
|
8
|
+
import * as UiCore from "@itwin/core-react";
|
|
9
|
+
import { UiFramework } from "@itwin/appui-react";
|
|
10
|
+
import { useSourceMapContext } from "./MapLayerManager";
|
|
11
|
+
import { MapUrlDialog } from "./MapUrlDialog";
|
|
12
|
+
import { ConfirmMessageDialog } from "./ConfirmMessageDialog";
|
|
13
|
+
import { Button, Input } from "@itwin/itwinui-react";
|
|
14
|
+
import { MapLayerPreferences } from "../../MapLayerPreferences";
|
|
15
|
+
import { MapLayersUI } from "../../mapLayers";
|
|
16
|
+
// cSpell:ignore droppable Sublayer
|
|
17
|
+
var LayerAction;
|
|
18
|
+
(function (LayerAction) {
|
|
19
|
+
LayerAction[LayerAction["Attached"] = 0] = "Attached";
|
|
20
|
+
LayerAction[LayerAction["Edited"] = 1] = "Edited";
|
|
21
|
+
})(LayerAction || (LayerAction = {}));
|
|
22
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
23
|
+
function AttachLayerPanel({ isOverlay, onLayerAttached, onHandleOutsideClick }) {
|
|
24
|
+
var _a, _b;
|
|
25
|
+
const [layerNameToAdd, setLayerNameToAdd] = React.useState();
|
|
26
|
+
const [sourceFilterString, setSourceFilterString] = React.useState();
|
|
27
|
+
const { placeholderLabel, addCustomLayerLabel, addCustomLayerToolTip, loadingMapSources, removeLayerDefButtonTitle, editLayerDefButtonTitle, removeLayerDefDialogTitle } = React.useMemo(() => {
|
|
28
|
+
return {
|
|
29
|
+
placeholderLabel: MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.SearchPlaceholder"),
|
|
30
|
+
addCustomLayerLabel: MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.Custom"),
|
|
31
|
+
addCustomLayerToolTip: MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.AttachCustomLayer"),
|
|
32
|
+
loadingMapSources: MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.LoadingMapSources"),
|
|
33
|
+
removeLayerDefButtonTitle: MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.RemoveLayerDefButtonTitle"),
|
|
34
|
+
editLayerDefButtonTitle: MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.EditLayerDefButtonTitle"),
|
|
35
|
+
removeLayerDefDialogTitle: MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.RemoveLayerDefDialogTitle"),
|
|
36
|
+
};
|
|
37
|
+
}, []);
|
|
38
|
+
const [loading, setLoading] = React.useState(false);
|
|
39
|
+
const [layerNameUnderCursor, setLayerNameUnderCursor] = React.useState();
|
|
40
|
+
const resumeOutsideClick = React.useCallback(() => {
|
|
41
|
+
if (onHandleOutsideClick) {
|
|
42
|
+
onHandleOutsideClick(true);
|
|
43
|
+
}
|
|
44
|
+
}, [onHandleOutsideClick]);
|
|
45
|
+
// 'isMounted' is used to prevent any async operation once the hook has been
|
|
46
|
+
// unloaded. Otherwise we get a 'Can't perform a React state update on an unmounted component.' warning in the console.
|
|
47
|
+
const isMounted = React.useRef(false);
|
|
48
|
+
React.useEffect(() => {
|
|
49
|
+
isMounted.current = true;
|
|
50
|
+
return () => {
|
|
51
|
+
isMounted.current = false;
|
|
52
|
+
// We close any open dialogs that we might have opened
|
|
53
|
+
// This was added because the modal dialog remained remained displayed after the session expired.
|
|
54
|
+
UiFramework.dialogs.modal.close();
|
|
55
|
+
};
|
|
56
|
+
}, []);
|
|
57
|
+
const handleFilterTextChanged = React.useCallback((event) => {
|
|
58
|
+
setSourceFilterString(event.target.value);
|
|
59
|
+
}, []);
|
|
60
|
+
const { loadingSources, sources, activeViewport, backgroundLayers, overlayLayers, mapLayerOptions } = useSourceMapContext();
|
|
61
|
+
const mapTypesOptions = mapLayerOptions === null || mapLayerOptions === void 0 ? void 0 : mapLayerOptions.mapTypeOptions;
|
|
62
|
+
const iTwinId = (_a = activeViewport === null || activeViewport === void 0 ? void 0 : activeViewport.iModel) === null || _a === void 0 ? void 0 : _a.iTwinId;
|
|
63
|
+
const iModelId = (_b = activeViewport === null || activeViewport === void 0 ? void 0 : activeViewport.iModel) === null || _b === void 0 ? void 0 : _b.iModelId;
|
|
64
|
+
const styleContainsLayer = React.useCallback((name) => {
|
|
65
|
+
if (backgroundLayers) {
|
|
66
|
+
if (-1 !== backgroundLayers.findIndex((layer) => layer.name === name))
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
if (overlayLayers) {
|
|
70
|
+
if (-1 !== overlayLayers.findIndex((layer) => layer.name === name))
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
return false;
|
|
74
|
+
}, [backgroundLayers, overlayLayers]);
|
|
75
|
+
const handleModalUrlDialogOk = React.useCallback((action) => {
|
|
76
|
+
if (LayerAction.Attached === action) {
|
|
77
|
+
// close popup and refresh UI
|
|
78
|
+
onLayerAttached();
|
|
79
|
+
}
|
|
80
|
+
resumeOutsideClick();
|
|
81
|
+
}, [onLayerAttached, resumeOutsideClick]);
|
|
82
|
+
const handleModalUrlDialogCancel = React.useCallback(() => {
|
|
83
|
+
// close popup and refresh UI
|
|
84
|
+
setLoading(false);
|
|
85
|
+
UiFramework.dialogs.modal.close();
|
|
86
|
+
resumeOutsideClick();
|
|
87
|
+
}, [resumeOutsideClick]);
|
|
88
|
+
React.useEffect(() => {
|
|
89
|
+
async function attemptToAddLayer(layerName) {
|
|
90
|
+
if (layerName && activeViewport) {
|
|
91
|
+
// if the layer is not in the style add it now.
|
|
92
|
+
if (undefined === (backgroundLayers === null || backgroundLayers === void 0 ? void 0 : backgroundLayers.find((layer) => layerName === layer.name)) && undefined === (overlayLayers === null || overlayLayers === void 0 ? void 0 : overlayLayers.find((layer) => layerName === layer.name))) {
|
|
93
|
+
const mapLayerSettings = sources === null || sources === void 0 ? void 0 : sources.find((source) => source.name === layerName);
|
|
94
|
+
if (mapLayerSettings === undefined) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
try {
|
|
98
|
+
if (isMounted.current) {
|
|
99
|
+
setLoading(true);
|
|
100
|
+
}
|
|
101
|
+
const { status, subLayers } = await mapLayerSettings.validateSource();
|
|
102
|
+
if (status === MapLayerSourceStatus.Valid || status === MapLayerSourceStatus.RequireAuth) {
|
|
103
|
+
if (status === MapLayerSourceStatus.Valid) {
|
|
104
|
+
const settings = mapLayerSettings.toLayerSettings(subLayers);
|
|
105
|
+
if (settings) {
|
|
106
|
+
activeViewport.displayStyle.attachMapLayer({ settings, isOverlay });
|
|
107
|
+
activeViewport.invalidateRenderPlan();
|
|
108
|
+
const msg = IModelApp.localization.getLocalizedString("mapLayers:Messages.MapLayerAttached", { sourceName: settings.name, sourceUrl: settings.url });
|
|
109
|
+
IModelApp.notifications.outputMessage(new NotifyMessageDetails(OutputMessagePriority.Info, msg));
|
|
110
|
+
}
|
|
111
|
+
if (isMounted.current) {
|
|
112
|
+
setLoading(false);
|
|
113
|
+
}
|
|
114
|
+
if (onLayerAttached) {
|
|
115
|
+
onLayerAttached();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
else if (status === MapLayerSourceStatus.RequireAuth && isMounted.current) {
|
|
119
|
+
UiFramework.dialogs.modal.open(React.createElement(MapUrlDialog, { activeViewport: activeViewport, isOverlay: isOverlay, layerRequiringCredentials: mapLayerSettings.toJSON(), onOkResult: () => handleModalUrlDialogOk(LayerAction.Attached), onCancelResult: handleModalUrlDialogCancel, mapTypesOptions: mapTypesOptions }));
|
|
120
|
+
if (onHandleOutsideClick) {
|
|
121
|
+
onHandleOutsideClick(false);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
const msg = IModelApp.localization.getLocalizedString("mapLayers:Messages.MapLayerValidationFailed", { sourceUrl: mapLayerSettings.url });
|
|
127
|
+
IModelApp.notifications.outputMessage(new NotifyMessageDetails(OutputMessagePriority.Error, msg));
|
|
128
|
+
if (isMounted.current) {
|
|
129
|
+
setLoading(false);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
if (isMounted.current) {
|
|
135
|
+
setLoading(false);
|
|
136
|
+
}
|
|
137
|
+
const msg = IModelApp.localization.getLocalizedString("mapLayers:Messages.MapLayerAttachError", { error: err, sourceUrl: mapLayerSettings.url });
|
|
138
|
+
IModelApp.notifications.outputMessage(new NotifyMessageDetails(OutputMessagePriority.Error, msg));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
if (layerNameToAdd) {
|
|
145
|
+
attemptToAddLayer(layerNameToAdd); // eslint-disable-line @typescript-eslint/no-floating-promises
|
|
146
|
+
if (isMounted.current) {
|
|
147
|
+
setLayerNameToAdd(undefined);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}, [setLayerNameToAdd, layerNameToAdd, activeViewport, sources, backgroundLayers, isOverlay, overlayLayers, onLayerAttached, handleModalUrlDialogOk, mapTypesOptions, handleModalUrlDialogCancel, onHandleOutsideClick]);
|
|
151
|
+
const options = React.useMemo(() => sources === null || sources === void 0 ? void 0 : sources.filter((source) => !styleContainsLayer(source.name)), [sources, styleContainsLayer]);
|
|
152
|
+
const filteredOptions = React.useMemo(() => {
|
|
153
|
+
if (undefined === sourceFilterString || 0 === sourceFilterString.length) {
|
|
154
|
+
return options;
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
return options === null || options === void 0 ? void 0 : options.filter((option) => option.name.toLowerCase().includes(sourceFilterString === null || sourceFilterString === void 0 ? void 0 : sourceFilterString.toLowerCase()));
|
|
158
|
+
}
|
|
159
|
+
}, [options, sourceFilterString]);
|
|
160
|
+
const handleAddNewMapSource = React.useCallback(() => {
|
|
161
|
+
UiFramework.dialogs.modal.open(React.createElement(MapUrlDialog, { activeViewport: activeViewport, isOverlay: isOverlay, onOkResult: () => handleModalUrlDialogOk(LayerAction.Attached), onCancelResult: handleModalUrlDialogCancel, mapTypesOptions: mapTypesOptions }));
|
|
162
|
+
if (onHandleOutsideClick) {
|
|
163
|
+
onHandleOutsideClick(false);
|
|
164
|
+
}
|
|
165
|
+
return;
|
|
166
|
+
}, [activeViewport, handleModalUrlDialogCancel, handleModalUrlDialogOk, isOverlay, mapTypesOptions, onHandleOutsideClick]);
|
|
167
|
+
const handleAttach = React.useCallback((mapName) => {
|
|
168
|
+
setLayerNameToAdd(mapName);
|
|
169
|
+
}, []);
|
|
170
|
+
const handleKeypressOnSourceList = React.useCallback((event) => {
|
|
171
|
+
var _a, _b;
|
|
172
|
+
const key = event.key;
|
|
173
|
+
if (key === "Enter") {
|
|
174
|
+
event.preventDefault();
|
|
175
|
+
const mapName = (_b = (_a = event.currentTarget) === null || _a === void 0 ? void 0 : _a.dataset) === null || _b === void 0 ? void 0 : _b.value;
|
|
176
|
+
if (mapName && mapName.length) {
|
|
177
|
+
handleAttach(mapName);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}, [handleAttach]);
|
|
181
|
+
const onListboxValueChange = React.useCallback((mapName) => {
|
|
182
|
+
setLayerNameToAdd(mapName);
|
|
183
|
+
}, []);
|
|
184
|
+
const handleNoConfirmation = React.useCallback((_layerName) => {
|
|
185
|
+
UiFramework.dialogs.modal.close();
|
|
186
|
+
resumeOutsideClick();
|
|
187
|
+
}, [resumeOutsideClick]);
|
|
188
|
+
const handleYesConfirmation = React.useCallback(async (source) => {
|
|
189
|
+
const layerName = source.name;
|
|
190
|
+
if (!!iTwinId) {
|
|
191
|
+
try {
|
|
192
|
+
await MapLayerPreferences.deleteByName(source, iTwinId, iModelId);
|
|
193
|
+
const msg = MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.RemoveLayerDefSuccess", { layerName });
|
|
194
|
+
IModelApp.notifications.outputMessage(new NotifyMessageDetails(OutputMessagePriority.Info, msg));
|
|
195
|
+
}
|
|
196
|
+
catch (err) {
|
|
197
|
+
const msg = MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.RemoveLayerDefError", { layerName });
|
|
198
|
+
IModelApp.notifications.outputMessage(new NotifyMessageDetails(OutputMessagePriority.Error, msg));
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
UiFramework.dialogs.modal.close();
|
|
202
|
+
resumeOutsideClick();
|
|
203
|
+
}, [iTwinId, iModelId, resumeOutsideClick]);
|
|
204
|
+
/*
|
|
205
|
+
Handle Remove layer button clicked
|
|
206
|
+
*/
|
|
207
|
+
const onItemRemoveButtonClicked = React.useCallback((source, event) => {
|
|
208
|
+
event.stopPropagation(); // We don't want the owning ListBox to react on mouse click.
|
|
209
|
+
const layerName = source.name;
|
|
210
|
+
const msg = MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.RemoveLayerDefDialogMessage", { layerName });
|
|
211
|
+
UiFramework.dialogs.modal.open(React.createElement(ConfirmMessageDialog, { className: "map-sources-delete-confirmation", title: removeLayerDefDialogTitle, message: msg, maxWidth: 400, onClose: () => handleNoConfirmation(layerName), onEscape: () => handleNoConfirmation(layerName), onYesResult: async () => handleYesConfirmation(source), onNoResult: () => handleNoConfirmation(layerName) }));
|
|
212
|
+
if (onHandleOutsideClick) {
|
|
213
|
+
onHandleOutsideClick(false);
|
|
214
|
+
}
|
|
215
|
+
}, [handleNoConfirmation, handleYesConfirmation, onHandleOutsideClick, removeLayerDefDialogTitle]);
|
|
216
|
+
/*
|
|
217
|
+
Handle Edit layer button clicked
|
|
218
|
+
*/
|
|
219
|
+
const onItemEditButtonClicked = React.useCallback((event) => {
|
|
220
|
+
var _a, _b, _c;
|
|
221
|
+
event.stopPropagation(); // We don't want the owning ListBox to react on mouse click.
|
|
222
|
+
const targetLayerName = (_c = (_b = (_a = event === null || event === void 0 ? void 0 : event.currentTarget) === null || _a === void 0 ? void 0 : _a.parentNode) === null || _b === void 0 ? void 0 : _b.dataset) === null || _c === void 0 ? void 0 : _c.value;
|
|
223
|
+
const matchingSource = sources.find((layerSource) => layerSource.name === targetLayerName);
|
|
224
|
+
// we expect a single layer source matching this name
|
|
225
|
+
if (matchingSource === undefined) {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
UiFramework.dialogs.modal.open(React.createElement(MapUrlDialog, { activeViewport: activeViewport, isOverlay: isOverlay, mapLayerSourceToEdit: matchingSource, onOkResult: () => handleModalUrlDialogOk(LayerAction.Edited), onCancelResult: handleModalUrlDialogCancel, mapTypesOptions: mapTypesOptions }));
|
|
229
|
+
if (onHandleOutsideClick) {
|
|
230
|
+
onHandleOutsideClick(false);
|
|
231
|
+
}
|
|
232
|
+
}, [activeViewport, handleModalUrlDialogCancel, handleModalUrlDialogOk, isOverlay, mapTypesOptions, onHandleOutsideClick, sources]);
|
|
233
|
+
return (React.createElement("div", { className: "map-manager-header" },
|
|
234
|
+
(loading || loadingSources) && React.createElement(UiCore.LoadingSpinner, { message: loadingMapSources }),
|
|
235
|
+
React.createElement("div", { className: "map-manager-source-listbox-header" },
|
|
236
|
+
React.createElement(Input, { type: "text", className: "map-manager-source-list-filter", placeholder: placeholderLabel, value: sourceFilterString, onChange: handleFilterTextChanged, size: "small" }),
|
|
237
|
+
React.createElement(Button, { className: "map-manager-add-source-button", title: addCustomLayerToolTip, onClick: handleAddNewMapSource }, addCustomLayerLabel)),
|
|
238
|
+
React.createElement("div", { className: "map-manager-sources" },
|
|
239
|
+
React.createElement(UiCore.Listbox, { id: "map-sources", selectedValue: layerNameToAdd, className: "map-manager-source-list", onKeyPress: handleKeypressOnSourceList, onListboxValueChange: onListboxValueChange }, filteredOptions === null || filteredOptions === void 0 ? void 0 : filteredOptions.map((source) => React.createElement(UiCore.ListboxItem, { key: source.name, className: "map-source-list-entry", value: source.name, onMouseEnter: () => setLayerNameUnderCursor(source.name), onMouseLeave: () => setLayerNameUnderCursor(undefined) },
|
|
240
|
+
React.createElement("span", { className: "map-source-list-entry-name", title: source.name }, source.name),
|
|
241
|
+
// otherwise list feels cluttered.
|
|
242
|
+
(!!iTwinId && layerNameUnderCursor && layerNameUnderCursor === source.name) &&
|
|
243
|
+
React.createElement(React.Fragment, null,
|
|
244
|
+
React.createElement(Button, { size: "small", styleType: "borderless", className: "map-source-list-entry-button", title: editLayerDefButtonTitle, onClick: onItemEditButtonClicked },
|
|
245
|
+
React.createElement(UiCore.Icon, { iconSpec: "icon-edit" })),
|
|
246
|
+
React.createElement(Button, { size: "small", styleType: "borderless", className: "map-source-list-entry-button", title: removeLayerDefButtonTitle, onClick: (event) => { onItemRemoveButtonClicked(source, event); } },
|
|
247
|
+
React.createElement(UiCore.Icon, { iconSpec: "icon-delete" })))))))));
|
|
248
|
+
}
|
|
249
|
+
/** @internal */
|
|
250
|
+
export var AttachLayerButtonType;
|
|
251
|
+
(function (AttachLayerButtonType) {
|
|
252
|
+
AttachLayerButtonType[AttachLayerButtonType["Primary"] = 0] = "Primary";
|
|
253
|
+
AttachLayerButtonType[AttachLayerButtonType["Blue"] = 1] = "Blue";
|
|
254
|
+
AttachLayerButtonType[AttachLayerButtonType["Icon"] = 2] = "Icon";
|
|
255
|
+
})(AttachLayerButtonType || (AttachLayerButtonType = {}));
|
|
256
|
+
/** @internal */
|
|
257
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
258
|
+
export function AttachLayerPopupButton(props) {
|
|
259
|
+
const { showAttachLayerLabel, hideAttachLayerLabel, addCustomLayerButtonLabel } = React.useMemo(() => {
|
|
260
|
+
return {
|
|
261
|
+
showAttachLayerLabel: MapLayersUI.localization.getLocalizedString("mapLayers:AttachLayerPopup.Attach"),
|
|
262
|
+
hideAttachLayerLabel: MapLayersUI.localization.getLocalizedString("mapLayers:AttachLayerPopup.Close"),
|
|
263
|
+
addCustomLayerButtonLabel: MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.AddCustomLayerButtonLabel"),
|
|
264
|
+
};
|
|
265
|
+
}, []);
|
|
266
|
+
const [handleOutsideClick, setHandleOutsideClick] = React.useState(true);
|
|
267
|
+
const [popupOpen, setPopupOpen] = React.useState(false);
|
|
268
|
+
const buttonRef = React.useRef(null);
|
|
269
|
+
const panelRef = React.useRef(null);
|
|
270
|
+
// 'isMounted' is used to prevent any async operation once the hook has been
|
|
271
|
+
// unloaded. Otherwise we get a 'Can't perform a React state update on an unmounted component.' warning in the console.
|
|
272
|
+
const isMounted = React.useRef(false);
|
|
273
|
+
React.useEffect(() => {
|
|
274
|
+
isMounted.current = true;
|
|
275
|
+
return () => {
|
|
276
|
+
isMounted.current = false;
|
|
277
|
+
};
|
|
278
|
+
}, []);
|
|
279
|
+
const togglePopup = React.useCallback(() => {
|
|
280
|
+
setPopupOpen(!popupOpen);
|
|
281
|
+
}, [popupOpen]);
|
|
282
|
+
const handleClosePopup = React.useCallback(() => {
|
|
283
|
+
setPopupOpen(false);
|
|
284
|
+
}, []);
|
|
285
|
+
const onHandleOutsideClick = React.useCallback((event) => {
|
|
286
|
+
if (!handleOutsideClick) {
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
// If clicking on button that open panel - don't trigger outside click processing
|
|
290
|
+
if ((buttonRef === null || buttonRef === void 0 ? void 0 : buttonRef.current) && (buttonRef === null || buttonRef === void 0 ? void 0 : buttonRef.current.contains(event.target))) {
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
// If clicking the panel, this is not an outside clicked
|
|
294
|
+
if (panelRef.current && (panelRef === null || panelRef === void 0 ? void 0 : panelRef.current.contains(event.target))) {
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
// If we reach this point, we got an outside clicked, no close the popup
|
|
298
|
+
setPopupOpen(false);
|
|
299
|
+
}, [handleOutsideClick]);
|
|
300
|
+
const { refreshFromStyle } = useSourceMapContext();
|
|
301
|
+
const handleLayerAttached = React.useCallback(() => {
|
|
302
|
+
if (!isMounted.current) {
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
setPopupOpen(false);
|
|
306
|
+
refreshFromStyle();
|
|
307
|
+
}, [refreshFromStyle]);
|
|
308
|
+
function renderButton() {
|
|
309
|
+
let button;
|
|
310
|
+
if (props.buttonType === undefined || props.buttonType === AttachLayerButtonType.Icon) {
|
|
311
|
+
button = (React.createElement(Button, { disabled: props.disabled, size: "small", styleType: "borderless", ref: buttonRef, className: "map-manager-attach-layer-button", title: popupOpen ? hideAttachLayerLabel : showAttachLayerLabel, onClick: togglePopup },
|
|
312
|
+
React.createElement(UiCore.WebFontIcon, { iconName: "icon-add" })));
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
const determineStyleType = () => {
|
|
316
|
+
switch (props.buttonType) {
|
|
317
|
+
case AttachLayerButtonType.Blue:
|
|
318
|
+
return "high-visibility";
|
|
319
|
+
case AttachLayerButtonType.Primary:
|
|
320
|
+
default:
|
|
321
|
+
return "cta";
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
const styleType = determineStyleType();
|
|
325
|
+
button = (React.createElement(Button, { disabled: props.disabled, ref: buttonRef, styleType: styleType, title: popupOpen ? hideAttachLayerLabel : showAttachLayerLabel, onClick: togglePopup }, addCustomLayerButtonLabel));
|
|
326
|
+
}
|
|
327
|
+
return button;
|
|
328
|
+
}
|
|
329
|
+
return (React.createElement(React.Fragment, null,
|
|
330
|
+
renderButton(),
|
|
331
|
+
React.createElement(UiCore.Popup, { isOpen: popupOpen, position: RelativePosition.BottomRight, onClose: handleClosePopup, onOutsideClick: onHandleOutsideClick, target: buttonRef.current, closeOnEnter: false, closeOnContextMenu: false },
|
|
332
|
+
React.createElement("div", { ref: panelRef, className: "map-sources-popup-panel" },
|
|
333
|
+
React.createElement(AttachLayerPanel, { isOverlay: props.isOverlay, onLayerAttached: handleLayerAttached, onHandleOutsideClick: setHandleOutsideClick })))));
|
|
334
|
+
}
|
|
335
335
|
//# sourceMappingURL=AttachLayerPopupButton.js.map
|