@itwin/map-layers 4.0.0-dev.8 → 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.
Files changed (199) hide show
  1. package/CHANGELOG.md +746 -848
  2. package/README.md +32 -32
  3. package/lib/cjs/MapLayerPreferences.d.ts +88 -88
  4. package/lib/cjs/MapLayerPreferences.js +312 -312
  5. package/lib/cjs/MapLayerPreferences.js.map +1 -1
  6. package/lib/cjs/map-layers.d.ts +6 -6
  7. package/lib/cjs/map-layers.js +22 -22
  8. package/lib/cjs/mapLayers.d.ts +26 -44
  9. package/lib/cjs/mapLayers.d.ts.map +1 -1
  10. package/lib/cjs/mapLayers.js +34 -63
  11. package/lib/cjs/mapLayers.js.map +1 -1
  12. package/lib/cjs/ui/FeatureInfoUiItemsProvider.d.ts +16 -11
  13. package/lib/cjs/ui/FeatureInfoUiItemsProvider.d.ts.map +1 -1
  14. package/lib/cjs/ui/FeatureInfoUiItemsProvider.js +47 -52
  15. package/lib/cjs/ui/FeatureInfoUiItemsProvider.js.map +1 -1
  16. package/lib/cjs/ui/Interfaces.d.ts +50 -50
  17. package/lib/cjs/ui/Interfaces.js +2 -2
  18. package/lib/cjs/ui/Interfaces.js.map +1 -1
  19. package/lib/cjs/ui/MapFeatureInfoTool.d.ts +13 -13
  20. package/lib/cjs/ui/MapFeatureInfoTool.d.ts.map +1 -1
  21. package/lib/cjs/ui/MapFeatureInfoTool.js +50 -50
  22. package/lib/cjs/ui/MapFeatureInfoTool.js.map +1 -1
  23. package/lib/cjs/ui/MapLayersUiItemsProvider.d.ts +8 -8
  24. package/lib/cjs/ui/MapLayersUiItemsProvider.d.ts.map +1 -1
  25. package/lib/cjs/ui/MapLayersUiItemsProvider.js +35 -38
  26. package/lib/cjs/ui/MapLayersUiItemsProvider.js.map +1 -1
  27. package/lib/cjs/ui/widget/AttachLayerPopupButton.d.ts +13 -14
  28. package/lib/cjs/ui/widget/AttachLayerPopupButton.d.ts.map +1 -1
  29. package/lib/cjs/ui/widget/AttachLayerPopupButton.js +338 -338
  30. package/lib/cjs/ui/widget/AttachLayerPopupButton.js.map +1 -1
  31. package/lib/cjs/ui/widget/BasemapPanel.d.ts +7 -8
  32. package/lib/cjs/ui/widget/BasemapPanel.d.ts.map +1 -1
  33. package/lib/cjs/ui/widget/BasemapPanel.js +156 -156
  34. package/lib/cjs/ui/widget/BasemapPanel.js.map +1 -1
  35. package/lib/cjs/ui/widget/BasemapPanel.scss +87 -87
  36. package/lib/cjs/ui/widget/ConfirmMessageDialog.d.ts +20 -21
  37. package/lib/cjs/ui/widget/ConfirmMessageDialog.d.ts.map +1 -1
  38. package/lib/cjs/ui/widget/ConfirmMessageDialog.js +25 -25
  39. package/lib/cjs/ui/widget/ConfirmMessageDialog.js.map +1 -1
  40. package/lib/cjs/ui/widget/FeatureInfoDataProvider.d.ts +35 -40
  41. package/lib/cjs/ui/widget/FeatureInfoDataProvider.d.ts.map +1 -1
  42. package/lib/cjs/ui/widget/FeatureInfoDataProvider.js +140 -139
  43. package/lib/cjs/ui/widget/FeatureInfoDataProvider.js.map +1 -1
  44. package/lib/cjs/ui/widget/FeatureInfoWidget.d.ts +6 -7
  45. package/lib/cjs/ui/widget/FeatureInfoWidget.d.ts.map +1 -1
  46. package/lib/cjs/ui/widget/FeatureInfoWidget.js +76 -71
  47. package/lib/cjs/ui/widget/FeatureInfoWidget.js.map +1 -1
  48. package/lib/cjs/ui/widget/MapLayerDroppable.d.ts +18 -19
  49. package/lib/cjs/ui/widget/MapLayerDroppable.d.ts.map +1 -1
  50. package/lib/cjs/ui/widget/MapLayerDroppable.js +88 -88
  51. package/lib/cjs/ui/widget/MapLayerDroppable.js.map +1 -1
  52. package/lib/cjs/ui/widget/MapLayerManager.d.ts +26 -26
  53. package/lib/cjs/ui/widget/MapLayerManager.js +403 -403
  54. package/lib/cjs/ui/widget/MapLayerManager.js.map +1 -1
  55. package/lib/cjs/ui/widget/MapLayerManager.scss +409 -409
  56. package/lib/cjs/ui/widget/MapLayerSettingsMenu.d.ts +11 -12
  57. package/lib/cjs/ui/widget/MapLayerSettingsMenu.d.ts.map +1 -1
  58. package/lib/cjs/ui/widget/MapLayerSettingsMenu.js +83 -83
  59. package/lib/cjs/ui/widget/MapLayerSettingsMenu.js.map +1 -1
  60. package/lib/cjs/ui/widget/MapLayerSettingsPopupButton.d.ts +6 -7
  61. package/lib/cjs/ui/widget/MapLayerSettingsPopupButton.d.ts.map +1 -1
  62. package/lib/cjs/ui/widget/MapLayerSettingsPopupButton.js +65 -65
  63. package/lib/cjs/ui/widget/MapLayerSettingsPopupButton.js.map +1 -1
  64. package/lib/cjs/ui/widget/MapLayerSettingsPopupButton.scss +20 -20
  65. package/lib/cjs/ui/widget/MapLayersWidget.d.ts +10 -11
  66. package/lib/cjs/ui/widget/MapLayersWidget.d.ts.map +1 -1
  67. package/lib/cjs/ui/widget/MapLayersWidget.js +31 -31
  68. package/lib/cjs/ui/widget/MapLayersWidget.js.map +1 -1
  69. package/lib/cjs/ui/widget/MapManagerSettings.d.ts +2 -3
  70. package/lib/cjs/ui/widget/MapManagerSettings.d.ts.map +1 -1
  71. package/lib/cjs/ui/widget/MapManagerSettings.js +200 -200
  72. package/lib/cjs/ui/widget/MapManagerSettings.js.map +1 -1
  73. package/lib/cjs/ui/widget/MapManagerSettings.scss +29 -29
  74. package/lib/cjs/ui/widget/MapUrlDialog.d.ts +22 -23
  75. package/lib/cjs/ui/widget/MapUrlDialog.d.ts.map +1 -1
  76. package/lib/cjs/ui/widget/MapUrlDialog.js +533 -527
  77. package/lib/cjs/ui/widget/MapUrlDialog.js.map +1 -1
  78. package/lib/cjs/ui/widget/MapUrlDialog.scss +99 -100
  79. package/lib/cjs/ui/widget/SelectMapFormat.d.ts +17 -18
  80. package/lib/cjs/ui/widget/SelectMapFormat.d.ts.map +1 -1
  81. package/lib/cjs/ui/widget/SelectMapFormat.js +59 -59
  82. package/lib/cjs/ui/widget/SelectMapFormat.js.map +1 -1
  83. package/lib/cjs/ui/widget/SubLayersDataProvider.d.ts +18 -20
  84. package/lib/cjs/ui/widget/SubLayersDataProvider.d.ts.map +1 -1
  85. package/lib/cjs/ui/widget/SubLayersDataProvider.js +75 -76
  86. package/lib/cjs/ui/widget/SubLayersDataProvider.js.map +1 -1
  87. package/lib/cjs/ui/widget/SubLayersPopupButton.d.ts +9 -10
  88. package/lib/cjs/ui/widget/SubLayersPopupButton.d.ts.map +1 -1
  89. package/lib/cjs/ui/widget/SubLayersPopupButton.js +40 -40
  90. package/lib/cjs/ui/widget/SubLayersPopupButton.js.map +1 -1
  91. package/lib/cjs/ui/widget/SubLayersTree.d.ts +14 -15
  92. package/lib/cjs/ui/widget/SubLayersTree.d.ts.map +1 -1
  93. package/lib/cjs/ui/widget/SubLayersTree.js +419 -419
  94. package/lib/cjs/ui/widget/SubLayersTree.js.map +1 -1
  95. package/lib/cjs/ui/widget/SubLayersTree.scss +70 -69
  96. package/lib/cjs/ui/widget/TransparencyPopupButton.d.ts +13 -14
  97. package/lib/cjs/ui/widget/TransparencyPopupButton.d.ts.map +1 -1
  98. package/lib/cjs/ui/widget/TransparencyPopupButton.js +47 -47
  99. package/lib/cjs/ui/widget/TransparencyPopupButton.js.map +1 -1
  100. package/lib/cjs/ui/widget/TransparencyPopupButton.scss +35 -36
  101. package/lib/esm/MapLayerPreferences.d.ts +88 -88
  102. package/lib/esm/MapLayerPreferences.js +308 -308
  103. package/lib/esm/MapLayerPreferences.js.map +1 -1
  104. package/lib/esm/map-layers.d.ts +6 -6
  105. package/lib/esm/map-layers.js +10 -10
  106. package/lib/esm/mapLayers.d.ts +26 -44
  107. package/lib/esm/mapLayers.d.ts.map +1 -1
  108. package/lib/esm/mapLayers.js +30 -59
  109. package/lib/esm/mapLayers.js.map +1 -1
  110. package/lib/esm/ui/FeatureInfoUiItemsProvider.d.ts +16 -11
  111. package/lib/esm/ui/FeatureInfoUiItemsProvider.d.ts.map +1 -1
  112. package/lib/esm/ui/FeatureInfoUiItemsProvider.js +43 -48
  113. package/lib/esm/ui/FeatureInfoUiItemsProvider.js.map +1 -1
  114. package/lib/esm/ui/Interfaces.d.ts +50 -50
  115. package/lib/esm/ui/Interfaces.js +1 -1
  116. package/lib/esm/ui/Interfaces.js.map +1 -1
  117. package/lib/esm/ui/MapFeatureInfoTool.d.ts +13 -13
  118. package/lib/esm/ui/MapFeatureInfoTool.d.ts.map +1 -1
  119. package/lib/esm/ui/MapFeatureInfoTool.js +45 -45
  120. package/lib/esm/ui/MapFeatureInfoTool.js.map +1 -1
  121. package/lib/esm/ui/MapLayersUiItemsProvider.d.ts +8 -8
  122. package/lib/esm/ui/MapLayersUiItemsProvider.d.ts.map +1 -1
  123. package/lib/esm/ui/MapLayersUiItemsProvider.js +31 -34
  124. package/lib/esm/ui/MapLayersUiItemsProvider.js.map +1 -1
  125. package/lib/esm/ui/widget/AttachLayerPopupButton.d.ts +13 -14
  126. package/lib/esm/ui/widget/AttachLayerPopupButton.d.ts.map +1 -1
  127. package/lib/esm/ui/widget/AttachLayerPopupButton.js +334 -334
  128. package/lib/esm/ui/widget/AttachLayerPopupButton.js.map +1 -1
  129. package/lib/esm/ui/widget/BasemapPanel.d.ts +7 -8
  130. package/lib/esm/ui/widget/BasemapPanel.d.ts.map +1 -1
  131. package/lib/esm/ui/widget/BasemapPanel.js +152 -152
  132. package/lib/esm/ui/widget/BasemapPanel.js.map +1 -1
  133. package/lib/esm/ui/widget/BasemapPanel.scss +87 -87
  134. package/lib/esm/ui/widget/ConfirmMessageDialog.d.ts +20 -21
  135. package/lib/esm/ui/widget/ConfirmMessageDialog.d.ts.map +1 -1
  136. package/lib/esm/ui/widget/ConfirmMessageDialog.js +21 -21
  137. package/lib/esm/ui/widget/ConfirmMessageDialog.js.map +1 -1
  138. package/lib/esm/ui/widget/FeatureInfoDataProvider.d.ts +35 -40
  139. package/lib/esm/ui/widget/FeatureInfoDataProvider.d.ts.map +1 -1
  140. package/lib/esm/ui/widget/FeatureInfoDataProvider.js +136 -135
  141. package/lib/esm/ui/widget/FeatureInfoDataProvider.js.map +1 -1
  142. package/lib/esm/ui/widget/FeatureInfoWidget.d.ts +6 -7
  143. package/lib/esm/ui/widget/FeatureInfoWidget.d.ts.map +1 -1
  144. package/lib/esm/ui/widget/FeatureInfoWidget.js +72 -67
  145. package/lib/esm/ui/widget/FeatureInfoWidget.js.map +1 -1
  146. package/lib/esm/ui/widget/MapLayerDroppable.d.ts +18 -19
  147. package/lib/esm/ui/widget/MapLayerDroppable.d.ts.map +1 -1
  148. package/lib/esm/ui/widget/MapLayerDroppable.js +84 -84
  149. package/lib/esm/ui/widget/MapLayerDroppable.js.map +1 -1
  150. package/lib/esm/ui/widget/MapLayerManager.d.ts +26 -26
  151. package/lib/esm/ui/widget/MapLayerManager.js +398 -398
  152. package/lib/esm/ui/widget/MapLayerManager.js.map +1 -1
  153. package/lib/esm/ui/widget/MapLayerManager.scss +409 -409
  154. package/lib/esm/ui/widget/MapLayerSettingsMenu.d.ts +11 -12
  155. package/lib/esm/ui/widget/MapLayerSettingsMenu.d.ts.map +1 -1
  156. package/lib/esm/ui/widget/MapLayerSettingsMenu.js +79 -79
  157. package/lib/esm/ui/widget/MapLayerSettingsMenu.js.map +1 -1
  158. package/lib/esm/ui/widget/MapLayerSettingsPopupButton.d.ts +6 -7
  159. package/lib/esm/ui/widget/MapLayerSettingsPopupButton.d.ts.map +1 -1
  160. package/lib/esm/ui/widget/MapLayerSettingsPopupButton.js +61 -61
  161. package/lib/esm/ui/widget/MapLayerSettingsPopupButton.js.map +1 -1
  162. package/lib/esm/ui/widget/MapLayerSettingsPopupButton.scss +20 -20
  163. package/lib/esm/ui/widget/MapLayersWidget.d.ts +10 -11
  164. package/lib/esm/ui/widget/MapLayersWidget.d.ts.map +1 -1
  165. package/lib/esm/ui/widget/MapLayersWidget.js +27 -27
  166. package/lib/esm/ui/widget/MapLayersWidget.js.map +1 -1
  167. package/lib/esm/ui/widget/MapManagerSettings.d.ts +2 -3
  168. package/lib/esm/ui/widget/MapManagerSettings.d.ts.map +1 -1
  169. package/lib/esm/ui/widget/MapManagerSettings.js +196 -196
  170. package/lib/esm/ui/widget/MapManagerSettings.js.map +1 -1
  171. package/lib/esm/ui/widget/MapManagerSettings.scss +29 -29
  172. package/lib/esm/ui/widget/MapUrlDialog.d.ts +22 -23
  173. package/lib/esm/ui/widget/MapUrlDialog.d.ts.map +1 -1
  174. package/lib/esm/ui/widget/MapUrlDialog.js +529 -523
  175. package/lib/esm/ui/widget/MapUrlDialog.js.map +1 -1
  176. package/lib/esm/ui/widget/MapUrlDialog.scss +99 -100
  177. package/lib/esm/ui/widget/SelectMapFormat.d.ts +17 -18
  178. package/lib/esm/ui/widget/SelectMapFormat.d.ts.map +1 -1
  179. package/lib/esm/ui/widget/SelectMapFormat.js +55 -55
  180. package/lib/esm/ui/widget/SelectMapFormat.js.map +1 -1
  181. package/lib/esm/ui/widget/SubLayersDataProvider.d.ts +18 -20
  182. package/lib/esm/ui/widget/SubLayersDataProvider.d.ts.map +1 -1
  183. package/lib/esm/ui/widget/SubLayersDataProvider.js +71 -72
  184. package/lib/esm/ui/widget/SubLayersDataProvider.js.map +1 -1
  185. package/lib/esm/ui/widget/SubLayersPopupButton.d.ts +9 -10
  186. package/lib/esm/ui/widget/SubLayersPopupButton.d.ts.map +1 -1
  187. package/lib/esm/ui/widget/SubLayersPopupButton.js +36 -36
  188. package/lib/esm/ui/widget/SubLayersPopupButton.js.map +1 -1
  189. package/lib/esm/ui/widget/SubLayersTree.d.ts +14 -15
  190. package/lib/esm/ui/widget/SubLayersTree.d.ts.map +1 -1
  191. package/lib/esm/ui/widget/SubLayersTree.js +414 -414
  192. package/lib/esm/ui/widget/SubLayersTree.js.map +1 -1
  193. package/lib/esm/ui/widget/SubLayersTree.scss +70 -69
  194. package/lib/esm/ui/widget/TransparencyPopupButton.d.ts +13 -14
  195. package/lib/esm/ui/widget/TransparencyPopupButton.d.ts.map +1 -1
  196. package/lib/esm/ui/widget/TransparencyPopupButton.js +43 -43
  197. package/lib/esm/ui/widget/TransparencyPopupButton.js.map +1 -1
  198. package/lib/esm/ui/widget/TransparencyPopupButton.scss +35 -36
  199. package/package.json +39 -38
@@ -1,528 +1,534 @@
1
- "use strict";
2
- /*---------------------------------------------------------------------------------------------
3
- * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
4
- * See LICENSE.md in the project root for license terms and full copyright notice.
5
- *--------------------------------------------------------------------------------------------*/
6
- // cSpell:ignore Modeless WMTS
7
- Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.MapUrlDialog = exports.MAP_TYPES = void 0;
9
- const appui_abstract_1 = require("@itwin/appui-abstract");
10
- const appui_react_1 = require("@itwin/appui-react");
11
- const itwinui_react_1 = require("@itwin/itwinui-react");
12
- const core_frontend_1 = require("@itwin/core-frontend");
13
- const core_react_1 = require("@itwin/core-react");
14
- const React = require("react");
15
- const MapLayerPreferences_1 = require("../../MapLayerPreferences");
16
- const mapLayers_1 = require("../../mapLayers");
17
- require("./MapUrlDialog.scss");
18
- const core_bentley_1 = require("@itwin/core-bentley");
19
- const SelectMapFormat_1 = require("./SelectMapFormat");
20
- exports.MAP_TYPES = {
21
- wms: "WMS",
22
- arcGis: "ArcGIS",
23
- wmts: "WMTS",
24
- tileUrl: "TileURL",
25
- arcGisFeature: "ArcGISFeature",
26
- };
27
- // eslint-disable-next-line @typescript-eslint/naming-convention
28
- function MapUrlDialog(props) {
29
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
30
- const { isOverlay, onOkResult, mapTypesOptions } = props;
31
- const getMapUrlFromProps = React.useCallback(() => {
32
- var _a;
33
- if (props.mapLayerSourceToEdit) {
34
- return props.mapLayerSourceToEdit.url;
35
- }
36
- else if ((_a = props.layerRequiringCredentials) === null || _a === void 0 ? void 0 : _a.url) {
37
- return props.layerRequiringCredentials.url;
38
- }
39
- return "";
40
- }, [props.layerRequiringCredentials, props.mapLayerSourceToEdit]);
41
- const getMapNameFromProps = React.useCallback(() => {
42
- var _a;
43
- if (props.mapLayerSourceToEdit) {
44
- return props.mapLayerSourceToEdit.name;
45
- }
46
- else if ((_a = props.layerRequiringCredentials) === null || _a === void 0 ? void 0 : _a.name) {
47
- return props.layerRequiringCredentials.name;
48
- }
49
- return "";
50
- }, [props.layerRequiringCredentials, props.mapLayerSourceToEdit]);
51
- const getFormatFromProps = React.useCallback(() => {
52
- var _a;
53
- if (props.mapLayerSourceToEdit) {
54
- return props.mapLayerSourceToEdit.formatId;
55
- }
56
- else if ((_a = props.layerRequiringCredentials) === null || _a === void 0 ? void 0 : _a.formatId) {
57
- return props.layerRequiringCredentials.formatId;
58
- }
59
- return undefined;
60
- }, [props.layerRequiringCredentials, props.mapLayerSourceToEdit]);
61
- const [dialogTitle] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString(props.layerRequiringCredentials || props.mapLayerSourceToEdit ? "mapLayers:CustomAttach.EditCustomLayer" : "mapLayers:CustomAttach.AttachCustomLayer"));
62
- const [typeLabel] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.Type"));
63
- const [nameLabel] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.Name"));
64
- const [nameInputPlaceHolder] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.NameInputPlaceHolder"));
65
- const [urlLabel] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.URL"));
66
- const [urlInputPlaceHolder] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.UrlInputPlaceHolder"));
67
- const [iTwinSettingsLabel] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.StoreOnITwinSettings"));
68
- const [modelSettingsLabel] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.StoreOnModelSettings"));
69
- const [missingCredentialsLabel] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.MissingCredentials"));
70
- const [invalidCredentialsLabel] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.InvalidCredentials"));
71
- const [externalLoginTitle] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.ExternalLogin"));
72
- const [externalLoginFailedMsg] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.ExternalLoginFailed"));
73
- const [externalLoginSucceededMsg] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.ExternalLoginSucceeded"));
74
- const [externalLoginWaitingMsg] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.ExternalLoginWaiting"));
75
- const [externalLoginTryAgainLabel] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.ExternalLoginTryAgain"));
76
- const [serverRequireCredentials, setServerRequireCredentials] = React.useState(false);
77
- const [invalidCredentialsProvided, setInvalidCredentialsProvided] = React.useState(false);
78
- const [layerAttachPending, setLayerAttachPending] = React.useState(false);
79
- const [layerAuthPending, setLayerAuthPending] = React.useState(false);
80
- const [mapUrl, setMapUrl] = React.useState(getMapUrlFromProps());
81
- const [mapName, setMapName] = React.useState(getMapNameFromProps());
82
- const [userName, setUserName] = React.useState("");
83
- const [password, setPassword] = React.useState("");
84
- const [noSaveSettingsWarning] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.NoSaveSettingsWarning"));
85
- const [passwordLabel] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:AuthenticationInputs.Password"));
86
- const [passwordRequiredLabel] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:AuthenticationInputs.PasswordRequired"));
87
- const [userNameLabel] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:AuthenticationInputs.Username"));
88
- const [userNameRequiredLabel] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:AuthenticationInputs.UsernameRequired"));
89
- const [settingsStorage, setSettingsStorageRadio] = React.useState("iTwin");
90
- const [oauthProcessSucceeded, setOAuthProcessSucceeded] = React.useState(undefined);
91
- const [showOauthPopup, setShowOauthPopup] = React.useState(false);
92
- const [externalLoginUrl, setExternalLoginUrl] = React.useState();
93
- const [onOauthProcessEnd] = React.useState(new core_bentley_1.BeEvent());
94
- const [accessClient, setAccessClient] = React.useState();
95
- const [isAccessClientInitialized, setAccessClientInitialized] = React.useState(false);
96
- const [mapType, setMapType] = React.useState((_a = getFormatFromProps()) !== null && _a !== void 0 ? _a : "ArcGIS");
97
- // 'isMounted' is used to prevent any async operation once the hook has been
98
- // unloaded. Otherwise we get a 'Can't perform a React state update on an unmounted component.' warning in the console.
99
- const isMounted = React.useRef(false);
100
- React.useEffect(() => {
101
- isMounted.current = true;
102
- return () => {
103
- isMounted.current = false;
104
- };
105
- }, []);
106
- const [isSettingsStorageAvailable] = React.useState(mapLayers_1.MapLayersUI.iTwinConfig && ((_c = (_b = props === null || props === void 0 ? void 0 : props.activeViewport) === null || _b === void 0 ? void 0 : _b.iModel) === null || _c === void 0 ? void 0 : _c.iTwinId));
107
- const [hasImodelContext] = React.useState(((_e = (_d = props === null || props === void 0 ? void 0 : props.activeViewport) === null || _d === void 0 ? void 0 : _d.iModel) === null || _e === void 0 ? void 0 : _e.iTwinId) !== undefined
108
- && props.activeViewport.iModel.iTwinId !== core_bentley_1.Guid.empty
109
- && ((_g = (_f = props === null || props === void 0 ? void 0 : props.activeViewport) === null || _f === void 0 ? void 0 : _f.iModel) === null || _g === void 0 ? void 0 : _g.iModelId) !== undefined
110
- && (props === null || props === void 0 ? void 0 : props.activeViewport.iModel.iModelId) !== core_bentley_1.Guid.empty);
111
- // Even though the settings storage is available,
112
- // we don't always want to enable it in the UI.
113
- const [settingsStorageDisabled] = React.useState(!isSettingsStorageAvailable || props.mapLayerSourceToEdit !== undefined || props.layerRequiringCredentials !== undefined);
114
- const [layerRequiringCredentialsIdx] = React.useState(() => {
115
- var _a;
116
- if (props.layerRequiringCredentials === undefined || !props.layerRequiringCredentials.name || !props.layerRequiringCredentials.url) {
117
- return undefined;
118
- }
119
- const indexInDisplayStyle = (_a = props.activeViewport) === null || _a === void 0 ? void 0 : _a.displayStyle.findMapLayerIndexByNameAndSource(props.layerRequiringCredentials.name, props.layerRequiringCredentials.url, isOverlay);
120
- if (indexInDisplayStyle === undefined || indexInDisplayStyle < 0) {
121
- return undefined;
122
- }
123
- else {
124
- return indexInDisplayStyle;
125
- }
126
- });
127
- const handleCancel = React.useCallback(() => {
128
- if (props.onCancelResult) {
129
- props.onCancelResult();
130
- return;
131
- }
132
- appui_react_1.ModalDialogManager.closeDialog();
133
- }, [props]);
134
- const onUsernameChange = React.useCallback((event) => {
135
- setUserName(event.target.value);
136
- if (invalidCredentialsProvided)
137
- setInvalidCredentialsProvided(false);
138
- }, [setUserName, invalidCredentialsProvided, setInvalidCredentialsProvided]);
139
- const onPasswordChange = React.useCallback((event) => {
140
- setPassword(event.target.value);
141
- if (invalidCredentialsProvided)
142
- setInvalidCredentialsProvided(false);
143
- }, [setPassword, invalidCredentialsProvided, setInvalidCredentialsProvided]);
144
- const handleArcGisLogin = React.useCallback(() => {
145
- setLayerAuthPending(true);
146
- setShowOauthPopup(true);
147
- if (oauthProcessSucceeded === false) {
148
- setOAuthProcessSucceeded(undefined);
149
- }
150
- }, [oauthProcessSucceeded]);
151
- // return true if authorization is needed
152
- const updateAuthState = React.useCallback(async (source, sourceValidation) => {
153
- const sourceRequireAuth = (sourceValidation.status === core_frontend_1.MapLayerSourceStatus.RequireAuth);
154
- const invalidCredentials = (sourceValidation.status === core_frontend_1.MapLayerSourceStatus.InvalidCredentials);
155
- if (sourceRequireAuth) {
156
- const settings = source.toLayerSettings();
157
- if (accessClient !== undefined && accessClient.getTokenServiceEndPoint !== undefined && settings !== undefined) {
158
- try {
159
- const tokenEndpoint = await accessClient.getTokenServiceEndPoint(settings.url);
160
- if (tokenEndpoint !== undefined) {
161
- const loginUrl = tokenEndpoint.getLoginUrl();
162
- setExternalLoginUrl(loginUrl);
163
- }
164
- }
165
- catch (_error) {
166
- }
167
- }
168
- }
169
- setServerRequireCredentials(sourceRequireAuth || invalidCredentials);
170
- if (invalidCredentials) {
171
- setInvalidCredentialsProvided(true);
172
- }
173
- else if (invalidCredentialsProvided) {
174
- setInvalidCredentialsProvided(false); // flag reset
175
- }
176
- return sourceRequireAuth || invalidCredentials;
177
- }, [accessClient, invalidCredentialsProvided]);
178
- const updateAttachedLayer = React.useCallback(async (source, validation) => {
179
- const vp = props === null || props === void 0 ? void 0 : props.activeViewport;
180
- if (vp === undefined || source === undefined || layerRequiringCredentialsIdx === undefined) {
181
- const error = mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:Messages.MapLayerAttachMissingViewOrSource");
182
- const msg = mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:Messages.MapLayerAttachError", { error, sourceUrl: source.url });
183
- core_frontend_1.IModelApp.notifications.outputMessage(new core_frontend_1.NotifyMessageDetails(core_frontend_1.OutputMessagePriority.Error, msg));
184
- return true;
185
- }
186
- // Layer is already attached,
187
- vp.displayStyle.changeMapLayerProps({
188
- subLayers: validation.subLayers,
189
- }, layerRequiringCredentialsIdx, isOverlay);
190
- vp.displayStyle.changeMapLayerCredentials(layerRequiringCredentialsIdx, isOverlay, source.userName, source.password);
191
- // Either initial attach/initialize failed or the layer failed to load at least one tile
192
- // because of an invalid token; in both cases tile tree needs to be fully reset
193
- const provider = vp.getMapLayerImageryProvider(layerRequiringCredentialsIdx, isOverlay);
194
- provider === null || provider === void 0 ? void 0 : provider.resetStatus();
195
- vp.resetMapLayer(layerRequiringCredentialsIdx, isOverlay);
196
- vp.invalidateRenderPlan();
197
- // This handler will close the layer source handler, and therefore the MapUrl dialog.
198
- // don't call it if the dialog needs to remains open.
199
- onOkResult();
200
- return true;
201
- }, [isOverlay, layerRequiringCredentialsIdx, onOkResult, props.activeViewport]);
202
- // Returns true if no further input is needed from end-user.
203
- const doAttach = React.useCallback(async (source, validation) => {
204
- const vp = props === null || props === void 0 ? void 0 : props.activeViewport;
205
- if (vp === undefined || source === undefined) {
206
- const error = mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:Messages.MapLayerAttachMissingViewOrSource");
207
- const msg = mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:Messages.MapLayerAttachError", { error, sourceUrl: source.url });
208
- core_frontend_1.IModelApp.notifications.outputMessage(new core_frontend_1.NotifyMessageDetails(core_frontend_1.OutputMessagePriority.Error, msg));
209
- return true;
210
- }
211
- // Update service settings if storage is available and we are not prompting user for credentials
212
- if (!settingsStorageDisabled && !props.layerRequiringCredentials) {
213
- const storeOnIModel = (hasImodelContext ? "Model" === settingsStorage : undefined);
214
- if (vp.iModel.iTwinId && !(await MapLayerPreferences_1.MapLayerPreferences.storeSource(source, vp.iModel.iTwinId, vp.iModel.iModelId, storeOnIModel))) {
215
- const msgError = mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:Messages.MapLayerPreferencesStoreFailed");
216
- core_frontend_1.IModelApp.notifications.outputMessage(new core_frontend_1.NotifyMessageDetails(core_frontend_1.OutputMessagePriority.Error, msgError));
217
- }
218
- }
219
- const settings = source.toLayerSettings(validation.subLayers);
220
- if (settings) {
221
- vp.displayStyle.attachMapLayer({ settings, isOverlay });
222
- const msg = core_frontend_1.IModelApp.localization.getLocalizedString("mapLayers:Messages.MapLayerAttached", { sourceName: source.name, sourceUrl: source.url });
223
- core_frontend_1.IModelApp.notifications.outputMessage(new core_frontend_1.NotifyMessageDetails(core_frontend_1.OutputMessagePriority.Info, msg));
224
- }
225
- else {
226
- const msgError = mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:Messages.MapLayerLayerSettingsConversionError");
227
- const msg = mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.MapLayerAttachError", { error: msgError, sourceUrl: source.url });
228
- core_frontend_1.IModelApp.notifications.outputMessage(new core_frontend_1.NotifyMessageDetails(core_frontend_1.OutputMessagePriority.Error, msg));
229
- }
230
- vp.invalidateRenderPlan();
231
- // This handler will close the layer source handler, and therefore the MapUrl dialog.
232
- // don't call it if the dialog needs to remains open.
233
- onOkResult();
234
- return true;
235
- }, [hasImodelContext, isOverlay, onOkResult, props === null || props === void 0 ? void 0 : props.activeViewport, props.layerRequiringCredentials, settingsStorage, settingsStorageDisabled]);
236
- // Validate the layer source and attempt to attach (or update) the layer.
237
- // Returns true if no further input is needed from end-user (i.e. close the dialog)
238
- const attemptAttachSource = React.useCallback(async (source) => {
239
- try {
240
- const validation = await source.validateSource(true);
241
- if (validation.status === core_frontend_1.MapLayerSourceStatus.Valid) {
242
- if (layerRequiringCredentialsIdx === undefined) {
243
- return await doAttach(source, validation);
244
- }
245
- else {
246
- return await updateAttachedLayer(source, validation);
247
- }
248
- }
249
- else if (validation.status === core_frontend_1.MapLayerSourceStatus.InvalidCoordinateSystem) {
250
- const msg = mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.InvalidCoordinateSystem");
251
- core_frontend_1.IModelApp.notifications.outputMessage(new core_frontend_1.NotifyMessageDetails(core_frontend_1.OutputMessagePriority.Error, msg));
252
- return true;
253
- }
254
- else {
255
- const authNeeded = await updateAuthState(source, validation);
256
- if (authNeeded) {
257
- return false;
258
- }
259
- else {
260
- const msg = mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.ValidationError");
261
- core_frontend_1.IModelApp.notifications.outputMessage(new core_frontend_1.NotifyMessageDetails(core_frontend_1.OutputMessagePriority.Error, `${msg} ${source.url}`));
262
- return true;
263
- }
264
- }
265
- return false;
266
- }
267
- catch (error) {
268
- const msg = mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:Messages.MapLayerAttachError", { error, sourceUrl: source.url });
269
- core_frontend_1.IModelApp.notifications.outputMessage(new core_frontend_1.NotifyMessageDetails(core_frontend_1.OutputMessagePriority.Error, msg));
270
- return true;
271
- }
272
- }, [updateAuthState, doAttach, layerRequiringCredentialsIdx, updateAttachedLayer]);
273
- const onNameChange = React.useCallback((event) => {
274
- setMapName(event.target.value);
275
- }, [setMapName]);
276
- const onRadioChange = React.useCallback((event) => {
277
- setSettingsStorageRadio(event.target.value);
278
- }, [setSettingsStorageRadio]);
279
- const onUrlChange = React.useCallback((event) => {
280
- setMapUrl(event.target.value);
281
- }, [setMapUrl]);
282
- const createSource = React.useCallback(() => {
283
- let source;
284
- if (mapUrl && mapName) {
285
- source = core_frontend_1.MapLayerSource.fromJSON({
286
- url: mapUrl,
287
- name: mapName,
288
- formatId: mapType
289
- });
290
- // Set credentials separately since they are not part of JSON
291
- if (source) {
292
- source.userName = userName || undefined; // When there is no value, empty string is always returned, in this case force it to undefined,
293
- source.password = password || undefined;
294
- }
295
- }
296
- return source;
297
- }, [mapName, mapType, mapUrl, password, userName]);
298
- const handleOk = React.useCallback(() => {
299
- const source = createSource();
300
- if (source === undefined || props.mapLayerSourceToEdit) {
301
- appui_react_1.ModalDialogManager.closeDialog();
302
- onOkResult();
303
- if (source === undefined) {
304
- // Close the dialog and inform end user something went wrong.
305
- const msgError = mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:Messages.MapLayerLayerSourceCreationFailed");
306
- const msg = mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:Messages.MapLayerAttachError", { error: msgError, sourceUrl: mapUrl });
307
- core_frontend_1.IModelApp.notifications.outputMessage(new core_frontend_1.NotifyMessageDetails(core_frontend_1.OutputMessagePriority.Error, msg));
308
- return;
309
- }
310
- // Simply change the source definition in the setting service
311
- if (props.mapLayerSourceToEdit !== undefined) {
312
- const vp = props.activeViewport;
313
- void (async () => {
314
- var _a, _b;
315
- if (isSettingsStorageAvailable && ((_a = vp === null || vp === void 0 ? void 0 : vp.iModel) === null || _a === void 0 ? void 0 : _a.iTwinId)) {
316
- try {
317
- await MapLayerPreferences_1.MapLayerPreferences.replaceSource(props.mapLayerSourceToEdit, source, vp.iModel.iTwinId, vp === null || vp === void 0 ? void 0 : vp.iModel.iModelId);
318
- }
319
- catch (err) {
320
- const errorMessage = core_frontend_1.IModelApp.localization.getLocalizedString("mapLayers:Messages.MapLayerEditError", { layerName: (_b = props.mapLayerSourceToEdit) === null || _b === void 0 ? void 0 : _b.name });
321
- core_frontend_1.IModelApp.notifications.outputMessage(new core_frontend_1.NotifyMessageDetails(core_frontend_1.OutputMessagePriority.Error, errorMessage));
322
- return;
323
- }
324
- }
325
- })();
326
- return;
327
- }
328
- }
329
- setLayerAttachPending(true);
330
- // Attach source asynchronously.
331
- void (async () => {
332
- try {
333
- const closeDialog = await attemptAttachSource(source);
334
- if (isMounted.current) {
335
- setLayerAttachPending(false);
336
- }
337
- // In theory the modal dialog should always get closed by the parent
338
- // AttachLayerPanel's 'onOkResult' handler. We close it here just in case.
339
- if (closeDialog) {
340
- appui_react_1.ModalDialogManager.closeDialog();
341
- onOkResult();
342
- }
343
- }
344
- catch (_error) {
345
- onOkResult();
346
- appui_react_1.ModalDialogManager.closeDialog();
347
- }
348
- })();
349
- }, [createSource, props.mapLayerSourceToEdit, props.activeViewport, onOkResult, mapUrl, isSettingsStorageAvailable, attemptAttachSource]);
350
- React.useEffect(() => {
351
- const handleOAuthProcessEnd = (success, _state) => {
352
- onOauthProcessEnd.raiseEvent(success, _state);
353
- };
354
- // Currently only arcgis support AccessClient
355
- const ac = core_frontend_1.IModelApp.mapLayerFormatRegistry.getAccessClient(exports.MAP_TYPES.arcGis);
356
- if (ac === null || ac === void 0 ? void 0 : ac.onOAuthProcessEnd) {
357
- setAccessClient(ac); // cache it, so we dont need to make another lookup;
358
- ac.onOAuthProcessEnd.addListener(handleOAuthProcessEnd);
359
- }
360
- setAccessClientInitialized(true);
361
- return () => {
362
- if (ac === null || ac === void 0 ? void 0 : ac.onOAuthProcessEnd) {
363
- ac.onOAuthProcessEnd.removeListener(handleOAuthProcessEnd);
364
- }
365
- setAccessClient(undefined);
366
- setAccessClientInitialized(false);
367
- };
368
- }, [mapType, onOauthProcessEnd, setAccessClient]);
369
- // After a map type change, make sure the different Oauth states are reset.
370
- React.useEffect(() => {
371
- // Reset few states
372
- setServerRequireCredentials(false);
373
- setInvalidCredentialsProvided(false);
374
- setShowOauthPopup(false);
375
- setOAuthProcessSucceeded(undefined);
376
- setExternalLoginUrl(undefined);
377
- }, [mapType]);
378
- // The first time the dialog is loaded and we already know the layer requires auth. (i.e ImageryProvider already made an attempt)
379
- // makes a request to discover the authentification types and adjust UI accordingly (i.e. username/password fields, Oauth popup)
380
- // Without this effect, user would have to manually click the 'OK' button in order to trigger the layer connection.
381
- React.useEffect(() => {
382
- // Attach source asynchronously.
383
- void (async () => {
384
- var _a, _b;
385
- if (isAccessClientInitialized && ((_a = props.layerRequiringCredentials) === null || _a === void 0 ? void 0 : _a.url) !== undefined && ((_b = props.layerRequiringCredentials) === null || _b === void 0 ? void 0 : _b.name) !== undefined) {
386
- try {
387
- const source = core_frontend_1.MapLayerSource.fromJSON({
388
- url: props.layerRequiringCredentials.url,
389
- name: props.layerRequiringCredentials.name,
390
- formatId: props.layerRequiringCredentials.formatId
391
- });
392
- if (source !== undefined) {
393
- setLayerAttachPending(true);
394
- const validation = await source.validateSource(true);
395
- if (isMounted.current) {
396
- setLayerAttachPending(false);
397
- }
398
- await updateAuthState(source, validation);
399
- }
400
- }
401
- catch (_error) { }
402
- }
403
- })();
404
- }, [isAccessClientInitialized, (_h = props.layerRequiringCredentials) === null || _h === void 0 ? void 0 : _h.formatId, (_j = props.layerRequiringCredentials) === null || _j === void 0 ? void 0 : _j.name, (_k = props.layerRequiringCredentials) === null || _k === void 0 ? void 0 : _k.url, updateAuthState]);
405
- const dialogContainer = React.useRef(null);
406
- const readyToSave = React.useCallback(() => {
407
- const credentialsSet = !!userName && !!password;
408
- return (!!mapUrl && !!mapName)
409
- && !layerAttachPending
410
- && (!serverRequireCredentials || credentialsSet)
411
- && !invalidCredentialsProvided
412
- && (externalLoginUrl === undefined || (externalLoginUrl !== undefined && oauthProcessSucceeded));
413
- }, [userName, password, mapUrl, mapName, serverRequireCredentials, layerAttachPending, invalidCredentialsProvided, externalLoginUrl, oauthProcessSucceeded]);
414
- const buttonCluster = React.useMemo(() => [
415
- { type: appui_abstract_1.DialogButtonType.OK, onClick: handleOk, disabled: !readyToSave() },
416
- { type: appui_abstract_1.DialogButtonType.Cancel, onClick: handleCancel },
417
- ], [readyToSave, handleCancel, handleOk]);
418
- const handleOnKeyDown = React.useCallback((event) => {
419
- if (event.key === appui_abstract_1.SpecialKey.Enter) {
420
- if (readyToSave())
421
- handleOk();
422
- }
423
- }, [handleOk, readyToSave]);
424
- // onOauthProcessEnd events handler
425
- React.useEffect(() => {
426
- const handleOauthProcess = (success, _state) => {
427
- setLayerAuthPending(false);
428
- if (success) {
429
- setOAuthProcessSucceeded(true);
430
- setShowOauthPopup(false);
431
- setLayerAttachPending(false);
432
- handleOk(); // Add the layer the same way the user would do by clicking 'ok'
433
- }
434
- else {
435
- setShowOauthPopup(false);
436
- setLayerAttachPending(false);
437
- setOAuthProcessSucceeded(false);
438
- }
439
- };
440
- onOauthProcessEnd.addListener(handleOauthProcess);
441
- return () => {
442
- onOauthProcessEnd.removeListener(handleOauthProcess);
443
- };
444
- }, [handleOk, onOauthProcessEnd]);
445
- //
446
- // Monitors authentication method changes
447
- React.useEffect(() => {
448
- if (serverRequireCredentials && oauthProcessSucceeded === undefined && externalLoginUrl !== undefined) {
449
- handleArcGisLogin();
450
- }
451
- }, [oauthProcessSucceeded, externalLoginUrl, handleArcGisLogin, serverRequireCredentials]);
452
- // Monitors Oauth2 popup was closed
453
- const handleOAuthPopupClose = React.useCallback(() => {
454
- setShowOauthPopup(false);
455
- setLayerAuthPending(false);
456
- if (oauthProcessSucceeded === undefined)
457
- setOAuthProcessSucceeded(false); // indicates there was a failed attempt
458
- }, [oauthProcessSucceeded]);
459
- // Utility function to get warning message section
460
- function renderWarningMessage() {
461
- let node;
462
- let warningMessage;
463
- // Get the proper warning message
464
- if (showOauthPopup) {
465
- warningMessage = externalLoginWaitingMsg;
466
- }
467
- else if (oauthProcessSucceeded === false) {
468
- warningMessage = externalLoginFailedMsg;
469
- }
470
- else if (oauthProcessSucceeded === true) {
471
- warningMessage = externalLoginSucceededMsg;
472
- }
473
- else if (invalidCredentialsProvided) {
474
- warningMessage = invalidCredentialsLabel;
475
- }
476
- else if (serverRequireCredentials && (!userName || !password)) {
477
- warningMessage = missingCredentialsLabel;
478
- }
479
- // Sometimes we want to add an extra node, such as a button
480
- let extraNode;
481
- if (oauthProcessSucceeded === false) {
482
- extraNode = React.createElement("div", null,
483
- React.createElement(itwinui_react_1.Button, { onClick: handleArcGisLogin }, externalLoginTryAgainLabel));
484
- }
485
- if (warningMessage !== undefined) {
486
- return (React.createElement("div", { className: "map-layer-source-warnMessage" },
487
- React.createElement(core_react_1.Icon, { className: "map-layer-source-warnMessage-icon", iconSpec: "icon-status-warning" }),
488
- React.createElement("span", { className: "map-layer-source-warnMessage-label" }, warningMessage),
489
- extraNode));
490
- }
491
- else {
492
- return (React.createElement("span", { className: "map-layer-source-placeholder" }, "\u00A0"));
493
- }
494
- return node;
495
- }
496
- // Use a hook to display the popup.
497
- // The display of the popup is controlled by the 'showOauthPopup' state variable.
498
- (0, core_react_1.useCrossOriginPopup)(showOauthPopup, externalLoginUrl, externalLoginTitle, 450, 450, handleOAuthPopupClose);
499
- return (React.createElement("div", { ref: dialogContainer },
500
- React.createElement(core_react_1.Dialog, { className: "map-layer-url-dialog", title: dialogTitle, opened: true, resizable: true, movable: true, modal: true, buttonCluster: buttonCluster, onClose: handleCancel, onEscape: handleCancel, minHeight: 120, maxWidth: 600, titleStyle: { paddingLeft: "10px" }, footerStyle: { paddingBottom: "10px", paddingRight: "10px" }, trapFocus: false },
501
- React.createElement("div", { className: "map-layer-url-dialog-content" },
502
- React.createElement("div", { className: "map-layer-source-url" },
503
- React.createElement("span", { className: "map-layer-source-label" }, typeLabel),
504
- React.createElement(SelectMapFormat_1.SelectMapFormat, { value: mapType, disabled: props.layerRequiringCredentials !== undefined || props.mapLayerSourceToEdit !== undefined || layerAttachPending || layerAuthPending, onChange: setMapType, mapTypesOptions: mapTypesOptions }),
505
- React.createElement("span", { className: "map-layer-source-label" }, nameLabel),
506
- React.createElement(itwinui_react_1.Input, { className: "map-layer-source-input", placeholder: nameInputPlaceHolder, onChange: onNameChange, value: mapName, disabled: props.layerRequiringCredentials !== undefined || layerAttachPending || layerAuthPending }),
507
- React.createElement("span", { className: "map-layer-source-label" }, urlLabel),
508
- React.createElement(itwinui_react_1.Input, { className: "map-layer-source-input", placeholder: urlInputPlaceHolder, onKeyPress: handleOnKeyDown, onChange: onUrlChange, disabled: props.mapLayerSourceToEdit !== undefined || layerAttachPending || layerAuthPending, value: mapUrl }),
509
- serverRequireCredentials
510
- && externalLoginUrl === undefined // external login is handled in popup
511
- && props.mapLayerSourceToEdit === undefined &&
512
- React.createElement(React.Fragment, null,
513
- React.createElement("span", { className: "map-layer-source-label" }, userNameLabel),
514
- React.createElement(itwinui_react_1.LabeledInput, { className: "map-layer-source-input", displayStyle: "inline", placeholder: serverRequireCredentials ? userNameRequiredLabel : userNameLabel, status: (!userName && serverRequireCredentials) || invalidCredentialsProvided ? "warning" : undefined, disabled: layerAttachPending || layerAuthPending, onChange: onUsernameChange, value: userName, size: "small" }),
515
- React.createElement("span", { className: "map-layer-source-label" }, passwordLabel),
516
- React.createElement(itwinui_react_1.LabeledInput, { className: "map-layer-source-input", displayStyle: "inline", type: "password", placeholder: serverRequireCredentials ? passwordRequiredLabel : passwordLabel, status: (!password && serverRequireCredentials) || invalidCredentialsProvided ? "warning" : undefined, disabled: layerAttachPending || layerAuthPending, onChange: onPasswordChange, onKeyPress: handleOnKeyDown, value: password, size: "small" })),
517
- isSettingsStorageAvailable &&
518
- React.createElement("div", { title: settingsStorageDisabled ? noSaveSettingsWarning : "" }, hasImodelContext &&
519
- React.createElement("div", null,
520
- React.createElement(itwinui_react_1.Radio, { disabled: settingsStorageDisabled, name: "settingsStorage", value: "iTwin", label: iTwinSettingsLabel, checked: settingsStorage === "iTwin", onChange: onRadioChange }),
521
- React.createElement(itwinui_react_1.Radio, { disabled: settingsStorageDisabled, name: "settingsStorage", value: "Model", label: modelSettingsLabel, checked: settingsStorage === "Model", onChange: onRadioChange }))))),
522
- renderWarningMessage(),
523
- (layerAttachPending || layerAuthPending) &&
524
- React.createElement("div", { className: "map-layer-source-progressBar" },
525
- React.createElement(itwinui_react_1.ProgressLinear, { indeterminate: true })))));
526
- }
527
- exports.MapUrlDialog = MapUrlDialog;
1
+ "use strict";
2
+ /*---------------------------------------------------------------------------------------------
3
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
4
+ * See LICENSE.md in the project root for license terms and full copyright notice.
5
+ *--------------------------------------------------------------------------------------------*/
6
+ // cSpell:ignore Modeless WMTS
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.MapUrlDialog = exports.MAP_TYPES = void 0;
9
+ const appui_abstract_1 = require("@itwin/appui-abstract");
10
+ const appui_react_1 = require("@itwin/appui-react");
11
+ const itwinui_react_1 = require("@itwin/itwinui-react");
12
+ const core_frontend_1 = require("@itwin/core-frontend");
13
+ const core_react_1 = require("@itwin/core-react");
14
+ const React = require("react");
15
+ const MapLayerPreferences_1 = require("../../MapLayerPreferences");
16
+ const mapLayers_1 = require("../../mapLayers");
17
+ require("./MapUrlDialog.scss");
18
+ const core_bentley_1 = require("@itwin/core-bentley");
19
+ const SelectMapFormat_1 = require("./SelectMapFormat");
20
+ exports.MAP_TYPES = {
21
+ wms: "WMS",
22
+ arcGis: "ArcGIS",
23
+ wmts: "WMTS",
24
+ tileUrl: "TileURL",
25
+ arcGisFeature: "ArcGISFeature",
26
+ };
27
+ // eslint-disable-next-line @typescript-eslint/naming-convention
28
+ function MapUrlDialog(props) {
29
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
30
+ const { isOverlay, onOkResult, mapTypesOptions } = props;
31
+ const getMapUrlFromProps = React.useCallback(() => {
32
+ var _a;
33
+ if (props.mapLayerSourceToEdit) {
34
+ return props.mapLayerSourceToEdit.url;
35
+ }
36
+ else if ((_a = props.layerRequiringCredentials) === null || _a === void 0 ? void 0 : _a.url) {
37
+ return props.layerRequiringCredentials.url;
38
+ }
39
+ return "";
40
+ }, [props.layerRequiringCredentials, props.mapLayerSourceToEdit]);
41
+ const getMapNameFromProps = React.useCallback(() => {
42
+ var _a;
43
+ if (props.mapLayerSourceToEdit) {
44
+ return props.mapLayerSourceToEdit.name;
45
+ }
46
+ else if ((_a = props.layerRequiringCredentials) === null || _a === void 0 ? void 0 : _a.name) {
47
+ return props.layerRequiringCredentials.name;
48
+ }
49
+ return "";
50
+ }, [props.layerRequiringCredentials, props.mapLayerSourceToEdit]);
51
+ const getFormatFromProps = React.useCallback(() => {
52
+ var _a;
53
+ if (props.mapLayerSourceToEdit) {
54
+ return props.mapLayerSourceToEdit.formatId;
55
+ }
56
+ else if ((_a = props.layerRequiringCredentials) === null || _a === void 0 ? void 0 : _a.formatId) {
57
+ return props.layerRequiringCredentials.formatId;
58
+ }
59
+ return undefined;
60
+ }, [props.layerRequiringCredentials, props.mapLayerSourceToEdit]);
61
+ const [dialogTitle] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString(props.layerRequiringCredentials || props.mapLayerSourceToEdit ? "mapLayers:CustomAttach.EditCustomLayer" : "mapLayers:CustomAttach.AttachCustomLayer"));
62
+ const [typeLabel] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.Type"));
63
+ const [nameLabel] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.Name"));
64
+ const [nameInputPlaceHolder] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.NameInputPlaceHolder"));
65
+ const [urlLabel] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.URL"));
66
+ const [urlInputPlaceHolder] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.UrlInputPlaceHolder"));
67
+ const [iTwinSettingsLabel] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.StoreOnITwinSettings"));
68
+ const [modelSettingsLabel] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.StoreOnModelSettings"));
69
+ const [missingCredentialsLabel] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.MissingCredentials"));
70
+ const [invalidCredentialsLabel] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.InvalidCredentials"));
71
+ const [externalLoginTitle] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.ExternalLogin"));
72
+ const [externalLoginFailedMsg] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.ExternalLoginFailed"));
73
+ const [externalLoginSucceededMsg] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.ExternalLoginSucceeded"));
74
+ const [externalLoginWaitingMsg] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.ExternalLoginWaiting"));
75
+ const [externalLoginTryAgainLabel] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.ExternalLoginTryAgain"));
76
+ const [serverRequireCredentials, setServerRequireCredentials] = React.useState(false);
77
+ const [invalidCredentialsProvided, setInvalidCredentialsProvided] = React.useState(false);
78
+ const [layerAttachPending, setLayerAttachPending] = React.useState(false);
79
+ const [layerAuthPending, setLayerAuthPending] = React.useState(false);
80
+ const [mapUrl, setMapUrl] = React.useState(getMapUrlFromProps());
81
+ const [mapName, setMapName] = React.useState(getMapNameFromProps());
82
+ const [userName, setUserName] = React.useState("");
83
+ const [password, setPassword] = React.useState("");
84
+ const [noSaveSettingsWarning] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.NoSaveSettingsWarning"));
85
+ const [passwordLabel] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:AuthenticationInputs.Password"));
86
+ const [passwordRequiredLabel] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:AuthenticationInputs.PasswordRequired"));
87
+ const [userNameLabel] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:AuthenticationInputs.Username"));
88
+ const [userNameRequiredLabel] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:AuthenticationInputs.UsernameRequired"));
89
+ const [settingsStorage, setSettingsStorageRadio] = React.useState("iTwin");
90
+ const [oauthProcessSucceeded, setOAuthProcessSucceeded] = React.useState(undefined);
91
+ const [showOauthPopup, setShowOauthPopup] = React.useState(false);
92
+ const [externalLoginUrl, setExternalLoginUrl] = React.useState();
93
+ const [onOauthProcessEnd] = React.useState(new core_bentley_1.BeEvent());
94
+ const [accessClient, setAccessClient] = React.useState();
95
+ const [isAccessClientInitialized, setAccessClientInitialized] = React.useState(false);
96
+ const [mapType, setMapType] = React.useState((_a = getFormatFromProps()) !== null && _a !== void 0 ? _a : "ArcGIS");
97
+ // 'isMounted' is used to prevent any async operation once the hook has been
98
+ // unloaded. Otherwise we get a 'Can't perform a React state update on an unmounted component.' warning in the console.
99
+ const isMounted = React.useRef(false);
100
+ React.useEffect(() => {
101
+ isMounted.current = true;
102
+ return () => {
103
+ isMounted.current = false;
104
+ };
105
+ }, []);
106
+ const [isSettingsStorageAvailable] = React.useState(mapLayers_1.MapLayersUI.iTwinConfig && ((_c = (_b = props === null || props === void 0 ? void 0 : props.activeViewport) === null || _b === void 0 ? void 0 : _b.iModel) === null || _c === void 0 ? void 0 : _c.iTwinId));
107
+ const [hasImodelContext] = React.useState(((_e = (_d = props === null || props === void 0 ? void 0 : props.activeViewport) === null || _d === void 0 ? void 0 : _d.iModel) === null || _e === void 0 ? void 0 : _e.iTwinId) !== undefined
108
+ && props.activeViewport.iModel.iTwinId !== core_bentley_1.Guid.empty
109
+ && ((_g = (_f = props === null || props === void 0 ? void 0 : props.activeViewport) === null || _f === void 0 ? void 0 : _f.iModel) === null || _g === void 0 ? void 0 : _g.iModelId) !== undefined
110
+ && (props === null || props === void 0 ? void 0 : props.activeViewport.iModel.iModelId) !== core_bentley_1.Guid.empty);
111
+ // Even though the settings storage is available,
112
+ // we don't always want to enable it in the UI.
113
+ const [settingsStorageDisabled] = React.useState(!isSettingsStorageAvailable || props.mapLayerSourceToEdit !== undefined || props.layerRequiringCredentials !== undefined);
114
+ const [layerRequiringCredentialsIdx] = React.useState(() => {
115
+ var _a;
116
+ if (props.layerRequiringCredentials === undefined || !props.layerRequiringCredentials.name || !props.layerRequiringCredentials.url) {
117
+ return undefined;
118
+ }
119
+ const indexInDisplayStyle = (_a = props.activeViewport) === null || _a === void 0 ? void 0 : _a.displayStyle.findMapLayerIndexByNameAndSource(props.layerRequiringCredentials.name, props.layerRequiringCredentials.url, isOverlay);
120
+ if (indexInDisplayStyle === undefined || indexInDisplayStyle < 0) {
121
+ return undefined;
122
+ }
123
+ else {
124
+ return indexInDisplayStyle;
125
+ }
126
+ });
127
+ const handleCancel = React.useCallback(() => {
128
+ if (props.onCancelResult) {
129
+ props.onCancelResult();
130
+ return;
131
+ }
132
+ appui_react_1.UiFramework.dialogs.modal.close();
133
+ }, [props]);
134
+ const onUsernameChange = React.useCallback((event) => {
135
+ setUserName(event.target.value);
136
+ if (invalidCredentialsProvided)
137
+ setInvalidCredentialsProvided(false);
138
+ }, [setUserName, invalidCredentialsProvided, setInvalidCredentialsProvided]);
139
+ const onPasswordChange = React.useCallback((event) => {
140
+ setPassword(event.target.value);
141
+ if (invalidCredentialsProvided)
142
+ setInvalidCredentialsProvided(false);
143
+ }, [setPassword, invalidCredentialsProvided, setInvalidCredentialsProvided]);
144
+ const handleArcGisLogin = React.useCallback(() => {
145
+ setLayerAuthPending(true);
146
+ setShowOauthPopup(true);
147
+ if (oauthProcessSucceeded === false) {
148
+ setOAuthProcessSucceeded(undefined);
149
+ }
150
+ }, [oauthProcessSucceeded]);
151
+ // return true if authorization is needed
152
+ const updateAuthState = React.useCallback(async (source, sourceValidation) => {
153
+ const sourceRequireAuth = (sourceValidation.status === core_frontend_1.MapLayerSourceStatus.RequireAuth);
154
+ const invalidCredentials = (sourceValidation.status === core_frontend_1.MapLayerSourceStatus.InvalidCredentials);
155
+ if (sourceRequireAuth) {
156
+ const settings = source.toLayerSettings();
157
+ if (accessClient !== undefined && accessClient.getTokenServiceEndPoint !== undefined && settings !== undefined) {
158
+ try {
159
+ const tokenEndpoint = await accessClient.getTokenServiceEndPoint(settings.url);
160
+ if (tokenEndpoint !== undefined) {
161
+ const loginUrl = tokenEndpoint.getLoginUrl();
162
+ setExternalLoginUrl(loginUrl);
163
+ }
164
+ }
165
+ catch (_error) {
166
+ }
167
+ }
168
+ }
169
+ setServerRequireCredentials(sourceRequireAuth || invalidCredentials);
170
+ if (invalidCredentials) {
171
+ setInvalidCredentialsProvided(true);
172
+ }
173
+ else if (invalidCredentialsProvided) {
174
+ setInvalidCredentialsProvided(false); // flag reset
175
+ }
176
+ return sourceRequireAuth || invalidCredentials;
177
+ }, [accessClient, invalidCredentialsProvided]);
178
+ const updateAttachedLayer = React.useCallback(async (source, validation) => {
179
+ const vp = props === null || props === void 0 ? void 0 : props.activeViewport;
180
+ if (vp === undefined || source === undefined || layerRequiringCredentialsIdx === undefined) {
181
+ const error = mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:Messages.MapLayerAttachMissingViewOrSource");
182
+ const msg = mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:Messages.MapLayerAttachError", { error, sourceUrl: source.url });
183
+ core_frontend_1.IModelApp.notifications.outputMessage(new core_frontend_1.NotifyMessageDetails(core_frontend_1.OutputMessagePriority.Error, msg));
184
+ return true;
185
+ }
186
+ // Layer is already attached,
187
+ vp.displayStyle.changeMapLayerProps({
188
+ subLayers: validation.subLayers,
189
+ }, layerRequiringCredentialsIdx, isOverlay);
190
+ vp.displayStyle.changeMapLayerCredentials(layerRequiringCredentialsIdx, isOverlay, source.userName, source.password);
191
+ // Either initial attach/initialize failed or the layer failed to load at least one tile
192
+ // because of an invalid token; in both cases tile tree needs to be fully reset
193
+ const provider = vp.getMapLayerImageryProvider(layerRequiringCredentialsIdx, isOverlay);
194
+ provider === null || provider === void 0 ? void 0 : provider.resetStatus();
195
+ vp.resetMapLayer(layerRequiringCredentialsIdx, isOverlay);
196
+ vp.invalidateRenderPlan();
197
+ // This handler will close the layer source handler, and therefore the MapUrl dialog.
198
+ // don't call it if the dialog needs to remains open.
199
+ onOkResult();
200
+ return true;
201
+ }, [isOverlay, layerRequiringCredentialsIdx, onOkResult, props.activeViewport]);
202
+ // Returns true if no further input is needed from end-user.
203
+ const doAttach = React.useCallback(async (source, validation) => {
204
+ const vp = props === null || props === void 0 ? void 0 : props.activeViewport;
205
+ if (vp === undefined || source === undefined) {
206
+ const error = mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:Messages.MapLayerAttachMissingViewOrSource");
207
+ const msg = mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:Messages.MapLayerAttachError", { error, sourceUrl: source.url });
208
+ core_frontend_1.IModelApp.notifications.outputMessage(new core_frontend_1.NotifyMessageDetails(core_frontend_1.OutputMessagePriority.Error, msg));
209
+ return true;
210
+ }
211
+ // Update service settings if storage is available and we are not prompting user for credentials
212
+ if (!settingsStorageDisabled && !props.layerRequiringCredentials) {
213
+ const storeOnIModel = (hasImodelContext ? "Model" === settingsStorage : undefined);
214
+ if (vp.iModel.iTwinId && !(await MapLayerPreferences_1.MapLayerPreferences.storeSource(source, vp.iModel.iTwinId, vp.iModel.iModelId, storeOnIModel))) {
215
+ const msgError = mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:Messages.MapLayerPreferencesStoreFailed");
216
+ core_frontend_1.IModelApp.notifications.outputMessage(new core_frontend_1.NotifyMessageDetails(core_frontend_1.OutputMessagePriority.Error, msgError));
217
+ }
218
+ }
219
+ // Some sources have a single non-visible sub-layer (i.e. ArcGIS World Topo Map); to avoid having a layer with no content (and no way to change the sub-layer visibility)
220
+ // we force the sub-layer visibility to ON.
221
+ let subLayers = validation.subLayers;
222
+ if (validation.subLayers && validation.subLayers.length === 1 && validation.subLayers[0].visible === false) {
223
+ subLayers = [{ ...validation.subLayers[0], visible: true }];
224
+ }
225
+ const settings = source.toLayerSettings(subLayers);
226
+ if (settings) {
227
+ vp.displayStyle.attachMapLayer({ settings, isOverlay });
228
+ const msg = core_frontend_1.IModelApp.localization.getLocalizedString("mapLayers:Messages.MapLayerAttached", { sourceName: source.name, sourceUrl: source.url });
229
+ core_frontend_1.IModelApp.notifications.outputMessage(new core_frontend_1.NotifyMessageDetails(core_frontend_1.OutputMessagePriority.Info, msg));
230
+ }
231
+ else {
232
+ const msgError = mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:Messages.MapLayerLayerSettingsConversionError");
233
+ const msg = mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.MapLayerAttachError", { error: msgError, sourceUrl: source.url });
234
+ core_frontend_1.IModelApp.notifications.outputMessage(new core_frontend_1.NotifyMessageDetails(core_frontend_1.OutputMessagePriority.Error, msg));
235
+ }
236
+ vp.invalidateRenderPlan();
237
+ // This handler will close the layer source handler, and therefore the MapUrl dialog.
238
+ // don't call it if the dialog needs to remains open.
239
+ onOkResult();
240
+ return true;
241
+ }, [hasImodelContext, isOverlay, onOkResult, props === null || props === void 0 ? void 0 : props.activeViewport, props.layerRequiringCredentials, settingsStorage, settingsStorageDisabled]);
242
+ // Validate the layer source and attempt to attach (or update) the layer.
243
+ // Returns true if no further input is needed from end-user (i.e. close the dialog)
244
+ const attemptAttachSource = React.useCallback(async (source) => {
245
+ try {
246
+ const validation = await source.validateSource(true);
247
+ if (validation.status === core_frontend_1.MapLayerSourceStatus.Valid) {
248
+ if (layerRequiringCredentialsIdx === undefined) {
249
+ return await doAttach(source, validation);
250
+ }
251
+ else {
252
+ return await updateAttachedLayer(source, validation);
253
+ }
254
+ }
255
+ else if (validation.status === core_frontend_1.MapLayerSourceStatus.InvalidCoordinateSystem) {
256
+ const msg = mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.InvalidCoordinateSystem");
257
+ core_frontend_1.IModelApp.notifications.outputMessage(new core_frontend_1.NotifyMessageDetails(core_frontend_1.OutputMessagePriority.Error, msg));
258
+ return true;
259
+ }
260
+ else {
261
+ const authNeeded = await updateAuthState(source, validation);
262
+ if (authNeeded) {
263
+ return false;
264
+ }
265
+ else {
266
+ const msg = mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.ValidationError");
267
+ core_frontend_1.IModelApp.notifications.outputMessage(new core_frontend_1.NotifyMessageDetails(core_frontend_1.OutputMessagePriority.Error, `${msg} ${source.url}`));
268
+ return true;
269
+ }
270
+ }
271
+ return false;
272
+ }
273
+ catch (error) {
274
+ const msg = mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:Messages.MapLayerAttachError", { error, sourceUrl: source.url });
275
+ core_frontend_1.IModelApp.notifications.outputMessage(new core_frontend_1.NotifyMessageDetails(core_frontend_1.OutputMessagePriority.Error, msg));
276
+ return true;
277
+ }
278
+ }, [updateAuthState, doAttach, layerRequiringCredentialsIdx, updateAttachedLayer]);
279
+ const onNameChange = React.useCallback((event) => {
280
+ setMapName(event.target.value);
281
+ }, [setMapName]);
282
+ const onRadioChange = React.useCallback((event) => {
283
+ setSettingsStorageRadio(event.target.value);
284
+ }, [setSettingsStorageRadio]);
285
+ const onUrlChange = React.useCallback((event) => {
286
+ setMapUrl(event.target.value);
287
+ }, [setMapUrl]);
288
+ const createSource = React.useCallback(() => {
289
+ let source;
290
+ if (mapUrl && mapName) {
291
+ source = core_frontend_1.MapLayerSource.fromJSON({
292
+ url: mapUrl,
293
+ name: mapName,
294
+ formatId: mapType
295
+ });
296
+ // Set credentials separately since they are not part of JSON
297
+ if (source) {
298
+ source.userName = userName || undefined; // When there is no value, empty string is always returned, in this case force it to undefined,
299
+ source.password = password || undefined;
300
+ }
301
+ }
302
+ return source;
303
+ }, [mapName, mapType, mapUrl, password, userName]);
304
+ const handleOk = React.useCallback(() => {
305
+ const source = createSource();
306
+ if (source === undefined || props.mapLayerSourceToEdit) {
307
+ appui_react_1.UiFramework.dialogs.modal.close();
308
+ onOkResult();
309
+ if (source === undefined) {
310
+ // Close the dialog and inform end user something went wrong.
311
+ const msgError = mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:Messages.MapLayerLayerSourceCreationFailed");
312
+ const msg = mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:Messages.MapLayerAttachError", { error: msgError, sourceUrl: mapUrl });
313
+ core_frontend_1.IModelApp.notifications.outputMessage(new core_frontend_1.NotifyMessageDetails(core_frontend_1.OutputMessagePriority.Error, msg));
314
+ return;
315
+ }
316
+ // Simply change the source definition in the setting service
317
+ if (props.mapLayerSourceToEdit !== undefined) {
318
+ const vp = props.activeViewport;
319
+ void (async () => {
320
+ var _a, _b;
321
+ if (isSettingsStorageAvailable && ((_a = vp === null || vp === void 0 ? void 0 : vp.iModel) === null || _a === void 0 ? void 0 : _a.iTwinId)) {
322
+ try {
323
+ await MapLayerPreferences_1.MapLayerPreferences.replaceSource(props.mapLayerSourceToEdit, source, vp.iModel.iTwinId, vp === null || vp === void 0 ? void 0 : vp.iModel.iModelId);
324
+ }
325
+ catch (err) {
326
+ const errorMessage = core_frontend_1.IModelApp.localization.getLocalizedString("mapLayers:Messages.MapLayerEditError", { layerName: (_b = props.mapLayerSourceToEdit) === null || _b === void 0 ? void 0 : _b.name });
327
+ core_frontend_1.IModelApp.notifications.outputMessage(new core_frontend_1.NotifyMessageDetails(core_frontend_1.OutputMessagePriority.Error, errorMessage));
328
+ return;
329
+ }
330
+ }
331
+ })();
332
+ return;
333
+ }
334
+ }
335
+ setLayerAttachPending(true);
336
+ // Attach source asynchronously.
337
+ void (async () => {
338
+ try {
339
+ const closeDialog = await attemptAttachSource(source);
340
+ if (isMounted.current) {
341
+ setLayerAttachPending(false);
342
+ }
343
+ // In theory the modal dialog should always get closed by the parent
344
+ // AttachLayerPanel's 'onOkResult' handler. We close it here just in case.
345
+ if (closeDialog) {
346
+ appui_react_1.UiFramework.dialogs.modal.close();
347
+ onOkResult();
348
+ }
349
+ }
350
+ catch (_error) {
351
+ onOkResult();
352
+ appui_react_1.UiFramework.dialogs.modal.close();
353
+ }
354
+ })();
355
+ }, [createSource, props.mapLayerSourceToEdit, props.activeViewport, onOkResult, mapUrl, isSettingsStorageAvailable, attemptAttachSource]);
356
+ React.useEffect(() => {
357
+ const handleOAuthProcessEnd = (success, _state) => {
358
+ onOauthProcessEnd.raiseEvent(success, _state);
359
+ };
360
+ // Currently only arcgis support AccessClient
361
+ const ac = core_frontend_1.IModelApp.mapLayerFormatRegistry.getAccessClient(exports.MAP_TYPES.arcGis);
362
+ if (ac === null || ac === void 0 ? void 0 : ac.onOAuthProcessEnd) {
363
+ setAccessClient(ac); // cache it, so we dont need to make another lookup;
364
+ ac.onOAuthProcessEnd.addListener(handleOAuthProcessEnd);
365
+ }
366
+ setAccessClientInitialized(true);
367
+ return () => {
368
+ if (ac === null || ac === void 0 ? void 0 : ac.onOAuthProcessEnd) {
369
+ ac.onOAuthProcessEnd.removeListener(handleOAuthProcessEnd);
370
+ }
371
+ setAccessClient(undefined);
372
+ setAccessClientInitialized(false);
373
+ };
374
+ }, [mapType, onOauthProcessEnd, setAccessClient]);
375
+ // After a map type change, make sure the different Oauth states are reset.
376
+ React.useEffect(() => {
377
+ // Reset few states
378
+ setServerRequireCredentials(false);
379
+ setInvalidCredentialsProvided(false);
380
+ setShowOauthPopup(false);
381
+ setOAuthProcessSucceeded(undefined);
382
+ setExternalLoginUrl(undefined);
383
+ }, [mapType]);
384
+ // The first time the dialog is loaded and we already know the layer requires auth. (i.e ImageryProvider already made an attempt)
385
+ // makes a request to discover the authentification types and adjust UI accordingly (i.e. username/password fields, Oauth popup)
386
+ // Without this effect, user would have to manually click the 'OK' button in order to trigger the layer connection.
387
+ React.useEffect(() => {
388
+ // Attach source asynchronously.
389
+ void (async () => {
390
+ var _a, _b;
391
+ if (isAccessClientInitialized && ((_a = props.layerRequiringCredentials) === null || _a === void 0 ? void 0 : _a.url) !== undefined && ((_b = props.layerRequiringCredentials) === null || _b === void 0 ? void 0 : _b.name) !== undefined) {
392
+ try {
393
+ const source = core_frontend_1.MapLayerSource.fromJSON({
394
+ url: props.layerRequiringCredentials.url,
395
+ name: props.layerRequiringCredentials.name,
396
+ formatId: props.layerRequiringCredentials.formatId
397
+ });
398
+ if (source !== undefined) {
399
+ setLayerAttachPending(true);
400
+ const validation = await source.validateSource(true);
401
+ if (isMounted.current) {
402
+ setLayerAttachPending(false);
403
+ }
404
+ await updateAuthState(source, validation);
405
+ }
406
+ }
407
+ catch (_error) { }
408
+ }
409
+ })();
410
+ }, [isAccessClientInitialized, (_h = props.layerRequiringCredentials) === null || _h === void 0 ? void 0 : _h.formatId, (_j = props.layerRequiringCredentials) === null || _j === void 0 ? void 0 : _j.name, (_k = props.layerRequiringCredentials) === null || _k === void 0 ? void 0 : _k.url, updateAuthState]);
411
+ const dialogContainer = React.useRef(null);
412
+ const readyToSave = React.useCallback(() => {
413
+ const credentialsSet = !!userName && !!password;
414
+ return (!!mapUrl && !!mapName)
415
+ && !layerAttachPending
416
+ && (!serverRequireCredentials || credentialsSet)
417
+ && !invalidCredentialsProvided
418
+ && (externalLoginUrl === undefined || (externalLoginUrl !== undefined && oauthProcessSucceeded));
419
+ }, [userName, password, mapUrl, mapName, serverRequireCredentials, layerAttachPending, invalidCredentialsProvided, externalLoginUrl, oauthProcessSucceeded]);
420
+ const buttonCluster = React.useMemo(() => [
421
+ { type: appui_abstract_1.DialogButtonType.OK, onClick: handleOk, disabled: !readyToSave() },
422
+ { type: appui_abstract_1.DialogButtonType.Cancel, onClick: handleCancel },
423
+ ], [readyToSave, handleCancel, handleOk]);
424
+ const handleOnKeyDown = React.useCallback((event) => {
425
+ if (event.key === appui_abstract_1.SpecialKey.Enter) {
426
+ if (readyToSave())
427
+ handleOk();
428
+ }
429
+ }, [handleOk, readyToSave]);
430
+ // onOauthProcessEnd events handler
431
+ React.useEffect(() => {
432
+ const handleOauthProcess = (success, _state) => {
433
+ setLayerAuthPending(false);
434
+ if (success) {
435
+ setOAuthProcessSucceeded(true);
436
+ setShowOauthPopup(false);
437
+ setLayerAttachPending(false);
438
+ handleOk(); // Add the layer the same way the user would do by clicking 'ok'
439
+ }
440
+ else {
441
+ setShowOauthPopup(false);
442
+ setLayerAttachPending(false);
443
+ setOAuthProcessSucceeded(false);
444
+ }
445
+ };
446
+ onOauthProcessEnd.addListener(handleOauthProcess);
447
+ return () => {
448
+ onOauthProcessEnd.removeListener(handleOauthProcess);
449
+ };
450
+ }, [handleOk, onOauthProcessEnd]);
451
+ //
452
+ // Monitors authentication method changes
453
+ React.useEffect(() => {
454
+ if (serverRequireCredentials && oauthProcessSucceeded === undefined && externalLoginUrl !== undefined) {
455
+ handleArcGisLogin();
456
+ }
457
+ }, [oauthProcessSucceeded, externalLoginUrl, handleArcGisLogin, serverRequireCredentials]);
458
+ // Monitors Oauth2 popup was closed
459
+ const handleOAuthPopupClose = React.useCallback(() => {
460
+ setShowOauthPopup(false);
461
+ setLayerAuthPending(false);
462
+ if (oauthProcessSucceeded === undefined)
463
+ setOAuthProcessSucceeded(false); // indicates there was a failed attempt
464
+ }, [oauthProcessSucceeded]);
465
+ // Utility function to get warning message section
466
+ function renderWarningMessage() {
467
+ let node;
468
+ let warningMessage;
469
+ // Get the proper warning message
470
+ if (showOauthPopup) {
471
+ warningMessage = externalLoginWaitingMsg;
472
+ }
473
+ else if (oauthProcessSucceeded === false) {
474
+ warningMessage = externalLoginFailedMsg;
475
+ }
476
+ else if (oauthProcessSucceeded === true) {
477
+ warningMessage = externalLoginSucceededMsg;
478
+ }
479
+ else if (invalidCredentialsProvided) {
480
+ warningMessage = invalidCredentialsLabel;
481
+ }
482
+ else if (serverRequireCredentials && (!userName || !password)) {
483
+ warningMessage = missingCredentialsLabel;
484
+ }
485
+ // Sometimes we want to add an extra node, such as a button
486
+ let extraNode;
487
+ if (oauthProcessSucceeded === false) {
488
+ extraNode = React.createElement("div", null,
489
+ React.createElement(itwinui_react_1.Button, { onClick: handleArcGisLogin }, externalLoginTryAgainLabel));
490
+ }
491
+ if (warningMessage !== undefined) {
492
+ return (React.createElement("div", { className: "map-layer-source-warnMessage" },
493
+ React.createElement(core_react_1.Icon, { className: "map-layer-source-warnMessage-icon", iconSpec: "icon-status-warning" }),
494
+ React.createElement("span", { className: "map-layer-source-warnMessage-label" }, warningMessage),
495
+ extraNode));
496
+ }
497
+ else {
498
+ return (React.createElement("span", { className: "map-layer-source-placeholder" }, "\u00A0"));
499
+ }
500
+ return node;
501
+ }
502
+ // Use a hook to display the popup.
503
+ // The display of the popup is controlled by the 'showOauthPopup' state variable.
504
+ (0, core_react_1.useCrossOriginPopup)(showOauthPopup, externalLoginUrl, externalLoginTitle, 450, 450, handleOAuthPopupClose);
505
+ return (React.createElement("div", { ref: dialogContainer },
506
+ React.createElement(core_react_1.Dialog, { className: "map-layer-url-dialog", title: dialogTitle, opened: true, resizable: true, movable: true, modal: true, buttonCluster: buttonCluster, onClose: handleCancel, onEscape: handleCancel, minHeight: 120, maxWidth: 600, titleStyle: { paddingLeft: "10px" }, footerStyle: { paddingBottom: "10px", paddingRight: "10px" }, trapFocus: false },
507
+ React.createElement("div", { className: "map-layer-url-dialog-content" },
508
+ React.createElement("div", { className: "map-layer-source-url" },
509
+ React.createElement("span", { className: "map-layer-source-label" }, typeLabel),
510
+ React.createElement(SelectMapFormat_1.SelectMapFormat, { value: mapType, disabled: props.layerRequiringCredentials !== undefined || props.mapLayerSourceToEdit !== undefined || layerAttachPending || layerAuthPending, onChange: setMapType, mapTypesOptions: mapTypesOptions }),
511
+ React.createElement("span", { className: "map-layer-source-label" }, nameLabel),
512
+ React.createElement(itwinui_react_1.Input, { className: "map-layer-source-input", placeholder: nameInputPlaceHolder, onChange: onNameChange, value: mapName, disabled: props.layerRequiringCredentials !== undefined || layerAttachPending || layerAuthPending }),
513
+ React.createElement("span", { className: "map-layer-source-label" }, urlLabel),
514
+ React.createElement(itwinui_react_1.Input, { className: "map-layer-source-input", placeholder: urlInputPlaceHolder, onKeyPress: handleOnKeyDown, onChange: onUrlChange, disabled: props.mapLayerSourceToEdit !== undefined || layerAttachPending || layerAuthPending, value: mapUrl }),
515
+ serverRequireCredentials
516
+ && externalLoginUrl === undefined // external login is handled in popup
517
+ && props.mapLayerSourceToEdit === undefined &&
518
+ React.createElement(React.Fragment, null,
519
+ React.createElement("span", { className: "map-layer-source-label" }, userNameLabel),
520
+ React.createElement(itwinui_react_1.LabeledInput, { className: "map-layer-source-input", displayStyle: "inline", placeholder: serverRequireCredentials ? userNameRequiredLabel : userNameLabel, status: (!userName && serverRequireCredentials) || invalidCredentialsProvided ? "warning" : undefined, disabled: layerAttachPending || layerAuthPending, onChange: onUsernameChange, value: userName, size: "small" }),
521
+ React.createElement("span", { className: "map-layer-source-label" }, passwordLabel),
522
+ React.createElement(itwinui_react_1.LabeledInput, { className: "map-layer-source-input", displayStyle: "inline", type: "password", placeholder: serverRequireCredentials ? passwordRequiredLabel : passwordLabel, status: (!password && serverRequireCredentials) || invalidCredentialsProvided ? "warning" : undefined, disabled: layerAttachPending || layerAuthPending, onChange: onPasswordChange, onKeyPress: handleOnKeyDown, value: password, size: "small" })),
523
+ isSettingsStorageAvailable &&
524
+ React.createElement("div", { title: settingsStorageDisabled ? noSaveSettingsWarning : "" }, hasImodelContext &&
525
+ React.createElement("div", null,
526
+ React.createElement(itwinui_react_1.Radio, { disabled: settingsStorageDisabled, name: "settingsStorage", value: "iTwin", label: iTwinSettingsLabel, checked: settingsStorage === "iTwin", onChange: onRadioChange }),
527
+ React.createElement(itwinui_react_1.Radio, { disabled: settingsStorageDisabled, name: "settingsStorage", value: "Model", label: modelSettingsLabel, checked: settingsStorage === "Model", onChange: onRadioChange }))))),
528
+ renderWarningMessage(),
529
+ (layerAttachPending || layerAuthPending) &&
530
+ React.createElement("div", { className: "map-layer-source-progressBar" },
531
+ React.createElement(itwinui_react_1.ProgressLinear, { indeterminate: true })))));
532
+ }
533
+ exports.MapUrlDialog = MapUrlDialog;
528
534
  //# sourceMappingURL=MapUrlDialog.js.map