@massdriver/backstage-plugin 1.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 (346) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +196 -0
  3. package/dist/MassdriverRouter.esm.js +78 -0
  4. package/dist/MassdriverRouter.esm.js.map +1 -0
  5. package/dist/api.esm.js +119 -0
  6. package/dist/api.esm.js.map +1 -0
  7. package/dist/assets/massdriver-logo-dark.svg +55 -0
  8. package/dist/assets/massdriver-logo-light.svg +50 -0
  9. package/dist/components/AttributesColumn.esm.js +95 -0
  10. package/dist/components/AttributesColumn.esm.js.map +1 -0
  11. package/dist/components/AttributesSummaryCell.esm.js +103 -0
  12. package/dist/components/AttributesSummaryCell.esm.js.map +1 -0
  13. package/dist/components/AuthedIcon.esm.js +26 -0
  14. package/dist/components/AuthedIcon.esm.js.map +1 -0
  15. package/dist/components/ConditionsCell.esm.js +48 -0
  16. package/dist/components/ConditionsCell.esm.js.map +1 -0
  17. package/dist/components/DisabledAction.esm.js +30 -0
  18. package/dist/components/DisabledAction.esm.js.map +1 -0
  19. package/dist/components/EntityMassdriverContent/EntityMassdriverContent.esm.js +80 -0
  20. package/dist/components/EntityMassdriverContent/EntityMassdriverContent.esm.js.map +1 -0
  21. package/dist/components/EntityMassdriverContent/index.esm.js +6 -0
  22. package/dist/components/EntityMassdriverContent/index.esm.js.map +1 -0
  23. package/dist/components/EntityMassdriverOverviewCard/EntityMassdriverOverviewCard.esm.js +75 -0
  24. package/dist/components/EntityMassdriverOverviewCard/EntityMassdriverOverviewCard.esm.js.map +1 -0
  25. package/dist/components/EntityMassdriverOverviewCard/index.esm.js +6 -0
  26. package/dist/components/EntityMassdriverOverviewCard/index.esm.js.map +1 -0
  27. package/dist/components/ForkPill.esm.js +84 -0
  28. package/dist/components/ForkPill.esm.js.map +1 -0
  29. package/dist/components/InstanceStatusIndicator.esm.js +21 -0
  30. package/dist/components/InstanceStatusIndicator.esm.js.map +1 -0
  31. package/dist/components/InstanceStatusPill.esm.js +67 -0
  32. package/dist/components/InstanceStatusPill.esm.js.map +1 -0
  33. package/dist/components/MassdriverIcon.esm.js +13 -0
  34. package/dist/components/MassdriverIcon.esm.js.map +1 -0
  35. package/dist/components/MassdriverSidebarItem.esm.js +45 -0
  36. package/dist/components/MassdriverSidebarItem.esm.js.map +1 -0
  37. package/dist/components/NotFound.esm.js +44 -0
  38. package/dist/components/NotFound.esm.js.map +1 -0
  39. package/dist/components/OpenInMassdriverButton.esm.js +24 -0
  40. package/dist/components/OpenInMassdriverButton.esm.js.map +1 -0
  41. package/dist/components/PageLayout.esm.js +88 -0
  42. package/dist/components/PageLayout.esm.js.map +1 -0
  43. package/dist/components/RouterLinkAdapter.esm.js +12 -0
  44. package/dist/components/RouterLinkAdapter.esm.js.map +1 -0
  45. package/dist/components/VersionBadge.esm.js +57 -0
  46. package/dist/components/VersionBadge.esm.js.map +1 -0
  47. package/dist/components/grantColumns.esm.js +56 -0
  48. package/dist/components/grantColumns.esm.js.map +1 -0
  49. package/dist/components/icons/BundleIcon.esm.js +7 -0
  50. package/dist/components/icons/BundleIcon.esm.js.map +1 -0
  51. package/dist/components/icons/FolderOutlinedIcon.esm.js +7 -0
  52. package/dist/components/icons/FolderOutlinedIcon.esm.js.map +1 -0
  53. package/dist/components/icons/TokenIcon.esm.js +7 -0
  54. package/dist/components/icons/TokenIcon.esm.js.map +1 -0
  55. package/dist/entity.esm.js +23 -0
  56. package/dist/entity.esm.js.map +1 -0
  57. package/dist/features/environment/CompareDeploymentsDialog/CompareDeploymentsDialog.esm.js +115 -0
  58. package/dist/features/environment/CompareDeploymentsDialog/CompareDeploymentsDialog.esm.js.map +1 -0
  59. package/dist/features/environment/CompareDeploymentsDialog/ResultsStep.esm.js +165 -0
  60. package/dist/features/environment/CompareDeploymentsDialog/ResultsStep.esm.js.map +1 -0
  61. package/dist/features/environment/CompareDeploymentsDialog/SelectStep.esm.js +216 -0
  62. package/dist/features/environment/CompareDeploymentsDialog/SelectStep.esm.js.map +1 -0
  63. package/dist/features/environment/CompareDeploymentsDialog/compareColumns.esm.js +86 -0
  64. package/dist/features/environment/CompareDeploymentsDialog/compareColumns.esm.js.map +1 -0
  65. package/dist/features/environment/CompareDeploymentsDialog/flattenDeploymentComparison.esm.js +57 -0
  66. package/dist/features/environment/CompareDeploymentsDialog/flattenDeploymentComparison.esm.js.map +1 -0
  67. package/dist/features/environment/CompareDeploymentsDialog/queries.esm.js +53 -0
  68. package/dist/features/environment/CompareDeploymentsDialog/queries.esm.js.map +1 -0
  69. package/dist/features/environment/CompareEnvironmentsDialog/CompareEnvironmentsDialog.esm.js +94 -0
  70. package/dist/features/environment/CompareEnvironmentsDialog/CompareEnvironmentsDialog.esm.js.map +1 -0
  71. package/dist/features/environment/CompareEnvironmentsDialog/ComparisonValueCell.esm.js +67 -0
  72. package/dist/features/environment/CompareEnvironmentsDialog/ComparisonValueCell.esm.js.map +1 -0
  73. package/dist/features/environment/CompareEnvironmentsDialog/ResultsStep.esm.js +202 -0
  74. package/dist/features/environment/CompareEnvironmentsDialog/ResultsStep.esm.js.map +1 -0
  75. package/dist/features/environment/CompareEnvironmentsDialog/SelectStep.esm.js +183 -0
  76. package/dist/features/environment/CompareEnvironmentsDialog/SelectStep.esm.js.map +1 -0
  77. package/dist/features/environment/CompareEnvironmentsDialog/compareColumns.esm.js +73 -0
  78. package/dist/features/environment/CompareEnvironmentsDialog/compareColumns.esm.js.map +1 -0
  79. package/dist/features/environment/CompareEnvironmentsDialog/flattenComparison.esm.js +70 -0
  80. package/dist/features/environment/CompareEnvironmentsDialog/flattenComparison.esm.js.map +1 -0
  81. package/dist/features/environment/CompareEnvironmentsDialog/queries.esm.js +32 -0
  82. package/dist/features/environment/CompareEnvironmentsDialog/queries.esm.js.map +1 -0
  83. package/dist/features/environment/EnvironmentGraphPage.esm.js +131 -0
  84. package/dist/features/environment/EnvironmentGraphPage.esm.js.map +1 -0
  85. package/dist/features/environment/GraphHeader/EnvironmentDefaults.esm.js +252 -0
  86. package/dist/features/environment/GraphHeader/EnvironmentDefaults.esm.js.map +1 -0
  87. package/dist/features/environment/GraphHeader/GraphHeader.esm.js +247 -0
  88. package/dist/features/environment/GraphHeader/GraphHeader.esm.js.map +1 -0
  89. package/dist/features/environment/GraphHeader/HeaderActions.esm.js +127 -0
  90. package/dist/features/environment/GraphHeader/HeaderActions.esm.js.map +1 -0
  91. package/dist/features/environment/GraphHeader/Switcher.esm.js +75 -0
  92. package/dist/features/environment/GraphHeader/Switcher.esm.js.map +1 -0
  93. package/dist/features/environment/GraphHeader/queries.esm.js +60 -0
  94. package/dist/features/environment/GraphHeader/queries.esm.js.map +1 -0
  95. package/dist/features/environment/InstanceDrawer/AlarmCard.esm.js +151 -0
  96. package/dist/features/environment/InstanceDrawer/AlarmCard.esm.js.map +1 -0
  97. package/dist/features/environment/InstanceDrawer/InstanceDrawer.esm.js +165 -0
  98. package/dist/features/environment/InstanceDrawer/InstanceDrawer.esm.js.map +1 -0
  99. package/dist/features/environment/InstanceDrawer/InstanceDrawerHeader.esm.js +241 -0
  100. package/dist/features/environment/InstanceDrawer/InstanceDrawerHeader.esm.js.map +1 -0
  101. package/dist/features/environment/InstanceDrawer/InstanceTabs.esm.js +119 -0
  102. package/dist/features/environment/InstanceDrawer/InstanceTabs.esm.js.map +1 -0
  103. package/dist/features/environment/InstanceDrawer/TabState.esm.js +30 -0
  104. package/dist/features/environment/InstanceDrawer/TabState.esm.js.map +1 -0
  105. package/dist/features/environment/InstanceDrawer/formsDataSource.esm.js +25 -0
  106. package/dist/features/environment/InstanceDrawer/formsDataSource.esm.js.map +1 -0
  107. package/dist/features/environment/InstanceDrawer/helpers.esm.js +282 -0
  108. package/dist/features/environment/InstanceDrawer/helpers.esm.js.map +1 -0
  109. package/dist/features/environment/InstanceDrawer/queries.esm.js +281 -0
  110. package/dist/features/environment/InstanceDrawer/queries.esm.js.map +1 -0
  111. package/dist/features/environment/InstanceDrawer/tabs/ConfigTab.esm.js +170 -0
  112. package/dist/features/environment/InstanceDrawer/tabs/ConfigTab.esm.js.map +1 -0
  113. package/dist/features/environment/InstanceDrawer/tabs/DependenciesTab.esm.js +413 -0
  114. package/dist/features/environment/InstanceDrawer/tabs/DependenciesTab.esm.js.map +1 -0
  115. package/dist/features/environment/InstanceDrawer/tabs/DeploymentLogsPanel.esm.js +191 -0
  116. package/dist/features/environment/InstanceDrawer/tabs/DeploymentLogsPanel.esm.js.map +1 -0
  117. package/dist/features/environment/InstanceDrawer/tabs/DeploymentReadOnlyActions.esm.js +63 -0
  118. package/dist/features/environment/InstanceDrawer/tabs/DeploymentReadOnlyActions.esm.js.map +1 -0
  119. package/dist/features/environment/InstanceDrawer/tabs/GuideTab.esm.js +48 -0
  120. package/dist/features/environment/InstanceDrawer/tabs/GuideTab.esm.js.map +1 -0
  121. package/dist/features/environment/InstanceDrawer/tabs/HistoryTab.esm.js +446 -0
  122. package/dist/features/environment/InstanceDrawer/tabs/HistoryTab.esm.js.map +1 -0
  123. package/dist/features/environment/InstanceDrawer/tabs/MonitorTab.esm.js +146 -0
  124. package/dist/features/environment/InstanceDrawer/tabs/MonitorTab.esm.js.map +1 -0
  125. package/dist/features/environment/InstanceDrawer/tabs/OverviewTab.esm.js +572 -0
  126. package/dist/features/environment/InstanceDrawer/tabs/OverviewTab.esm.js.map +1 -0
  127. package/dist/features/environment/InstanceDrawer/tabs/ResourcesTab.esm.js +471 -0
  128. package/dist/features/environment/InstanceDrawer/tabs/ResourcesTab.esm.js.map +1 -0
  129. package/dist/features/environment/InstanceDrawer/tabs/SecretsTab.esm.js +109 -0
  130. package/dist/features/environment/InstanceDrawer/tabs/SecretsTab.esm.js.map +1 -0
  131. package/dist/features/environment/InstanceDrawer/tabs/ViewDeploymentDetails.esm.js +384 -0
  132. package/dist/features/environment/InstanceDrawer/tabs/ViewDeploymentDetails.esm.js.map +1 -0
  133. package/dist/features/environment/InstanceDrawer/tabs/flattenParams.esm.js +23 -0
  134. package/dist/features/environment/InstanceDrawer/tabs/flattenParams.esm.js.map +1 -0
  135. package/dist/features/environment/InstanceDrawer/useInstanceApiQuery.esm.js +6 -0
  136. package/dist/features/environment/InstanceDrawer/useInstanceApiQuery.esm.js.map +1 -0
  137. package/dist/features/environment/InstanceDrawer/useOverflowMeasure.esm.js +55 -0
  138. package/dist/features/environment/InstanceDrawer/useOverflowMeasure.esm.js.map +1 -0
  139. package/dist/features/environment/InstanceDrawer/useResizableWidth.esm.js +44 -0
  140. package/dist/features/environment/InstanceDrawer/useResizableWidth.esm.js.map +1 -0
  141. package/dist/features/environment/components/InstanceStatusPill.esm.js +54 -0
  142. package/dist/features/environment/components/InstanceStatusPill.esm.js.map +1 -0
  143. package/dist/features/environment/graph/Diagram.esm.js +143 -0
  144. package/dist/features/environment/graph/Diagram.esm.js.map +1 -0
  145. package/dist/features/environment/graph/DiagramNode.constants.esm.js +5 -0
  146. package/dist/features/environment/graph/DiagramNode.constants.esm.js.map +1 -0
  147. package/dist/features/environment/graph/DiagramNode.esm.js +221 -0
  148. package/dist/features/environment/graph/DiagramNode.esm.js.map +1 -0
  149. package/dist/features/environment/graph/NodeMeta.esm.js +182 -0
  150. package/dist/features/environment/graph/NodeMeta.esm.js.map +1 -0
  151. package/dist/features/environment/graph/NodeVersionBadges.esm.js +150 -0
  152. package/dist/features/environment/graph/NodeVersionBadges.esm.js.map +1 -0
  153. package/dist/features/environment/graph/diagramFactory.esm.js +151 -0
  154. package/dist/features/environment/graph/diagramFactory.esm.js.map +1 -0
  155. package/dist/features/environment/graph/handles/ExpandableHandleWrapper.esm.js +174 -0
  156. package/dist/features/environment/graph/handles/ExpandableHandleWrapper.esm.js.map +1 -0
  157. package/dist/features/environment/graph/handles/NodeHandle.esm.js +45 -0
  158. package/dist/features/environment/graph/handles/NodeHandle.esm.js.map +1 -0
  159. package/dist/features/environment/graph/handles/NodeHandleTooltip.esm.js +134 -0
  160. package/dist/features/environment/graph/handles/NodeHandleTooltip.esm.js.map +1 -0
  161. package/dist/features/environment/graph/handles/handleTypes.esm.js +170 -0
  162. package/dist/features/environment/graph/handles/handleTypes.esm.js.map +1 -0
  163. package/dist/features/environment/graph/handles/useAnimationFrameSync.esm.js +19 -0
  164. package/dist/features/environment/graph/handles/useAnimationFrameSync.esm.js.map +1 -0
  165. package/dist/features/environment/graph/handles/useRadialPositions.esm.js +37 -0
  166. package/dist/features/environment/graph/handles/useRadialPositions.esm.js.map +1 -0
  167. package/dist/features/environment/graph/handles/useTransitionLifecycle.esm.js +19 -0
  168. package/dist/features/environment/graph/handles/useTransitionLifecycle.esm.js.map +1 -0
  169. package/dist/features/environment/graph/hasUndeployedPlan.esm.js +43 -0
  170. package/dist/features/environment/graph/hasUndeployedPlan.esm.js.map +1 -0
  171. package/dist/features/environment/graph/queries.esm.js +103 -0
  172. package/dist/features/environment/graph/queries.esm.js.map +1 -0
  173. package/dist/features/environment/graph/useDiagramSnapshot.esm.js +43 -0
  174. package/dist/features/environment/graph/useDiagramSnapshot.esm.js.map +1 -0
  175. package/dist/features/environment/realtime/RealtimeProvider.esm.js +43 -0
  176. package/dist/features/environment/realtime/RealtimeProvider.esm.js.map +1 -0
  177. package/dist/features/environment/realtime/queries.esm.js +76 -0
  178. package/dist/features/environment/realtime/queries.esm.js.map +1 -0
  179. package/dist/features/environment/realtime/useLiveRelayQuery.esm.js +36 -0
  180. package/dist/features/environment/realtime/useLiveRelayQuery.esm.js.map +1 -0
  181. package/dist/features/project/ProjectDetailsPage.esm.js +101 -0
  182. package/dist/features/project/ProjectDetailsPage.esm.js.map +1 -0
  183. package/dist/features/project/tabs/ComponentsTab.esm.js +149 -0
  184. package/dist/features/project/tabs/ComponentsTab.esm.js.map +1 -0
  185. package/dist/features/project/tabs/EnvStatus.esm.js +149 -0
  186. package/dist/features/project/tabs/EnvStatus.esm.js.map +1 -0
  187. package/dist/features/project/tabs/EnvironmentsTab.esm.js +199 -0
  188. package/dist/features/project/tabs/EnvironmentsTab.esm.js.map +1 -0
  189. package/dist/features/project/tabs/OverviewTab.esm.js +420 -0
  190. package/dist/features/project/tabs/OverviewTab.esm.js.map +1 -0
  191. package/dist/features/projects/ProjectsListPage.esm.js +50 -0
  192. package/dist/features/projects/ProjectsListPage.esm.js.map +1 -0
  193. package/dist/features/projects/ProjectsListPageLazy.esm.js +12 -0
  194. package/dist/features/projects/ProjectsListPageLazy.esm.js.map +1 -0
  195. package/dist/features/projects/projectColumns.esm.js +38 -0
  196. package/dist/features/projects/projectColumns.esm.js.map +1 -0
  197. package/dist/features/projects/useProjects.esm.js +48 -0
  198. package/dist/features/projects/useProjects.esm.js.map +1 -0
  199. package/dist/features/repo/DeploymentLogsDrawer.esm.js +213 -0
  200. package/dist/features/repo/DeploymentLogsDrawer.esm.js.map +1 -0
  201. package/dist/features/repo/DeploymentLogsDrawer.loading.esm.js +43 -0
  202. package/dist/features/repo/DeploymentLogsDrawer.loading.esm.js.map +1 -0
  203. package/dist/features/repo/FileTree.esm.js +179 -0
  204. package/dist/features/repo/FileTree.esm.js.map +1 -0
  205. package/dist/features/repo/FileViewer.esm.js +115 -0
  206. package/dist/features/repo/FileViewer.esm.js.map +1 -0
  207. package/dist/features/repo/FileViewer.helpers.esm.js +54 -0
  208. package/dist/features/repo/FileViewer.helpers.esm.js.map +1 -0
  209. package/dist/features/repo/RepoDetailsPage.esm.js +127 -0
  210. package/dist/features/repo/RepoDetailsPage.esm.js.map +1 -0
  211. package/dist/features/repo/RepoEmptyState.esm.js +58 -0
  212. package/dist/features/repo/RepoEmptyState.esm.js.map +1 -0
  213. package/dist/features/repo/RepoNoVersionsState.esm.js +29 -0
  214. package/dist/features/repo/RepoNoVersionsState.esm.js.map +1 -0
  215. package/dist/features/repo/RepoTabHeader.esm.js +30 -0
  216. package/dist/features/repo/RepoTabHeader.esm.js.map +1 -0
  217. package/dist/features/repo/RepoTabLayout.esm.js +18 -0
  218. package/dist/features/repo/RepoTabLayout.esm.js.map +1 -0
  219. package/dist/features/repo/RepoVersionSelect.esm.js +176 -0
  220. package/dist/features/repo/RepoVersionSelect.esm.js.map +1 -0
  221. package/dist/features/repo/ViewDeploymentDetailsDialog.esm.js +427 -0
  222. package/dist/features/repo/ViewDeploymentDetailsDialog.esm.js.map +1 -0
  223. package/dist/features/repo/deploymentHelpers.esm.js +74 -0
  224. package/dist/features/repo/deploymentHelpers.esm.js.map +1 -0
  225. package/dist/features/repo/fileTreeHelpers.esm.js +45 -0
  226. package/dist/features/repo/fileTreeHelpers.esm.js.map +1 -0
  227. package/dist/features/repo/flattenParams.esm.js +23 -0
  228. package/dist/features/repo/flattenParams.esm.js.map +1 -0
  229. package/dist/features/repo/queries.esm.js +239 -0
  230. package/dist/features/repo/queries.esm.js.map +1 -0
  231. package/dist/features/repo/repoFilter.esm.js +9 -0
  232. package/dist/features/repo/repoFilter.esm.js.map +1 -0
  233. package/dist/features/repo/repoTabs.esm.js +22 -0
  234. package/dist/features/repo/repoTabs.esm.js.map +1 -0
  235. package/dist/features/repo/resolveVersion.esm.js +22 -0
  236. package/dist/features/repo/resolveVersion.esm.js.map +1 -0
  237. package/dist/features/repo/tabs/DeploymentRow.esm.js +201 -0
  238. package/dist/features/repo/tabs/DeploymentRow.esm.js.map +1 -0
  239. package/dist/features/repo/tabs/DeploymentsTab.esm.js +188 -0
  240. package/dist/features/repo/tabs/DeploymentsTab.esm.js.map +1 -0
  241. package/dist/features/repo/tabs/DeploymentsTab.helpers.esm.js +46 -0
  242. package/dist/features/repo/tabs/DeploymentsTab.helpers.esm.js.map +1 -0
  243. package/dist/features/repo/tabs/DeploymentsTab.loading.esm.js +37 -0
  244. package/dist/features/repo/tabs/DeploymentsTab.loading.esm.js.map +1 -0
  245. package/dist/features/repo/tabs/FilesTab.esm.js +142 -0
  246. package/dist/features/repo/tabs/FilesTab.esm.js.map +1 -0
  247. package/dist/features/repo/tabs/InstanceRow.esm.js +121 -0
  248. package/dist/features/repo/tabs/InstanceRow.esm.js.map +1 -0
  249. package/dist/features/repo/tabs/InstancesTab.esm.js +147 -0
  250. package/dist/features/repo/tabs/InstancesTab.esm.js.map +1 -0
  251. package/dist/features/repo/tabs/InstancesTab.helpers.esm.js +44 -0
  252. package/dist/features/repo/tabs/InstancesTab.helpers.esm.js.map +1 -0
  253. package/dist/features/repo/tabs/InstancesTab.loading.esm.js +33 -0
  254. package/dist/features/repo/tabs/InstancesTab.loading.esm.js.map +1 -0
  255. package/dist/features/repo/tabs/OverviewTab.esm.js +77 -0
  256. package/dist/features/repo/tabs/OverviewTab.esm.js.map +1 -0
  257. package/dist/features/repo/tabs/PermissionsTab.esm.js +56 -0
  258. package/dist/features/repo/tabs/PermissionsTab.esm.js.map +1 -0
  259. package/dist/features/repo/tabs/VersionsTab.esm.js +152 -0
  260. package/dist/features/repo/tabs/VersionsTab.esm.js.map +1 -0
  261. package/dist/features/repo/useInfiniteRelayList.esm.js +92 -0
  262. package/dist/features/repo/useInfiniteRelayList.esm.js.map +1 -0
  263. package/dist/features/repo/useInfiniteScroll.esm.js +21 -0
  264. package/dist/features/repo/useInfiniteScroll.esm.js.map +1 -0
  265. package/dist/features/repos/ReposListPage.esm.js +53 -0
  266. package/dist/features/repos/ReposListPage.esm.js.map +1 -0
  267. package/dist/features/repos/queries.esm.js +40 -0
  268. package/dist/features/repos/queries.esm.js.map +1 -0
  269. package/dist/features/repos/repoColumns.esm.js +121 -0
  270. package/dist/features/repos/repoColumns.esm.js.map +1 -0
  271. package/dist/features/repos/useRepos.esm.js +22 -0
  272. package/dist/features/repos/useRepos.esm.js.map +1 -0
  273. package/dist/features/resource/OriginChip.esm.js +42 -0
  274. package/dist/features/resource/OriginChip.esm.js.map +1 -0
  275. package/dist/features/resource/ResourceDetailsPage.esm.js +167 -0
  276. package/dist/features/resource/ResourceDetailsPage.esm.js.map +1 -0
  277. package/dist/features/resource/queries.esm.js +141 -0
  278. package/dist/features/resource/queries.esm.js.map +1 -0
  279. package/dist/features/resource/tabs/GeneralTab.esm.js +247 -0
  280. package/dist/features/resource/tabs/GeneralTab.esm.js.map +1 -0
  281. package/dist/features/resource/tabs/GeneralTab.loading.esm.js +76 -0
  282. package/dist/features/resource/tabs/GeneralTab.loading.esm.js.map +1 -0
  283. package/dist/features/resource/tabs/PermissionsTab.esm.js +57 -0
  284. package/dist/features/resource/tabs/PermissionsTab.esm.js.map +1 -0
  285. package/dist/features/resource/tabs/SettingsTabLayout.esm.js +18 -0
  286. package/dist/features/resource/tabs/SettingsTabLayout.esm.js.map +1 -0
  287. package/dist/features/resource/tabs/TabHeader.esm.js +30 -0
  288. package/dist/features/resource/tabs/TabHeader.esm.js.map +1 -0
  289. package/dist/features/resource/tabs/UsagePanel.esm.js +35 -0
  290. package/dist/features/resource/tabs/UsagePanel.esm.js.map +1 -0
  291. package/dist/features/resource/tabs/UsageTab.esm.js +91 -0
  292. package/dist/features/resource/tabs/UsageTab.esm.js.map +1 -0
  293. package/dist/features/resource/tabs/UsageTab.helpers.esm.js +168 -0
  294. package/dist/features/resource/tabs/UsageTab.helpers.esm.js.map +1 -0
  295. package/dist/features/resources/ResourcesEmptyState.esm.js +148 -0
  296. package/dist/features/resources/ResourcesEmptyState.esm.js.map +1 -0
  297. package/dist/features/resources/ResourcesListPage.esm.js +115 -0
  298. package/dist/features/resources/ResourcesListPage.esm.js.map +1 -0
  299. package/dist/features/resources/queries.esm.js +50 -0
  300. package/dist/features/resources/queries.esm.js.map +1 -0
  301. package/dist/features/resources/resourceColumns.esm.js +158 -0
  302. package/dist/features/resources/resourceColumns.esm.js.map +1 -0
  303. package/dist/features/resources/resourceConstants.esm.js +7 -0
  304. package/dist/features/resources/resourceConstants.esm.js.map +1 -0
  305. package/dist/features/resources/toResourceRow.esm.js +29 -0
  306. package/dist/features/resources/toResourceRow.esm.js.map +1 -0
  307. package/dist/hooks/useAuthedSvg.esm.js +34 -0
  308. package/dist/hooks/useAuthedSvg.esm.js.map +1 -0
  309. package/dist/hooks/useCursorPagination.esm.js +40 -0
  310. package/dist/hooks/useCursorPagination.esm.js.map +1 -0
  311. package/dist/hooks/useMassdriverSubscription.esm.js +61 -0
  312. package/dist/hooks/useMassdriverSubscription.esm.js.map +1 -0
  313. package/dist/hooks/usePaginatedRelayQuery.esm.js +68 -0
  314. package/dist/hooks/usePaginatedRelayQuery.esm.js.map +1 -0
  315. package/dist/index.d.ts +256 -0
  316. package/dist/index.esm.js +8 -0
  317. package/dist/index.esm.js.map +1 -0
  318. package/dist/internalRoutes.esm.js +29 -0
  319. package/dist/internalRoutes.esm.js.map +1 -0
  320. package/dist/plugin.esm.js +57 -0
  321. package/dist/plugin.esm.js.map +1 -0
  322. package/dist/queries.esm.js +54 -0
  323. package/dist/queries.esm.js.map +1 -0
  324. package/dist/routes.esm.js +6 -0
  325. package/dist/routes.esm.js.map +1 -0
  326. package/dist/shell/MassdriverHeader.esm.js +37 -0
  327. package/dist/shell/MassdriverHeader.esm.js.map +1 -0
  328. package/dist/shell/MassdriverShell.esm.js +30 -0
  329. package/dist/shell/MassdriverShell.esm.js.map +1 -0
  330. package/dist/theme/MassdriverThemeScope.esm.js +30 -0
  331. package/dist/theme/MassdriverThemeScope.esm.js.map +1 -0
  332. package/dist/theme/ThemeModeContext.esm.js +35 -0
  333. package/dist/theme/ThemeModeContext.esm.js.map +1 -0
  334. package/dist/theme/muiClassNameAudit.esm.js +11 -0
  335. package/dist/theme/muiClassNameAudit.esm.js.map +1 -0
  336. package/dist/useInstances.esm.js +39 -0
  337. package/dist/useInstances.esm.js.map +1 -0
  338. package/dist/utils/attributes.esm.js +28 -0
  339. package/dist/utils/attributes.esm.js.map +1 -0
  340. package/dist/utils/conditions.esm.js +20 -0
  341. package/dist/utils/conditions.esm.js.map +1 -0
  342. package/dist/utils/formatRelativeTime.esm.js +40 -0
  343. package/dist/utils/formatRelativeTime.esm.js.map +1 -0
  344. package/dist/utils/instanceStatuses.esm.js +74 -0
  345. package/dist/utils/instanceStatuses.esm.js.map +1 -0
  346. package/package.json +92 -0
@@ -0,0 +1,36 @@
1
+ import { useState, useEffect } from 'react';
2
+ import { useApi } from '@backstage/frontend-plugin-api';
3
+ import { massdriverApiRef } from '../../../api.esm.js';
4
+ import { useRealtimeRevision } from './RealtimeProvider.esm.js';
5
+
6
+ const useLiveRelayQuery = (query, variables) => {
7
+ const api = useApi(massdriverApiRef);
8
+ const revision = useRealtimeRevision();
9
+ const [state, setState] = useState({ identity: "" });
10
+ const skip = variables === null;
11
+ const identity = `${query}|${JSON.stringify(variables)}`;
12
+ useEffect(() => {
13
+ if (skip) return void 0;
14
+ let cancelled = false;
15
+ api.query(query, variables).then(
16
+ (value) => {
17
+ if (!cancelled) setState({ identity, value });
18
+ },
19
+ (error) => {
20
+ if (!cancelled) setState({ identity, error });
21
+ }
22
+ );
23
+ return () => {
24
+ cancelled = true;
25
+ };
26
+ }, [api, query, identity, revision, skip]);
27
+ const fresh = state.identity === identity;
28
+ return {
29
+ value: !skip && fresh ? state.value : void 0,
30
+ error: !skip && fresh ? state.error : void 0,
31
+ loading: !skip && !fresh
32
+ };
33
+ };
34
+
35
+ export { useLiveRelayQuery };
36
+ //# sourceMappingURL=useLiveRelayQuery.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLiveRelayQuery.esm.js","sources":["../../../../src/features/environment/realtime/useLiveRelayQuery.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport { useApi } from '@backstage/frontend-plugin-api';\nimport { massdriverApiRef } from '../../../api';\nimport { useRealtimeRevision } from './RealtimeProvider';\n\ninterface LiveQueryState<T> {\n identity: string;\n value?: T;\n error?: Error;\n}\n\n/**\n * Relay query that stays live via the environment's realtime revision, with two\n * distinct refetch behaviors:\n *\n * - **Identity change** (query/variables): the previous result is dropped and\n * `loading` goes true — a different entity is being loaded, show a loader.\n * - **Revision bump** (realtime event): the previous result stays rendered and\n * swaps atomically when fresh data lands — never a loading flash. This is the\n * plugin's analogue of the web app's \"no skeleton flicker on subscription\n * refetch\" rule (see .claude/rules/realtime.md).\n *\n * Pass `variables: null` to skip (returns `{ loading: false }` with no value).\n */\nexport const useLiveRelayQuery = <T>(\n query: string,\n variables: Record<string, unknown> | null,\n): { value?: T; error?: Error; loading: boolean } => {\n const api = useApi(massdriverApiRef);\n const revision = useRealtimeRevision();\n const [state, setState] = useState<LiveQueryState<T>>({ identity: '' });\n\n const skip = variables === null;\n const identity = `${query}|${JSON.stringify(variables)}`;\n\n useEffect(() => {\n if (skip) return undefined;\n let cancelled = false;\n api.query(query, variables).then(\n value => {\n if (!cancelled) setState({ identity, value: value as T });\n },\n error => {\n if (!cancelled) setState({ identity, error: error as Error });\n },\n );\n return () => {\n cancelled = true;\n };\n // `variables` participates by value through `identity`.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [api, query, identity, revision, skip]);\n\n // A result only counts once it matches the current identity; until then the\n // hook is loading and stale state is hidden. Revision bumps keep the identity\n // (and therefore the rendered value) intact while the refetch is in flight.\n const fresh = state.identity === identity;\n return {\n value: !skip && fresh ? state.value : undefined,\n error: !skip && fresh ? state.error : undefined,\n loading: !skip && !fresh,\n };\n};\n\nexport default useLiveRelayQuery;\n"],"names":[],"mappings":";;;;;AAwBO,MAAM,iBAAA,GAAoB,CAC/B,KAAA,EACA,SAAA,KACmD;AACnD,EAAA,MAAM,GAAA,GAAM,OAAO,gBAAgB,CAAA;AACnC,EAAA,MAAM,WAAW,mBAAA,EAAoB;AACrC,EAAA,MAAM,CAAC,OAAO,QAAQ,CAAA,GAAI,SAA4B,EAAE,QAAA,EAAU,IAAI,CAAA;AAEtE,EAAA,MAAM,OAAO,SAAA,KAAc,IAAA;AAC3B,EAAA,MAAM,WAAW,CAAA,EAAG,KAAK,IAAI,IAAA,CAAK,SAAA,CAAU,SAAS,CAAC,CAAA,CAAA;AAEtD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,MAAM,OAAO,MAAA;AACjB,IAAA,IAAI,SAAA,GAAY,KAAA;AAChB,IAAA,GAAA,CAAI,KAAA,CAAM,KAAA,EAAO,SAAS,CAAA,CAAE,IAAA;AAAA,MAC1B,CAAA,KAAA,KAAS;AACP,QAAA,IAAI,CAAC,SAAA,EAAW,QAAA,CAAS,EAAE,QAAA,EAAU,OAAmB,CAAA;AAAA,MAC1D,CAAA;AAAA,MACA,CAAA,KAAA,KAAS;AACP,QAAA,IAAI,CAAC,SAAA,EAAW,QAAA,CAAS,EAAE,QAAA,EAAU,OAAuB,CAAA;AAAA,MAC9D;AAAA,KACF;AACA,IAAA,OAAO,MAAM;AACX,MAAA,SAAA,GAAY,IAAA;AAAA,IACd,CAAA;AAAA,EAGF,GAAG,CAAC,GAAA,EAAK,OAAO,QAAA,EAAU,QAAA,EAAU,IAAI,CAAC,CAAA;AAKzC,EAAA,MAAM,KAAA,GAAQ,MAAM,QAAA,KAAa,QAAA;AACjC,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,CAAC,IAAA,IAAQ,KAAA,GAAQ,MAAM,KAAA,GAAQ,MAAA;AAAA,IACtC,KAAA,EAAO,CAAC,IAAA,IAAQ,KAAA,GAAQ,MAAM,KAAA,GAAQ,MAAA;AAAA,IACtC,OAAA,EAAS,CAAC,IAAA,IAAQ,CAAC;AAAA,GACrB;AACF;;;;"}
@@ -0,0 +1,101 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { useApi } from '@backstage/frontend-plugin-api';
3
+ import { projectUrl } from '@massdriver/backstage-plugin-common';
4
+ import Box from '@massdriver/ui/Box';
5
+ import PageTabs from '@massdriver/ui/PageTabs';
6
+ import stylin from '@massdriver/ui/stylin';
7
+ import useAsync from 'react-use/esm/useAsync';
8
+ import { useParams } from 'react-router-dom';
9
+ import { massdriverApiRef } from '../../api.esm.js';
10
+ import { NotFound } from '../../components/NotFound.esm.js';
11
+ import { OpenInMassdriverButton } from '../../components/OpenInMassdriverButton.esm.js';
12
+ import { PageLayout } from '../../components/PageLayout.esm.js';
13
+ import { RouterLinkAdapter } from '../../components/RouterLinkAdapter.esm.js';
14
+ import { internalRoutes } from '../../internalRoutes.esm.js';
15
+ import { ComponentsTab } from './tabs/ComponentsTab.esm.js';
16
+ import { EnvironmentsTab } from './tabs/EnvironmentsTab.esm.js';
17
+ import { OverviewTab } from './tabs/OverviewTab.esm.js';
18
+
19
+ const TABS = [
20
+ { id: "overview", label: "Overview" },
21
+ { id: "components", label: "Components" },
22
+ { id: "environments", label: "Environments" }
23
+ ];
24
+ const PANELS = {
25
+ overview: OverviewTab,
26
+ components: ComponentsTab,
27
+ environments: EnvironmentsTab
28
+ };
29
+ const HEADER_QUERY = `
30
+ query MassdriverProjectHeader($organizationId: ID!, $id: ID!) {
31
+ project(organizationId: $organizationId, id: $id) {
32
+ id
33
+ name
34
+ description
35
+ }
36
+ }
37
+ `;
38
+ const ProjectDetailsPage = () => {
39
+ const api = useApi(massdriverApiRef);
40
+ const { projectId = "", tab } = useParams();
41
+ const activeTab = TABS.some((entry) => entry.id === tab) ? tab : "overview";
42
+ const {
43
+ value: project,
44
+ loading,
45
+ error
46
+ } = useAsync(async () => {
47
+ const data = await api.query(HEADER_QUERY, { id: projectId });
48
+ return data.project;
49
+ }, [api, projectId]);
50
+ if (!loading && !error && !project) {
51
+ return /* @__PURE__ */ jsx(
52
+ NotFound,
53
+ {
54
+ title: "Project not found",
55
+ message: "This project doesn't exist or you don't have access to it."
56
+ }
57
+ );
58
+ }
59
+ const tabs = TABS.map((entry) => ({
60
+ ...entry,
61
+ href: internalRoutes.projectTab(projectId, entry.id)
62
+ }));
63
+ const appProjectUrl = projectUrl(api.appUrl, api.organizationId, projectId);
64
+ return /* @__PURE__ */ jsx(
65
+ PageLayout,
66
+ {
67
+ title: project?.name ?? "",
68
+ description: project?.description,
69
+ headerActions: /* @__PURE__ */ jsxs(HeaderActions, { children: [
70
+ /* @__PURE__ */ jsx(OpenInMassdriverButton, { url: appProjectUrl, variant: "outlined", children: "Open in Massdriver" }),
71
+ /* @__PURE__ */ jsx(
72
+ OpenInMassdriverButton,
73
+ {
74
+ url: `${appProjectUrl}?cloneProject=true`,
75
+ variant: "outlined",
76
+ children: "Clone Project"
77
+ }
78
+ )
79
+ ] }),
80
+ flush: true,
81
+ children: /* @__PURE__ */ jsx(
82
+ PageTabs,
83
+ {
84
+ orientation: "vertical",
85
+ tabs,
86
+ panels: PANELS,
87
+ activeTab,
88
+ panelProps: { projectId },
89
+ LinkComponent: RouterLinkAdapter
90
+ }
91
+ )
92
+ }
93
+ );
94
+ };
95
+ const HeaderActions = stylin(Box)(({ theme }) => ({
96
+ display: "flex",
97
+ gap: theme.spacing(1.5)
98
+ }));
99
+
100
+ export { ProjectDetailsPage };
101
+ //# sourceMappingURL=ProjectDetailsPage.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProjectDetailsPage.esm.js","sources":["../../../src/features/project/ProjectDetailsPage.tsx"],"sourcesContent":["import { useApi } from '@backstage/frontend-plugin-api';\nimport { projectUrl } from '@massdriver/backstage-plugin-common';\nimport Box from '@massdriver/ui/Box';\nimport PageTabs from '@massdriver/ui/PageTabs';\nimport stylin from '@massdriver/ui/stylin';\nimport useAsync from 'react-use/esm/useAsync';\nimport { useParams } from 'react-router-dom';\nimport { massdriverApiRef } from '../../api';\nimport { NotFound } from '../../components/NotFound';\nimport { OpenInMassdriverButton } from '../../components/OpenInMassdriverButton';\nimport { PageLayout } from '../../components/PageLayout';\nimport { RouterLinkAdapter } from '../../components/RouterLinkAdapter';\nimport { internalRoutes } from '../../internalRoutes';\nimport { ComponentsTab } from './tabs/ComponentsTab';\nimport { EnvironmentsTab } from './tabs/EnvironmentsTab';\nimport { OverviewTab } from './tabs/OverviewTab';\n\nconst TABS = [\n { id: 'overview', label: 'Overview' },\n { id: 'components', label: 'Components' },\n { id: 'environments', label: 'Environments' },\n];\n\nconst PANELS: Record<string, (props: { projectId: string }) => JSX.Element> = {\n overview: OverviewTab,\n components: ComponentsTab,\n environments: EnvironmentsTab,\n};\n\nconst HEADER_QUERY = `\n query MassdriverProjectHeader($organizationId: ID!, $id: ID!) {\n project(organizationId: $organizationId, id: $id) {\n id\n name\n description\n }\n }\n`;\n\n/** Read-only project details: vertical side-tabs mirroring the web app. */\nexport const ProjectDetailsPage = () => {\n const api = useApi(massdriverApiRef);\n const { projectId = '', tab } = useParams();\n const activeTab = TABS.some(entry => entry.id === tab) ? tab! : 'overview';\n\n const {\n value: project,\n loading,\n error,\n } = useAsync(async () => {\n const data = (await api.query(HEADER_QUERY, { id: projectId })) as {\n project: { id: string; name?: string; description?: string } | null;\n };\n return data.project;\n }, [api, projectId]);\n\n if (!loading && !error && !project) {\n return (\n <NotFound\n title=\"Project not found\"\n message=\"This project doesn't exist or you don't have access to it.\"\n />\n );\n }\n\n const tabs = TABS.map(entry => ({\n ...entry,\n href: internalRoutes.projectTab(projectId, entry.id),\n }));\n\n const appProjectUrl = projectUrl(api.appUrl, api.organizationId, projectId);\n\n return (\n <PageLayout\n title={project?.name ?? ''}\n description={project?.description}\n headerActions={\n <HeaderActions>\n <OpenInMassdriverButton url={appProjectUrl} variant=\"outlined\">\n Open in Massdriver\n </OpenInMassdriverButton>\n <OpenInMassdriverButton\n url={`${appProjectUrl}?cloneProject=true`}\n variant=\"outlined\"\n >\n Clone Project\n </OpenInMassdriverButton>\n </HeaderActions>\n }\n flush\n >\n <PageTabs\n orientation=\"vertical\"\n tabs={tabs}\n panels={PANELS}\n activeTab={activeTab}\n panelProps={{ projectId }}\n LinkComponent={RouterLinkAdapter}\n />\n </PageLayout>\n );\n};\n\nconst HeaderActions = stylin(Box)(({ theme }: { theme: any }) => ({\n display: 'flex',\n gap: theme.spacing(1.5),\n}));\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,149 @@
1
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
+ import { useApi } from '@backstage/frontend-plugin-api';
3
+ import { parseInstanceId } from '@massdriver/backstage-plugin-common';
4
+ import Alert from '@massdriver/ui/Alert';
5
+ import Box from '@massdriver/ui/Box';
6
+ import DataList, { col } from '@massdriver/ui/DataList';
7
+ import IconTile from '@massdriver/ui/IconTile';
8
+ import Stack from '@massdriver/ui/Stack';
9
+ import Typography from '@massdriver/ui/Typography';
10
+ import ExtensionIcon from '@massdriver/ui/icons/ExtensionIcon';
11
+ import stylin from '@massdriver/ui/stylin';
12
+ import useAsync from 'react-use/esm/useAsync';
13
+ import { massdriverApiRef } from '../../../api.esm.js';
14
+ import { buildAttributesColumn, Code } from '../../../components/AttributesColumn.esm.js';
15
+ import { internalRoutes } from '../../../internalRoutes.esm.js';
16
+ import { EnvStatusStrip } from './EnvStatus.esm.js';
17
+
18
+ const COMPONENTS_QUERY = `
19
+ query MassdriverProjectComponents($organizationId: ID!, $id: ID!) {
20
+ project(organizationId: $organizationId, id: $id) {
21
+ id
22
+ components {
23
+ id
24
+ name
25
+ description
26
+ attributes
27
+ effectiveAttributes
28
+ ociRepo { id name icon }
29
+ instances(cursor: { limit: 100 }) {
30
+ items {
31
+ id
32
+ status
33
+ deployedVersion
34
+ resolvedVersion
35
+ availableUpgrade
36
+ environment { id name }
37
+ }
38
+ }
39
+ }
40
+ }
41
+ }
42
+ `;
43
+ const ComponentsTab = ({ projectId }) => {
44
+ const api = useApi(massdriverApiRef);
45
+ const { value, loading, error } = useAsync(async () => {
46
+ const data = await api.query(COMPONENTS_QUERY, { id: projectId });
47
+ return data.project?.components ?? [];
48
+ }, [api, projectId]);
49
+ const rows = (value ?? []).map((component) => ({
50
+ ...component,
51
+ typeName: component.ociRepo?.name,
52
+ instances: (component.instances?.items ?? []).filter(
53
+ Boolean
54
+ )
55
+ }));
56
+ const getInstanceUrl = (instance) => {
57
+ if (!instance.environment?.id || !instance.id) {
58
+ return null;
59
+ }
60
+ const { scopedEnvironmentId, scopedComponentId } = parseInstanceId(
61
+ instance.id
62
+ );
63
+ return internalRoutes.instance(
64
+ projectId,
65
+ scopedEnvironmentId,
66
+ scopedComponentId
67
+ );
68
+ };
69
+ const columns = [
70
+ col.custom(
71
+ "name",
72
+ "Name",
73
+ (_value, row) => /* @__PURE__ */ jsxs(NameCell, { children: [
74
+ /* @__PURE__ */ jsx(
75
+ IconTile,
76
+ {
77
+ src: row.ociRepo?.icon,
78
+ alt: row.ociRepo?.name,
79
+ size: "small",
80
+ fallback: /* @__PURE__ */ jsx(ExtensionIcon, {})
81
+ }
82
+ ),
83
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", children: row.name })
84
+ ] }),
85
+ { flex: 2, minWidth: 220, searchable: true }
86
+ ),
87
+ col.text("description", "Description", {
88
+ flex: 2,
89
+ minWidth: 200,
90
+ sortable: false,
91
+ searchable: true
92
+ }),
93
+ col.text("typeName", "Bundle Type", {
94
+ flex: 1,
95
+ minWidth: 160,
96
+ sortable: false
97
+ }),
98
+ buildAttributesColumn({
99
+ directText: "Key-value attributes assigned directly to this component. Attributes cascade to instances of the component across all environments.",
100
+ effectiveText: /* @__PURE__ */ jsxs(Fragment, { children: [
101
+ "The full attribute map the authorization system evaluates policies against for this component \u2014 the component's own user attributes plus auto-injected ",
102
+ /* @__PURE__ */ jsx(Code, { children: "md-*" }),
103
+ " system attributes."
104
+ ] })
105
+ }),
106
+ col.custom(
107
+ "status",
108
+ "Status across environments",
109
+ (_value, row) => /* @__PURE__ */ jsx(
110
+ EnvStatusStrip,
111
+ {
112
+ instances: row.instances,
113
+ getInstanceUrl
114
+ }
115
+ ),
116
+ { flex: 3, minWidth: 280, sortable: false, searchable: false }
117
+ )
118
+ ];
119
+ return /* @__PURE__ */ jsxs(Wrapper, { children: [
120
+ /* @__PURE__ */ jsx(Stack, { direction: "row", justifyContent: "space-between", alignItems: "center", children: /* @__PURE__ */ jsx(Typography, { variant: "h6", children: "Components" }) }),
121
+ error ? /* @__PURE__ */ jsx(Alert, { severity: "error", children: String(error.message ?? error) }) : /* @__PURE__ */ jsx(
122
+ DataList,
123
+ {
124
+ rows,
125
+ columns,
126
+ loading,
127
+ emptyMessage: "No components in this project yet.",
128
+ variant: "outlined"
129
+ }
130
+ )
131
+ ] });
132
+ };
133
+ const Wrapper = stylin(Box)(({ theme }) => ({
134
+ padding: theme.spacing(4),
135
+ maxWidth: 1400,
136
+ mx: "auto",
137
+ width: "100%",
138
+ display: "flex",
139
+ flexDirection: "column",
140
+ gap: theme.spacing(2)
141
+ }));
142
+ const NameCell = stylin(Box)(({ theme }) => ({
143
+ display: "flex",
144
+ alignItems: "center",
145
+ gap: theme.spacing(1)
146
+ }));
147
+
148
+ export { ComponentsTab };
149
+ //# sourceMappingURL=ComponentsTab.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ComponentsTab.esm.js","sources":["../../../../src/features/project/tabs/ComponentsTab.tsx"],"sourcesContent":["import { useApi } from '@backstage/frontend-plugin-api';\nimport { parseInstanceId } from '@massdriver/backstage-plugin-common';\nimport Alert from '@massdriver/ui/Alert';\nimport Box from '@massdriver/ui/Box';\nimport { col } from '@massdriver/ui/DataList';\nimport DataList from '@massdriver/ui/DataList';\nimport IconTile from '@massdriver/ui/IconTile';\nimport Stack from '@massdriver/ui/Stack';\nimport Typography from '@massdriver/ui/Typography';\nimport ExtensionIcon from '@massdriver/ui/icons/ExtensionIcon';\nimport stylin from '@massdriver/ui/stylin';\nimport useAsync from 'react-use/esm/useAsync';\nimport { massdriverApiRef } from '../../../api';\nimport {\n buildAttributesColumn,\n Code,\n} from '../../../components/AttributesColumn';\nimport { internalRoutes } from '../../../internalRoutes';\nimport { EnvInstance, EnvStatusStrip } from './EnvStatus';\n\ninterface ComponentRow {\n id: string;\n name: string;\n description?: string | null;\n attributes?: unknown;\n effectiveAttributes?: unknown;\n ociRepo?: { id: string; name?: string; icon?: string } | null;\n typeName?: string;\n instances: EnvInstance[];\n}\n\nconst COMPONENTS_QUERY = `\n query MassdriverProjectComponents($organizationId: ID!, $id: ID!) {\n project(organizationId: $organizationId, id: $id) {\n id\n components {\n id\n name\n description\n attributes\n effectiveAttributes\n ociRepo { id name icon }\n instances(cursor: { limit: 100 }) {\n items {\n id\n status\n deployedVersion\n resolvedVersion\n availableUpgrade\n environment { id name }\n }\n }\n }\n }\n }\n`;\n\n/** Read-only Components tab: components with status across environments. */\nexport const ComponentsTab = ({ projectId }: { projectId: string }) => {\n const api = useApi(massdriverApiRef);\n const { value, loading, error } = useAsync(async () => {\n const data = (await api.query(COMPONENTS_QUERY, { id: projectId })) as {\n project: {\n components?: Array<{\n id: string;\n name: string;\n description?: string | null;\n attributes?: unknown;\n effectiveAttributes?: unknown;\n ociRepo?: { id: string; name?: string; icon?: string } | null;\n instances?: { items?: (EnvInstance | null)[] | null };\n }> | null;\n } | null;\n };\n return data.project?.components ?? [];\n }, [api, projectId]);\n\n const rows: ComponentRow[] = (value ?? []).map(component => ({\n ...component,\n typeName: component.ociRepo?.name,\n instances: (component.instances?.items ?? []).filter(\n Boolean,\n ) as EnvInstance[],\n }));\n\n const getInstanceUrl = (instance: EnvInstance): string | null => {\n if (!instance.environment?.id || !instance.id) {\n return null;\n }\n const { scopedEnvironmentId, scopedComponentId } = parseInstanceId(\n instance.id,\n );\n return internalRoutes.instance(\n projectId,\n scopedEnvironmentId,\n scopedComponentId,\n );\n };\n\n const columns = [\n col.custom(\n 'name',\n 'Name',\n (_value: unknown, row: ComponentRow) => (\n <NameCell>\n <IconTile\n src={row.ociRepo?.icon}\n alt={row.ociRepo?.name}\n size=\"small\"\n fallback={<ExtensionIcon />}\n />\n <Typography variant=\"body2\">{row.name}</Typography>\n </NameCell>\n ),\n { flex: 2, minWidth: 220, searchable: true },\n ),\n col.text('description', 'Description', {\n flex: 2,\n minWidth: 200,\n sortable: false,\n searchable: true,\n }),\n col.text('typeName', 'Bundle Type', {\n flex: 1,\n minWidth: 160,\n sortable: false,\n }),\n buildAttributesColumn({\n directText:\n 'Key-value attributes assigned directly to this component. Attributes cascade to instances of the component across all environments.',\n effectiveText: (\n <>\n The full attribute map the authorization system evaluates policies\n against for this component — the component's own user attributes plus\n auto-injected <Code>md-*</Code> system attributes.\n </>\n ),\n }),\n col.custom(\n 'status',\n 'Status across environments',\n (_value: unknown, row: ComponentRow) => (\n <EnvStatusStrip\n instances={row.instances}\n getInstanceUrl={getInstanceUrl}\n />\n ),\n { flex: 3, minWidth: 280, sortable: false, searchable: false },\n ),\n ];\n\n return (\n <Wrapper>\n <Stack direction=\"row\" justifyContent=\"space-between\" alignItems=\"center\">\n <Typography variant=\"h6\">Components</Typography>\n </Stack>\n {error ? (\n <Alert severity=\"error\">{String(error.message ?? error)}</Alert>\n ) : (\n <DataList\n rows={rows}\n columns={columns}\n loading={loading}\n emptyMessage=\"No components in this project yet.\"\n variant=\"outlined\"\n />\n )}\n </Wrapper>\n );\n};\n\nconst Wrapper = stylin(Box)(({ theme }: { theme: any }) => ({\n padding: theme.spacing(4),\n maxWidth: 1400,\n mx: 'auto',\n width: '100%',\n display: 'flex',\n flexDirection: 'column',\n gap: theme.spacing(2),\n}));\n\nconst NameCell = stylin(Box)(({ theme }: { theme: any }) => ({\n display: 'flex',\n alignItems: 'center',\n gap: theme.spacing(1),\n}));\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,149 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import Box from '@massdriver/ui/Box';
3
+ import Tooltip from '@massdriver/ui/Tooltip';
4
+ import Typography from '@massdriver/ui/Typography';
5
+ import stylin from '@massdriver/ui/stylin';
6
+ import { instanceStatusColors } from '@massdriver/ui/theme';
7
+ import { RouterLinkAdapter } from '../../../components/RouterLinkAdapter.esm.js';
8
+
9
+ const STATUS_LABELS = {
10
+ INITIALIZED: "Not deployed yet",
11
+ PROVISIONED: "Provisioned",
12
+ DECOMMISSIONED: "Decommissioned",
13
+ FAILED: "Failed",
14
+ EXTERNAL: "External"
15
+ };
16
+ const labelFor = (status) => (status && STATUS_LABELS[status]) ?? status ?? "Unknown";
17
+ const colorFor = (status) => (status && instanceStatusColors[status]) ?? instanceStatusColors.INITIALIZED;
18
+ const EnvStatusStrip = ({
19
+ instances,
20
+ getInstanceUrl
21
+ }) => {
22
+ if (!instances || instances.length === 0) {
23
+ return /* @__PURE__ */ jsx(EmptyText, { variant: "caption", color: "text.secondary", children: "Not deployed in any environment" });
24
+ }
25
+ return /* @__PURE__ */ jsx(Strip, { children: instances.map((instance) => /* @__PURE__ */ jsx(
26
+ EnvStatusChip,
27
+ {
28
+ instance,
29
+ href: getInstanceUrl?.(instance) ?? null
30
+ },
31
+ instance.id
32
+ )) });
33
+ };
34
+ const EnvStatusChip = ({
35
+ instance,
36
+ href
37
+ }) => {
38
+ const color = colorFor(instance.status);
39
+ const versionLabel = instance.deployedVersion ?? "\u2014";
40
+ const showResolved = instance.resolvedVersion && instance.resolvedVersion !== instance.deployedVersion;
41
+ const tooltipRows = [
42
+ instance.environment?.name && {
43
+ label: "Environment",
44
+ value: instance.environment.name
45
+ },
46
+ { label: "Status", value: labelFor(instance.status) },
47
+ {
48
+ label: "Deployed",
49
+ value: instance.deployedVersion ? `v${instance.deployedVersion}` : "Not deployed"
50
+ },
51
+ showResolved && {
52
+ label: "Resolves to",
53
+ value: `v${instance.resolvedVersion}`
54
+ },
55
+ instance.availableUpgrade && {
56
+ label: "Upgrade available",
57
+ value: `v${instance.availableUpgrade}`
58
+ }
59
+ ].filter(Boolean);
60
+ const content = /* @__PURE__ */ jsxs(Chip, { interactive: Boolean(href), children: [
61
+ /* @__PURE__ */ jsx(Dot, { color }),
62
+ /* @__PURE__ */ jsx(Name, { variant: "caption", children: instance.environment?.name }),
63
+ /* @__PURE__ */ jsx(Version, { variant: "caption", children: versionLabel })
64
+ ] });
65
+ return /* @__PURE__ */ jsx(
66
+ Tooltip,
67
+ {
68
+ arrow: true,
69
+ enterDelay: 400,
70
+ placement: "top",
71
+ slotProps: { tooltip: { sx: { maxWidth: 260 } } },
72
+ title: /* @__PURE__ */ jsx(TooltipBody, { children: tooltipRows.map((row) => /* @__PURE__ */ jsxs(TooltipRow, { children: [
73
+ /* @__PURE__ */ jsx(TooltipLabel, { children: row.label }),
74
+ /* @__PURE__ */ jsx(TooltipValue, { children: row.value })
75
+ ] }, row.label)) }),
76
+ children: href ? /* @__PURE__ */ jsx(ChipLink, { href, children: content }) : content
77
+ }
78
+ );
79
+ };
80
+ const Strip = stylin(Box)(({ theme }) => ({
81
+ display: "flex",
82
+ flexWrap: "wrap",
83
+ gap: theme.spacing(0.75),
84
+ alignItems: "center"
85
+ }));
86
+ const EmptyText = stylin(Typography)(({ theme }) => ({
87
+ fontStyle: "italic",
88
+ paddingTop: theme.spacing(0.5),
89
+ paddingBottom: theme.spacing(0.5)
90
+ }));
91
+ const ChipLink = stylin(RouterLinkAdapter)({ textDecoration: "none" });
92
+ const Chip = stylin(Box, ["interactive"])(
93
+ ({ theme, interactive }) => ({
94
+ display: "inline-flex",
95
+ alignItems: "center",
96
+ gap: theme.spacing(0.5),
97
+ padding: `${theme.spacing(0.25)} ${theme.spacing(1)}`,
98
+ borderRadius: theme.custom.general.borderRadiusSm,
99
+ backgroundColor: theme.palette.background.field,
100
+ border: `1px solid ${theme.palette.divider}`,
101
+ textDecoration: "none",
102
+ transition: "background-color 120ms ease, border-color 120ms ease",
103
+ ...interactive && {
104
+ cursor: "pointer",
105
+ "&:hover": {
106
+ backgroundColor: theme.palette.action.hover,
107
+ borderColor: theme.palette.text.secondary
108
+ }
109
+ }
110
+ })
111
+ );
112
+ const Dot = stylin("span", ["color"])(({ color }) => ({
113
+ width: 8,
114
+ height: 8,
115
+ borderRadius: "50%",
116
+ flexShrink: 0,
117
+ backgroundColor: color
118
+ }));
119
+ const Name = stylin(Typography)(({ theme }) => ({
120
+ color: theme.palette.text.primary,
121
+ fontWeight: theme.typography.fontWeightMedium
122
+ }));
123
+ const Version = stylin(Typography)(({ theme }) => ({
124
+ color: theme.palette.text.secondary,
125
+ fontFamily: theme.typography.fontFamilyMono
126
+ }));
127
+ const TooltipBody = stylin(Box)(({ theme }) => ({
128
+ display: "flex",
129
+ flexDirection: "column",
130
+ gap: theme.spacing(0.25)
131
+ }));
132
+ const TooltipRow = stylin(Box)(({ theme }) => ({
133
+ display: "flex",
134
+ gap: theme.spacing(1),
135
+ fontSize: 11,
136
+ lineHeight: 1.4
137
+ }));
138
+ const TooltipLabel = stylin("span")({
139
+ fontWeight: 600,
140
+ color: "inherit",
141
+ opacity: 0.75
142
+ });
143
+ const TooltipValue = stylin("span")(({ theme }) => ({
144
+ color: "inherit",
145
+ fontFamily: theme.typography.fontFamilyMono
146
+ }));
147
+
148
+ export { EnvStatusStrip };
149
+ //# sourceMappingURL=EnvStatus.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EnvStatus.esm.js","sources":["../../../../src/features/project/tabs/EnvStatus.tsx"],"sourcesContent":["import Box from '@massdriver/ui/Box';\nimport Tooltip from '@massdriver/ui/Tooltip';\nimport Typography from '@massdriver/ui/Typography';\nimport stylin from '@massdriver/ui/stylin';\nimport { instanceStatusColors } from '@massdriver/ui/theme';\nimport { RouterLinkAdapter } from '../../../components/RouterLinkAdapter';\n\nexport interface EnvInstance {\n id: string;\n status?: string | null;\n deployedVersion?: string | null;\n resolvedVersion?: string | null;\n availableUpgrade?: string | null;\n environment?: { id: string; name?: string | null } | null;\n}\n\nconst STATUS_LABELS: Record<string, string> = {\n INITIALIZED: 'Not deployed yet',\n PROVISIONED: 'Provisioned',\n DECOMMISSIONED: 'Decommissioned',\n FAILED: 'Failed',\n EXTERNAL: 'External',\n};\n\nconst labelFor = (status?: string | null) =>\n (status && STATUS_LABELS[status]) ?? status ?? 'Unknown';\nconst colorFor = (status?: string | null) =>\n (status && instanceStatusColors[status]) ?? instanceStatusColors.INITIALIZED;\n\n/** Chips showing an instance's status per environment (mirrors the web app). */\nexport const EnvStatusStrip = ({\n instances,\n getInstanceUrl,\n}: {\n instances?: EnvInstance[] | null;\n getInstanceUrl?: (instance: EnvInstance) => string | null;\n}) => {\n if (!instances || instances.length === 0) {\n return (\n <EmptyText variant=\"caption\" color=\"text.secondary\">\n Not deployed in any environment\n </EmptyText>\n );\n }\n return (\n <Strip>\n {instances.map(instance => (\n <EnvStatusChip\n key={instance.id}\n instance={instance}\n href={getInstanceUrl?.(instance) ?? null}\n />\n ))}\n </Strip>\n );\n};\n\nconst EnvStatusChip = ({\n instance,\n href,\n}: {\n instance: EnvInstance;\n href: string | null;\n}) => {\n const color = colorFor(instance.status);\n const versionLabel = instance.deployedVersion ?? '—';\n const showResolved =\n instance.resolvedVersion &&\n instance.resolvedVersion !== instance.deployedVersion;\n\n const tooltipRows = [\n instance.environment?.name && {\n label: 'Environment',\n value: instance.environment.name,\n },\n { label: 'Status', value: labelFor(instance.status) },\n {\n label: 'Deployed',\n value: instance.deployedVersion\n ? `v${instance.deployedVersion}`\n : 'Not deployed',\n },\n showResolved && {\n label: 'Resolves to',\n value: `v${instance.resolvedVersion}`,\n },\n instance.availableUpgrade && {\n label: 'Upgrade available',\n value: `v${instance.availableUpgrade}`,\n },\n ].filter(Boolean) as { label: string; value: string }[];\n\n const content = (\n <Chip interactive={Boolean(href)}>\n <Dot color={color} />\n <Name variant=\"caption\">{instance.environment?.name}</Name>\n <Version variant=\"caption\">{versionLabel}</Version>\n </Chip>\n );\n\n return (\n <Tooltip\n arrow\n enterDelay={400}\n placement=\"top\"\n slotProps={{ tooltip: { sx: { maxWidth: 260 } } }}\n title={\n <TooltipBody>\n {tooltipRows.map(row => (\n <TooltipRow key={row.label}>\n <TooltipLabel>{row.label}</TooltipLabel>\n <TooltipValue>{row.value}</TooltipValue>\n </TooltipRow>\n ))}\n </TooltipBody>\n }\n >\n {href ? <ChipLink href={href}>{content}</ChipLink> : content}\n </Tooltip>\n );\n};\n\nconst Strip = stylin(Box)(({ theme }: { theme: any }) => ({\n display: 'flex',\n flexWrap: 'wrap',\n gap: theme.spacing(0.75),\n alignItems: 'center',\n}));\n\nconst EmptyText = stylin(Typography)(({ theme }: { theme: any }) => ({\n fontStyle: 'italic',\n paddingTop: theme.spacing(0.5),\n paddingBottom: theme.spacing(0.5),\n}));\n\nconst ChipLink = stylin(RouterLinkAdapter)({ textDecoration: 'none' });\n\nconst Chip = stylin(Box, ['interactive'])(\n ({ theme, interactive }: { theme: any; interactive: boolean }) => ({\n display: 'inline-flex',\n alignItems: 'center',\n gap: theme.spacing(0.5),\n padding: `${theme.spacing(0.25)} ${theme.spacing(1)}`,\n borderRadius: theme.custom.general.borderRadiusSm,\n backgroundColor: theme.palette.background.field,\n border: `1px solid ${theme.palette.divider}`,\n textDecoration: 'none',\n transition: 'background-color 120ms ease, border-color 120ms ease',\n ...(interactive && {\n cursor: 'pointer',\n '&:hover': {\n backgroundColor: theme.palette.action.hover,\n borderColor: theme.palette.text.secondary,\n },\n }),\n }),\n);\n\nconst Dot = stylin('span', ['color'])(({ color }: { color: string }) => ({\n width: 8,\n height: 8,\n borderRadius: '50%',\n flexShrink: 0,\n backgroundColor: color,\n}));\n\nconst Name = stylin(Typography)(({ theme }: { theme: any }) => ({\n color: theme.palette.text.primary,\n fontWeight: theme.typography.fontWeightMedium,\n}));\n\nconst Version = stylin(Typography)(({ theme }: { theme: any }) => ({\n color: theme.palette.text.secondary,\n fontFamily: theme.typography.fontFamilyMono,\n}));\n\nconst TooltipBody = stylin(Box)(({ theme }: { theme: any }) => ({\n display: 'flex',\n flexDirection: 'column',\n gap: theme.spacing(0.25),\n}));\n\nconst TooltipRow = stylin(Box)(({ theme }: { theme: any }) => ({\n display: 'flex',\n gap: theme.spacing(1),\n fontSize: 11,\n lineHeight: 1.4,\n}));\n\nconst TooltipLabel = stylin('span')({\n fontWeight: 600,\n color: 'inherit',\n opacity: 0.75,\n});\n\nconst TooltipValue = stylin('span')(({ theme }: { theme: any }) => ({\n color: 'inherit',\n fontFamily: theme.typography.fontFamilyMono,\n}));\n"],"names":[],"mappings":";;;;;;;;AAgBA,MAAM,aAAA,GAAwC;AAAA,EAC5C,WAAA,EAAa,kBAAA;AAAA,EACb,WAAA,EAAa,aAAA;AAAA,EACb,cAAA,EAAgB,gBAAA;AAAA,EAChB,MAAA,EAAQ,QAAA;AAAA,EACR,QAAA,EAAU;AACZ,CAAA;AAEA,MAAM,WAAW,CAAC,MAAA,KAAA,CACf,UAAU,aAAA,CAAc,MAAM,MAAM,MAAA,IAAU,SAAA;AACjD,MAAM,WAAW,CAAC,MAAA,KAAA,CACf,UAAU,oBAAA,CAAqB,MAAM,MAAM,oBAAA,CAAqB,WAAA;AAG5D,MAAM,iBAAiB,CAAC;AAAA,EAC7B,SAAA;AAAA,EACA;AACF,CAAA,KAGM;AACJ,EAAA,IAAI,CAAC,SAAA,IAAa,SAAA,CAAU,MAAA,KAAW,CAAA,EAAG;AACxC,IAAA,2BACG,SAAA,EAAA,EAAU,OAAA,EAAQ,SAAA,EAAU,KAAA,EAAM,kBAAiB,QAAA,EAAA,iCAAA,EAEpD,CAAA;AAAA,EAEJ;AACA,EAAA,uBACE,GAAA,CAAC,KAAA,EAAA,EACE,QAAA,EAAA,SAAA,CAAU,GAAA,CAAI,CAAA,QAAA,qBACb,GAAA;AAAA,IAAC,aAAA;AAAA,IAAA;AAAA,MAEC,QAAA;AAAA,MACA,IAAA,EAAM,cAAA,GAAiB,QAAQ,CAAA,IAAK;AAAA,KAAA;AAAA,IAF/B,QAAA,CAAS;AAAA,GAIjB,CAAA,EACH,CAAA;AAEJ;AAEA,MAAM,gBAAgB,CAAC;AAAA,EACrB,QAAA;AAAA,EACA;AACF,CAAA,KAGM;AACJ,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,QAAA,CAAS,MAAM,CAAA;AACtC,EAAA,MAAM,YAAA,GAAe,SAAS,eAAA,IAAmB,QAAA;AACjD,EAAA,MAAM,YAAA,GACJ,QAAA,CAAS,eAAA,IACT,QAAA,CAAS,oBAAoB,QAAA,CAAS,eAAA;AAExC,EAAA,MAAM,WAAA,GAAc;AAAA,IAClB,QAAA,CAAS,aAAa,IAAA,IAAQ;AAAA,MAC5B,KAAA,EAAO,aAAA;AAAA,MACP,KAAA,EAAO,SAAS,WAAA,CAAY;AAAA,KAC9B;AAAA,IACA,EAAE,KAAA,EAAO,QAAA,EAAU,OAAO,QAAA,CAAS,QAAA,CAAS,MAAM,CAAA,EAAE;AAAA,IACpD;AAAA,MACE,KAAA,EAAO,UAAA;AAAA,MACP,OAAO,QAAA,CAAS,eAAA,GACZ,CAAA,CAAA,EAAI,QAAA,CAAS,eAAe,CAAA,CAAA,GAC5B;AAAA,KACN;AAAA,IACA,YAAA,IAAgB;AAAA,MACd,KAAA,EAAO,aAAA;AAAA,MACP,KAAA,EAAO,CAAA,CAAA,EAAI,QAAA,CAAS,eAAe,CAAA;AAAA,KACrC;AAAA,IACA,SAAS,gBAAA,IAAoB;AAAA,MAC3B,KAAA,EAAO,mBAAA;AAAA,MACP,KAAA,EAAO,CAAA,CAAA,EAAI,QAAA,CAAS,gBAAgB,CAAA;AAAA;AACtC,GACF,CAAE,OAAO,OAAO,CAAA;AAEhB,EAAA,MAAM,0BACJ,IAAA,CAAC,IAAA,EAAA,EAAK,WAAA,EAAa,OAAA,CAAQ,IAAI,CAAA,EAC7B,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,OAAI,KAAA,EAAc,CAAA;AAAA,wBAClB,IAAA,EAAA,EAAK,OAAA,EAAQ,SAAA,EAAW,QAAA,EAAA,QAAA,CAAS,aAAa,IAAA,EAAK,CAAA;AAAA,oBACpD,GAAA,CAAC,OAAA,EAAA,EAAQ,OAAA,EAAQ,SAAA,EAAW,QAAA,EAAA,YAAA,EAAa;AAAA,GAAA,EAC3C,CAAA;AAGF,EAAA,uBACE,GAAA;AAAA,IAAC,OAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAK,IAAA;AAAA,MACL,UAAA,EAAY,GAAA;AAAA,MACZ,SAAA,EAAU,KAAA;AAAA,MACV,SAAA,EAAW,EAAE,OAAA,EAAS,EAAE,IAAI,EAAE,QAAA,EAAU,GAAA,EAAI,EAAE,EAAE;AAAA,MAChD,uBACE,GAAA,CAAC,WAAA,EAAA,EACE,sBAAY,GAAA,CAAI,CAAA,GAAA,0BACd,UAAA,EAAA,EACC,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,YAAA,EAAA,EAAc,cAAI,KAAA,EAAM,CAAA;AAAA,wBACzB,GAAA,CAAC,YAAA,EAAA,EAAc,QAAA,EAAA,GAAA,CAAI,KAAA,EAAM;AAAA,OAAA,EAAA,EAFV,GAAA,CAAI,KAGrB,CACD,CAAA,EACH,CAAA;AAAA,MAGD,QAAA,EAAA,IAAA,mBAAO,GAAA,CAAC,QAAA,EAAA,EAAS,IAAA,EAAa,mBAAQ,CAAA,GAAc;AAAA;AAAA,GACvD;AAEJ,CAAA;AAEA,MAAM,QAAQ,MAAA,CAAO,GAAG,EAAE,CAAC,EAAE,OAAM,MAAuB;AAAA,EACxD,OAAA,EAAS,MAAA;AAAA,EACT,QAAA,EAAU,MAAA;AAAA,EACV,GAAA,EAAK,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA;AAAA,EACvB,UAAA,EAAY;AACd,CAAA,CAAE,CAAA;AAEF,MAAM,YAAY,MAAA,CAAO,UAAU,EAAE,CAAC,EAAE,OAAM,MAAuB;AAAA,EACnE,SAAA,EAAW,QAAA;AAAA,EACX,UAAA,EAAY,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA;AAAA,EAC7B,aAAA,EAAe,KAAA,CAAM,OAAA,CAAQ,GAAG;AAClC,CAAA,CAAE,CAAA;AAEF,MAAM,WAAW,MAAA,CAAO,iBAAiB,EAAE,EAAE,cAAA,EAAgB,QAAQ,CAAA;AAErE,MAAM,IAAA,GAAO,MAAA,CAAO,GAAA,EAAK,CAAC,aAAa,CAAC,CAAA;AAAA,EACtC,CAAC,EAAE,KAAA,EAAO,WAAA,EAAY,MAA6C;AAAA,IACjE,OAAA,EAAS,aAAA;AAAA,IACT,UAAA,EAAY,QAAA;AAAA,IACZ,GAAA,EAAK,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA;AAAA,IACtB,OAAA,EAAS,CAAA,EAAG,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAC,CAAA,CAAA,EAAI,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAA;AAAA,IACnD,YAAA,EAAc,KAAA,CAAM,MAAA,CAAO,OAAA,CAAQ,cAAA;AAAA,IACnC,eAAA,EAAiB,KAAA,CAAM,OAAA,CAAQ,UAAA,CAAW,KAAA;AAAA,IAC1C,MAAA,EAAQ,CAAA,UAAA,EAAa,KAAA,CAAM,OAAA,CAAQ,OAAO,CAAA,CAAA;AAAA,IAC1C,cAAA,EAAgB,MAAA;AAAA,IAChB,UAAA,EAAY,sDAAA;AAAA,IACZ,GAAI,WAAA,IAAe;AAAA,MACjB,MAAA,EAAQ,SAAA;AAAA,MACR,SAAA,EAAW;AAAA,QACT,eAAA,EAAiB,KAAA,CAAM,OAAA,CAAQ,MAAA,CAAO,KAAA;AAAA,QACtC,WAAA,EAAa,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK;AAAA;AAClC;AACF,GACF;AACF,CAAA;AAEA,MAAM,GAAA,GAAM,MAAA,CAAO,MAAA,EAAQ,CAAC,OAAO,CAAC,CAAA,CAAE,CAAC,EAAE,KAAA,EAAM,MAA0B;AAAA,EACvE,KAAA,EAAO,CAAA;AAAA,EACP,MAAA,EAAQ,CAAA;AAAA,EACR,YAAA,EAAc,KAAA;AAAA,EACd,UAAA,EAAY,CAAA;AAAA,EACZ,eAAA,EAAiB;AACnB,CAAA,CAAE,CAAA;AAEF,MAAM,OAAO,MAAA,CAAO,UAAU,EAAE,CAAC,EAAE,OAAM,MAAuB;AAAA,EAC9D,KAAA,EAAO,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK,OAAA;AAAA,EAC1B,UAAA,EAAY,MAAM,UAAA,CAAW;AAC/B,CAAA,CAAE,CAAA;AAEF,MAAM,UAAU,MAAA,CAAO,UAAU,EAAE,CAAC,EAAE,OAAM,MAAuB;AAAA,EACjE,KAAA,EAAO,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK,SAAA;AAAA,EAC1B,UAAA,EAAY,MAAM,UAAA,CAAW;AAC/B,CAAA,CAAE,CAAA;AAEF,MAAM,cAAc,MAAA,CAAO,GAAG,EAAE,CAAC,EAAE,OAAM,MAAuB;AAAA,EAC9D,OAAA,EAAS,MAAA;AAAA,EACT,aAAA,EAAe,QAAA;AAAA,EACf,GAAA,EAAK,KAAA,CAAM,OAAA,CAAQ,IAAI;AACzB,CAAA,CAAE,CAAA;AAEF,MAAM,aAAa,MAAA,CAAO,GAAG,EAAE,CAAC,EAAE,OAAM,MAAuB;AAAA,EAC7D,OAAA,EAAS,MAAA;AAAA,EACT,GAAA,EAAK,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA;AAAA,EACpB,QAAA,EAAU,EAAA;AAAA,EACV,UAAA,EAAY;AACd,CAAA,CAAE,CAAA;AAEF,MAAM,YAAA,GAAe,MAAA,CAAO,MAAM,CAAA,CAAE;AAAA,EAClC,UAAA,EAAY,GAAA;AAAA,EACZ,KAAA,EAAO,SAAA;AAAA,EACP,OAAA,EAAS;AACX,CAAC,CAAA;AAED,MAAM,eAAe,MAAA,CAAO,MAAM,EAAE,CAAC,EAAE,OAAM,MAAuB;AAAA,EAClE,KAAA,EAAO,SAAA;AAAA,EACP,UAAA,EAAY,MAAM,UAAA,CAAW;AAC/B,CAAA,CAAE,CAAA;;;;"}