@tak-ps/cloudtak 12.54.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 (483) hide show
  1. package/README.md +34 -0
  2. package/dist/types/plugin.d.ts +99 -0
  3. package/dist/types/src/App.vue.d.ts +5 -0
  4. package/dist/types/src/base/chatroom-chats.d.ts +17 -0
  5. package/dist/types/src/base/chatroom.d.ts +47 -0
  6. package/dist/types/src/base/cot.d.ts +94 -0
  7. package/dist/types/src/base/database.d.ts +115 -0
  8. package/dist/types/src/base/events.d.ts +30 -0
  9. package/dist/types/src/base/filter.d.ts +41 -0
  10. package/dist/types/src/base/handler.d.ts +11 -0
  11. package/dist/types/src/base/icon.d.ts +4 -0
  12. package/dist/types/src/base/notification.d.ts +37 -0
  13. package/dist/types/src/base/overlay.d.ts +94 -0
  14. package/dist/types/src/base/subscription-feature.d.ts +49 -0
  15. package/dist/types/src/base/subscription-log.d.ts +32 -0
  16. package/dist/types/src/base/subscription.d.ts +115 -0
  17. package/dist/types/src/base/utils/styles.d.ts +11 -0
  18. package/dist/types/src/base/validators.d.ts +9 -0
  19. package/dist/types/src/components/Admin/AdminImports.vue.d.ts +3 -0
  20. package/dist/types/src/components/Admin/AdminLayers.vue.d.ts +3 -0
  21. package/dist/types/src/components/Admin/AdminMissionTemplate.vue.d.ts +3 -0
  22. package/dist/types/src/components/Admin/AdminMissionTemplateLog.vue.d.ts +3 -0
  23. package/dist/types/src/components/Admin/AdminMissionTemplates.vue.d.ts +3 -0
  24. package/dist/types/src/components/Admin/AdminOverlays.vue.d.ts +3 -0
  25. package/dist/types/src/components/Admin/AdminPalette.vue.d.ts +3 -0
  26. package/dist/types/src/components/Admin/AdminPaletteFeature.vue.d.ts +3 -0
  27. package/dist/types/src/components/Admin/AdminPalettes.vue.d.ts +3 -0
  28. package/dist/types/src/components/Admin/AdminServer.vue.d.ts +3 -0
  29. package/dist/types/src/components/Admin/AdminTasks.vue.d.ts +3 -0
  30. package/dist/types/src/components/Admin/AdminUser.vue.d.ts +3 -0
  31. package/dist/types/src/components/Admin/AdminUsers.vue.d.ts +3 -0
  32. package/dist/types/src/components/Admin/AdminVideos.vue.d.ts +3 -0
  33. package/dist/types/src/components/Admin/Server/ServerConnection.vue.d.ts +3 -0
  34. package/dist/types/src/components/Admin/Server/ServerInjectorModal.vue.d.ts +11 -0
  35. package/dist/types/src/components/Admin/Server/ServerInjectors.vue.d.ts +3 -0
  36. package/dist/types/src/components/Admin/Server/ServerPackages.vue.d.ts +3 -0
  37. package/dist/types/src/components/Admin/Server/ServerRepeaters.vue.d.ts +3 -0
  38. package/dist/types/src/components/Admin/Server/ServerVideos.vue.d.ts +3 -0
  39. package/dist/types/src/components/Admin/Tasks/AdminRawTasks.vue.d.ts +3 -0
  40. package/dist/types/src/components/Admin/Videos/AdminVideoLeases.vue.d.ts +3 -0
  41. package/dist/types/src/components/Admin/Videos/AdminVideoService.vue.d.ts +3 -0
  42. package/dist/types/src/components/Admin/Videos/VideoConfig.vue.d.ts +7 -0
  43. package/dist/types/src/components/Admin/Videos/VideoConfigPort.vue.d.ts +8 -0
  44. package/dist/types/src/components/CloudTAK/CoTView.vue.d.ts +3 -0
  45. package/dist/types/src/components/CloudTAK/CoordInput.vue.d.ts +7 -0
  46. package/dist/types/src/components/CloudTAK/DrawTools.vue.d.ts +3 -0
  47. package/dist/types/src/components/CloudTAK/FeatView.vue.d.ts +8 -0
  48. package/dist/types/src/components/CloudTAK/GeoJSONInput.vue.d.ts +24 -0
  49. package/dist/types/src/components/CloudTAK/MainMenu.vue.d.ts +9 -0
  50. package/dist/types/src/components/CloudTAK/MainMenuContents.vue.d.ts +16 -0
  51. package/dist/types/src/components/CloudTAK/Map.vue.d.ts +8 -0
  52. package/dist/types/src/components/CloudTAK/MapLoading.vue.d.ts +3 -0
  53. package/dist/types/src/components/CloudTAK/Menu/Debugger.vue.d.ts +3 -0
  54. package/dist/types/src/components/CloudTAK/Menu/MenuBasemaps.vue.d.ts +3 -0
  55. package/dist/types/src/components/CloudTAK/Menu/MenuChannels.vue.d.ts +3 -0
  56. package/dist/types/src/components/CloudTAK/Menu/MenuChats.vue.d.ts +3 -0
  57. package/dist/types/src/components/CloudTAK/Menu/MenuConnections.vue.d.ts +3 -0
  58. package/dist/types/src/components/CloudTAK/Menu/MenuContacts.vue.d.ts +3 -0
  59. package/dist/types/src/components/CloudTAK/Menu/MenuFeatures.vue.d.ts +3 -0
  60. package/dist/types/src/components/CloudTAK/Menu/MenuFeaturesDeleted.vue.d.ts +3 -0
  61. package/dist/types/src/components/CloudTAK/Menu/MenuFiles.vue.d.ts +3 -0
  62. package/dist/types/src/components/CloudTAK/Menu/MenuImport.vue.d.ts +3 -0
  63. package/dist/types/src/components/CloudTAK/Menu/MenuImports.vue.d.ts +3 -0
  64. package/dist/types/src/components/CloudTAK/Menu/MenuItemCard.vue.d.ts +101 -0
  65. package/dist/types/src/components/CloudTAK/Menu/MenuMission.vue.d.ts +3 -0
  66. package/dist/types/src/components/CloudTAK/Menu/MenuMissions.vue.d.ts +3 -0
  67. package/dist/types/src/components/CloudTAK/Menu/MenuOverlayExplorer.vue.d.ts +3 -0
  68. package/dist/types/src/components/CloudTAK/Menu/MenuOverlays.vue.d.ts +3 -0
  69. package/dist/types/src/components/CloudTAK/Menu/MenuPackage.vue.d.ts +3 -0
  70. package/dist/types/src/components/CloudTAK/Menu/MenuPackages.vue.d.ts +3 -0
  71. package/dist/types/src/components/CloudTAK/Menu/MenuRoutes.vue.d.ts +3 -0
  72. package/dist/types/src/components/CloudTAK/Menu/MenuRoutesNew.vue.d.ts +3 -0
  73. package/dist/types/src/components/CloudTAK/Menu/MenuSettings.vue.d.ts +3 -0
  74. package/dist/types/src/components/CloudTAK/Menu/MenuSettingsCallsign.vue.d.ts +3 -0
  75. package/dist/types/src/components/CloudTAK/Menu/MenuSettingsDisplay.vue.d.ts +3 -0
  76. package/dist/types/src/components/CloudTAK/Menu/MenuVideos.vue.d.ts +3 -0
  77. package/dist/types/src/components/CloudTAK/Menu/MenuVideosRemote.vue.d.ts +3 -0
  78. package/dist/types/src/components/CloudTAK/Menu/Mission/MissionContents.vue.d.ts +11 -0
  79. package/dist/types/src/components/CloudTAK/Menu/Mission/MissionCreate.vue.d.ts +7 -0
  80. package/dist/types/src/components/CloudTAK/Menu/Mission/MissionInfo.vue.d.ts +11 -0
  81. package/dist/types/src/components/CloudTAK/Menu/Mission/MissionInviteModal.vue.d.ts +17 -0
  82. package/dist/types/src/components/CloudTAK/Menu/Mission/MissionLayerCreate.vue.d.ts +13 -0
  83. package/dist/types/src/components/CloudTAK/Menu/Mission/MissionLayerEdit.vue.d.ts +15 -0
  84. package/dist/types/src/components/CloudTAK/Menu/Mission/MissionLayerTree.vue.d.ts +15 -0
  85. package/dist/types/src/components/CloudTAK/Menu/Mission/MissionLayers.vue.d.ts +8 -0
  86. package/dist/types/src/components/CloudTAK/Menu/Mission/MissionLog.vue.d.ts +9 -0
  87. package/dist/types/src/components/CloudTAK/Menu/Mission/MissionLogs.vue.d.ts +7 -0
  88. package/dist/types/src/components/CloudTAK/Menu/Mission/MissionTimeline.vue.d.ts +7 -0
  89. package/dist/types/src/components/CloudTAK/Menu/Mission/MissionUsers.vue.d.ts +7 -0
  90. package/dist/types/src/components/CloudTAK/Menu/Mission/PendingInvites.vue.d.ts +11 -0
  91. package/dist/types/src/components/CloudTAK/Menu/Overlays/TreeMission.vue.d.ts +7 -0
  92. package/dist/types/src/components/CloudTAK/Menu/Overlays/TreeVector.vue.d.ts +13 -0
  93. package/dist/types/src/components/CloudTAK/Menu/Videos/VideoLeaseModal.vue.d.ts +16 -0
  94. package/dist/types/src/components/CloudTAK/Menu/Videos/VideosRemoteFeed.vue.d.ts +13 -0
  95. package/dist/types/src/components/CloudTAK/Notifications.vue.d.ts +3 -0
  96. package/dist/types/src/components/CloudTAK/Query/Magnetic.vue.d.ts +7 -0
  97. package/dist/types/src/components/CloudTAK/Query/Reverse.vue.d.ts +8 -0
  98. package/dist/types/src/components/CloudTAK/Query/Sun.vue.d.ts +7 -0
  99. package/dist/types/src/components/CloudTAK/Query/Weather.vue.d.ts +7 -0
  100. package/dist/types/src/components/CloudTAK/QueryView.vue.d.ts +3 -0
  101. package/dist/types/src/components/CloudTAK/RangeInput.vue.d.ts +7 -0
  102. package/dist/types/src/components/CloudTAK/RangeRingsInput.vue.d.ts +7 -0
  103. package/dist/types/src/components/CloudTAK/util/Breadcrumb.vue.d.ts +6 -0
  104. package/dist/types/src/components/CloudTAK/util/ChannelInfo.vue.d.ts +15 -0
  105. package/dist/types/src/components/CloudTAK/util/ContactPuck.vue.d.ts +7 -0
  106. package/dist/types/src/components/CloudTAK/util/Coordinate.vue.d.ts +67 -0
  107. package/dist/types/src/components/CloudTAK/util/CoordinateType.vue.d.ts +27 -0
  108. package/dist/types/src/components/CloudTAK/util/CopyButton.vue.d.ts +32 -0
  109. package/dist/types/src/components/CloudTAK/util/CopyField.vue.d.ts +122 -0
  110. package/dist/types/src/components/CloudTAK/util/DrawOverlay.vue.d.ts +3 -0
  111. package/dist/types/src/components/CloudTAK/util/EmptyInfo.vue.d.ts +24 -0
  112. package/dist/types/src/components/CloudTAK/util/FeatureIcon.vue.d.ts +23 -0
  113. package/dist/types/src/components/CloudTAK/util/FeatureRow.vue.d.ts +81 -0
  114. package/dist/types/src/components/CloudTAK/util/FloatingAttachment.vue.d.ts +17 -0
  115. package/dist/types/src/components/CloudTAK/util/FloatingVideo.vue.d.ts +27 -0
  116. package/dist/types/src/components/CloudTAK/util/GroupSelect.vue.d.ts +14 -0
  117. package/dist/types/src/components/CloudTAK/util/JSONModal.vue.d.ts +27 -0
  118. package/dist/types/src/components/CloudTAK/util/Keywords.vue.d.ts +6 -0
  119. package/dist/types/src/components/CloudTAK/util/LineLength.vue.d.ts +24 -0
  120. package/dist/types/src/components/CloudTAK/util/MenuTemplate.vue.d.ts +71 -0
  121. package/dist/types/src/components/CloudTAK/util/MultipleSelect.vue.d.ts +7 -0
  122. package/dist/types/src/components/CloudTAK/util/NotificationIcon.vue.d.ts +10 -0
  123. package/dist/types/src/components/CloudTAK/util/NotificationToast.vue.d.ts +13 -0
  124. package/dist/types/src/components/CloudTAK/util/PolygonArea.vue.d.ts +24 -0
  125. package/dist/types/src/components/CloudTAK/util/PropertyBattery.vue.d.ts +13 -0
  126. package/dist/types/src/components/CloudTAK/util/PropertyBearing.vue.d.ts +58 -0
  127. package/dist/types/src/components/CloudTAK/util/PropertyCreator.vue.d.ts +7 -0
  128. package/dist/types/src/components/CloudTAK/util/PropertyDistance.vue.d.ts +54 -0
  129. package/dist/types/src/components/CloudTAK/util/PropertyElevation.vue.d.ts +32 -0
  130. package/dist/types/src/components/CloudTAK/util/PropertyEmail.vue.d.ts +13 -0
  131. package/dist/types/src/components/CloudTAK/util/PropertyLinks.vue.d.ts +14 -0
  132. package/dist/types/src/components/CloudTAK/util/PropertyMetadata.vue.d.ts +7 -0
  133. package/dist/types/src/components/CloudTAK/util/PropertyMilSym.vue.d.ts +25 -0
  134. package/dist/types/src/components/CloudTAK/util/PropertyPhone.vue.d.ts +13 -0
  135. package/dist/types/src/components/CloudTAK/util/PropertySpeed.vue.d.ts +23 -0
  136. package/dist/types/src/components/CloudTAK/util/PropertyStyle.vue.d.ts +7 -0
  137. package/dist/types/src/components/CloudTAK/util/PropertyTimes.vue.d.ts +7 -0
  138. package/dist/types/src/components/CloudTAK/util/PropertyType.vue.d.ts +27 -0
  139. package/dist/types/src/components/CloudTAK/util/SearchBox.vue.d.ts +37 -0
  140. package/dist/types/src/components/CloudTAK/util/SelectFeats.vue.d.ts +7 -0
  141. package/dist/types/src/components/CloudTAK/util/SettingsCallsign.vue.d.ts +28 -0
  142. package/dist/types/src/components/CloudTAK/util/Share.vue.d.ts +14 -0
  143. package/dist/types/src/components/CloudTAK/util/ShareToMission.vue.d.ts +53 -0
  144. package/dist/types/src/components/CloudTAK/util/ShareToPackage.vue.d.ts +62 -0
  145. package/dist/types/src/components/CloudTAK/util/SlideDownHeader.vue.d.ts +41 -0
  146. package/dist/types/src/components/CloudTAK/util/StandardItem.vue.d.ts +18 -0
  147. package/dist/types/src/components/CloudTAK/util/Subscriptions.vue.d.ts +7 -0
  148. package/dist/types/src/components/CloudTAK/util/VideoLeaseSourceType.vue.d.ts +6 -0
  149. package/dist/types/src/components/CloudTAK/util/WarnChannels.vue.d.ts +7 -0
  150. package/dist/types/src/components/CloudTAK/util/WarnConfiguration.vue.d.ts +7 -0
  151. package/dist/types/src/components/Configure.vue.d.ts +3 -0
  152. package/dist/types/src/components/ETL/Connection/AgencyBadge.vue.d.ts +8 -0
  153. package/dist/types/src/components/ETL/Connection/ConnectionFiles.vue.d.ts +3 -0
  154. package/dist/types/src/components/ETL/Connection/ConnectionTokens.vue.d.ts +3 -0
  155. package/dist/types/src/components/ETL/Connection/ConnectionVideos.vue.d.ts +3 -0
  156. package/dist/types/src/components/ETL/Connection/StatusDot.vue.d.ts +13 -0
  157. package/dist/types/src/components/ETL/Connection/TokenModal.vue.d.ts +16 -0
  158. package/dist/types/src/components/ETL/Connection.vue.d.ts +3 -0
  159. package/dist/types/src/components/ETL/ConnectionCard.vue.d.ts +16 -0
  160. package/dist/types/src/components/ETL/Connections.vue.d.ts +3 -0
  161. package/dist/types/src/components/ETL/Data.vue.d.ts +3 -0
  162. package/dist/types/src/components/ETL/Layer/LayerIncomingConfig.vue.d.ts +27 -0
  163. package/dist/types/src/components/ETL/Layer/LayerOutgoingConfig.vue.d.ts +27 -0
  164. package/dist/types/src/components/ETL/Layer/utils/QueryInput.vue.d.ts +56 -0
  165. package/dist/types/src/components/ETL/Layer/utils/StatusDot.vue.d.ts +7 -0
  166. package/dist/types/src/components/ETL/Layer.vue.d.ts +3 -0
  167. package/dist/types/src/components/Home.vue.d.ts +13 -0
  168. package/dist/types/src/components/Loading.vue.d.ts +3 -0
  169. package/dist/types/src/components/Login.vue.d.ts +7 -0
  170. package/dist/types/src/components/LostUser.vue.d.ts +3 -0
  171. package/dist/types/src/components/PageFooter.vue.d.ts +3 -0
  172. package/dist/types/src/components/ServerAdmin.vue.d.ts +3 -0
  173. package/dist/types/src/components/VideoWall/Main.vue.d.ts +3 -0
  174. package/dist/types/src/components/VideoWall.vue.d.ts +13 -0
  175. package/dist/types/src/components/util/GroupSelect.vue.d.ts +14 -0
  176. package/dist/types/src/components/util/InitialAuthor.vue.d.ts +6 -0
  177. package/dist/types/src/components/util/StatusDot.vue.d.ts +8 -0
  178. package/dist/types/src/components/util/Upload.vue.d.ts +46 -0
  179. package/dist/types/src/components/util/UploadLogo.vue.d.ts +14 -0
  180. package/dist/types/src/main.d.ts +1 -0
  181. package/dist/types/src/pages/admin/main.d.ts +1 -0
  182. package/dist/types/src/pages/connection/main.d.ts +1 -0
  183. package/dist/types/src/pages/docs/App.vue.d.ts +4 -0
  184. package/dist/types/src/pages/docs/main.d.ts +1 -0
  185. package/dist/types/src/pages/video/main.d.ts +1 -0
  186. package/dist/types/src/std.d.ts +19 -0
  187. package/dist/types/src/stores/brand.d.ts +7 -0
  188. package/dist/types/src/stores/float.d.ts +42 -0
  189. package/dist/types/src/stores/map.d.ts +115 -0
  190. package/dist/types/src/stores/modules/draw.d.ts +35 -0
  191. package/dist/types/src/stores/modules/icons.d.ts +38 -0
  192. package/dist/types/src/stores/modules/menu.d.ts +34 -0
  193. package/dist/types/src/test/setup.d.ts +1 -0
  194. package/dist/types/src/timediff.d.ts +1 -0
  195. package/dist/types/src/types.d.ts +158 -0
  196. package/dist/types/src/video.d.ts +1 -0
  197. package/dist/types/src/workers/atlas-connection.d.ts +12 -0
  198. package/dist/types/src/workers/atlas-database.d.ts +134 -0
  199. package/dist/types/src/workers/atlas-profile.d.ts +39 -0
  200. package/dist/types/src/workers/atlas-team.d.ts +13 -0
  201. package/dist/types/src/workers/atlas.d.ts +19 -0
  202. package/package.json +97 -0
  203. package/src/App.vue +341 -0
  204. package/src/base/chatroom-chats.ts +124 -0
  205. package/src/base/chatroom.ts +202 -0
  206. package/src/base/cot.ts +625 -0
  207. package/src/base/database.ts +150 -0
  208. package/src/base/events.ts +43 -0
  209. package/src/base/filter.ts +163 -0
  210. package/src/base/handler.ts +67 -0
  211. package/src/base/icon.ts +16 -0
  212. package/src/base/notification.ts +163 -0
  213. package/src/base/overlay.ts +558 -0
  214. package/src/base/subscription-feature.ts +224 -0
  215. package/src/base/subscription-log.ts +174 -0
  216. package/src/base/subscription.ts +489 -0
  217. package/src/base/utils/styles.ts +430 -0
  218. package/src/base/validators.ts +66 -0
  219. package/src/components/Admin/AdminConfig.vue +487 -0
  220. package/src/components/Admin/AdminConnections.vue +195 -0
  221. package/src/components/Admin/AdminDatas.vue +165 -0
  222. package/src/components/Admin/AdminExport.vue +121 -0
  223. package/src/components/Admin/AdminImports.vue +222 -0
  224. package/src/components/Admin/AdminLayerTemplate.vue +91 -0
  225. package/src/components/Admin/AdminLayers.vue +301 -0
  226. package/src/components/Admin/AdminMissionTemplate.vue +259 -0
  227. package/src/components/Admin/AdminMissionTemplateLog.vue +273 -0
  228. package/src/components/Admin/AdminMissionTemplates.vue +189 -0
  229. package/src/components/Admin/AdminOverlays.vue +232 -0
  230. package/src/components/Admin/AdminOverlaysEdit.vue +355 -0
  231. package/src/components/Admin/AdminPalette.vue +214 -0
  232. package/src/components/Admin/AdminPaletteFeature.vue +208 -0
  233. package/src/components/Admin/AdminPalettes.vue +189 -0
  234. package/src/components/Admin/AdminServer.vue +143 -0
  235. package/src/components/Admin/AdminTasks.vue +60 -0
  236. package/src/components/Admin/AdminUser.vue +263 -0
  237. package/src/components/Admin/AdminUsers.vue +183 -0
  238. package/src/components/Admin/AdminVideos.vue +60 -0
  239. package/src/components/Admin/Server/ServerConnection.vue +322 -0
  240. package/src/components/Admin/Server/ServerInjectorModal.vue +125 -0
  241. package/src/components/Admin/Server/ServerInjectors.vue +104 -0
  242. package/src/components/Admin/Server/ServerPackages.vue +159 -0
  243. package/src/components/Admin/Server/ServerRepeaters.vue +105 -0
  244. package/src/components/Admin/Server/ServerVideos.vue +83 -0
  245. package/src/components/Admin/Tasks/AdminRawTasks.vue +148 -0
  246. package/src/components/Admin/Tasks/AdminTasks.vue +286 -0
  247. package/src/components/Admin/Videos/AdminVideoLeases.vue +198 -0
  248. package/src/components/Admin/Videos/AdminVideoService.vue +67 -0
  249. package/src/components/Admin/Videos/VideoConfig.vue +132 -0
  250. package/src/components/Admin/Videos/VideoConfigPath.vue +58 -0
  251. package/src/components/Admin/Videos/VideoConfigPort.vue +40 -0
  252. package/src/components/CloudTAK/CoTView.vue +915 -0
  253. package/src/components/CloudTAK/CoordInput.vue +110 -0
  254. package/src/components/CloudTAK/DrawTools.vue +200 -0
  255. package/src/components/CloudTAK/FeatView.vue +242 -0
  256. package/src/components/CloudTAK/GeoJSONInput.vue +226 -0
  257. package/src/components/CloudTAK/MainMenu.vue +190 -0
  258. package/src/components/CloudTAK/MainMenuContents.vue +360 -0
  259. package/src/components/CloudTAK/Map.vue +972 -0
  260. package/src/components/CloudTAK/MapLoading.vue +31 -0
  261. package/src/components/CloudTAK/Menu/Basemaps/EditModal.vue +427 -0
  262. package/src/components/CloudTAK/Menu/Debugger.vue +118 -0
  263. package/src/components/CloudTAK/Menu/Iconset/EditModal.vue +118 -0
  264. package/src/components/CloudTAK/Menu/MenuBasemaps.vue +410 -0
  265. package/src/components/CloudTAK/Menu/MenuChannels.vue +206 -0
  266. package/src/components/CloudTAK/Menu/MenuChat.vue +222 -0
  267. package/src/components/CloudTAK/Menu/MenuChats.vue +167 -0
  268. package/src/components/CloudTAK/Menu/MenuConnections.vue +166 -0
  269. package/src/components/CloudTAK/Menu/MenuContacts.vue +245 -0
  270. package/src/components/CloudTAK/Menu/MenuFeatures.vue +718 -0
  271. package/src/components/CloudTAK/Menu/MenuFeaturesDeleted.vue +217 -0
  272. package/src/components/CloudTAK/Menu/MenuFiles.vue +433 -0
  273. package/src/components/CloudTAK/Menu/MenuIcon.vue +236 -0
  274. package/src/components/CloudTAK/Menu/MenuIconset.vue +128 -0
  275. package/src/components/CloudTAK/Menu/MenuIconsets.vue +266 -0
  276. package/src/components/CloudTAK/Menu/MenuImport.vue +198 -0
  277. package/src/components/CloudTAK/Menu/MenuImports.vue +199 -0
  278. package/src/components/CloudTAK/Menu/MenuItemCard.vue +240 -0
  279. package/src/components/CloudTAK/Menu/MenuMission.vue +324 -0
  280. package/src/components/CloudTAK/Menu/MenuMissions.vue +334 -0
  281. package/src/components/CloudTAK/Menu/MenuOverlayExplorer.vue +434 -0
  282. package/src/components/CloudTAK/Menu/MenuOverlays.vue +560 -0
  283. package/src/components/CloudTAK/Menu/MenuPackage.vue +340 -0
  284. package/src/components/CloudTAK/Menu/MenuPackages.vue +193 -0
  285. package/src/components/CloudTAK/Menu/MenuRoutes.vue +186 -0
  286. package/src/components/CloudTAK/Menu/MenuRoutesNew.vue +193 -0
  287. package/src/components/CloudTAK/Menu/MenuSettings.vue +95 -0
  288. package/src/components/CloudTAK/Menu/MenuSettingsCallsign.vue +12 -0
  289. package/src/components/CloudTAK/Menu/MenuSettingsDisplay.vue +144 -0
  290. package/src/components/CloudTAK/Menu/MenuSettingsTokens.vue +83 -0
  291. package/src/components/CloudTAK/Menu/MenuVideos.vue +436 -0
  292. package/src/components/CloudTAK/Menu/MenuVideosRemote.vue +203 -0
  293. package/src/components/CloudTAK/Menu/Mission/MissionContents.vue +211 -0
  294. package/src/components/CloudTAK/Menu/Mission/MissionCreate.vue +372 -0
  295. package/src/components/CloudTAK/Menu/Mission/MissionInfo.vue +331 -0
  296. package/src/components/CloudTAK/Menu/Mission/MissionInviteModal.vue +107 -0
  297. package/src/components/CloudTAK/Menu/Mission/MissionLayerCreate.vue +77 -0
  298. package/src/components/CloudTAK/Menu/Mission/MissionLayerEdit.vue +77 -0
  299. package/src/components/CloudTAK/Menu/Mission/MissionLayerTree.vue +194 -0
  300. package/src/components/CloudTAK/Menu/Mission/MissionLayers.vue +157 -0
  301. package/src/components/CloudTAK/Menu/Mission/MissionLog.vue +170 -0
  302. package/src/components/CloudTAK/Menu/Mission/MissionLogs.vue +194 -0
  303. package/src/components/CloudTAK/Menu/Mission/MissionTimeline.vue +142 -0
  304. package/src/components/CloudTAK/Menu/Mission/MissionUsers.vue +74 -0
  305. package/src/components/CloudTAK/Menu/Mission/PendingInvites.vue +130 -0
  306. package/src/components/CloudTAK/Menu/Overlays/DeleteModal.vue +57 -0
  307. package/src/components/CloudTAK/Menu/Overlays/TreeCots.vue +497 -0
  308. package/src/components/CloudTAK/Menu/Overlays/TreeMission.vue +32 -0
  309. package/src/components/CloudTAK/Menu/Overlays/TreeVector.vue +113 -0
  310. package/src/components/CloudTAK/Menu/Settings/TokenModal.vue +110 -0
  311. package/src/components/CloudTAK/Menu/Videos/VideoLeaseModal.vue +753 -0
  312. package/src/components/CloudTAK/Menu/Videos/VideosRemoteFeed.vue +75 -0
  313. package/src/components/CloudTAK/Notifications.vue +195 -0
  314. package/src/components/CloudTAK/Query/Magnetic.vue +80 -0
  315. package/src/components/CloudTAK/Query/Reverse.vue +65 -0
  316. package/src/components/CloudTAK/Query/Sun.vue +178 -0
  317. package/src/components/CloudTAK/Query/Weather.vue +195 -0
  318. package/src/components/CloudTAK/QueryView.vue +134 -0
  319. package/src/components/CloudTAK/RadialMenu/LICENSE +21 -0
  320. package/src/components/CloudTAK/RadialMenu/README.md +63 -0
  321. package/src/components/CloudTAK/RadialMenu/RadialMenu.css +85 -0
  322. package/src/components/CloudTAK/RadialMenu/RadialMenu.js +534 -0
  323. package/src/components/CloudTAK/RadialMenu/RadialMenu.vue +257 -0
  324. package/src/components/CloudTAK/RangeInput.vue +155 -0
  325. package/src/components/CloudTAK/RangeRingsInput.vue +269 -0
  326. package/src/components/CloudTAK/util/Breadcrumb.vue +85 -0
  327. package/src/components/CloudTAK/util/ChannelInfo.vue +25 -0
  328. package/src/components/CloudTAK/util/Contact.vue +131 -0
  329. package/src/components/CloudTAK/util/ContactPuck.vue +40 -0
  330. package/src/components/CloudTAK/util/Coordinate.vue +313 -0
  331. package/src/components/CloudTAK/util/CoordinateType.vue +134 -0
  332. package/src/components/CloudTAK/util/CopyButton.vue +67 -0
  333. package/src/components/CloudTAK/util/CopyField.vue +286 -0
  334. package/src/components/CloudTAK/util/DrawOverlay.vue +254 -0
  335. package/src/components/CloudTAK/util/EmptyInfo.vue +71 -0
  336. package/src/components/CloudTAK/util/FeatureIcon.vue +134 -0
  337. package/src/components/CloudTAK/util/FeatureRow.vue +206 -0
  338. package/src/components/CloudTAK/util/FloatingAttachment.vue +191 -0
  339. package/src/components/CloudTAK/util/FloatingVideo.vue +654 -0
  340. package/src/components/CloudTAK/util/GenericSelect.vue +125 -0
  341. package/src/components/CloudTAK/util/GroupSelect.vue +129 -0
  342. package/src/components/CloudTAK/util/Icons.vue +146 -0
  343. package/src/components/CloudTAK/util/JSONModal.vue +57 -0
  344. package/src/components/CloudTAK/util/Keywords.vue +31 -0
  345. package/src/components/CloudTAK/util/LineLength.vue +121 -0
  346. package/src/components/CloudTAK/util/MenuItem.vue +21 -0
  347. package/src/components/CloudTAK/util/MenuTemplate.vue +137 -0
  348. package/src/components/CloudTAK/util/MultipleSelect.vue +103 -0
  349. package/src/components/CloudTAK/util/NotificationIcon.vue +50 -0
  350. package/src/components/CloudTAK/util/NotificationToast.vue +125 -0
  351. package/src/components/CloudTAK/util/PolygonArea.vue +109 -0
  352. package/src/components/CloudTAK/util/PropertyAttachments.vue +224 -0
  353. package/src/components/CloudTAK/util/PropertyBattery.vue +44 -0
  354. package/src/components/CloudTAK/util/PropertyBearing.vue +148 -0
  355. package/src/components/CloudTAK/util/PropertyCreator.vue +61 -0
  356. package/src/components/CloudTAK/util/PropertyDistance.vue +182 -0
  357. package/src/components/CloudTAK/util/PropertyElevation.vue +84 -0
  358. package/src/components/CloudTAK/util/PropertyEmail.vue +44 -0
  359. package/src/components/CloudTAK/util/PropertyLinks.vue +148 -0
  360. package/src/components/CloudTAK/util/PropertyMetadata.vue +53 -0
  361. package/src/components/CloudTAK/util/PropertyMilSym.vue +62 -0
  362. package/src/components/CloudTAK/util/PropertyPhone.vue +61 -0
  363. package/src/components/CloudTAK/util/PropertySensor.vue +129 -0
  364. package/src/components/CloudTAK/util/PropertySpeed.vue +91 -0
  365. package/src/components/CloudTAK/util/PropertyStyle.vue +202 -0
  366. package/src/components/CloudTAK/util/PropertyTimes.vue +95 -0
  367. package/src/components/CloudTAK/util/PropertyType.vue +274 -0
  368. package/src/components/CloudTAK/util/SearchBox.vue +314 -0
  369. package/src/components/CloudTAK/util/SelectFeats.vue +190 -0
  370. package/src/components/CloudTAK/util/SettingsCallsign.vue +151 -0
  371. package/src/components/CloudTAK/util/Share.vue +496 -0
  372. package/src/components/CloudTAK/util/ShareToMission.vue +223 -0
  373. package/src/components/CloudTAK/util/ShareToPackage.vue +250 -0
  374. package/src/components/CloudTAK/util/SlideDownHeader.vue +92 -0
  375. package/src/components/CloudTAK/util/StandardItem.vue +42 -0
  376. package/src/components/CloudTAK/util/Subscriptions.vue +151 -0
  377. package/src/components/CloudTAK/util/TagEntry.vue +301 -0
  378. package/src/components/CloudTAK/util/UploadImport.vue +195 -0
  379. package/src/components/CloudTAK/util/VideoLeaseSourceType.vue +66 -0
  380. package/src/components/CloudTAK/util/WarnChannels.vue +56 -0
  381. package/src/components/CloudTAK/util/WarnConfiguration.vue +34 -0
  382. package/src/components/Configure.vue +259 -0
  383. package/src/components/ETL/Connection/AgencyBadge.vue +102 -0
  384. package/src/components/ETL/Connection/AgencySelect.vue +185 -0
  385. package/src/components/ETL/Connection/CertificateLogin.vue +75 -0
  386. package/src/components/ETL/Connection/CertificateMachineUser.vue +228 -0
  387. package/src/components/ETL/Connection/CertificateP12.vue +104 -0
  388. package/src/components/ETL/Connection/CertificateRaw.vue +50 -0
  389. package/src/components/ETL/Connection/ConnectionData.vue +174 -0
  390. package/src/components/ETL/Connection/ConnectionFiles.vue +182 -0
  391. package/src/components/ETL/Connection/ConnectionGroups.vue +181 -0
  392. package/src/components/ETL/Connection/ConnectionLayer.vue +180 -0
  393. package/src/components/ETL/Connection/ConnectionTokens.vue +147 -0
  394. package/src/components/ETL/Connection/ConnectionVideos.vue +151 -0
  395. package/src/components/ETL/Connection/Events.vue +88 -0
  396. package/src/components/ETL/Connection/StatusDot.vue +48 -0
  397. package/src/components/ETL/Connection/TokenModal.vue +136 -0
  398. package/src/components/ETL/Connection.vue +194 -0
  399. package/src/components/ETL/ConnectionCard.vue +265 -0
  400. package/src/components/ETL/ConnectionEdit.vue +448 -0
  401. package/src/components/ETL/Connections.vue +148 -0
  402. package/src/components/ETL/Data/DataFiles.vue +245 -0
  403. package/src/components/ETL/Data/DataGroups.vue +45 -0
  404. package/src/components/ETL/Data/DataLayer.vue +144 -0
  405. package/src/components/ETL/Data/Location.vue +238 -0
  406. package/src/components/ETL/Data.vue +259 -0
  407. package/src/components/ETL/DataEdit.vue +212 -0
  408. package/src/components/ETL/Layer/LayerAlarm.vue +307 -0
  409. package/src/components/ETL/Layer/LayerDeployment.vue +388 -0
  410. package/src/components/ETL/Layer/LayerEnvironment.vue +259 -0
  411. package/src/components/ETL/Layer/LayerIncomingConfig.vue +401 -0
  412. package/src/components/ETL/Layer/LayerIncomingEnvironmentArcGIS.vue +354 -0
  413. package/src/components/ETL/Layer/LayerIncomingSchema.vue +138 -0
  414. package/src/components/ETL/Layer/LayerIncomingStyles.vue +349 -0
  415. package/src/components/ETL/Layer/LayerOutgoingConfig.vue +204 -0
  416. package/src/components/ETL/Layer/LayerOutgoingEnvironmentArcGIS.vue +279 -0
  417. package/src/components/ETL/Layer/utils/QueryInput.vue +52 -0
  418. package/src/components/ETL/Layer/utils/Schema.vue +322 -0
  419. package/src/components/ETL/Layer/utils/SchemaModal.vue +77 -0
  420. package/src/components/ETL/Layer/utils/StatusDot.vue +38 -0
  421. package/src/components/ETL/Layer/utils/StyleLinkModal.vue +83 -0
  422. package/src/components/ETL/Layer/utils/StyleLinks.vue +139 -0
  423. package/src/components/ETL/Layer/utils/StyleSingle.vue +885 -0
  424. package/src/components/ETL/Layer/utils/StyleTemplate.vue +97 -0
  425. package/src/components/ETL/Layer/utils/TaskModal.vue +217 -0
  426. package/src/components/ETL/Layer.vue +560 -0
  427. package/src/components/ETL/LayerEdit.vue +276 -0
  428. package/src/components/ETL/Styling/Layer.vue +311 -0
  429. package/src/components/ETL/Styling/ObjectInput.vue +46 -0
  430. package/src/components/ETL/Styling/Style.vue +233 -0
  431. package/src/components/Home.vue +17 -0
  432. package/src/components/Loading.vue +42 -0
  433. package/src/components/Login.vue +198 -0
  434. package/src/components/LostUser.vue +31 -0
  435. package/src/components/PageFooter.vue +41 -0
  436. package/src/components/ServerAdmin.vue +408 -0
  437. package/src/components/VideoWall/Main.vue +79 -0
  438. package/src/components/VideoWall.vue +17 -0
  439. package/src/components/util/DataSelect.vue +148 -0
  440. package/src/components/util/EsriFilter.vue +140 -0
  441. package/src/components/util/EsriPortal.vue +422 -0
  442. package/src/components/util/EsriPortalCreate.vue +72 -0
  443. package/src/components/util/EsriServer.vue +368 -0
  444. package/src/components/util/GroupSelect.vue +166 -0
  445. package/src/components/util/IconSelect.vue +302 -0
  446. package/src/components/util/InitialAuthor.vue +28 -0
  447. package/src/components/util/LayerSelect.vue +162 -0
  448. package/src/components/util/LayerTaskSelect.vue +311 -0
  449. package/src/components/util/LayerTemplateSelect.vue +173 -0
  450. package/src/components/util/LoginModal.vue +110 -0
  451. package/src/components/util/PublicTilesSelect.vue +171 -0
  452. package/src/components/util/StatusDot.vue +31 -0
  453. package/src/components/util/TableFooter.vue +64 -0
  454. package/src/components/util/TableHeader.vue +127 -0
  455. package/src/components/util/Upload.vue +220 -0
  456. package/src/components/util/UploadCSV.vue +46 -0
  457. package/src/components/util/UploadLogo.vue +83 -0
  458. package/src/components/util/UploadP12.vue +93 -0
  459. package/src/components/util/UserSelect.vue +151 -0
  460. package/src/derived-types.d.ts +35243 -0
  461. package/src/main.ts +264 -0
  462. package/src/pages/admin/main.ts +208 -0
  463. package/src/pages/connection/main.ts +158 -0
  464. package/src/pages/docs/App.vue +19 -0
  465. package/src/pages/docs/main.ts +6 -0
  466. package/src/pages/video/main.ts +27 -0
  467. package/src/std.ts +152 -0
  468. package/src/stores/brand.ts +28 -0
  469. package/src/stores/float.ts +113 -0
  470. package/src/stores/map.ts +931 -0
  471. package/src/stores/modules/draw.ts +413 -0
  472. package/src/stores/modules/icons.ts +185 -0
  473. package/src/stores/modules/menu.ts +281 -0
  474. package/src/test/setup.ts +43 -0
  475. package/src/timediff.ts +33 -0
  476. package/src/types.ts +226 -0
  477. package/src/video.ts +27 -0
  478. package/src/vite-env.d.ts +9 -0
  479. package/src/workers/atlas-connection.ts +236 -0
  480. package/src/workers/atlas-database.ts +764 -0
  481. package/src/workers/atlas-profile.ts +374 -0
  482. package/src/workers/atlas-team.ts +90 -0
  483. package/src/workers/atlas.ts +81 -0
@@ -0,0 +1,931 @@
1
+ /*
2
+ * MapStore - Maintain the state of the MapLibreGL Instance
3
+ *
4
+ * Terminology:
5
+ * - Overlay - The "container" that is saved in the DB that contains a reference to a single GIS source and potentially many rendered layers
6
+ * - Layer - MapLibre - Ref: https://maplibre.org/maplibre-style-spec/layers/
7
+ * - Source - MapLibre - Ref: https://maplibre.org/maplibre-style-spec/sources/
8
+ */
9
+
10
+ import { v4 as randomUUID } from 'uuid';
11
+ import { defineStore } from 'pinia'
12
+ import { markRaw } from 'vue';
13
+ import DrawTool, { DrawToolMode } from './modules/draw.ts';
14
+ import IconManager from './modules/icons.ts';
15
+ import MenuManager from './modules/menu.ts';
16
+ import * as Comlink from 'comlink';
17
+ import AtlasWorker from '../workers/atlas.ts?worker&url';
18
+ import COT from '../base/cot.ts';
19
+ import type { DatabaseType } from '../base/database.ts';
20
+ import { db } from '../base/database.ts';
21
+ import { WorkerMessageType, LocationState } from '../base/events.ts';
22
+ import type { WorkerMessage } from '../base/events.ts';
23
+ import Overlay from '../base/overlay.ts';
24
+ import Subscription from '../base/subscription.ts';
25
+ import { std, stdurl } from '../std.js';
26
+ import mapgl from 'maplibre-gl'
27
+ import type Atlas from '../workers/atlas.ts';
28
+ import { CloudTAKTransferHandler } from '../base/handler.ts';
29
+
30
+ import type { ProfileOverlay, ProfileOverlayList, Basemap, APIList, Feature, MapConfig } from '../types.ts';
31
+ import type { LngLat, LngLatLike, Point, MapMouseEvent, MapGeoJSONFeature, GeoJSONSource } from 'maplibre-gl';
32
+
33
+ export type TAKNotification = { type: string; name: string; body: string; url: string; created: string; }
34
+
35
+ export const useMapStore = defineStore('cloudtak', {
36
+ state: (): {
37
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
38
+ _map?: any;
39
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
40
+ _draw?: any;
41
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
42
+ _icons?: any;
43
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
44
+ _menu?: any;
45
+
46
+ db: DatabaseType;
47
+ channel: BroadcastChannel;
48
+
49
+ toImport: Feature[]
50
+
51
+ // Lock the map view to a given CoT - The last element is the currently locked value
52
+ // this is an array so that things like the radial menu can temporarily lock state but remember the previous lock value when they are closed
53
+ locked: Array<string>;
54
+
55
+ callsign: string;
56
+ zoom: string;
57
+ location: LocationState;
58
+ distanceUnit: string;
59
+ manualLocationMode: boolean;
60
+ isMobileDetected: boolean;
61
+ gpsWatchId: number | null;
62
+
63
+ toastOffset: {
64
+ x: number;
65
+ y: number;
66
+ };
67
+
68
+ permissions: {
69
+ location: boolean;
70
+ notification: boolean;
71
+ }
72
+
73
+ worker: Comlink.Remote<Atlas>;
74
+ mission: Subscription | undefined;
75
+ mapConfig: MapConfig;
76
+ container?: HTMLElement;
77
+ hasTerrain: boolean;
78
+ hasNoChannels: boolean;
79
+ isTerrainEnabled: boolean;
80
+ isLoaded: boolean;
81
+ isOpen: boolean;
82
+ pitch: number;
83
+ bearing: number;
84
+ selected: Map<string, COT>;
85
+ select: {
86
+ mode?: string;
87
+ feats: Array<COT | MapGeoJSONFeature>;
88
+ x: number;
89
+ y: number;
90
+ popup?: mapgl.Popup;
91
+ },
92
+ radial: {
93
+ mode: string | undefined;
94
+ cot: Feature | MapGeoJSONFeature | undefined;
95
+ x: number;
96
+ y: number;
97
+ lngLat?: LngLat;
98
+ },
99
+ overlays: Array<Overlay>
100
+ } => {
101
+ const worker = Comlink.wrap<Atlas>(new Worker(AtlasWorker, {
102
+ type: 'module'
103
+ }));
104
+
105
+ new CloudTAKTransferHandler(
106
+ worker,
107
+ Comlink.transferHandlers,
108
+ true
109
+ );
110
+
111
+ return {
112
+ worker,
113
+ callsign: 'Unknown',
114
+ toImport: [],
115
+ location: LocationState.Loading,
116
+ db,
117
+ channel: new BroadcastChannel("cloudtak"),
118
+ zoom: 'conditional',
119
+ distanceUnit: 'meter',
120
+ toastOffset: { x: 70, y: 10 },
121
+ manualLocationMode: false,
122
+ gpsWatchId: null,
123
+ isMobileDetected: false,
124
+ locked: [],
125
+ hasTerrain: false,
126
+ hasNoChannels: false,
127
+ isTerrainEnabled: false,
128
+ isOpen: false,
129
+ isLoaded: false,
130
+ pitch: 0,
131
+ bearing: 0,
132
+ mission: undefined,
133
+ permissions: {
134
+ location: false,
135
+ notification: false
136
+ },
137
+ select: {
138
+ mode: undefined,
139
+ feats: [],
140
+ x: 0, y: 0,
141
+ },
142
+ mapConfig: {
143
+ center: '-100,40',
144
+ zoom: 4,
145
+ pitch: 0,
146
+ bearing: 0
147
+ },
148
+ radial: {
149
+ mode: undefined,
150
+ cot: undefined,
151
+ x: 0, y: 0,
152
+ lngLat: undefined
153
+ },
154
+ overlays: [],
155
+
156
+ selected: new Map()
157
+ }
158
+ },
159
+ getters: {
160
+ map: function(): mapgl.Map {
161
+ if (!this._map) throw new Error('Map has not yet initialized');
162
+ return this._map as mapgl.Map;
163
+ },
164
+ draw: function(): DrawTool {
165
+ if (!this._draw) throw new Error('Drawing Tools have not yet initialized');
166
+ return this._draw as DrawTool;
167
+ },
168
+ icons: function(): IconManager {
169
+ if (!this._icons) throw new Error('Icon Manager has not yet initialized');
170
+ return this._icons as IconManager;
171
+ },
172
+ menu: function(): MenuManager {
173
+ if (!this._menu) throw new Error('Menu Manager has not yet initialized');
174
+ return this._menu as MenuManager;
175
+ }
176
+ },
177
+ actions: {
178
+ destroy: function() {
179
+ this.channel.close();
180
+
181
+ // Clean up GPS watch
182
+ if (this.gpsWatchId !== null) {
183
+ navigator.geolocation.clearWatch(this.gpsWatchId);
184
+ this.gpsWatchId = null;
185
+ }
186
+
187
+ if (this._map) {
188
+ try {
189
+ this._map.remove();
190
+ delete this._map;
191
+ } catch (err) {
192
+ console.error(err);
193
+ }
194
+ }
195
+ this.$reset();
196
+ },
197
+ removeOverlay: async function(overlay: Overlay) {
198
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
199
+ const pos = (this.overlays as any[]).indexOf(overlay)
200
+ if (pos === -1) return;
201
+
202
+ this.overlays.splice(pos, 1)
203
+
204
+ await overlay.delete();
205
+ if (overlay.mode === 'mission' && overlay.mode_id) {
206
+ const sub = await Subscription.from(overlay.mode_id, localStorage.token, {
207
+ subscribed: true
208
+ });
209
+
210
+ if (sub) {
211
+ await sub.update({ subscribed: false });
212
+ }
213
+ }
214
+ },
215
+ makeActiveMission: async function(mission?: Subscription): Promise<void> {
216
+ this.mission = mission;
217
+ await this.worker.db.makeActiveMission(mission ? mission.meta.guid : undefined);
218
+
219
+ if (mission) {
220
+ for (const overlay of this.overlays) {
221
+ if (overlay.mode !== 'mission' || !overlay.mode_id) continue;
222
+
223
+ if (overlay.mode_id !== mission.meta.guid && overlay.active) {
224
+ // The API call to make active will disable all active overlays on the backend so no need for networkIO
225
+ overlay.active = false;
226
+ } else if (overlay.mode_id === mission.meta.guid) {
227
+ overlay.active = true;
228
+
229
+ await overlay.save();
230
+ }
231
+ }
232
+ } else {
233
+ for (const overlay of this.overlays) {
234
+ if (overlay.mode !== 'mission' || !overlay.mode_id) continue;
235
+
236
+ if (overlay.active) {
237
+ overlay.active = false;
238
+ await overlay.save();
239
+ }
240
+ }
241
+ }
242
+ },
243
+ getOverlayById(id: number): Overlay | null {
244
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
245
+ for (const overlay of (this.overlays as any[])) {
246
+
247
+ if (overlay.id === id) return overlay as Overlay
248
+ }
249
+
250
+ return null;
251
+ },
252
+ getOverlayByName(name: string): Overlay | null {
253
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
254
+ for (const overlay of (this.overlays as any[])) {
255
+
256
+ if (overlay.name === name) return overlay as Overlay
257
+ }
258
+
259
+ return null;
260
+ },
261
+ getOverlayByMode(mode: string, mode_id: string): Overlay | null {
262
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
263
+ for (const overlay of (this.overlays as any[])) {
264
+
265
+ if (overlay.mode === mode && overlay.mode_id === mode_id) {
266
+ return overlay as Overlay;
267
+ }
268
+ }
269
+
270
+ return null;
271
+ },
272
+ listTerrain: async function(): Promise<APIList<Basemap>> {
273
+ // Courtesy add terrain data
274
+ const burl = stdurl('/api/basemap');
275
+ burl.searchParams.append('type', 'raster-dem');
276
+ burl.searchParams.append('limit', '1');
277
+ const basemaps = await std(burl) as APIList<Basemap>;
278
+
279
+ return basemaps;
280
+ },
281
+
282
+ // TODO: Convert to overlay
283
+ addTerrain: async function(): Promise<void> {
284
+ const basemaps = await this.listTerrain();
285
+ if (basemaps.items.length && !this.map.getSource('-2')) {
286
+ this.map.addSource('-2', {
287
+ type: 'raster-dem',
288
+ url: String(stdurl(`/api/basemap/${basemaps.items[0].id}/tiles?token=${localStorage.token}`)),
289
+ tileSize: 256
290
+ })
291
+
292
+ this.map.setTerrain({
293
+ source: '-2',
294
+ exaggeration: 1.5
295
+ });
296
+
297
+ this.isTerrainEnabled = true;
298
+ } else {
299
+ this.hasTerrain = false;
300
+ }
301
+ },
302
+
303
+ removeTerrain: function(): void {
304
+ this.map.setTerrain(null);
305
+ this.map.removeSource('-2');
306
+
307
+ this.isTerrainEnabled = false;
308
+ },
309
+
310
+ returnHome: function(): void {
311
+ const flyTo = {
312
+ zoom: this.mapConfig.zoom,
313
+ pitch: this.mapConfig.pitch,
314
+ bearing: this.mapConfig.bearing,
315
+ center: this.mapConfig.center.split(',').map(Number) as LngLatLike,
316
+ speed: Infinity
317
+ };
318
+
319
+ this.map.flyTo(flyTo);
320
+ },
321
+
322
+ /**
323
+ * Trigger a rerender of the underlying GeoJSON Features
324
+ */
325
+ refresh: async function(): Promise<void> {
326
+ await this.updateCOT();
327
+ },
328
+ updateCOT: async function(): Promise<void> {
329
+ try {
330
+ const diff = await this.worker.db.diff();
331
+
332
+ if (
333
+ (diff.add && diff.add.length)
334
+ || (diff.remove && diff.remove.length)
335
+ || (diff.update && diff.update.length)
336
+ ) {
337
+ const source = this.map.getSource('-1') as GeoJSONSource
338
+ if (source) source.updateData(diff);
339
+ }
340
+
341
+ if (this.locked.length && await this.worker.db.has(this.locked[this.locked.length - 1])) {
342
+ const featid = this.locked[this.locked.length - 1];
343
+ if (featid) {
344
+ const feat = await this.worker.db.get(featid);
345
+ if (feat && feat.geometry.type === "Point") {
346
+ const flyTo = {
347
+ center: feat.properties.center as LngLatLike,
348
+ speed: Infinity
349
+ };
350
+ this.map.flyTo(flyTo);
351
+
352
+ }
353
+ }
354
+ }
355
+ } catch (err) {
356
+ console.error(err);
357
+ }
358
+ },
359
+
360
+ /**
361
+ * Given a mission Guid, attempt to refresh the Map Layer, loading the mission if it isn't already loaded
362
+ * @returns {boolean} True if successful, false if not
363
+ */
364
+ loadMission: async function(
365
+ guid: string,
366
+ opts?: {
367
+ reload: boolean;
368
+ }
369
+ ): Promise<Subscription | null> {
370
+ const overlay = this.getOverlayByMode('mission', guid)
371
+ if (!overlay || !overlay.mode_id) {
372
+ console.error(`Mission:${guid} not found in overlays`);
373
+ return null;
374
+ }
375
+
376
+ if (!this.map) throw new Error('Cannot loadMission before map has loaded');
377
+ const oStore = this.map.getSource(String(overlay.id));
378
+
379
+ if (!oStore) {
380
+ console.error(`Mission:${guid} No Source Found`);
381
+ return null
382
+ }
383
+
384
+ const sub = await Subscription.load(guid, {
385
+ token: localStorage.token,
386
+ reload: opts?.reload || false,
387
+ subscribed: true,
388
+ missiontoken: overlay.token || undefined
389
+ });
390
+
391
+ // @ts-expect-error Source.setData is not defined
392
+ oStore.setData(await sub.feature.collection(false));
393
+
394
+ await sub.update({ dirty: false });
395
+
396
+ return sub;
397
+ },
398
+ init: async function(container: HTMLElement) {
399
+ this.container = container;
400
+
401
+ await this.worker.init(localStorage.token);
402
+
403
+ this.channel.onmessage = async (event: MessageEvent<WorkerMessage>) => {
404
+ const msg = event.data;
405
+
406
+ if (!msg || !msg.type) return;
407
+
408
+ if (msg.type === WorkerMessageType.Map_FitBounds) {
409
+ if (msg.body.options.speed === null) {
410
+ msg.body.options.speed = Infinity;
411
+ }
412
+
413
+ map.fitBounds(msg.body.bounds, msg.body.options);
414
+ } else if (msg.type === WorkerMessageType.Map_FlyTo) {
415
+ if (msg.body.speed === null) {
416
+ msg.body.speed = Infinity;
417
+ }
418
+
419
+ if (!msg.body.zoom) msg.body.zoom = this.map.getZoom();
420
+
421
+ map.flyTo(msg.body);
422
+ } else if (msg.type === WorkerMessageType.Profile_Location_Source) {
423
+ this.location = msg.body.source as LocationState;
424
+ } else if (msg.type === WorkerMessageType.Profile_Callsign) {
425
+ this.callsign = msg.body.callsign;
426
+ } else if (msg.type === WorkerMessageType.Profile_Display_Zoom) {
427
+ this.zoom = msg.body.zoom;
428
+ } else if (msg.type === WorkerMessageType.Profile_Icon_Rotation) {
429
+ this.updateIconRotation(msg.body.enabled);
430
+ } else if (msg.type === WorkerMessageType.Profile_Distance_Unit) {
431
+ this.updateDistanceUnit(msg.body.unit);
432
+ } else if (msg.type === WorkerMessageType.Map_Projection) {
433
+ map.setProjection(msg.body);
434
+ } else if (msg.type === WorkerMessageType.Connection_Open) {
435
+ this.isOpen = true;
436
+ } else if (msg.type === WorkerMessageType.Connection_Close) {
437
+ this.isOpen = false;
438
+ } else if (msg.type === WorkerMessageType.Channels_None) {
439
+ this.hasNoChannels = true;
440
+ } else if (msg.type === WorkerMessageType.Channels_List) {
441
+ this.hasNoChannels = false;
442
+ } else if (msg.type === WorkerMessageType.Mission_Change_Feature) {
443
+ await this.loadMission(msg.body.guid);
444
+ } else if (msg.type === WorkerMessageType.Contact_Change) {
445
+ if (this._menu) await this._menu.updateContactsCount();
446
+ }
447
+ }
448
+
449
+ if ("geolocation" in navigator) {
450
+ const status = await navigator.permissions
451
+ .query({ name: "geolocation" })
452
+
453
+ this.permissions.location = status.state === 'granted' ? true : false
454
+ status.onchange = () => {
455
+ this.permissions.location = status.state === 'granted' ? true : false
456
+ };
457
+
458
+ this.startGPSWatch();
459
+ } else {
460
+ console.error('Browser does not appear to support Geolocation');
461
+ }
462
+
463
+ if ('Notification' in window) {
464
+ const status = await navigator.permissions
465
+ .query({ name: "notifications" })
466
+
467
+ this.permissions.notification = status.state === 'granted' ? true : false
468
+
469
+ if (!this.permissions.notification) {
470
+ Notification.requestPermission()
471
+ }
472
+
473
+ status.onchange = () => {
474
+ this.permissions.notification = status.state === 'granted' ? true : false
475
+
476
+ if (!this.permissions.notification) {
477
+ Notification.requestPermission()
478
+ }
479
+ };
480
+ } else {
481
+ console.error('Browser does not appear to support Notifications');
482
+ }
483
+
484
+ const sprites = await IconManager.sprites();
485
+ this.mapConfig = await std('/api/config/map') as MapConfig;
486
+
487
+ const init: mapgl.MapOptions = {
488
+ container: this.container,
489
+ hash: true,
490
+ attributionControl: {},
491
+ fadeDuration: 0,
492
+ zoom: this.mapConfig.zoom,
493
+ pitch: this.mapConfig.pitch,
494
+ bearing: this.mapConfig.bearing,
495
+ center: this.mapConfig.center.split(',').map(Number) as LngLatLike,
496
+ maxPitch: 85,
497
+ style: {
498
+ version: 8,
499
+ glyphs: String(stdurl('/api/fonts')) + '/{fontstack}/{range}.pbf?token=' + localStorage.token,
500
+ sprite: sprites,
501
+ sources: {
502
+ '-1': {
503
+ type: 'geojson',
504
+ cluster: false,
505
+ data: { type: 'FeatureCollection', features: [] }
506
+ }
507
+ },
508
+ layers: [{
509
+ id: 'background',
510
+ type: 'background',
511
+ paint: { 'background-color': 'hsl(47, 26%, 88%)' }
512
+ }]
513
+ }
514
+ };
515
+
516
+ if (!init.style || typeof init.style === 'string') throw new Error('init.style must be an object');
517
+
518
+ const map = new mapgl.Map(init);
519
+
520
+ // Add scale control
521
+ const scaleControl = new mapgl.ScaleControl({
522
+ maxWidth: 100,
523
+ unit: 'metric'
524
+ });
525
+ map.addControl(scaleControl, 'bottom-left');
526
+ // Store reference for later use
527
+ (map as mapgl.Map & { _scaleControl?: mapgl.ScaleControl })._scaleControl = scaleControl;
528
+
529
+ this._map = markRaw(map);
530
+ this._draw = new DrawTool(this);
531
+ this._icons = markRaw(new IconManager(map));
532
+ this._menu = markRaw(new MenuManager(this));
533
+ await this._menu!.init();
534
+
535
+ // If we missed the Profile_Location_Source make sure it gets synced
536
+ const loc = await this.worker.profile.location;
537
+ this.location = loc.source;
538
+
539
+ const profile = await this.worker.profile.load()
540
+ this.callsign = profile.tak_callsign;
541
+ this.zoom = profile.display_zoom;
542
+ // Initialize icon rotation setting after overlays are loaded
543
+ setTimeout(() => {
544
+ this.updateIconRotation(profile.display_icon_rotation);
545
+ }, 100);
546
+
547
+ this.distanceUnit = profile.display_distance;
548
+
549
+ // Initialize scale control settings
550
+ this.updateDistanceUnit(profile.display_distance);
551
+
552
+ this.isOpen = await this.worker.conn.isOpen;
553
+ },
554
+ startGPSWatch: function(): void {
555
+ if (!("geolocation" in navigator)) return;
556
+
557
+ // Clear existing watch if any
558
+ if (this.gpsWatchId !== null) {
559
+ navigator.geolocation.clearWatch(this.gpsWatchId);
560
+ }
561
+
562
+ this.gpsWatchId = navigator.geolocation.watchPosition((position) => {
563
+ if (!this.manualLocationMode) {
564
+ this.channel.postMessage({
565
+ type: WorkerMessageType.Profile_Location_Coordinates,
566
+ body: {
567
+ accuracy: position.coords.accuracy,
568
+ altitude: position.coords.altitude,
569
+ coordinates: [ position.coords.longitude, position.coords.latitude ]
570
+ }
571
+ })
572
+ }
573
+ }, (err) => {
574
+ if (err.code !== 0) {
575
+ console.error('Location Error', err);
576
+ }
577
+ }, {
578
+ maximumAge: 0,
579
+ timeout: 1500,
580
+ enableHighAccuracy: true
581
+ });
582
+ },
583
+ initOverlays: async function() {
584
+ if (!this.map) throw new Error('Cannot initLayers before map has loaded');
585
+
586
+ const map: mapgl.Map = this.map as mapgl.Map;
587
+
588
+ map.on('rotate', () => {
589
+ this.bearing = map.getBearing()
590
+ })
591
+
592
+ map.on('pitch', () => {
593
+ this.pitch = map.getPitch()
594
+ })
595
+
596
+ map.on('styleimagemissing', (e) => {
597
+ this.icons.onStyleImageMissing(e);
598
+ })
599
+
600
+ map.on('moveend', async () => {
601
+ if (this.draw.mode !== DrawToolMode.STATIC) {
602
+ this.draw.snapping = await this.worker.db.snapping(this.map.getBounds().toArray());
603
+ } else {
604
+ this.draw.snapping.clear();
605
+ }
606
+ });
607
+
608
+ map.on('click', async (e: MapMouseEvent) => {
609
+ if (this.draw.mode !== DrawToolMode.STATIC) return;
610
+
611
+ if (this.radial.mode) {
612
+ // Clicking away closes the radial menu
613
+ this.radial.mode = undefined;
614
+ this.radial.cot = undefined;
615
+ return;
616
+ }
617
+
618
+ if (this.select.feats) this.select.feats = [];
619
+
620
+ // Ignore Non-Clickable Layer
621
+ const clickMap: Map<string, { type: string, id: string }> = new Map();
622
+ for (const overlay of this.overlays) {
623
+ for (const c of overlay._clickable) {
624
+ clickMap.set(c.id, c);
625
+ }
626
+ }
627
+
628
+ // Each Visual Layer will return a Feature for a click
629
+ // Since a single "feature" may exist in multiple layers (text, polygon, line) etc
630
+ // dedupe them based on the ID
631
+ const dedupe: Map<string, MapGeoJSONFeature> = new Map();
632
+ map.queryRenderedFeatures(e.point)
633
+ .filter((feat) => {
634
+ return clickMap.has(feat.layer.id);
635
+ })
636
+ .forEach((feat) => {
637
+ dedupe.set(String(feat.properties.id || feat.id), feat);
638
+ })
639
+
640
+ const features = Array.from(dedupe.values());
641
+
642
+ if (!features.length) return;
643
+
644
+ // MultiSelect Mode
645
+ if (e.originalEvent.ctrlKey && features.length) {
646
+ const cot = await this.worker.db.get(features[0].properties.id, {
647
+ mission: true
648
+ });
649
+
650
+ if (!cot) return;
651
+ this.selected.set(cot.id, cot);
652
+ } else if (features.length === 1) {
653
+ this.radialClick(features[0], {
654
+ lngLat: e.lngLat,
655
+ point: e.point
656
+ })
657
+ } else if (features.length > 1) {
658
+ if (e.point.x < 150 || e.point.y < 150) {
659
+ const flyTo: mapgl.FlyToOptions = {
660
+ speed: Infinity,
661
+ center: [e.lngLat.lng, e.lngLat.lat]
662
+ };
663
+
664
+ if (map.getZoom() < 3) flyTo.zoom = 4;
665
+ map.flyTo(flyTo)
666
+
667
+ this.select.x = this.container ? this.container.clientWidth / 2 : 0;
668
+ this.select.y = this.container ? this.container.clientHeight / 2 : 0;
669
+ } else {
670
+ this.select.x = e.point.x;
671
+ this.select.y = e.point.y;
672
+ }
673
+
674
+ const feats = [];
675
+
676
+ for (const feat of features) {
677
+ // TODO: Support Multi Select with both CoT and VT Features
678
+ if (!feat.properties.id) continue;
679
+
680
+ const cot = await this.worker.db.get(feat.properties.id, {
681
+ mission: true
682
+ });
683
+
684
+ if (cot) {
685
+ feats.push(cot);
686
+ } else {
687
+ feats.push(feat);
688
+ }
689
+ }
690
+
691
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
692
+ this.select.feats = feats as any;
693
+ }
694
+ });
695
+
696
+ map.on('contextmenu', (e) => {
697
+ if (this.draw.editing) return;
698
+
699
+ const id = randomUUID();
700
+ this.radialClick({
701
+ id,
702
+ type: 'Feature',
703
+ path: '/',
704
+ properties: {
705
+ id,
706
+ callsign: 'New Feature',
707
+ archived: true,
708
+ type: 'u-d-p',
709
+ how: 'm-g',
710
+ time: new Date().toISOString(),
711
+ start: new Date().toISOString(),
712
+ stale: new Date(Date.now() + 2 * (60 * 60 * 1000)).toISOString(),
713
+ center: [ e.lngLat.lng, e.lngLat.lat ],
714
+ 'marker-color': '#00ff00',
715
+ 'marker-opacity': 1
716
+ },
717
+ geometry: {
718
+ type: 'Point',
719
+ coordinates: [e.lngLat.lng, e.lngLat.lat]
720
+ }
721
+ }, {
722
+ mode: 'context',
723
+ point: e.point,
724
+ lngLat: e.lngLat
725
+ });
726
+ });
727
+
728
+ const url = stdurl('/api/profile/overlay');
729
+ url.searchParams.append('sort', 'pos');
730
+ url.searchParams.append('order', 'asc');
731
+ url.searchParams.append('limit', '100');
732
+ const profileOverlays = await std(url) as ProfileOverlayList;
733
+ this.hasTerrain = profileOverlays.available.terrain;
734
+
735
+ const hasBasemap = profileOverlays.items.some((o: ProfileOverlay) => {
736
+ return o.mode === 'basemap'
737
+ });
738
+
739
+ // Courtesy add an initial basemap
740
+ if (!hasBasemap) {
741
+ const burl = stdurl('/api/basemap');
742
+ burl.searchParams.append('type', 'raster');
743
+ const basemaps = await std(burl) as APIList<Basemap>;
744
+
745
+ if (basemaps.items.length > 0) {
746
+ const basemap = await Overlay.create({
747
+ name: basemaps.items[0].name,
748
+ pos: -1,
749
+ type: 'raster',
750
+ url: String(stdurl(`/api/basemap/${basemaps.items[0].id}/tiles`)),
751
+ mode: 'basemap',
752
+ mode_id: String(basemaps.items[0].id)
753
+ });
754
+
755
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
756
+ (this.overlays as any[]).push(basemap);
757
+ }
758
+ }
759
+
760
+ // Parallelize Overlay Creation
761
+ const overlayPromises = profileOverlays.items.map(item =>
762
+ Overlay.create(item as ProfileOverlay, { skipSave: true, skipLayers: true })
763
+ );
764
+
765
+ const newOverlays = await Promise.all(overlayPromises);
766
+
767
+ for (const overlay of newOverlays) {
768
+ await overlay.addLayers();
769
+ }
770
+
771
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
772
+ (this.overlays as any[]).push(...newOverlays);
773
+
774
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
775
+ (this.overlays as any[]).push(await Overlay.internal({
776
+ id: -1,
777
+ name: 'CoT Icons',
778
+ type: 'geojson',
779
+ }));
780
+
781
+ // Data Syncs are specially loaded as they are dynamic
782
+ // Parallelize Mission Loading
783
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
784
+ const missionOverlays = (this.overlays as any[]).filter((overlay: Overlay) => overlay.mode === 'mission' && overlay.mode_id);
785
+ const missionPromises = missionOverlays.map(async (overlay: Overlay) => {
786
+ const source = map.getSource(String(overlay.id));
787
+ if (!source) return;
788
+
789
+ try {
790
+ const sub = await this.loadMission(overlay.mode_id!, {
791
+ reload: true
792
+ });
793
+
794
+ if (sub && overlay.active) {
795
+ await this.makeActiveMission(sub);
796
+ }
797
+ } catch (err) {
798
+ console.error('Failed to load Mission', err)
799
+ overlay._error = err instanceof Error ? err : new Error(String(err));
800
+ }
801
+ });
802
+
803
+ await Promise.all(missionPromises);
804
+
805
+ this.isLoaded = true;
806
+
807
+ await this.updateAttribution();
808
+ },
809
+ updateIconRotation: function(enabled: boolean): void {
810
+ for (const overlay of this.overlays) {
811
+ if (overlay.type === 'geojson') {
812
+ // Update icon rotation
813
+ const iconLayerId = `${overlay.id}-icon`;
814
+ if (this.map.getLayer(iconLayerId)) {
815
+ this.map.setLayoutProperty(iconLayerId, 'icon-rotate', enabled ? ['get', 'course'] : 0);
816
+ }
817
+
818
+ // Update course arrow filter based on rotation setting
819
+ const courseLayerId = `${overlay.id}-course`;
820
+ if (this.map.getLayer(courseLayerId)) {
821
+ if (enabled) {
822
+ // When rotation enabled, only show course arrows for grouped features
823
+ this.map.setFilter(courseLayerId, [
824
+ 'all',
825
+ ['==', '$type', 'Point'],
826
+ ['has', 'course'],
827
+ ['has', 'group']
828
+ ]);
829
+ } else {
830
+ // When rotation disabled, show course arrows for all features with course
831
+ this.map.setFilter(courseLayerId, [
832
+ 'all',
833
+ ['==', '$type', 'Point'],
834
+ ['has', 'course']
835
+ ]);
836
+ }
837
+ }
838
+
839
+ // Update text offset
840
+ const textLayerId = `${overlay.id}-text-point`;
841
+ if (this.map.getLayer(textLayerId)) {
842
+ this.map.setLayoutProperty(textLayerId, 'text-offset', [0, enabled ? 2 : 2.5]);
843
+ }
844
+ }
845
+ }
846
+
847
+ // Force a map repaint to ensure changes are visible immediately
848
+ this.map.triggerRepaint();
849
+ },
850
+ updateDistanceUnit: function(unit: string): void {
851
+ this.distanceUnit = unit;
852
+ // Remove existing scale control and add new one with correct unit
853
+ const mapWithControl = this.map as mapgl.Map & { _scaleControl?: mapgl.ScaleControl };
854
+ const existingControl = mapWithControl._scaleControl;
855
+ if (existingControl) {
856
+ this.map.removeControl(existingControl);
857
+ const scaleControl = new mapgl.ScaleControl({
858
+ maxWidth: 100,
859
+ unit: unit === 'mile' ? 'imperial' : 'metric'
860
+ });
861
+ this.map.addControl(scaleControl, 'bottom-left');
862
+ mapWithControl._scaleControl = scaleControl;
863
+ }
864
+ },
865
+ updateAttribution: async function(): Promise<void> {
866
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
867
+ const attributionOverlays = (this.overlays as any[]).filter((o: Overlay) => o.mode === 'basemap' && o.mode_id && o.visible);
868
+ const attributionPromises = attributionOverlays.map(async (overlay: Overlay) => {
869
+ try {
870
+ const basemap = await std(`/api/basemap/${overlay.mode_id}`) as { attribution?: string };
871
+ return basemap.attribution;
872
+ } catch (err) {
873
+ console.warn('Failed to load basemap attribution:', err);
874
+ return null;
875
+ }
876
+ });
877
+
878
+ const results = await Promise.all(attributionPromises);
879
+ const attributions = results.filter((a): a is string => !!a);
880
+
881
+ // Update attribution by manipulating the DOM directly
882
+ const attributionContainer = document.querySelector('.maplibregl-ctrl-attrib-inner');
883
+ if (attributionContainer && attributions.length > 0) {
884
+ attributionContainer.innerHTML = attributions.join(' | ');
885
+ }
886
+ },
887
+
888
+ /**
889
+ * Determine if the feature is from the CoT store or a clicked VT feature
890
+ */
891
+ featureSource: function(feat: MapGeoJSONFeature | Feature): string | void {
892
+ const clickMap: Map<string, { type: string, id: string }> = new Map();
893
+ for (const overlay of this.overlays) {
894
+ for (const c of overlay._clickable) {
895
+ clickMap.set(c.id, c);
896
+ }
897
+ }
898
+
899
+ if (!('layer' in feat)) return;
900
+ const click = clickMap.get(feat.layer.id);
901
+ if (!click) return;
902
+ return click.type;
903
+ },
904
+
905
+ radialClick: async function(feat: MapGeoJSONFeature | Feature, opts: {
906
+ lngLat: LngLat;
907
+ point: Point;
908
+ mode?: string;
909
+ }): Promise<void> {
910
+ // If the call is coming from MultipleSelect, ensure this menu is closed
911
+ this.select.feats = [];
912
+
913
+ if (!opts.mode) opts.mode = this.featureSource(feat) || 'feat';
914
+
915
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
916
+ (this.radial as any).cot = feat;
917
+ this.radial.mode = opts.mode;
918
+
919
+ if (feat.geometry && feat.geometry.type === 'Point' && feat.properties && feat.properties.center) {
920
+ if (typeof feat.properties.center === 'string') {
921
+ const parts = JSON.parse(feat.properties.center);
922
+ this.radial.lngLat = new mapgl.LngLat(parts[0], parts[1]);
923
+ } else {
924
+ this.radial.lngLat = mapgl.LngLat.convert(feat.properties.center as LngLatLike);
925
+ }
926
+ } else {
927
+ this.radial.lngLat = opts.lngLat;
928
+ }
929
+ }
930
+ }
931
+ })