@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,427 @@
1
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
+ import { useMemo } from 'react';
3
+ import { useSearchParams } from 'react-router-dom';
4
+ import { useApi } from '@backstage/frontend-plugin-api';
5
+ import useAsync from 'react-use/esm/useAsync';
6
+ import { Dialog, DialogHeader, DialogActions, DialogContent } from '@massdriver/ui/Dialog';
7
+ import Box from '@massdriver/ui/Box';
8
+ import Typography from '@massdriver/ui/Typography';
9
+ import Button from '@massdriver/ui/Button';
10
+ import Tooltip from '@massdriver/ui/Tooltip';
11
+ import IconButton from '@massdriver/ui/IconButton';
12
+ import CopyButton from '@massdriver/ui/CopyButton';
13
+ import Alert from '@massdriver/ui/Alert';
14
+ import LoadingIndicator from '@massdriver/ui/LoadingIndicator';
15
+ import DataList, { col } from '@massdriver/ui/DataList';
16
+ import stylin from '@massdriver/ui/stylin';
17
+ import CloseIcon from '@massdriver/ui/icons/CloseIcon';
18
+ import HistoryIcon from '@massdriver/ui/icons/HistoryIcon';
19
+ import { massdriverApiRef } from '../../api.esm.js';
20
+ import { InstanceStatusPill } from '../../components/InstanceStatusPill.esm.js';
21
+ import VersionBadge from '../../components/VersionBadge.esm.js';
22
+ import { composeInstanceStatus, formatInstanceStatus, isDeploymentActive } from '../../utils/instanceStatuses.esm.js';
23
+ import { formatRelativeTime } from '../../utils/formatRelativeTime.esm.js';
24
+ import { DEPLOYMENT_DETAIL_QUERY } from './queries.esm.js';
25
+ import { formatElapsed, formatAbsoluteDateTime, parsePlanMessage, parseRollbackMessage, stripMessageContext, deploymentHasLogs, parseMap, truncateDeploymentId, formatAttributeValue } from './deploymentHelpers.esm.js';
26
+ import flattenParams from './flattenParams.esm.js';
27
+
28
+ const TRUNCATE_LENGTH = 64;
29
+ const formatParamValue = (value) => {
30
+ if (typeof value === "string") return value;
31
+ try {
32
+ return JSON.stringify(value);
33
+ } catch {
34
+ return String(value);
35
+ }
36
+ };
37
+ const renderValueCell = (_value, row) => {
38
+ const value = row.value;
39
+ if (value == null) return /* @__PURE__ */ jsx(NullLiteral, { children: "null" });
40
+ const display = formatParamValue(value);
41
+ const truncated = display.length > TRUNCATE_LENGTH;
42
+ const visible = truncated ? `${display.slice(0, TRUNCATE_LENGTH)}\u2026` : display;
43
+ const cell = /* @__PURE__ */ jsx(ValueText, { children: visible });
44
+ return truncated ? /* @__PURE__ */ jsx(Tooltip, { title: display, arrow: true, placement: "top", children: /* @__PURE__ */ jsx("span", { children: cell }) }) : cell;
45
+ };
46
+ const COLUMNS = [
47
+ col.text("path", "Path", {
48
+ flex: 2,
49
+ minWidth: 200,
50
+ sortable: true,
51
+ searchable: true
52
+ }),
53
+ col.custom("value", "Value", renderValueCell, {
54
+ flex: 3,
55
+ minWidth: 220,
56
+ sortable: false,
57
+ searchable: false
58
+ })
59
+ ];
60
+ const isActiveStatus = (derivedStatus) => {
61
+ if (!derivedStatus) return false;
62
+ const [, deploymentStatus] = derivedStatus.split("_");
63
+ return isDeploymentActive(deploymentStatus);
64
+ };
65
+ const buildHeading = (componentName, derivedStatus, time) => {
66
+ const verb = derivedStatus ? formatInstanceStatus(derivedStatus).toLowerCase() : null;
67
+ if (!componentName && !verb) return "Deployment";
68
+ if (!verb) return `${componentName} deployment`;
69
+ const tail = time && time !== "--" && !isActiveStatus(derivedStatus) ? ` ${time}` : "";
70
+ return componentName ? `${componentName} \xB7 ${verb}${tail}` : `${verb}${tail}`;
71
+ };
72
+ const ViewDeploymentDetailsDialog = () => {
73
+ const api = useApi(massdriverApiRef);
74
+ const [searchParams, setSearchParams] = useSearchParams();
75
+ const deploymentId = searchParams.get("deployment");
76
+ const open = Boolean(deploymentId);
77
+ const setParam = (key, value2) => {
78
+ setSearchParams(
79
+ (prev) => {
80
+ const next = new URLSearchParams(prev);
81
+ if (value2) next.set(key, value2);
82
+ else next.delete(key);
83
+ return next;
84
+ },
85
+ { replace: false }
86
+ );
87
+ };
88
+ const onClose = () => setParam("deployment", null);
89
+ const onShowSource = (sourceId) => setParam("deployment", sourceId);
90
+ const { value, loading, error } = useAsync(async () => {
91
+ if (!deploymentId) return null;
92
+ const data = await api.query(DEPLOYMENT_DETAIL_QUERY, {
93
+ id: deploymentId
94
+ });
95
+ return data.deployment;
96
+ }, [api, deploymentId]);
97
+ const deployment = value;
98
+ const paramRows = useMemo(
99
+ () => flattenParams(deployment?.params),
100
+ [deployment?.params]
101
+ );
102
+ const derivedStatus = composeInstanceStatus(
103
+ deployment?.action,
104
+ deployment?.status
105
+ );
106
+ const componentName = deployment?.instance?.component?.name;
107
+ const elapsed = formatElapsed(deployment?.elapsedTime);
108
+ const occurredIso = deployment?.lastTransitionedAt ?? deployment?.createdAt;
109
+ const time = formatRelativeTime(occurredIso);
110
+ const absoluteDate = formatAbsoluteDateTime(occurredIso);
111
+ const deployedBy = deployment?.deployedBy ?? "system";
112
+ const statusLabel = formatInstanceStatus(derivedStatus);
113
+ const heading = buildHeading(componentName, derivedStatus, time);
114
+ const planSource = deployment?.action === "PLAN" ? parsePlanMessage(deployment?.message) : null;
115
+ const rollbackSource = parseRollbackMessage(deployment?.message);
116
+ const displayMessage = stripMessageContext(deployment?.message);
117
+ const isProposed = deployment?.status === "PROPOSED";
118
+ const hasLogs = deploymentHasLogs(deployment?.status);
119
+ const onViewLogs = () => {
120
+ if (!deployment) return;
121
+ setParam("logs", deployment.id);
122
+ };
123
+ const attributes = parseMap(deployment?.effectiveAttributes);
124
+ const attributeEntries = attributes ? Object.entries(attributes) : [];
125
+ return /* @__PURE__ */ jsxs(Dialog, { open, onClose, maxWidth: "md", fullWidth: true, children: [
126
+ /* @__PURE__ */ jsx(
127
+ DialogHeader,
128
+ {
129
+ icon: /* @__PURE__ */ jsx(HistoryIcon, {}),
130
+ actions: /* @__PURE__ */ jsx(IconButton, { onClick: onClose, "aria-label": "Close deployment details", children: /* @__PURE__ */ jsx(CloseIcon, {}) }),
131
+ children: heading
132
+ }
133
+ ),
134
+ /* @__PURE__ */ jsx(Body, { children: loading ? /* @__PURE__ */ jsx(Centered, { children: /* @__PURE__ */ jsx(LoadingIndicator, {}) }) : error ? /* @__PURE__ */ jsx(Alert, { severity: "error", children: String(error.message ?? error) }) : deployment ? /* @__PURE__ */ jsxs(Fragment, { children: [
135
+ /* @__PURE__ */ jsxs(SummaryCard, { children: [
136
+ /* @__PURE__ */ jsxs(SummaryHeader, { children: [
137
+ /* @__PURE__ */ jsxs(SummaryHeaderLeft, { children: [
138
+ /* @__PURE__ */ jsx(
139
+ InstanceStatusPill,
140
+ {
141
+ status: derivedStatus,
142
+ onClick: hasLogs ? onViewLogs : void 0
143
+ }
144
+ ),
145
+ deployment.version ? /* @__PURE__ */ jsx(VersionBadge, { version: deployment.version }) : null
146
+ ] }),
147
+ hasLogs ? /* @__PURE__ */ jsx(HeaderActions, { children: /* @__PURE__ */ jsx(
148
+ Button,
149
+ {
150
+ variant: "outlined",
151
+ size: "small",
152
+ onClick: onViewLogs,
153
+ children: "View logs"
154
+ }
155
+ ) }) : null
156
+ ] }),
157
+ /* @__PURE__ */ jsxs(DefList, { children: [
158
+ /* @__PURE__ */ jsxs(DefRow, { children: [
159
+ /* @__PURE__ */ jsx(DefLabel, { children: "Status" }),
160
+ /* @__PURE__ */ jsx(DefValue, { children: statusLabel })
161
+ ] }),
162
+ /* @__PURE__ */ jsxs(DefRow, { children: [
163
+ /* @__PURE__ */ jsx(DefLabel, { children: "Occurred" }),
164
+ /* @__PURE__ */ jsxs(DefValue, { children: [
165
+ time,
166
+ absoluteDate ? /* @__PURE__ */ jsx(DefMuted, { children: ` \xB7 ${absoluteDate}` }) : null
167
+ ] })
168
+ ] }),
169
+ /* @__PURE__ */ jsxs(DefRow, { children: [
170
+ /* @__PURE__ */ jsx(DefLabel, { children: "Duration" }),
171
+ /* @__PURE__ */ jsx(DefValue, { children: elapsed ?? "\u2014" })
172
+ ] }),
173
+ /* @__PURE__ */ jsxs(DefRow, { children: [
174
+ /* @__PURE__ */ jsx(DefLabel, { children: "Deployed by" }),
175
+ /* @__PURE__ */ jsx(DefValue, { children: /* @__PURE__ */ jsx("strong", { children: deployedBy }) })
176
+ ] }),
177
+ /* @__PURE__ */ jsxs(DefRow, { children: [
178
+ /* @__PURE__ */ jsx(DefLabel, { children: "Deployment ID" }),
179
+ /* @__PURE__ */ jsxs(DefValue, { children: [
180
+ /* @__PURE__ */ jsx(Mono, { children: deployment.id }),
181
+ /* @__PURE__ */ jsx(
182
+ CopyButton,
183
+ {
184
+ text: deployment.id,
185
+ ariaLabel: "Copy deployment ID"
186
+ }
187
+ )
188
+ ] })
189
+ ] })
190
+ ] }),
191
+ planSource ? /* @__PURE__ */ jsxs(PlanSourceBlock, { children: [
192
+ /* @__PURE__ */ jsxs(
193
+ PlanSourceLink,
194
+ {
195
+ variant: "text",
196
+ size: "small",
197
+ onClick: () => onShowSource(planSource.sourceId),
198
+ children: [
199
+ "Planned deployment of",
200
+ " ",
201
+ truncateDeploymentId(planSource.sourceId)
202
+ ]
203
+ }
204
+ ),
205
+ displayMessage ? /* @__PURE__ */ jsxs(MessageQuote, { children: [
206
+ '"',
207
+ displayMessage,
208
+ '"'
209
+ ] }) : null
210
+ ] }) : rollbackSource ? /* @__PURE__ */ jsxs(PlanSourceBlock, { children: [
211
+ /* @__PURE__ */ jsxs(
212
+ PlanSourceLink,
213
+ {
214
+ variant: "text",
215
+ size: "small",
216
+ onClick: () => onShowSource(rollbackSource.sourceId),
217
+ children: [
218
+ isProposed ? "Proposed rollback to deployment" : "Rollback to deployment",
219
+ " ",
220
+ truncateDeploymentId(rollbackSource.sourceId),
221
+ rollbackSource.version ? ` (v${rollbackSource.version})` : ""
222
+ ]
223
+ }
224
+ ),
225
+ displayMessage ? /* @__PURE__ */ jsxs(MessageQuote, { children: [
226
+ '"',
227
+ displayMessage,
228
+ '"'
229
+ ] }) : null
230
+ ] }) : displayMessage ? /* @__PURE__ */ jsxs(MessageQuote, { children: [
231
+ '"',
232
+ displayMessage,
233
+ '"'
234
+ ] }) : null
235
+ ] }),
236
+ /* @__PURE__ */ jsxs(Section, { children: [
237
+ /* @__PURE__ */ jsx(SectionHeading, { variant: "subtitle1", children: "Attributes" }),
238
+ /* @__PURE__ */ jsx(Card, { children: attributeEntries.length === 0 ? /* @__PURE__ */ jsx(EmptyNote, { children: "No effective attributes." }) : attributeEntries.map(([key, attrValue]) => /* @__PURE__ */ jsxs(RowLine, { children: [
239
+ /* @__PURE__ */ jsx(MonoLabel, { title: key, children: key }),
240
+ /* @__PURE__ */ jsx(MonoValue, { title: formatAttributeValue(attrValue), children: formatAttributeValue(attrValue) })
241
+ ] }, key)) })
242
+ ] }),
243
+ /* @__PURE__ */ jsxs(Section, { children: [
244
+ /* @__PURE__ */ jsx(SectionHeading, { variant: "subtitle1", children: "Snapshot params" }),
245
+ /* @__PURE__ */ jsx(
246
+ DataList,
247
+ {
248
+ rows: paramRows,
249
+ columns: COLUMNS,
250
+ searchable: true,
251
+ searchPlaceholder: "Search path\u2026",
252
+ defaultSort: { field: "path", direction: "asc" },
253
+ defaultPageSize: 5,
254
+ variant: "outlined",
255
+ size: "small",
256
+ emptyMessage: "No parameters captured for this deployment."
257
+ }
258
+ )
259
+ ] })
260
+ ] }) : null }),
261
+ /* @__PURE__ */ jsx(DialogActions, { children: /* @__PURE__ */ jsx(Button, { variant: "contained", onClick: onClose, children: "Close" }) })
262
+ ] });
263
+ };
264
+ const Body = stylin(DialogContent)(({ theme }) => ({
265
+ display: "flex",
266
+ flexDirection: "column",
267
+ gap: theme.spacing(2),
268
+ "& > *": {
269
+ flexShrink: 0
270
+ }
271
+ }));
272
+ const Centered = stylin(Box)(({ theme }) => ({
273
+ display: "flex",
274
+ justifyContent: "center",
275
+ padding: theme.spacing(6)
276
+ }));
277
+ const SummaryCard = stylin(Box)(({ theme }) => ({
278
+ display: "flex",
279
+ flexDirection: "column",
280
+ gap: theme.spacing(2.5),
281
+ padding: theme.spacing(2.5, 3),
282
+ borderRadius: 1,
283
+ border: `1px solid ${theme.palette.divider}`,
284
+ backgroundColor: theme.palette.background.paper
285
+ }));
286
+ const SummaryHeader = stylin(Box)(({ theme }) => ({
287
+ display: "flex",
288
+ alignItems: "center",
289
+ justifyContent: "space-between",
290
+ flexWrap: "wrap",
291
+ gap: theme.spacing(1.5)
292
+ }));
293
+ const SummaryHeaderLeft = stylin(Box)(({ theme }) => ({
294
+ display: "flex",
295
+ alignItems: "center",
296
+ flexWrap: "wrap",
297
+ gap: theme.spacing(1.5)
298
+ }));
299
+ const HeaderActions = stylin(Box)(({ theme }) => ({
300
+ display: "flex",
301
+ alignItems: "center",
302
+ gap: theme.spacing(1)
303
+ }));
304
+ const DefList = stylin(Box)(({ theme }) => ({
305
+ display: "flex",
306
+ flexDirection: "column",
307
+ gap: theme.spacing(1.25)
308
+ }));
309
+ const DefRow = stylin(Box)(({ theme }) => ({
310
+ display: "grid",
311
+ gridTemplateColumns: `${theme.spacing(18)} 1fr`,
312
+ alignItems: "center",
313
+ gap: theme.spacing(2),
314
+ [theme.breakpoints.down("sm")]: {
315
+ gridTemplateColumns: "1fr",
316
+ gap: theme.spacing(0.25)
317
+ }
318
+ }));
319
+ const DefLabel = stylin(Typography)(({ theme }) => ({
320
+ color: theme.palette.text.secondary,
321
+ fontSize: theme.typography.body2.fontSize,
322
+ textTransform: "uppercase",
323
+ letterSpacing: "0.04em",
324
+ fontWeight: theme.typography.fontWeightMedium
325
+ }));
326
+ const DefValue = stylin(Typography)(({ theme }) => ({
327
+ color: theme.palette.text.primary,
328
+ fontSize: theme.typography.body1.fontSize,
329
+ display: "flex",
330
+ alignItems: "center",
331
+ gap: theme.spacing(0.75),
332
+ minWidth: 0
333
+ }));
334
+ const DefMuted = stylin("span")(({ theme }) => ({
335
+ color: theme.palette.text.secondary
336
+ }));
337
+ const Mono = stylin("span")(({ theme }) => ({
338
+ fontFamily: theme.typography.fontFamilyMono,
339
+ fontSize: theme.typography.body2.fontSize,
340
+ color: theme.palette.text.primary,
341
+ wordBreak: "break-all",
342
+ minWidth: 0
343
+ }));
344
+ const MessageQuote = stylin(Box)(({ theme }) => ({
345
+ fontStyle: "italic",
346
+ color: theme.palette.text.secondary,
347
+ borderLeft: `3px solid ${theme.palette.divider}`,
348
+ paddingLeft: theme.spacing(1.5),
349
+ paddingTop: theme.spacing(0.5),
350
+ paddingBottom: theme.spacing(0.5)
351
+ }));
352
+ const PlanSourceBlock = stylin(Box)(({ theme }) => ({
353
+ display: "flex",
354
+ flexDirection: "column",
355
+ gap: theme.spacing(1),
356
+ alignItems: "flex-start"
357
+ }));
358
+ const PlanSourceLink = stylin(Button)(({ theme }) => ({
359
+ alignSelf: "flex-start",
360
+ padding: theme.spacing(0.25, 1),
361
+ marginLeft: theme.spacing(-1)
362
+ }));
363
+ const Section = stylin(Box)(({ theme }) => ({
364
+ display: "flex",
365
+ flexDirection: "column",
366
+ gap: theme.spacing(1)
367
+ }));
368
+ const SectionHeading = stylin(Typography)(({ theme }) => ({
369
+ fontWeight: theme.typography.fontWeightBold
370
+ }));
371
+ const Card = stylin(Box)(({ theme }) => ({
372
+ border: `1px solid ${theme.palette.divider}`,
373
+ borderRadius: 1,
374
+ padding: theme.spacing(1),
375
+ display: "flex",
376
+ flexDirection: "column",
377
+ gap: theme.spacing(0.5),
378
+ overflow: "hidden"
379
+ }));
380
+ const RowLine = stylin(Box)(({ theme }) => ({
381
+ display: "flex",
382
+ alignItems: "center",
383
+ gap: theme.spacing(1),
384
+ flexWrap: "wrap",
385
+ minWidth: 0
386
+ }));
387
+ const MonoLabel = stylin(Typography)(({ theme }) => ({
388
+ fontSize: theme.typography.pxToRem(11),
389
+ color: theme.palette.text.secondary,
390
+ minWidth: 110,
391
+ fontFamily: theme.typography.fontFamilyMono,
392
+ overflow: "hidden",
393
+ textOverflow: "ellipsis",
394
+ whiteSpace: "nowrap"
395
+ }));
396
+ const MonoValue = stylin(Typography)(({ theme }) => ({
397
+ fontSize: theme.typography.pxToRem(12),
398
+ color: theme.palette.text.primary,
399
+ fontFamily: theme.typography.fontFamilyMono,
400
+ overflow: "hidden",
401
+ textOverflow: "ellipsis",
402
+ whiteSpace: "nowrap",
403
+ flex: 1,
404
+ minWidth: 0
405
+ }));
406
+ const EmptyNote = stylin(Typography)(({ theme }) => ({
407
+ fontSize: theme.typography.pxToRem(12),
408
+ color: theme.palette.text.secondary,
409
+ fontStyle: "italic"
410
+ }));
411
+ const ValueText = stylin(Box)(({ theme }) => ({
412
+ fontFamily: theme.typography.fontFamilyMono,
413
+ fontSize: theme.typography.caption.fontSize,
414
+ color: theme.palette.text.secondary,
415
+ whiteSpace: "nowrap",
416
+ overflow: "hidden",
417
+ textOverflow: "ellipsis"
418
+ }));
419
+ const NullLiteral = stylin(Box)(({ theme }) => ({
420
+ fontStyle: "italic",
421
+ color: theme.palette.text.secondary,
422
+ fontFamily: theme.typography.fontFamilyMono,
423
+ fontSize: theme.typography.caption.fontSize
424
+ }));
425
+
426
+ export { ViewDeploymentDetailsDialog };
427
+ //# sourceMappingURL=ViewDeploymentDetailsDialog.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ViewDeploymentDetailsDialog.esm.js","sources":["../../../src/features/repo/ViewDeploymentDetailsDialog.tsx"],"sourcesContent":["import { useMemo } from 'react';\nimport { useSearchParams } from 'react-router-dom';\nimport { useApi } from '@backstage/frontend-plugin-api';\nimport useAsync from 'react-use/esm/useAsync';\nimport {\n Dialog,\n DialogActions,\n DialogContent,\n DialogHeader,\n} from '@massdriver/ui/Dialog';\nimport Box from '@massdriver/ui/Box';\nimport Typography from '@massdriver/ui/Typography';\nimport Button from '@massdriver/ui/Button';\nimport Tooltip from '@massdriver/ui/Tooltip';\nimport IconButton from '@massdriver/ui/IconButton';\nimport CopyButton from '@massdriver/ui/CopyButton';\nimport Alert from '@massdriver/ui/Alert';\nimport LoadingIndicator from '@massdriver/ui/LoadingIndicator';\nimport DataList, { col } from '@massdriver/ui/DataList';\nimport stylin from '@massdriver/ui/stylin';\nimport CloseIcon from '@massdriver/ui/icons/CloseIcon';\nimport HistoryIcon from '@massdriver/ui/icons/HistoryIcon';\nimport { massdriverApiRef } from '../../api';\nimport { InstanceStatusPill } from '../../components/InstanceStatusPill';\nimport VersionBadge from '../../components/VersionBadge';\nimport {\n composeInstanceStatus,\n formatInstanceStatus,\n isDeploymentActive,\n} from '../../utils/instanceStatuses';\nimport { formatRelativeTime } from '../../utils/formatRelativeTime';\nimport { DEPLOYMENT_DETAIL_QUERY } from './queries';\nimport {\n deploymentHasLogs,\n formatAbsoluteDateTime,\n formatAttributeValue,\n formatElapsed,\n parseMap,\n parsePlanMessage,\n parseRollbackMessage,\n stripMessageContext,\n truncateDeploymentId,\n} from './deploymentHelpers';\nimport flattenParams from './flattenParams';\nimport type { DeploymentDetail } from './types';\n\nconst TRUNCATE_LENGTH = 64;\n\nconst formatParamValue = (value: unknown): string => {\n if (typeof value === 'string') return value;\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n};\n\n// Present-value cell mirroring the web dialog's ComparisonValueCell (that\n// component lives under features/environment here, which repo code can't\n// import — so its read-only rendering is inlined).\nconst renderValueCell = (_value: unknown, row: { value: unknown }) => {\n const value = row.value;\n if (value == null) return <NullLiteral>null</NullLiteral>;\n const display = formatParamValue(value);\n const truncated = display.length > TRUNCATE_LENGTH;\n const visible = truncated ? `${display.slice(0, TRUNCATE_LENGTH)}…` : display;\n const cell = <ValueText>{visible}</ValueText>;\n return truncated ? (\n <Tooltip title={display} arrow placement=\"top\">\n <span>{cell}</span>\n </Tooltip>\n ) : (\n cell\n );\n};\n\nconst COLUMNS = [\n col.text('path', 'Path', {\n flex: 2,\n minWidth: 200,\n sortable: true,\n searchable: true,\n }),\n col.custom('value', 'Value', renderValueCell, {\n flex: 3,\n minWidth: 220,\n sortable: false,\n searchable: false,\n }),\n];\n\nconst isActiveStatus = (derivedStatus?: string | null): boolean => {\n if (!derivedStatus) return false;\n const [, deploymentStatus] = derivedStatus.split('_');\n return isDeploymentActive(deploymentStatus);\n};\n\n// Heading reads as \"{component} · {action verb} [time-ago]\". Active deployments\n// drop the trailing time-ago (it reads oddly for an in-flight thing); terminal\n// states keep it. Ported from the web dialog's buildHeading.\nconst buildHeading = (\n componentName: string | null | undefined,\n derivedStatus: string | null,\n time: string,\n): string => {\n const verb = derivedStatus\n ? formatInstanceStatus(derivedStatus).toLowerCase()\n : null;\n if (!componentName && !verb) return 'Deployment';\n if (!verb) return `${componentName} deployment`;\n const tail =\n time && time !== '--' && !isActiveStatus(derivedStatus) ? ` ${time}` : '';\n return componentName ? `${componentName} · ${verb}${tail}` : `${verb}${tail}`;\n};\n\n/**\n * In-place deployment details dialog for the repo Deployments tab. Faithful port\n * of apps/web/shared/components/ViewDeploymentDetailsDialog — driven by the same\n * `deployment` URL param the web reads via useDialogParam (mirrored here with\n * react-router's useSearchParams). The web repo page passes\n * `canApprove={false} canPlan={false}` (and no canRollback), under which the web\n * view renders no approve/reject/plan/rollback affordance at all — so none are\n * ported. The status pill and a \"View logs\" button open the logs drawer (the\n * `logs` param); the plan/rollback source links re-target the `deployment`\n * param, as in the web.\n */\nexport const ViewDeploymentDetailsDialog = () => {\n const api = useApi(massdriverApiRef);\n const [searchParams, setSearchParams] = useSearchParams();\n const deploymentId = searchParams.get('deployment');\n const open = Boolean(deploymentId);\n\n const setParam = (key: string, value: string | null) => {\n setSearchParams(\n prev => {\n const next = new URLSearchParams(prev);\n if (value) next.set(key, value);\n else next.delete(key);\n return next;\n },\n { replace: false },\n );\n };\n\n const onClose = () => setParam('deployment', null);\n const onShowSource = (sourceId: string) => setParam('deployment', sourceId);\n\n const { value, loading, error } = useAsync(async () => {\n if (!deploymentId) return null;\n const data = (await api.query(DEPLOYMENT_DETAIL_QUERY, {\n id: deploymentId,\n })) as { deployment: DeploymentDetail | null };\n return data.deployment;\n }, [api, deploymentId]);\n\n const deployment = value;\n const paramRows = useMemo(\n () => flattenParams(deployment?.params),\n [deployment?.params],\n );\n\n const derivedStatus = composeInstanceStatus(\n deployment?.action,\n deployment?.status,\n );\n const componentName = deployment?.instance?.component?.name;\n const elapsed = formatElapsed(deployment?.elapsedTime);\n const occurredIso = deployment?.lastTransitionedAt ?? deployment?.createdAt;\n const time = formatRelativeTime(occurredIso);\n const absoluteDate = formatAbsoluteDateTime(occurredIso);\n const deployedBy = deployment?.deployedBy ?? 'system';\n const statusLabel = formatInstanceStatus(derivedStatus);\n const heading = buildHeading(componentName, derivedStatus, time);\n\n const planSource =\n deployment?.action === 'PLAN'\n ? parsePlanMessage(deployment?.message)\n : null;\n const rollbackSource = parseRollbackMessage(deployment?.message);\n const displayMessage = stripMessageContext(deployment?.message);\n const isProposed = deployment?.status === 'PROPOSED';\n const hasLogs = deploymentHasLogs(deployment?.status);\n\n // Keep the dialog open beneath the logs drawer (which renders above it),\n // matching the web — the drawer's own `logs` param drives it.\n const onViewLogs = () => {\n if (!deployment) return;\n setParam('logs', deployment.id);\n };\n\n const attributes = parseMap(deployment?.effectiveAttributes);\n const attributeEntries = attributes ? Object.entries(attributes) : [];\n\n return (\n <Dialog open={open} onClose={onClose} maxWidth=\"md\" fullWidth>\n <DialogHeader\n icon={<HistoryIcon />}\n actions={\n <IconButton onClick={onClose} aria-label=\"Close deployment details\">\n <CloseIcon />\n </IconButton>\n }\n >\n {heading}\n </DialogHeader>\n <Body>\n {loading ? (\n <Centered>\n <LoadingIndicator />\n </Centered>\n ) : error ? (\n <Alert severity=\"error\">{String(error.message ?? error)}</Alert>\n ) : deployment ? (\n <>\n <SummaryCard>\n <SummaryHeader>\n <SummaryHeaderLeft>\n <InstanceStatusPill\n status={derivedStatus}\n onClick={hasLogs ? onViewLogs : undefined}\n />\n {deployment.version ? (\n <VersionBadge version={deployment.version} />\n ) : null}\n </SummaryHeaderLeft>\n {hasLogs ? (\n <HeaderActions>\n <Button\n variant=\"outlined\"\n size=\"small\"\n onClick={onViewLogs}\n >\n View logs\n </Button>\n </HeaderActions>\n ) : null}\n </SummaryHeader>\n\n <DefList>\n <DefRow>\n <DefLabel>Status</DefLabel>\n <DefValue>{statusLabel}</DefValue>\n </DefRow>\n <DefRow>\n <DefLabel>Occurred</DefLabel>\n <DefValue>\n {time}\n {absoluteDate ? (\n <DefMuted>{` · ${absoluteDate}`}</DefMuted>\n ) : null}\n </DefValue>\n </DefRow>\n <DefRow>\n <DefLabel>Duration</DefLabel>\n <DefValue>{elapsed ?? '—'}</DefValue>\n </DefRow>\n <DefRow>\n <DefLabel>Deployed by</DefLabel>\n <DefValue>\n <strong>{deployedBy}</strong>\n </DefValue>\n </DefRow>\n <DefRow>\n <DefLabel>Deployment ID</DefLabel>\n <DefValue>\n <Mono>{deployment.id}</Mono>\n <CopyButton\n text={deployment.id}\n ariaLabel=\"Copy deployment ID\"\n />\n </DefValue>\n </DefRow>\n </DefList>\n\n {planSource ? (\n <PlanSourceBlock>\n <PlanSourceLink\n variant=\"text\"\n size=\"small\"\n onClick={() => onShowSource(planSource.sourceId)}\n >\n Planned deployment of{' '}\n {truncateDeploymentId(planSource.sourceId)}\n </PlanSourceLink>\n {displayMessage ? (\n <MessageQuote>\"{displayMessage}\"</MessageQuote>\n ) : null}\n </PlanSourceBlock>\n ) : rollbackSource ? (\n <PlanSourceBlock>\n <PlanSourceLink\n variant=\"text\"\n size=\"small\"\n onClick={() => onShowSource(rollbackSource.sourceId)}\n >\n {isProposed\n ? 'Proposed rollback to deployment'\n : 'Rollback to deployment'}{' '}\n {truncateDeploymentId(rollbackSource.sourceId)}\n {rollbackSource.version\n ? ` (v${rollbackSource.version})`\n : ''}\n </PlanSourceLink>\n {displayMessage ? (\n <MessageQuote>\"{displayMessage}\"</MessageQuote>\n ) : null}\n </PlanSourceBlock>\n ) : displayMessage ? (\n <MessageQuote>\"{displayMessage}\"</MessageQuote>\n ) : null}\n </SummaryCard>\n\n <Section>\n <SectionHeading variant=\"subtitle1\">Attributes</SectionHeading>\n <Card>\n {attributeEntries.length === 0 ? (\n <EmptyNote>No effective attributes.</EmptyNote>\n ) : (\n attributeEntries.map(([key, attrValue]) => (\n <RowLine key={key}>\n <MonoLabel title={key}>{key}</MonoLabel>\n <MonoValue title={formatAttributeValue(attrValue)}>\n {formatAttributeValue(attrValue)}\n </MonoValue>\n </RowLine>\n ))\n )}\n </Card>\n </Section>\n\n <Section>\n <SectionHeading variant=\"subtitle1\">\n Snapshot params\n </SectionHeading>\n <DataList\n rows={paramRows}\n columns={COLUMNS}\n searchable\n searchPlaceholder=\"Search path…\"\n defaultSort={{ field: 'path', direction: 'asc' }}\n defaultPageSize={5}\n variant=\"outlined\"\n size=\"small\"\n emptyMessage=\"No parameters captured for this deployment.\"\n />\n </Section>\n </>\n ) : null}\n </Body>\n <DialogActions>\n <Button variant=\"contained\" onClick={onClose}>\n Close\n </Button>\n </DialogActions>\n </Dialog>\n );\n};\n\nexport default ViewDeploymentDetailsDialog;\n\nconst Body = stylin(DialogContent)(({ theme }: { theme: any }) => ({\n display: 'flex',\n flexDirection: 'column',\n gap: theme.spacing(2),\n '& > *': {\n flexShrink: 0,\n },\n}));\n\nconst Centered = stylin(Box)(({ theme }: { theme: any }) => ({\n display: 'flex',\n justifyContent: 'center',\n padding: theme.spacing(6),\n}));\n\nconst SummaryCard = stylin(Box)(({ theme }: { theme: any }) => ({\n display: 'flex',\n flexDirection: 'column',\n gap: theme.spacing(2.5),\n padding: theme.spacing(2.5, 3),\n borderRadius: 1,\n border: `1px solid ${theme.palette.divider}`,\n backgroundColor: theme.palette.background.paper,\n}));\n\nconst SummaryHeader = stylin(Box)(({ theme }: { theme: any }) => ({\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n flexWrap: 'wrap',\n gap: theme.spacing(1.5),\n}));\n\nconst SummaryHeaderLeft = stylin(Box)(({ theme }: { theme: any }) => ({\n display: 'flex',\n alignItems: 'center',\n flexWrap: 'wrap',\n gap: theme.spacing(1.5),\n}));\n\nconst HeaderActions = stylin(Box)(({ theme }: { theme: any }) => ({\n display: 'flex',\n alignItems: 'center',\n gap: theme.spacing(1),\n}));\n\nconst DefList = stylin(Box)(({ theme }: { theme: any }) => ({\n display: 'flex',\n flexDirection: 'column',\n gap: theme.spacing(1.25),\n}));\n\nconst DefRow = stylin(Box)(({ theme }: { theme: any }) => ({\n display: 'grid',\n gridTemplateColumns: `${theme.spacing(18)} 1fr`,\n alignItems: 'center',\n gap: theme.spacing(2),\n [theme.breakpoints.down('sm')]: {\n gridTemplateColumns: '1fr',\n gap: theme.spacing(0.25),\n },\n}));\n\nconst DefLabel = stylin(Typography)(({ theme }: { theme: any }) => ({\n color: theme.palette.text.secondary,\n fontSize: theme.typography.body2.fontSize,\n textTransform: 'uppercase',\n letterSpacing: '0.04em',\n fontWeight: theme.typography.fontWeightMedium,\n}));\n\nconst DefValue = stylin(Typography)(({ theme }: { theme: any }) => ({\n color: theme.palette.text.primary,\n fontSize: theme.typography.body1.fontSize,\n display: 'flex',\n alignItems: 'center',\n gap: theme.spacing(0.75),\n minWidth: 0,\n}));\n\nconst DefMuted = stylin('span')(({ theme }: { theme: any }) => ({\n color: theme.palette.text.secondary,\n}));\n\nconst Mono = stylin('span')(({ theme }: { theme: any }) => ({\n fontFamily: theme.typography.fontFamilyMono,\n fontSize: theme.typography.body2.fontSize,\n color: theme.palette.text.primary,\n wordBreak: 'break-all',\n minWidth: 0,\n}));\n\nconst MessageQuote = stylin(Box)(({ theme }: { theme: any }) => ({\n fontStyle: 'italic',\n color: theme.palette.text.secondary,\n borderLeft: `3px solid ${theme.palette.divider}`,\n paddingLeft: theme.spacing(1.5),\n paddingTop: theme.spacing(0.5),\n paddingBottom: theme.spacing(0.5),\n}));\n\nconst PlanSourceBlock = stylin(Box)(({ theme }: { theme: any }) => ({\n display: 'flex',\n flexDirection: 'column',\n gap: theme.spacing(1),\n alignItems: 'flex-start',\n}));\n\nconst PlanSourceLink = stylin(Button)(({ theme }: { theme: any }) => ({\n alignSelf: 'flex-start',\n padding: theme.spacing(0.25, 1),\n marginLeft: theme.spacing(-1),\n}));\n\nconst Section = stylin(Box)(({ theme }: { theme: any }) => ({\n display: 'flex',\n flexDirection: 'column',\n gap: theme.spacing(1),\n}));\n\nconst SectionHeading = stylin(Typography)(({ theme }: { theme: any }) => ({\n fontWeight: theme.typography.fontWeightBold,\n}));\n\nconst Card = stylin(Box)(({ theme }: { theme: any }) => ({\n border: `1px solid ${theme.palette.divider}`,\n borderRadius: 1,\n padding: theme.spacing(1),\n display: 'flex',\n flexDirection: 'column',\n gap: theme.spacing(0.5),\n overflow: 'hidden',\n}));\n\nconst RowLine = stylin(Box)(({ theme }: { theme: any }) => ({\n display: 'flex',\n alignItems: 'center',\n gap: theme.spacing(1),\n flexWrap: 'wrap',\n minWidth: 0,\n}));\n\nconst MonoLabel = stylin(Typography)(({ theme }: { theme: any }) => ({\n fontSize: theme.typography.pxToRem(11),\n color: theme.palette.text.secondary,\n minWidth: 110,\n fontFamily: theme.typography.fontFamilyMono,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n}));\n\nconst MonoValue = stylin(Typography)(({ theme }: { theme: any }) => ({\n fontSize: theme.typography.pxToRem(12),\n color: theme.palette.text.primary,\n fontFamily: theme.typography.fontFamilyMono,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n flex: 1,\n minWidth: 0,\n}));\n\nconst EmptyNote = stylin(Typography)(({ theme }: { theme: any }) => ({\n fontSize: theme.typography.pxToRem(12),\n color: theme.palette.text.secondary,\n fontStyle: 'italic',\n}));\n\nconst ValueText = stylin(Box)(({ theme }: { theme: any }) => ({\n fontFamily: theme.typography.fontFamilyMono,\n fontSize: theme.typography.caption.fontSize,\n color: theme.palette.text.secondary,\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n}));\n\nconst NullLiteral = stylin(Box)(({ theme }: { theme: any }) => ({\n fontStyle: 'italic',\n color: theme.palette.text.secondary,\n fontFamily: theme.typography.fontFamilyMono,\n fontSize: theme.typography.caption.fontSize,\n}));\n"],"names":["value"],"mappings":"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"}
@@ -0,0 +1,74 @@
1
+ import { formatInstanceStatus, composeInstanceStatus } from '../../utils/instanceStatuses.esm.js';
2
+ export { isDeploymentActive } from '../../utils/instanceStatuses.esm.js';
3
+
4
+ const truncateDeploymentId = (id) => {
5
+ if (!id) return "";
6
+ const parts = id.split("-");
7
+ return parts.length > 1 ? parts[parts.length - 1] : id;
8
+ };
9
+ const PLAN_SOURCE_REGEX = /^Planning deployment ([0-9a-fA-F-]{36})(?:\n([\s\S]*))?$/;
10
+ const parsePlanMessage = (message) => {
11
+ if (!message) return null;
12
+ const match = PLAN_SOURCE_REGEX.exec(message);
13
+ if (!match) return null;
14
+ return { sourceId: match[1], sourceMessage: match[2] ?? "" };
15
+ };
16
+ const formatElapsed = (seconds) => {
17
+ if (!seconds || seconds <= 0) return null;
18
+ const minutes = Math.floor(seconds / 60);
19
+ const remainder = seconds % 60;
20
+ return `${minutes}m ${remainder}s`;
21
+ };
22
+ const ROLLBACK_SOURCE_REGEX = /^Rollback to deployment ([0-9a-fA-F-]{36}) \(v([^)]*)\)(?:\n([\s\S]*))?$/;
23
+ const parseRollbackMessage = (message) => {
24
+ if (!message) return null;
25
+ const match = ROLLBACK_SOURCE_REGEX.exec(message);
26
+ return match ? { sourceId: match[1], version: match[2], sourceMessage: match[3] ?? "" } : null;
27
+ };
28
+ const stripMessageContext = (message) => {
29
+ const current = message ?? "";
30
+ if (!current) return current;
31
+ const plan = parsePlanMessage(current);
32
+ if (plan) return stripMessageContext(plan.sourceMessage);
33
+ const rollback = parseRollbackMessage(current);
34
+ if (rollback) return stripMessageContext(rollback.sourceMessage);
35
+ return current;
36
+ };
37
+ const formatDeploymentStatus = (action, status) => formatInstanceStatus(composeInstanceStatus(action, status));
38
+ const STATUSES_WITHOUT_LOGS = ["PROPOSED", "APPROVED", "REJECTED"];
39
+ const deploymentHasLogs = (status) => Boolean(status) && !STATUSES_WITHOUT_LOGS.includes(status);
40
+ const composeLogsText = (logs) => {
41
+ if (!Array.isArray(logs) || logs.length === 0) return "";
42
+ const joined = logs.map((line) => line?.message ?? "").join("");
43
+ return `
44
+ ${joined}${joined.endsWith("\n") ? "" : "\n"}`;
45
+ };
46
+ const parseMap = (value) => {
47
+ if (value == null) return null;
48
+ if (typeof value === "object") return value;
49
+ try {
50
+ return JSON.parse(value);
51
+ } catch {
52
+ return null;
53
+ }
54
+ };
55
+ const formatAttributeValue = (value) => {
56
+ if (value === "*") return "any";
57
+ if (Array.isArray(value))
58
+ return value.length === 0 ? "any" : value.join(", ");
59
+ return String(value);
60
+ };
61
+ const ABSOLUTE_FORMATTER = new Intl.DateTimeFormat("en", {
62
+ month: "short",
63
+ day: "numeric",
64
+ hour: "numeric",
65
+ minute: "2-digit"
66
+ });
67
+ const formatAbsoluteDateTime = (isoString, fallback = "") => {
68
+ if (!isoString) return fallback;
69
+ const date = new Date(isoString);
70
+ return Number.isNaN(date.getTime()) ? fallback : ABSOLUTE_FORMATTER.format(date);
71
+ };
72
+
73
+ export { STATUSES_WITHOUT_LOGS, composeLogsText, deploymentHasLogs, formatAbsoluteDateTime, formatAttributeValue, formatDeploymentStatus, formatElapsed, parseMap, parsePlanMessage, parseRollbackMessage, stripMessageContext, truncateDeploymentId };
74
+ //# sourceMappingURL=deploymentHelpers.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deploymentHelpers.esm.js","sources":["../../../src/features/repo/deploymentHelpers.ts"],"sourcesContent":["// Ported from apps/web/shared/utils/historyHelpers.js and the web app's\n// ViewDeploymentDetailsDialog / DeploymentLogsDrawer components — the pieces the\n// deployments list, the in-place details dialog, and the logs drawer need.\nimport {\n composeInstanceStatus,\n formatInstanceStatus,\n} from '../../utils/instanceStatuses';\n\n// Re-exported for the logs drawer, which decides off deployment liveness\n// whether to keep the log subscription open.\nexport { isDeploymentActive } from '../../utils/instanceStatuses';\n\n/** The last hyphen-delimited segment of a deployment id (a short handle). */\nexport const truncateDeploymentId = (id?: string | null): string => {\n if (!id) return '';\n const parts = id.split('-');\n return parts.length > 1 ? parts[parts.length - 1] : id;\n};\n\nconst PLAN_SOURCE_REGEX =\n /^Planning deployment ([0-9a-fA-F-]{36})(?:\\n([\\s\\S]*))?$/;\n\n/**\n * Plan deployments encode their source deployment id in the message\n * (\"Planning deployment <uuid>\\n<source-message>\"). Returns the parsed source\n * id + human message, or null when the message isn't a plan precursor.\n */\nexport const parsePlanMessage = (\n message?: string | null,\n): { sourceId: string; sourceMessage: string } | null => {\n if (!message) return null;\n const match = PLAN_SOURCE_REGEX.exec(message);\n if (!match) return null;\n return { sourceId: match[1], sourceMessage: match[2] ?? '' };\n};\n\n/**\n * Ported from apps/web/shared/utils/historyHelpers.js — a deployment's elapsed\n * run time as \"Xm Ys\". Returns null for missing / non-positive durations so the\n * row can omit the segment entirely.\n */\nexport const formatElapsed = (seconds?: number | null): string | null => {\n if (!seconds || seconds <= 0) return null;\n const minutes = Math.floor(seconds / 60);\n const remainder = seconds % 60;\n return `${minutes}m ${remainder}s`;\n};\n\nconst ROLLBACK_SOURCE_REGEX =\n /^Rollback to deployment ([0-9a-fA-F-]{36}) \\(v([^)]*)\\)(?:\\n([\\s\\S]*))?$/;\n\n/**\n * Rollback proposals encode their source deployment + version in the message\n * (\"Rollback to deployment <uuid> (v<version>)\\n<source-message>\"). Returns the\n * parsed source id/version/message, or null when it isn't a rollback precursor.\n */\nexport const parseRollbackMessage = (\n message?: string | null,\n): { sourceId: string; version: string; sourceMessage: string } | null => {\n if (!message) return null;\n const match = ROLLBACK_SOURCE_REGEX.exec(message);\n return match\n ? { sourceId: match[1], version: match[2], sourceMessage: match[3] ?? '' }\n : null;\n};\n\n/**\n * Strip the plan/rollback precursor from a message, leaving only the\n * human-authored note. Recurses because a rollback's source can itself be a\n * plan. Ported from the web app's `stripMessageContext`.\n */\nexport const stripMessageContext = (message?: string | null): string => {\n const current = message ?? '';\n if (!current) return current;\n const plan = parsePlanMessage(current);\n if (plan) return stripMessageContext(plan.sourceMessage);\n const rollback = parseRollbackMessage(current);\n if (rollback) return stripMessageContext(rollback.sourceMessage);\n return current;\n};\n\n/**\n * Compound human label for a deployment (action + deployment status), e.g.\n * \"Provision Running\", \"Provisioning Failed\", \"Provisioned\".\n */\nexport const formatDeploymentStatus = (\n action?: string | null,\n status?: string | null,\n): string => formatInstanceStatus(composeInstanceStatus(action, status));\n\n// Statuses that never produce a deployment log stream — everything else has (or\n// will have) logs to view in-app. Ported from the web dialog's\n// STATUSES_WITHOUT_LOGS.\nexport const STATUSES_WITHOUT_LOGS = ['PROPOSED', 'APPROVED', 'REJECTED'];\n\nexport const deploymentHasLogs = (status?: string | null): boolean =>\n Boolean(status) && !STATUSES_WITHOUT_LOGS.includes(status as string);\n\n/**\n * Join a deployment's log batches into a single string for LogViewer, matching\n * the web app's `composeText`: each batch may already carry its own newlines, so\n * concatenate without inserting separators and guarantee a trailing newline.\n */\nexport const composeLogsText = (\n logs?: ({ message?: string | null } | null)[] | null,\n): string => {\n if (!Array.isArray(logs) || logs.length === 0) return '';\n const joined = logs.map(line => line?.message ?? '').join('');\n return `\\n${joined}${joined.endsWith('\\n') ? '' : '\\n'}`;\n};\n\nexport const parseMap = (value: unknown): Record<string, unknown> | null => {\n if (value == null) return null;\n if (typeof value === 'object') return value as Record<string, unknown>;\n try {\n return JSON.parse(value as string);\n } catch {\n return null;\n }\n};\n\nexport const formatAttributeValue = (value: unknown): string => {\n if (value === '*') return 'any';\n if (Array.isArray(value))\n return value.length === 0 ? 'any' : value.join(', ');\n return String(value);\n};\n\nconst ABSOLUTE_FORMATTER = new Intl.DateTimeFormat('en', {\n month: 'short',\n day: 'numeric',\n hour: 'numeric',\n minute: '2-digit',\n});\n\n/** Compact absolute timestamp for the details def-list (\"Jul 9, 3:04 PM\"). */\nexport const formatAbsoluteDateTime = (\n isoString?: string | null,\n fallback = '',\n): string => {\n if (!isoString) return fallback;\n const date = new Date(isoString);\n return Number.isNaN(date.getTime())\n ? fallback\n : ABSOLUTE_FORMATTER.format(date);\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ const materialize = (node) => {
2
+ const folders = Object.values(node.children).map(materialize).sort((left, right) => left.name.localeCompare(right.name));
3
+ const files = [...node.files].sort(
4
+ (left, right) => left.name.localeCompare(right.name)
5
+ );
6
+ return { name: node.name, path: node.path, folders, files };
7
+ };
8
+ const buildFileTree = (files) => {
9
+ const root = { name: "", path: "", children: {}, files: [] };
10
+ (files ?? []).forEach((file) => {
11
+ if (!file?.name) return;
12
+ const segments = file.name.split("/").filter(Boolean);
13
+ if (segments.length === 0) return;
14
+ const fileName = segments[segments.length - 1];
15
+ const dirSegments = segments.slice(0, -1);
16
+ const dirNode = dirSegments.reduce((node, segment) => {
17
+ const path = node.path ? `${node.path}/${segment}` : segment;
18
+ if (!node.children[segment]) {
19
+ node.children[segment] = {
20
+ name: segment,
21
+ path,
22
+ children: {},
23
+ files: []
24
+ };
25
+ }
26
+ return node.children[segment];
27
+ }, root);
28
+ dirNode.files.push({ name: fileName, path: file.name, file });
29
+ });
30
+ return materialize(root);
31
+ };
32
+ const ancestorPaths = (selectedPath) => {
33
+ if (!selectedPath) return /* @__PURE__ */ new Set();
34
+ const segments = selectedPath.split("/").filter(Boolean);
35
+ const ancestors = /* @__PURE__ */ new Set();
36
+ segments.slice(0, -1).reduce((prefix, segment) => {
37
+ const path = prefix ? `${prefix}/${segment}` : segment;
38
+ ancestors.add(path);
39
+ return path;
40
+ }, "");
41
+ return ancestors;
42
+ };
43
+
44
+ export { ancestorPaths, buildFileTree };
45
+ //# sourceMappingURL=fileTreeHelpers.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileTreeHelpers.esm.js","sources":["../../../src/features/repo/fileTreeHelpers.ts"],"sourcesContent":["import type { RepoFile } from './types';\n\n// Ported from apps/web/features/repos/components/FileTree/FileTree.helpers.js.\n\nexport interface FileNode {\n name: string;\n path: string;\n file: RepoFile;\n}\n\nexport interface TreeNode {\n name: string;\n path: string;\n folders: TreeNode[];\n files: FileNode[];\n}\n\ninterface MutableNode {\n name: string;\n path: string;\n children: Record<string, MutableNode>;\n files: FileNode[];\n}\n\nconst materialize = (node: MutableNode): TreeNode => {\n const folders = Object.values(node.children)\n .map(materialize)\n .sort((left, right) => left.name.localeCompare(right.name));\n const files = [...node.files].sort((left, right) =>\n left.name.localeCompare(right.name),\n );\n return { name: node.name, path: node.path, folders, files };\n};\n\n/**\n * Build a nested tree from a flat list of files keyed by their path. Folders\n * sort before files; alpha within each group.\n */\nexport const buildFileTree = (\n files: RepoFile[] | null | undefined,\n): TreeNode => {\n const root: MutableNode = { name: '', path: '', children: {}, files: [] };\n\n (files ?? []).forEach(file => {\n if (!file?.name) return;\n const segments = file.name.split('/').filter(Boolean);\n if (segments.length === 0) return;\n\n const fileName = segments[segments.length - 1];\n const dirSegments = segments.slice(0, -1);\n\n const dirNode = dirSegments.reduce((node, segment) => {\n const path = node.path ? `${node.path}/${segment}` : segment;\n if (!node.children[segment]) {\n node.children[segment] = {\n name: segment,\n path,\n children: {},\n files: [],\n };\n }\n return node.children[segment];\n }, root);\n\n dirNode.files.push({ name: fileName, path: file.name, file });\n });\n\n return materialize(root);\n};\n\n/**\n * Returns the set of folder paths that contain `selectedPath`, so the tree can\n * auto-expand to reveal the selection.\n */\nexport const ancestorPaths = (\n selectedPath: string | null | undefined,\n): Set<string> => {\n if (!selectedPath) return new Set();\n const segments = selectedPath.split('/').filter(Boolean);\n const ancestors = new Set<string>();\n segments.slice(0, -1).reduce((prefix, segment) => {\n const path = prefix ? `${prefix}/${segment}` : segment;\n ancestors.add(path);\n return path;\n }, '');\n return ancestors;\n};\n"],"names":[],"mappings":"AAwBA,MAAM,WAAA,GAAc,CAAC,IAAA,KAAgC;AACnD,EAAA,MAAM,UAAU,MAAA,CAAO,MAAA,CAAO,KAAK,QAAQ,CAAA,CACxC,IAAI,WAAW,CAAA,CACf,IAAA,CAAK,CAAC,MAAM,KAAA,KAAU,IAAA,CAAK,KAAK,aAAA,CAAc,KAAA,CAAM,IAAI,CAAC,CAAA;AAC5D,EAAA,MAAM,KAAA,GAAQ,CAAC,GAAG,IAAA,CAAK,KAAK,CAAA,CAAE,IAAA;AAAA,IAAK,CAAC,IAAA,EAAM,KAAA,KACxC,KAAK,IAAA,CAAK,aAAA,CAAc,MAAM,IAAI;AAAA,GACpC;AACA,EAAA,OAAO,EAAE,MAAM,IAAA,CAAK,IAAA,EAAM,MAAM,IAAA,CAAK,IAAA,EAAM,SAAS,KAAA,EAAM;AAC5D,CAAA;AAMO,MAAM,aAAA,GAAgB,CAC3B,KAAA,KACa;AACb,EAAA,MAAM,IAAA,GAAoB,EAAE,IAAA,EAAM,EAAA,EAAI,IAAA,EAAM,EAAA,EAAI,QAAA,EAAU,EAAC,EAAG,KAAA,EAAO,EAAC,EAAE;AAExE,EAAA,CAAC,KAAA,IAAS,EAAC,EAAG,OAAA,CAAQ,CAAA,IAAA,KAAQ;AAC5B,IAAA,IAAI,CAAC,MAAM,IAAA,EAAM;AACjB,IAAA,MAAM,WAAW,IAAA,CAAK,IAAA,CAAK,MAAM,GAAG,CAAA,CAAE,OAAO,OAAO,CAAA;AACpD,IAAA,IAAI,QAAA,CAAS,WAAW,CAAA,EAAG;AAE3B,IAAA,MAAM,QAAA,GAAW,QAAA,CAAS,QAAA,CAAS,MAAA,GAAS,CAAC,CAAA;AAC7C,IAAA,MAAM,WAAA,GAAc,QAAA,CAAS,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAExC,IAAA,MAAM,OAAA,GAAU,WAAA,CAAY,MAAA,CAAO,CAAC,MAAM,OAAA,KAAY;AACpD,MAAA,MAAM,IAAA,GAAO,KAAK,IAAA,GAAO,CAAA,EAAG,KAAK,IAAI,CAAA,CAAA,EAAI,OAAO,CAAA,CAAA,GAAK,OAAA;AACrD,MAAA,IAAI,CAAC,IAAA,CAAK,QAAA,CAAS,OAAO,CAAA,EAAG;AAC3B,QAAA,IAAA,CAAK,QAAA,CAAS,OAAO,CAAA,GAAI;AAAA,UACvB,IAAA,EAAM,OAAA;AAAA,UACN,IAAA;AAAA,UACA,UAAU,EAAC;AAAA,UACX,OAAO;AAAC,SACV;AAAA,MACF;AACA,MAAA,OAAO,IAAA,CAAK,SAAS,OAAO,CAAA;AAAA,IAC9B,GAAG,IAAI,CAAA;AAEP,IAAA,OAAA,CAAQ,KAAA,CAAM,KAAK,EAAE,IAAA,EAAM,UAAU,IAAA,EAAM,IAAA,CAAK,IAAA,EAAM,IAAA,EAAM,CAAA;AAAA,EAC9D,CAAC,CAAA;AAED,EAAA,OAAO,YAAY,IAAI,CAAA;AACzB;AAMO,MAAM,aAAA,GAAgB,CAC3B,YAAA,KACgB;AAChB,EAAA,IAAI,CAAC,YAAA,EAAc,uBAAO,IAAI,GAAA,EAAI;AAClC,EAAA,MAAM,WAAW,YAAA,CAAa,KAAA,CAAM,GAAG,CAAA,CAAE,OAAO,OAAO,CAAA;AACvD,EAAA,MAAM,SAAA,uBAAgB,GAAA,EAAY;AAClC,EAAA,QAAA,CAAS,MAAM,CAAA,EAAG,EAAE,EAAE,MAAA,CAAO,CAAC,QAAQ,OAAA,KAAY;AAChD,IAAA,MAAM,OAAO,MAAA,GAAS,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,OAAO,CAAA,CAAA,GAAK,OAAA;AAC/C,IAAA,SAAA,CAAU,IAAI,IAAI,CAAA;AAClB,IAAA,OAAO,IAAA;AAAA,EACT,GAAG,EAAE,CAAA;AACL,EAAA,OAAO,SAAA;AACT;;;;"}