@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,151 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import Box from '@massdriver/ui/Box';
3
+ import Typography from '@massdriver/ui/Typography';
4
+ import ErrorOutlineIcon from '@massdriver/ui/icons/ErrorOutlineIcon';
5
+ import CheckCircleOutlineIcon from '@massdriver/ui/icons/CheckCircleOutlineIcon';
6
+ import stylin from '@massdriver/ui/stylin';
7
+ import { isFiring, getSeverity, formatMetricLine, describeThreshold, getStatusLabel, formatAbsoluteDateTime, formatAlarmDimensions } from './helpers.esm.js';
8
+
9
+ const AlarmCard = ({ alarm }) => {
10
+ const firing = isFiring(alarm);
11
+ const severity = getSeverity(alarm);
12
+ const metricLine = formatMetricLine(alarm.metric);
13
+ const dimensions = alarm.metric?.dimensions ?? [];
14
+ const threshold = describeThreshold(alarm);
15
+ const occurredAt = alarm.currentState?.occurredAt;
16
+ const message = alarm.currentState?.message;
17
+ const displayName = alarm.displayName || "Unnamed alarm";
18
+ return /* @__PURE__ */ jsxs(Card, { children: [
19
+ /* @__PURE__ */ jsxs(Header, { severity, children: [
20
+ /* @__PURE__ */ jsxs(HeaderLeft, { children: [
21
+ firing ? /* @__PURE__ */ jsx(ErrorOutlineIcon, { fontSize: "inherit" }) : alarm.currentState ? /* @__PURE__ */ jsx(CheckCircleOutlineIcon, { fontSize: "inherit" }) : null,
22
+ /* @__PURE__ */ jsx(HeaderLabel, { children: getStatusLabel(alarm.currentState) })
23
+ ] }),
24
+ occurredAt ? /* @__PURE__ */ jsxs(HeaderTime, { children: [
25
+ firing ? "Triggered" : "Last cleared",
26
+ " ",
27
+ formatAbsoluteDateTime(occurredAt)
28
+ ] }) : null
29
+ ] }),
30
+ /* @__PURE__ */ jsxs(Body, { children: [
31
+ /* @__PURE__ */ jsx(Title, { title: displayName, children: displayName }),
32
+ metricLine ? /* @__PURE__ */ jsx(MetricLine, { title: metricLine, children: metricLine }) : null,
33
+ threshold ? /* @__PURE__ */ jsxs(ThresholdBlock, { children: [
34
+ /* @__PURE__ */ jsx(ThresholdLabel, { children: "Triggers when" }),
35
+ " ",
36
+ /* @__PURE__ */ jsx(ThresholdValue, { children: threshold })
37
+ ] }) : null,
38
+ message ? /* @__PURE__ */ jsx(Message, { children: message }) : null,
39
+ dimensions.length ? /* @__PURE__ */ jsx(DimensionsFooter, { title: formatAlarmDimensions(dimensions), children: formatAlarmDimensions(dimensions) }) : null
40
+ ] })
41
+ ] });
42
+ };
43
+ const Card = stylin(Box)(({ theme }) => ({
44
+ display: "flex",
45
+ flexDirection: "column",
46
+ borderRadius: 1,
47
+ border: `1px solid ${theme.palette.divider}`,
48
+ backgroundColor: theme.palette.background.paper,
49
+ overflow: "hidden"
50
+ }));
51
+ const Header = stylin(Box, ["severity"])(
52
+ ({ theme, severity }) => {
53
+ const palette = {
54
+ firing: {
55
+ color: theme.palette.error.contrastText,
56
+ backgroundColor: theme.palette.error.main
57
+ },
58
+ ok: {
59
+ color: theme.palette.success.dark,
60
+ backgroundColor: theme.palette.success.lighter ?? theme.palette.success.light
61
+ },
62
+ unknown: {
63
+ color: theme.palette.text.secondary,
64
+ backgroundColor: theme.palette.action.hover
65
+ }
66
+ };
67
+ const tone = palette[severity] ?? palette.unknown;
68
+ return {
69
+ display: "flex",
70
+ alignItems: "center",
71
+ justifyContent: "space-between",
72
+ gap: theme.spacing(1),
73
+ padding: theme.spacing(0.5, 1.25),
74
+ color: tone.color,
75
+ backgroundColor: tone.backgroundColor,
76
+ fontSize: theme.typography.pxToRem(11)
77
+ };
78
+ }
79
+ );
80
+ const HeaderLeft = stylin(Box)(({ theme }) => ({
81
+ display: "flex",
82
+ alignItems: "center",
83
+ gap: theme.spacing(0.5),
84
+ fontSize: 14
85
+ }));
86
+ const HeaderLabel = stylin(Box)(({ theme }) => ({
87
+ fontWeight: 600,
88
+ letterSpacing: "0.04em",
89
+ textTransform: "uppercase",
90
+ fontSize: theme.typography.pxToRem(10)
91
+ }));
92
+ const HeaderTime = stylin(Box)(({ theme }) => ({
93
+ fontSize: theme.typography.pxToRem(11),
94
+ opacity: 0.95
95
+ }));
96
+ const Body = stylin(Box)(({ theme }) => ({
97
+ display: "flex",
98
+ flexDirection: "column",
99
+ gap: theme.spacing(0.75),
100
+ padding: theme.spacing(1.25)
101
+ }));
102
+ const Title = stylin(Typography)(({ theme }) => ({
103
+ fontSize: theme.typography.pxToRem(14),
104
+ fontWeight: 600,
105
+ color: theme.palette.text.primary,
106
+ overflow: "hidden",
107
+ textOverflow: "ellipsis",
108
+ whiteSpace: "nowrap"
109
+ }));
110
+ const MetricLine = stylin(Typography)(({ theme }) => ({
111
+ fontSize: theme.typography.pxToRem(12),
112
+ color: theme.palette.text.secondary,
113
+ overflow: "hidden",
114
+ textOverflow: "ellipsis",
115
+ whiteSpace: "nowrap"
116
+ }));
117
+ const ThresholdBlock = stylin(Box)(({ theme }) => ({
118
+ padding: theme.spacing(0.75, 1),
119
+ borderRadius: 1,
120
+ backgroundColor: theme.palette.action.hover,
121
+ fontSize: theme.typography.pxToRem(12),
122
+ lineHeight: 1.4
123
+ }));
124
+ const ThresholdLabel = stylin("span")(({ theme }) => ({
125
+ color: theme.palette.text.secondary
126
+ }));
127
+ const ThresholdValue = stylin("span")(({ theme }) => ({
128
+ color: theme.palette.text.primary,
129
+ fontWeight: 500
130
+ }));
131
+ const Message = stylin(Typography)(({ theme }) => ({
132
+ fontSize: theme.typography.pxToRem(12),
133
+ color: theme.palette.text.secondary,
134
+ lineHeight: 1.4,
135
+ whiteSpace: "pre-wrap",
136
+ wordBreak: "break-word"
137
+ }));
138
+ const DimensionsFooter = stylin(Typography)(({ theme }) => ({
139
+ fontSize: theme.typography.pxToRem(11),
140
+ color: theme.palette.text.disabled,
141
+ display: "-webkit-box",
142
+ WebkitLineClamp: 2,
143
+ WebkitBoxOrient: "vertical",
144
+ overflow: "hidden",
145
+ textOverflow: "ellipsis",
146
+ lineHeight: 1.4,
147
+ wordBreak: "break-all"
148
+ }));
149
+
150
+ export { AlarmCard, AlarmCard as default };
151
+ //# sourceMappingURL=AlarmCard.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AlarmCard.esm.js","sources":["../../../../src/features/environment/InstanceDrawer/AlarmCard.tsx"],"sourcesContent":["import Box from '@massdriver/ui/Box';\nimport Typography from '@massdriver/ui/Typography';\nimport ErrorOutlineIcon from '@massdriver/ui/icons/ErrorOutlineIcon';\nimport CheckCircleOutlineIcon from '@massdriver/ui/icons/CheckCircleOutlineIcon';\nimport stylin from '@massdriver/ui/stylin';\nimport {\n describeThreshold,\n formatAbsoluteDateTime,\n formatAlarmDimensions,\n formatMetricLine,\n getSeverity,\n getStatusLabel,\n isFiring,\n} from './helpers';\nimport type { Alarm } from './types';\n\n/** Read-only alarm card, faithful port of the web app's AlarmCard. */\nexport const AlarmCard = ({ alarm }: { alarm: Alarm }) => {\n const firing = isFiring(alarm);\n const severity = getSeverity(alarm);\n const metricLine = formatMetricLine(alarm.metric);\n const dimensions = alarm.metric?.dimensions ?? [];\n const threshold = describeThreshold(alarm);\n const occurredAt = alarm.currentState?.occurredAt;\n const message = alarm.currentState?.message;\n const displayName = alarm.displayName || 'Unnamed alarm';\n\n return (\n <Card>\n <Header severity={severity}>\n <HeaderLeft>\n {firing ? (\n <ErrorOutlineIcon fontSize=\"inherit\" />\n ) : alarm.currentState ? (\n <CheckCircleOutlineIcon fontSize=\"inherit\" />\n ) : null}\n <HeaderLabel>{getStatusLabel(alarm.currentState)}</HeaderLabel>\n </HeaderLeft>\n {occurredAt ? (\n <HeaderTime>\n {firing ? 'Triggered' : 'Last cleared'}{' '}\n {formatAbsoluteDateTime(occurredAt)}\n </HeaderTime>\n ) : null}\n </Header>\n <Body>\n <Title title={displayName}>{displayName}</Title>\n {metricLine ? (\n <MetricLine title={metricLine}>{metricLine}</MetricLine>\n ) : null}\n {threshold ? (\n <ThresholdBlock>\n <ThresholdLabel>Triggers when</ThresholdLabel>{' '}\n <ThresholdValue>{threshold}</ThresholdValue>\n </ThresholdBlock>\n ) : null}\n {message ? <Message>{message}</Message> : null}\n {dimensions.length ? (\n <DimensionsFooter title={formatAlarmDimensions(dimensions)}>\n {formatAlarmDimensions(dimensions)}\n </DimensionsFooter>\n ) : null}\n </Body>\n </Card>\n );\n};\n\nexport default AlarmCard;\n\nconst Card = stylin(Box)(({ theme }: { theme: any }) => ({\n display: 'flex',\n flexDirection: 'column',\n borderRadius: 1,\n border: `1px solid ${theme.palette.divider}`,\n backgroundColor: theme.palette.background.paper,\n overflow: 'hidden',\n}));\n\nconst Header = stylin(Box, ['severity'])(\n ({ theme, severity }: { theme: any; severity: string }) => {\n const palette: Record<string, { color: string; backgroundColor: string }> =\n {\n firing: {\n color: theme.palette.error.contrastText,\n backgroundColor: theme.palette.error.main,\n },\n ok: {\n color: theme.palette.success.dark,\n backgroundColor:\n theme.palette.success.lighter ?? theme.palette.success.light,\n },\n unknown: {\n color: theme.palette.text.secondary,\n backgroundColor: theme.palette.action.hover,\n },\n };\n const tone = palette[severity] ?? palette.unknown;\n return {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: theme.spacing(1),\n padding: theme.spacing(0.5, 1.25),\n color: tone.color,\n backgroundColor: tone.backgroundColor,\n fontSize: theme.typography.pxToRem(11),\n };\n },\n);\n\nconst HeaderLeft = stylin(Box)(({ theme }: { theme: any }) => ({\n display: 'flex',\n alignItems: 'center',\n gap: theme.spacing(0.5),\n fontSize: 14,\n}));\n\nconst HeaderLabel = stylin(Box)(({ theme }: { theme: any }) => ({\n fontWeight: 600,\n letterSpacing: '0.04em',\n textTransform: 'uppercase',\n fontSize: theme.typography.pxToRem(10),\n}));\n\nconst HeaderTime = stylin(Box)(({ theme }: { theme: any }) => ({\n fontSize: theme.typography.pxToRem(11),\n opacity: 0.95,\n}));\n\nconst Body = stylin(Box)(({ theme }: { theme: any }) => ({\n display: 'flex',\n flexDirection: 'column',\n gap: theme.spacing(0.75),\n padding: theme.spacing(1.25),\n}));\n\nconst Title = stylin(Typography)(({ theme }: { theme: any }) => ({\n fontSize: theme.typography.pxToRem(14),\n fontWeight: 600,\n color: theme.palette.text.primary,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n}));\n\nconst MetricLine = stylin(Typography)(({ theme }: { theme: any }) => ({\n fontSize: theme.typography.pxToRem(12),\n color: theme.palette.text.secondary,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n}));\n\nconst ThresholdBlock = stylin(Box)(({ theme }: { theme: any }) => ({\n padding: theme.spacing(0.75, 1),\n borderRadius: 1,\n backgroundColor: theme.palette.action.hover,\n fontSize: theme.typography.pxToRem(12),\n lineHeight: 1.4,\n}));\n\nconst ThresholdLabel = stylin('span')(({ theme }: { theme: any }) => ({\n color: theme.palette.text.secondary,\n}));\n\nconst ThresholdValue = stylin('span')(({ theme }: { theme: any }) => ({\n color: theme.palette.text.primary,\n fontWeight: 500,\n}));\n\nconst Message = stylin(Typography)(({ theme }: { theme: any }) => ({\n fontSize: theme.typography.pxToRem(12),\n color: theme.palette.text.secondary,\n lineHeight: 1.4,\n whiteSpace: 'pre-wrap',\n wordBreak: 'break-word',\n}));\n\nconst DimensionsFooter = stylin(Typography)(({ theme }: { theme: any }) => ({\n fontSize: theme.typography.pxToRem(11),\n color: theme.palette.text.disabled,\n display: '-webkit-box',\n WebkitLineClamp: 2,\n WebkitBoxOrient: 'vertical',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n lineHeight: 1.4,\n wordBreak: 'break-all',\n}));\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,165 @@
1
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
+ import { useApi } from '@backstage/frontend-plugin-api';
3
+ import { useSearchParams } from 'react-router-dom';
4
+ import { parseEnvironmentId, composeInstanceId, instanceUrl } from '@massdriver/backstage-plugin-common';
5
+ import Box from '@massdriver/ui/Box';
6
+ import Alert from '@massdriver/ui/Alert';
7
+ import LoadingIndicator from '@massdriver/ui/LoadingIndicator';
8
+ import stylin from '@massdriver/ui/stylin';
9
+ import { massdriverApiRef } from '../../../api.esm.js';
10
+ import { NotFound } from '../../../components/NotFound.esm.js';
11
+ import { useInstanceApiQuery } from './useInstanceApiQuery.esm.js';
12
+ import { useResizableWidth } from './useResizableWidth.esm.js';
13
+ import { PANEL_QUERY } from './queries.esm.js';
14
+ import { InstanceDrawerHeader } from './InstanceDrawerHeader.esm.js';
15
+ import { InstanceTabs } from './InstanceTabs.esm.js';
16
+ import { ConfigTab } from './tabs/ConfigTab.esm.js';
17
+ import { OverviewTab } from './tabs/OverviewTab.esm.js';
18
+ import { ResourcesTab } from './tabs/ResourcesTab.esm.js';
19
+ import { DependenciesTab } from './tabs/DependenciesTab.esm.js';
20
+ import { MonitorTab } from './tabs/MonitorTab.esm.js';
21
+ import { HistoryTab } from './tabs/HistoryTab.esm.js';
22
+ import { GuideTab } from './tabs/GuideTab.esm.js';
23
+ import { SecretsTab } from './tabs/SecretsTab.esm.js';
24
+
25
+ const DEFAULT_TAB = "overview";
26
+ const BASE_TABS = [
27
+ { id: "overview", label: "Overview" },
28
+ { id: "config", label: "Config" },
29
+ { id: "history", label: "History" },
30
+ { id: "monitor", label: "Monitor" },
31
+ { id: "guide", label: "Guide" },
32
+ { id: "dependencies", label: "Dependencies" },
33
+ { id: "resources", label: "Resources" }
34
+ ];
35
+ const InstanceDrawer = ({
36
+ projectId,
37
+ environmentId,
38
+ scopedComponentId,
39
+ onClose
40
+ }) => {
41
+ const api = useApi(massdriverApiRef);
42
+ const [searchParams, setSearchParams] = useSearchParams();
43
+ const { width, panelRef, onResizeStart } = useResizableWidth();
44
+ const isOpen = Boolean(scopedComponentId);
45
+ const activeTab = searchParams.get("tab") || DEFAULT_TAB;
46
+ const { scopedEnvironmentId } = parseEnvironmentId(environmentId);
47
+ const fullInstanceId = isOpen && projectId && scopedEnvironmentId && scopedComponentId ? composeInstanceId(projectId, scopedEnvironmentId, scopedComponentId) : null;
48
+ const { value, loading, error } = useInstanceApiQuery(PANEL_QUERY, fullInstanceId);
49
+ const instance = value?.instance;
50
+ const secretFields = (instance?.secretFields ?? []).filter(
51
+ Boolean
52
+ );
53
+ const tabs = secretFields.length ? [
54
+ ...BASE_TABS.slice(0, 3),
55
+ { id: "secrets", label: "Secrets" },
56
+ ...BASE_TABS.slice(3)
57
+ ] : BASE_TABS;
58
+ const tabExists = tabs.some((tab) => tab.id === activeTab);
59
+ const resolvedTab = tabExists ? activeTab : DEFAULT_TAB;
60
+ const handleClose = () => onClose();
61
+ const handleTabChange = (tabId) => {
62
+ setSearchParams((previous) => {
63
+ const next = new URLSearchParams(previous);
64
+ next.set("tab", tabId);
65
+ return next;
66
+ });
67
+ };
68
+ const appUrl = fullInstanceId && api.appUrl ? `${instanceUrl(
69
+ api.appUrl,
70
+ api.organizationId,
71
+ fullInstanceId
72
+ )}?tab=${resolvedTab}` : "";
73
+ const renderTab = () => {
74
+ switch (resolvedTab) {
75
+ case "config":
76
+ return /* @__PURE__ */ jsx(ConfigTab, { instanceId: fullInstanceId });
77
+ case "resources":
78
+ return /* @__PURE__ */ jsx(ResourcesTab, { instanceId: fullInstanceId });
79
+ case "dependencies":
80
+ return /* @__PURE__ */ jsx(DependenciesTab, { instanceId: fullInstanceId });
81
+ case "monitor":
82
+ return /* @__PURE__ */ jsx(MonitorTab, { instanceId: fullInstanceId });
83
+ case "history":
84
+ return /* @__PURE__ */ jsx(HistoryTab, { instanceId: fullInstanceId });
85
+ case "guide":
86
+ return /* @__PURE__ */ jsx(GuideTab, { instanceId: fullInstanceId });
87
+ case "secrets":
88
+ return /* @__PURE__ */ jsx(SecretsTab, { secretFields });
89
+ case "overview":
90
+ default:
91
+ return /* @__PURE__ */ jsx(OverviewTab, { instanceId: fullInstanceId });
92
+ }
93
+ };
94
+ if (!isOpen) return null;
95
+ return /* @__PURE__ */ jsxs(Panel, { ref: panelRef, style: { width }, children: [
96
+ /* @__PURE__ */ jsx(ResizeHandle, { onMouseDown: onResizeStart, "data-testid": "resize-handle" }),
97
+ /* @__PURE__ */ jsx(
98
+ InstanceDrawerHeader,
99
+ {
100
+ instance,
101
+ appUrl,
102
+ onClose: handleClose
103
+ }
104
+ ),
105
+ loading ? /* @__PURE__ */ jsx(Centered, { children: /* @__PURE__ */ jsx(LoadingIndicator, {}) }) : error ? /* @__PURE__ */ jsx(Padded, { children: /* @__PURE__ */ jsx(Alert, { severity: "error", children: String(error.message ?? error) }) }) : !instance ? /* @__PURE__ */ jsx(
106
+ NotFound,
107
+ {
108
+ title: "Instance not found",
109
+ message: "This instance doesn't exist or you don't have access to it."
110
+ }
111
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
112
+ /* @__PURE__ */ jsx(
113
+ InstanceTabs,
114
+ {
115
+ tabs,
116
+ activeTab: resolvedTab,
117
+ onTabChange: handleTabChange
118
+ }
119
+ ),
120
+ /* @__PURE__ */ jsx(ContentArea, { role: "tabpanel", children: renderTab() })
121
+ ] })
122
+ ] });
123
+ };
124
+ const Panel = stylin(Box)(({ theme }) => ({
125
+ position: "absolute",
126
+ top: 0,
127
+ right: 0,
128
+ bottom: 0,
129
+ maxWidth: "100%",
130
+ zIndex: 10,
131
+ display: "flex",
132
+ flexDirection: "column",
133
+ overflow: "hidden",
134
+ backgroundColor: theme.palette.background.paper,
135
+ borderLeft: `1px solid ${theme.palette.divider}`,
136
+ boxShadow: theme.shadows[8]
137
+ }));
138
+ const ResizeHandle = stylin(Box)(({ theme }) => ({
139
+ position: "absolute",
140
+ top: 0,
141
+ bottom: 0,
142
+ left: 0,
143
+ width: theme.spacing(0.75),
144
+ cursor: "col-resize",
145
+ zIndex: 1,
146
+ "&:hover": {
147
+ backgroundColor: theme.palette.action.hover
148
+ }
149
+ }));
150
+ const ContentArea = stylin(Box)(({ theme }) => ({
151
+ flex: 1,
152
+ overflow: "auto",
153
+ padding: theme.spacing(2)
154
+ }));
155
+ const Centered = stylin(Box)(({ theme }) => ({
156
+ display: "flex",
157
+ justifyContent: "center",
158
+ padding: theme.spacing(6)
159
+ }));
160
+ const Padded = stylin(Box)(({ theme }) => ({
161
+ padding: theme.spacing(2)
162
+ }));
163
+
164
+ export { InstanceDrawer };
165
+ //# sourceMappingURL=InstanceDrawer.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InstanceDrawer.esm.js","sources":["../../../../src/features/environment/InstanceDrawer/InstanceDrawer.tsx"],"sourcesContent":["import { useApi } from '@backstage/frontend-plugin-api';\nimport { useSearchParams } from 'react-router-dom';\nimport {\n composeInstanceId,\n instanceUrl,\n parseEnvironmentId,\n} from '@massdriver/backstage-plugin-common';\nimport Box from '@massdriver/ui/Box';\nimport Alert from '@massdriver/ui/Alert';\nimport LoadingIndicator from '@massdriver/ui/LoadingIndicator';\nimport stylin from '@massdriver/ui/stylin';\nimport { massdriverApiRef } from '../../../api';\nimport { NotFound } from '../../../components/NotFound';\nimport { useInstanceApiQuery } from './useInstanceApiQuery';\nimport { useResizableWidth } from './useResizableWidth';\nimport { PANEL_QUERY } from './queries';\nimport { InstanceDrawerHeader } from './InstanceDrawerHeader';\nimport { InstanceTabs } from './InstanceTabs';\nimport ConfigTab from './tabs/ConfigTab';\nimport OverviewTab from './tabs/OverviewTab';\nimport ResourcesTab from './tabs/ResourcesTab';\nimport DependenciesTab from './tabs/DependenciesTab';\nimport MonitorTab from './tabs/MonitorTab';\nimport HistoryTab from './tabs/HistoryTab';\nimport GuideTab from './tabs/GuideTab';\nimport SecretsTab from './tabs/SecretsTab';\nimport type { PanelInstance, SecretField } from './types';\n\nconst DEFAULT_TAB = 'overview';\n\n// App tab order. Secrets is spliced in (after History) only when the instance\n// declares secret fields (see below).\nconst BASE_TABS = [\n { id: 'overview', label: 'Overview' },\n { id: 'config', label: 'Config' },\n { id: 'history', label: 'History' },\n { id: 'monitor', label: 'Monitor' },\n { id: 'guide', label: 'Guide' },\n { id: 'dependencies', label: 'Dependencies' },\n { id: 'resources', label: 'Resources' },\n];\n\n/**\n * Read-only instance drawer rendered over the environment graph. Opens when the\n * `scopedComponentId` route param is present (the `.../instances/:scopedComponentId`\n * sub-route, mirroring the web app); closing navigates back to the environment\n * route. The active tab is carried in the `?tab=` query param.\n */\nexport const InstanceDrawer = ({\n projectId,\n environmentId,\n scopedComponentId,\n onClose,\n}: {\n projectId: string;\n environmentId: string;\n scopedComponentId?: string;\n onClose: () => void;\n}) => {\n const api = useApi(massdriverApiRef);\n const [searchParams, setSearchParams] = useSearchParams();\n const { width, panelRef, onResizeStart } = useResizableWidth();\n\n const isOpen = Boolean(scopedComponentId);\n const activeTab = searchParams.get('tab') || DEFAULT_TAB;\n\n const { scopedEnvironmentId } = parseEnvironmentId(environmentId);\n const fullInstanceId =\n isOpen && projectId && scopedEnvironmentId && scopedComponentId\n ? composeInstanceId(projectId, scopedEnvironmentId, scopedComponentId)\n : null;\n\n const { value, loading, error } = useInstanceApiQuery<{\n instance: PanelInstance | null;\n }>(PANEL_QUERY, fullInstanceId);\n const instance = value?.instance;\n\n const secretFields = (instance?.secretFields ?? []).filter(\n Boolean,\n ) as SecretField[];\n\n const tabs = secretFields.length\n ? [\n ...BASE_TABS.slice(0, 3),\n { id: 'secrets', label: 'Secrets' },\n ...BASE_TABS.slice(3),\n ]\n : BASE_TABS;\n\n const tabExists = tabs.some(tab => tab.id === activeTab);\n const resolvedTab = tabExists ? activeTab : DEFAULT_TAB;\n\n const handleClose = () => onClose();\n\n const handleTabChange = (tabId: string) => {\n setSearchParams(previous => {\n const next = new URLSearchParams(previous);\n next.set('tab', tabId);\n return next;\n });\n };\n\n const appUrl =\n fullInstanceId && api.appUrl\n ? `${instanceUrl(\n api.appUrl,\n api.organizationId,\n fullInstanceId,\n )}?tab=${resolvedTab}`\n : '';\n\n const renderTab = () => {\n switch (resolvedTab) {\n case 'config':\n return <ConfigTab instanceId={fullInstanceId} />;\n case 'resources':\n return <ResourcesTab instanceId={fullInstanceId} />;\n case 'dependencies':\n return <DependenciesTab instanceId={fullInstanceId} />;\n case 'monitor':\n return <MonitorTab instanceId={fullInstanceId} />;\n case 'history':\n return <HistoryTab instanceId={fullInstanceId} />;\n case 'guide':\n return <GuideTab instanceId={fullInstanceId} />;\n case 'secrets':\n return <SecretsTab secretFields={secretFields} />;\n case 'overview':\n default:\n return <OverviewTab instanceId={fullInstanceId} />;\n }\n };\n\n if (!isOpen) return null;\n\n return (\n <Panel ref={panelRef} style={{ width }}>\n <ResizeHandle onMouseDown={onResizeStart} data-testid=\"resize-handle\" />\n <InstanceDrawerHeader\n instance={instance}\n appUrl={appUrl}\n onClose={handleClose}\n />\n {loading ? (\n <Centered>\n <LoadingIndicator />\n </Centered>\n ) : error ? (\n <Padded>\n <Alert severity=\"error\">{String(error.message ?? error)}</Alert>\n </Padded>\n ) : !instance ? (\n <NotFound\n title=\"Instance not found\"\n message=\"This instance doesn't exist or you don't have access to it.\"\n />\n ) : (\n <>\n <InstanceTabs\n tabs={tabs}\n activeTab={resolvedTab}\n onTabChange={handleTabChange}\n />\n <ContentArea role=\"tabpanel\">{renderTab()}</ContentArea>\n </>\n )}\n </Panel>\n );\n};\n\nexport default InstanceDrawer;\n\n// Read-only panel pinned to the right edge of the environment graph. Uses a\n// plain absolutely-positioned Box rather than @massdriver/ui/Drawer: MUI v5's\n// Drawer relies on its Slide transition (and a Modal/portal for the temporary\n// variant), which does not paint reliably inside Backstage's hybrid runtime\n// (its own MUI v4 layer + the scoped `mdui` Emotion cache). Fixed width for now;\n// a drag-to-resize handle can be reintroduced later. GraphArea is `position:\n// relative`, so this anchors to it.\nconst Panel = stylin(Box)(({ theme }: { theme: any }) => ({\n position: 'absolute',\n top: 0,\n right: 0,\n bottom: 0,\n maxWidth: '100%',\n zIndex: 10,\n display: 'flex',\n flexDirection: 'column',\n overflow: 'hidden',\n backgroundColor: theme.palette.background.paper,\n borderLeft: `1px solid ${theme.palette.divider}`,\n boxShadow: theme.shadows[8],\n}));\n\nconst ResizeHandle = stylin(Box)(({ theme }: { theme: any }) => ({\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 0,\n width: theme.spacing(0.75),\n cursor: 'col-resize',\n zIndex: 1,\n '&:hover': {\n backgroundColor: theme.palette.action.hover,\n },\n}));\n\nconst ContentArea = stylin(Box)(({ theme }: { theme: any }) => ({\n flex: 1,\n overflow: 'auto',\n padding: theme.spacing(2),\n}));\n\nconst Centered = stylin(Box)(({ theme }: { theme: any }) => ({\n display: 'flex',\n justifyContent: 'center',\n padding: theme.spacing(6),\n}));\n\nconst Padded = stylin(Box)(({ theme }: { theme: any }) => ({\n padding: theme.spacing(2),\n}));\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,241 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import Box from '@massdriver/ui/Box';
3
+ import Typography from '@massdriver/ui/Typography';
4
+ import Tooltip from '@massdriver/ui/Tooltip';
5
+ import { CloseIconButton } from '@massdriver/ui/IconButton';
6
+ import NotificationsIcon from '@massdriver/ui/icons/NotificationsIcon';
7
+ import AttachMoneyIcon from '@massdriver/ui/icons/AttachMoneyIcon';
8
+ import EditIcon from '@massdriver/ui/icons/EditIcon';
9
+ import ArrowUpwardIcon from '@massdriver/ui/icons/ArrowUpwardIcon';
10
+ import ArrowDownwardIcon from '@massdriver/ui/icons/ArrowDownwardIcon';
11
+ import stylin from '@massdriver/ui/stylin';
12
+ import VersionBadge from '../../../components/VersionBadge.esm.js';
13
+ import InstanceStatusPill from '../components/InstanceStatusPill.esm.js';
14
+ import { OpenInMassdriverButton } from '../../../components/OpenInMassdriverButton.esm.js';
15
+ import { formatCurrency } from '../../../utils/formatRelativeTime.esm.js';
16
+ import { formatRelativeTime } from './helpers.esm.js';
17
+
18
+ const countActiveAlarms = (instance) => (instance?.alarms?.items ?? []).filter(
19
+ (alarm) => alarm?.currentState?.status === "ALARM"
20
+ ).length;
21
+ const InstanceDrawerHeader = ({
22
+ instance,
23
+ appUrl,
24
+ onClose
25
+ }) => {
26
+ const title = instance?.component?.name;
27
+ return /* @__PURE__ */ jsxs(HeaderRoot, { children: [
28
+ /* @__PURE__ */ jsxs(TopRow, { children: [
29
+ /* @__PURE__ */ jsxs(TitleArea, { children: [
30
+ title ? /* @__PURE__ */ jsx(Title, { variant: "h6", title, children: title }) : null,
31
+ instance?.version ? /* @__PURE__ */ jsx(VersionBadge, { version: instance.version, showPinnedWarning: true }) : null,
32
+ instance?.id ? /* @__PURE__ */ jsx(
33
+ InstanceStatusPill,
34
+ {
35
+ instance: { id: instance.id, status: instance.status }
36
+ }
37
+ ) : null
38
+ ] }),
39
+ /* @__PURE__ */ jsxs(Actions, { children: [
40
+ appUrl ? /* @__PURE__ */ jsx(
41
+ OpenInMassdriverButton,
42
+ {
43
+ url: appUrl,
44
+ variant: "outlined",
45
+ size: "small"
46
+ }
47
+ ) : null,
48
+ /* @__PURE__ */ jsx(CloseIconButton, { onClick: onClose, tooltip: "Close panel" })
49
+ ] })
50
+ ] }),
51
+ instance ? /* @__PURE__ */ jsx(InstanceMeta, { instance }) : null
52
+ ] });
53
+ };
54
+ const InstanceMeta = ({ instance }) => {
55
+ const numAlerts = countActiveAlarms(instance);
56
+ const cost = instance.cost;
57
+ return /* @__PURE__ */ jsxs(MetaGrid, { children: [
58
+ /* @__PURE__ */ jsx(AlertsRow, { numAlerts }),
59
+ /* @__PURE__ */ jsx(
60
+ CostRow,
61
+ {
62
+ label: "yesterday",
63
+ sample: cost?.lastDay,
64
+ average: cost?.dailyAverage
65
+ }
66
+ ),
67
+ /* @__PURE__ */ jsx(EditedRow, { updatedAt: instance.updatedAt }),
68
+ /* @__PURE__ */ jsx(
69
+ CostRow,
70
+ {
71
+ label: "last month",
72
+ sample: cost?.lastMonth,
73
+ average: cost?.monthlyAverage
74
+ }
75
+ )
76
+ ] });
77
+ };
78
+ const AlertsRow = ({ numAlerts }) => {
79
+ const hasAlerts = numAlerts > 0;
80
+ const label = hasAlerts ? `${numAlerts} active alert${numAlerts === 1 ? "" : "s"}` : "no active alerts";
81
+ return /* @__PURE__ */ jsxs(MetaRow, { title: label, children: [
82
+ /* @__PURE__ */ jsx(AlertsIcon, { hasAlerts }),
83
+ /* @__PURE__ */ jsx(RowText, { hasAlerts, children: label })
84
+ ] });
85
+ };
86
+ const EditedRow = ({ updatedAt }) => {
87
+ const label = `last edited ${formatRelativeTime(updatedAt)}`;
88
+ return /* @__PURE__ */ jsxs(MetaRow, { title: label, children: [
89
+ /* @__PURE__ */ jsx(StyledEditIcon, {}),
90
+ /* @__PURE__ */ jsx(RowText, { children: label })
91
+ ] });
92
+ };
93
+ const CostRow = ({
94
+ label,
95
+ sample,
96
+ average
97
+ }) => {
98
+ const amount = sample?.amount;
99
+ const averageAmount = average?.amount;
100
+ const currency = sample?.currency || average?.currency || "USD";
101
+ const hasValue = amount != null;
102
+ const formatted = formatCurrency(amount, currency, "---");
103
+ const formattedAverage = averageAmount != null ? formatCurrency(averageAmount, currency, "---") : null;
104
+ return /* @__PURE__ */ jsxs(MetaRow, { title: `${label}: ${formatted}`, children: [
105
+ /* @__PURE__ */ jsx(MoneyIcon, { active: hasValue }),
106
+ /* @__PURE__ */ jsxs(RowText, { children: [
107
+ label,
108
+ ":\xA0",
109
+ hasValue ? /* @__PURE__ */ jsxs(CostInline, { children: [
110
+ /* @__PURE__ */ jsx(CostNumber, { children: formatted }),
111
+ averageAmount != null && amount !== averageAmount ? /* @__PURE__ */ jsx(
112
+ Tooltip,
113
+ {
114
+ title: formattedAverage ? `${formattedAverage} average` : "",
115
+ arrow: true,
116
+ placement: "right",
117
+ children: /* @__PURE__ */ jsx(TrendWrap, { children: amount > averageAmount ? /* @__PURE__ */ jsx(TrendUp, {}) : /* @__PURE__ */ jsx(TrendDown, {}) })
118
+ }
119
+ ) : null
120
+ ] }) : "---"
121
+ ] })
122
+ ] });
123
+ };
124
+ const HeaderRoot = stylin(Box)(({ theme }) => ({
125
+ display: "flex",
126
+ flexDirection: "column",
127
+ gap: theme.spacing(1),
128
+ padding: theme.spacing(1.5, 2),
129
+ backgroundColor: theme.palette.background.paper,
130
+ borderBottom: `1px solid ${theme.palette.divider}`
131
+ }));
132
+ const TopRow = stylin(Box)(({ theme }) => ({
133
+ display: "flex",
134
+ alignItems: "center",
135
+ justifyContent: "space-between",
136
+ gap: theme.spacing(1.5),
137
+ minHeight: 32,
138
+ minWidth: 0
139
+ }));
140
+ const TitleArea = stylin(Box)(({ theme }) => ({
141
+ display: "flex",
142
+ alignItems: "center",
143
+ gap: theme.spacing(1),
144
+ flex: 1,
145
+ minWidth: 0
146
+ }));
147
+ const Title = stylin(Typography)(({ theme }) => ({
148
+ fontSize: "1.25rem",
149
+ fontWeight: 600,
150
+ lineHeight: 1.2,
151
+ color: theme.palette.text.primary,
152
+ overflow: "hidden",
153
+ textOverflow: "ellipsis",
154
+ whiteSpace: "nowrap",
155
+ minWidth: 0
156
+ }));
157
+ const Actions = stylin(Box)(({ theme }) => ({
158
+ display: "flex",
159
+ alignItems: "center",
160
+ gap: theme.spacing(1),
161
+ flexShrink: 0
162
+ }));
163
+ const MetaGrid = stylin(Box)(({ theme }) => ({
164
+ display: "grid",
165
+ gridTemplateColumns: "1fr 1fr",
166
+ rowGap: theme.spacing(0.5),
167
+ columnGap: theme.spacing(2),
168
+ marginTop: theme.spacing(0.5),
169
+ minWidth: 0
170
+ }));
171
+ const MetaRow = stylin(Box)({
172
+ display: "flex",
173
+ alignItems: "center",
174
+ gap: "6px",
175
+ minWidth: 0,
176
+ overflow: "hidden"
177
+ });
178
+ const RowText = stylin(Typography, ["hasAlerts"])(
179
+ ({ theme, hasAlerts }) => ({
180
+ fontSize: "14px",
181
+ fontWeight: 400,
182
+ color: hasAlerts ? theme.palette.error.main : theme.palette.text.secondary,
183
+ overflow: "hidden",
184
+ textOverflow: "ellipsis",
185
+ whiteSpace: "nowrap",
186
+ minWidth: 0
187
+ })
188
+ );
189
+ const StyledEditIcon = stylin(EditIcon)(({ theme }) => ({
190
+ width: 16,
191
+ height: 16,
192
+ flexShrink: 0,
193
+ color: theme.palette.text.secondary
194
+ }));
195
+ const AlertsIcon = stylin(NotificationsIcon, ["hasAlerts"])(
196
+ ({ theme, hasAlerts }) => ({
197
+ width: 16,
198
+ height: 16,
199
+ flexShrink: 0,
200
+ color: hasAlerts ? theme.palette.error.main : theme.palette.text.secondary
201
+ })
202
+ );
203
+ const MoneyIcon = stylin(AttachMoneyIcon, ["active"])(
204
+ ({ theme, active }) => ({
205
+ width: 16,
206
+ height: 16,
207
+ flexShrink: 0,
208
+ color: active ? theme.palette.success.main : theme.palette.text.secondary
209
+ })
210
+ );
211
+ const TrendUp = stylin(ArrowUpwardIcon)(({ theme }) => ({
212
+ width: 16,
213
+ height: 16,
214
+ color: theme.palette.error.main
215
+ }));
216
+ const TrendDown = stylin(ArrowDownwardIcon)(({ theme }) => ({
217
+ width: 16,
218
+ height: 16,
219
+ color: theme.palette.success.main
220
+ }));
221
+ const CostInline = stylin("span")({
222
+ display: "inline-flex",
223
+ alignItems: "center",
224
+ gap: "2px",
225
+ minWidth: 0
226
+ });
227
+ const CostNumber = stylin("span")({
228
+ fontWeight: 600,
229
+ overflow: "hidden",
230
+ textOverflow: "ellipsis",
231
+ whiteSpace: "nowrap",
232
+ minWidth: 0
233
+ });
234
+ const TrendWrap = stylin("span")({
235
+ display: "inline-flex",
236
+ alignItems: "center",
237
+ flexShrink: 0
238
+ });
239
+
240
+ export { InstanceDrawerHeader };
241
+ //# sourceMappingURL=InstanceDrawerHeader.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InstanceDrawerHeader.esm.js","sources":["../../../../src/features/environment/InstanceDrawer/InstanceDrawerHeader.tsx"],"sourcesContent":["import Box from '@massdriver/ui/Box';\nimport Typography from '@massdriver/ui/Typography';\nimport Tooltip from '@massdriver/ui/Tooltip';\nimport { CloseIconButton } from '@massdriver/ui/IconButton';\nimport NotificationsIcon from '@massdriver/ui/icons/NotificationsIcon';\nimport AttachMoneyIcon from '@massdriver/ui/icons/AttachMoneyIcon';\nimport EditIcon from '@massdriver/ui/icons/EditIcon';\nimport ArrowUpwardIcon from '@massdriver/ui/icons/ArrowUpwardIcon';\nimport ArrowDownwardIcon from '@massdriver/ui/icons/ArrowDownwardIcon';\nimport stylin from '@massdriver/ui/stylin';\nimport VersionBadge from '../../../components/VersionBadge';\nimport InstanceStatusPill from '../components/InstanceStatusPill';\nimport { OpenInMassdriverButton } from '../../../components/OpenInMassdriverButton';\nimport { formatCurrency } from '../../../utils/formatRelativeTime';\nimport { formatRelativeTime } from './helpers';\nimport type { Money, PanelInstance } from './types';\n\nconst countActiveAlarms = (instance?: PanelInstance | null): number =>\n (instance?.alarms?.items ?? []).filter(\n alarm => alarm?.currentState?.status === 'ALARM',\n ).length;\n\nexport const InstanceDrawerHeader = ({\n instance,\n appUrl,\n onClose,\n}: {\n instance?: PanelInstance | null;\n appUrl: string;\n onClose: () => void;\n}) => {\n const title = instance?.component?.name;\n\n return (\n <HeaderRoot>\n <TopRow>\n <TitleArea>\n {title ? (\n <Title variant=\"h6\" title={title}>\n {title}\n </Title>\n ) : null}\n {instance?.version ? (\n <VersionBadge version={instance.version} showPinnedWarning />\n ) : null}\n {instance?.id ? (\n <InstanceStatusPill\n instance={{ id: instance.id, status: instance.status }}\n />\n ) : null}\n </TitleArea>\n <Actions>\n {appUrl ? (\n <OpenInMassdriverButton\n url={appUrl}\n variant=\"outlined\"\n size=\"small\"\n />\n ) : null}\n <CloseIconButton onClick={onClose} tooltip=\"Close panel\" />\n </Actions>\n </TopRow>\n {instance ? <InstanceMeta instance={instance} /> : null}\n </HeaderRoot>\n );\n};\n\nexport default InstanceDrawerHeader;\n\nconst InstanceMeta = ({ instance }: { instance: PanelInstance }) => {\n const numAlerts = countActiveAlarms(instance);\n const cost = instance.cost;\n return (\n <MetaGrid>\n <AlertsRow numAlerts={numAlerts} />\n <CostRow\n label=\"yesterday\"\n sample={cost?.lastDay}\n average={cost?.dailyAverage}\n />\n <EditedRow updatedAt={instance.updatedAt} />\n <CostRow\n label=\"last month\"\n sample={cost?.lastMonth}\n average={cost?.monthlyAverage}\n />\n </MetaGrid>\n );\n};\n\nconst AlertsRow = ({ numAlerts }: { numAlerts: number }) => {\n const hasAlerts = numAlerts > 0;\n const label = hasAlerts\n ? `${numAlerts} active alert${numAlerts === 1 ? '' : 's'}`\n : 'no active alerts';\n return (\n <MetaRow title={label}>\n <AlertsIcon hasAlerts={hasAlerts} />\n <RowText hasAlerts={hasAlerts}>{label}</RowText>\n </MetaRow>\n );\n};\n\nconst EditedRow = ({ updatedAt }: { updatedAt?: string | null }) => {\n const label = `last edited ${formatRelativeTime(updatedAt)}`;\n return (\n <MetaRow title={label}>\n <StyledEditIcon />\n <RowText>{label}</RowText>\n </MetaRow>\n );\n};\n\nconst CostRow = ({\n label,\n sample,\n average,\n}: {\n label: string;\n sample?: Money | null;\n average?: Money | null;\n}) => {\n const amount = sample?.amount;\n const averageAmount = average?.amount;\n const currency = sample?.currency || average?.currency || 'USD';\n const hasValue = amount != null;\n const formatted = formatCurrency(amount, currency, '---');\n const formattedAverage =\n averageAmount != null\n ? formatCurrency(averageAmount, currency, '---')\n : null;\n\n return (\n <MetaRow title={`${label}: ${formatted}`}>\n <MoneyIcon active={hasValue} />\n <RowText>\n {label}:&nbsp;\n {hasValue ? (\n <CostInline>\n <CostNumber>{formatted}</CostNumber>\n {averageAmount != null && amount !== averageAmount ? (\n <Tooltip\n title={formattedAverage ? `${formattedAverage} average` : ''}\n arrow\n placement=\"right\"\n >\n <TrendWrap>\n {(amount as number) > (averageAmount as number) ? (\n <TrendUp />\n ) : (\n <TrendDown />\n )}\n </TrendWrap>\n </Tooltip>\n ) : null}\n </CostInline>\n ) : (\n '---'\n )}\n </RowText>\n </MetaRow>\n );\n};\n\nconst HeaderRoot = stylin(Box)(({ theme }: { theme: any }) => ({\n display: 'flex',\n flexDirection: 'column',\n gap: theme.spacing(1),\n padding: theme.spacing(1.5, 2),\n backgroundColor: theme.palette.background.paper,\n borderBottom: `1px solid ${theme.palette.divider}`,\n}));\n\nconst TopRow = stylin(Box)(({ theme }: { theme: any }) => ({\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: theme.spacing(1.5),\n minHeight: 32,\n minWidth: 0,\n}));\n\nconst TitleArea = stylin(Box)(({ theme }: { theme: any }) => ({\n display: 'flex',\n alignItems: 'center',\n gap: theme.spacing(1),\n flex: 1,\n minWidth: 0,\n}));\n\nconst Title = stylin(Typography)(({ theme }: { theme: any }) => ({\n fontSize: '1.25rem',\n fontWeight: 600,\n lineHeight: 1.2,\n color: theme.palette.text.primary,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n minWidth: 0,\n}));\n\nconst Actions = stylin(Box)(({ theme }: { theme: any }) => ({\n display: 'flex',\n alignItems: 'center',\n gap: theme.spacing(1),\n flexShrink: 0,\n}));\n\nconst MetaGrid = stylin(Box)(({ theme }: { theme: any }) => ({\n display: 'grid',\n gridTemplateColumns: '1fr 1fr',\n rowGap: theme.spacing(0.5),\n columnGap: theme.spacing(2),\n marginTop: theme.spacing(0.5),\n minWidth: 0,\n}));\n\nconst MetaRow = stylin(Box)({\n display: 'flex',\n alignItems: 'center',\n gap: '6px',\n minWidth: 0,\n overflow: 'hidden',\n});\n\nconst RowText = stylin(Typography, ['hasAlerts'])(\n ({ theme, hasAlerts }: { theme: any; hasAlerts?: boolean }) => ({\n fontSize: '14px',\n fontWeight: 400,\n color: hasAlerts ? theme.palette.error.main : theme.palette.text.secondary,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n minWidth: 0,\n }),\n);\n\nconst StyledEditIcon = stylin(EditIcon)(({ theme }: { theme: any }) => ({\n width: 16,\n height: 16,\n flexShrink: 0,\n color: theme.palette.text.secondary,\n}));\n\nconst AlertsIcon = stylin(NotificationsIcon, ['hasAlerts'])(\n ({ theme, hasAlerts }: { theme: any; hasAlerts?: boolean }) => ({\n width: 16,\n height: 16,\n flexShrink: 0,\n color: hasAlerts ? theme.palette.error.main : theme.palette.text.secondary,\n }),\n);\n\nconst MoneyIcon = stylin(AttachMoneyIcon, ['active'])(\n ({ theme, active }: { theme: any; active?: boolean }) => ({\n width: 16,\n height: 16,\n flexShrink: 0,\n color: active ? theme.palette.success.main : theme.palette.text.secondary,\n }),\n);\n\nconst TrendUp = stylin(ArrowUpwardIcon)(({ theme }: { theme: any }) => ({\n width: 16,\n height: 16,\n color: theme.palette.error.main,\n}));\n\nconst TrendDown = stylin(ArrowDownwardIcon)(({ theme }: { theme: any }) => ({\n width: 16,\n height: 16,\n color: theme.palette.success.main,\n}));\n\nconst CostInline = stylin('span')({\n display: 'inline-flex',\n alignItems: 'center',\n gap: '2px',\n minWidth: 0,\n});\n\nconst CostNumber = stylin('span')({\n fontWeight: 600,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n minWidth: 0,\n});\n\nconst TrendWrap = stylin('span')({\n display: 'inline-flex',\n alignItems: 'center',\n flexShrink: 0,\n});\n"],"names":[],"mappings":"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"}