@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.
- package/LICENSE +202 -0
- package/README.md +196 -0
- package/dist/MassdriverRouter.esm.js +78 -0
- package/dist/MassdriverRouter.esm.js.map +1 -0
- package/dist/api.esm.js +119 -0
- package/dist/api.esm.js.map +1 -0
- package/dist/assets/massdriver-logo-dark.svg +55 -0
- package/dist/assets/massdriver-logo-light.svg +50 -0
- package/dist/components/AttributesColumn.esm.js +95 -0
- package/dist/components/AttributesColumn.esm.js.map +1 -0
- package/dist/components/AttributesSummaryCell.esm.js +103 -0
- package/dist/components/AttributesSummaryCell.esm.js.map +1 -0
- package/dist/components/AuthedIcon.esm.js +26 -0
- package/dist/components/AuthedIcon.esm.js.map +1 -0
- package/dist/components/ConditionsCell.esm.js +48 -0
- package/dist/components/ConditionsCell.esm.js.map +1 -0
- package/dist/components/DisabledAction.esm.js +30 -0
- package/dist/components/DisabledAction.esm.js.map +1 -0
- package/dist/components/EntityMassdriverContent/EntityMassdriverContent.esm.js +80 -0
- package/dist/components/EntityMassdriverContent/EntityMassdriverContent.esm.js.map +1 -0
- package/dist/components/EntityMassdriverContent/index.esm.js +6 -0
- package/dist/components/EntityMassdriverContent/index.esm.js.map +1 -0
- package/dist/components/EntityMassdriverOverviewCard/EntityMassdriverOverviewCard.esm.js +75 -0
- package/dist/components/EntityMassdriverOverviewCard/EntityMassdriverOverviewCard.esm.js.map +1 -0
- package/dist/components/EntityMassdriverOverviewCard/index.esm.js +6 -0
- package/dist/components/EntityMassdriverOverviewCard/index.esm.js.map +1 -0
- package/dist/components/ForkPill.esm.js +84 -0
- package/dist/components/ForkPill.esm.js.map +1 -0
- package/dist/components/InstanceStatusIndicator.esm.js +21 -0
- package/dist/components/InstanceStatusIndicator.esm.js.map +1 -0
- package/dist/components/InstanceStatusPill.esm.js +67 -0
- package/dist/components/InstanceStatusPill.esm.js.map +1 -0
- package/dist/components/MassdriverIcon.esm.js +13 -0
- package/dist/components/MassdriverIcon.esm.js.map +1 -0
- package/dist/components/MassdriverSidebarItem.esm.js +45 -0
- package/dist/components/MassdriverSidebarItem.esm.js.map +1 -0
- package/dist/components/NotFound.esm.js +44 -0
- package/dist/components/NotFound.esm.js.map +1 -0
- package/dist/components/OpenInMassdriverButton.esm.js +24 -0
- package/dist/components/OpenInMassdriverButton.esm.js.map +1 -0
- package/dist/components/PageLayout.esm.js +88 -0
- package/dist/components/PageLayout.esm.js.map +1 -0
- package/dist/components/RouterLinkAdapter.esm.js +12 -0
- package/dist/components/RouterLinkAdapter.esm.js.map +1 -0
- package/dist/components/VersionBadge.esm.js +57 -0
- package/dist/components/VersionBadge.esm.js.map +1 -0
- package/dist/components/grantColumns.esm.js +56 -0
- package/dist/components/grantColumns.esm.js.map +1 -0
- package/dist/components/icons/BundleIcon.esm.js +7 -0
- package/dist/components/icons/BundleIcon.esm.js.map +1 -0
- package/dist/components/icons/FolderOutlinedIcon.esm.js +7 -0
- package/dist/components/icons/FolderOutlinedIcon.esm.js.map +1 -0
- package/dist/components/icons/TokenIcon.esm.js +7 -0
- package/dist/components/icons/TokenIcon.esm.js.map +1 -0
- package/dist/entity.esm.js +23 -0
- package/dist/entity.esm.js.map +1 -0
- package/dist/features/environment/CompareDeploymentsDialog/CompareDeploymentsDialog.esm.js +115 -0
- package/dist/features/environment/CompareDeploymentsDialog/CompareDeploymentsDialog.esm.js.map +1 -0
- package/dist/features/environment/CompareDeploymentsDialog/ResultsStep.esm.js +165 -0
- package/dist/features/environment/CompareDeploymentsDialog/ResultsStep.esm.js.map +1 -0
- package/dist/features/environment/CompareDeploymentsDialog/SelectStep.esm.js +216 -0
- package/dist/features/environment/CompareDeploymentsDialog/SelectStep.esm.js.map +1 -0
- package/dist/features/environment/CompareDeploymentsDialog/compareColumns.esm.js +86 -0
- package/dist/features/environment/CompareDeploymentsDialog/compareColumns.esm.js.map +1 -0
- package/dist/features/environment/CompareDeploymentsDialog/flattenDeploymentComparison.esm.js +57 -0
- package/dist/features/environment/CompareDeploymentsDialog/flattenDeploymentComparison.esm.js.map +1 -0
- package/dist/features/environment/CompareDeploymentsDialog/queries.esm.js +53 -0
- package/dist/features/environment/CompareDeploymentsDialog/queries.esm.js.map +1 -0
- package/dist/features/environment/CompareEnvironmentsDialog/CompareEnvironmentsDialog.esm.js +94 -0
- package/dist/features/environment/CompareEnvironmentsDialog/CompareEnvironmentsDialog.esm.js.map +1 -0
- package/dist/features/environment/CompareEnvironmentsDialog/ComparisonValueCell.esm.js +67 -0
- package/dist/features/environment/CompareEnvironmentsDialog/ComparisonValueCell.esm.js.map +1 -0
- package/dist/features/environment/CompareEnvironmentsDialog/ResultsStep.esm.js +202 -0
- package/dist/features/environment/CompareEnvironmentsDialog/ResultsStep.esm.js.map +1 -0
- package/dist/features/environment/CompareEnvironmentsDialog/SelectStep.esm.js +183 -0
- package/dist/features/environment/CompareEnvironmentsDialog/SelectStep.esm.js.map +1 -0
- package/dist/features/environment/CompareEnvironmentsDialog/compareColumns.esm.js +73 -0
- package/dist/features/environment/CompareEnvironmentsDialog/compareColumns.esm.js.map +1 -0
- package/dist/features/environment/CompareEnvironmentsDialog/flattenComparison.esm.js +70 -0
- package/dist/features/environment/CompareEnvironmentsDialog/flattenComparison.esm.js.map +1 -0
- package/dist/features/environment/CompareEnvironmentsDialog/queries.esm.js +32 -0
- package/dist/features/environment/CompareEnvironmentsDialog/queries.esm.js.map +1 -0
- package/dist/features/environment/EnvironmentGraphPage.esm.js +131 -0
- package/dist/features/environment/EnvironmentGraphPage.esm.js.map +1 -0
- package/dist/features/environment/GraphHeader/EnvironmentDefaults.esm.js +252 -0
- package/dist/features/environment/GraphHeader/EnvironmentDefaults.esm.js.map +1 -0
- package/dist/features/environment/GraphHeader/GraphHeader.esm.js +247 -0
- package/dist/features/environment/GraphHeader/GraphHeader.esm.js.map +1 -0
- package/dist/features/environment/GraphHeader/HeaderActions.esm.js +127 -0
- package/dist/features/environment/GraphHeader/HeaderActions.esm.js.map +1 -0
- package/dist/features/environment/GraphHeader/Switcher.esm.js +75 -0
- package/dist/features/environment/GraphHeader/Switcher.esm.js.map +1 -0
- package/dist/features/environment/GraphHeader/queries.esm.js +60 -0
- package/dist/features/environment/GraphHeader/queries.esm.js.map +1 -0
- package/dist/features/environment/InstanceDrawer/AlarmCard.esm.js +151 -0
- package/dist/features/environment/InstanceDrawer/AlarmCard.esm.js.map +1 -0
- package/dist/features/environment/InstanceDrawer/InstanceDrawer.esm.js +165 -0
- package/dist/features/environment/InstanceDrawer/InstanceDrawer.esm.js.map +1 -0
- package/dist/features/environment/InstanceDrawer/InstanceDrawerHeader.esm.js +241 -0
- package/dist/features/environment/InstanceDrawer/InstanceDrawerHeader.esm.js.map +1 -0
- package/dist/features/environment/InstanceDrawer/InstanceTabs.esm.js +119 -0
- package/dist/features/environment/InstanceDrawer/InstanceTabs.esm.js.map +1 -0
- package/dist/features/environment/InstanceDrawer/TabState.esm.js +30 -0
- package/dist/features/environment/InstanceDrawer/TabState.esm.js.map +1 -0
- package/dist/features/environment/InstanceDrawer/formsDataSource.esm.js +25 -0
- package/dist/features/environment/InstanceDrawer/formsDataSource.esm.js.map +1 -0
- package/dist/features/environment/InstanceDrawer/helpers.esm.js +282 -0
- package/dist/features/environment/InstanceDrawer/helpers.esm.js.map +1 -0
- package/dist/features/environment/InstanceDrawer/queries.esm.js +281 -0
- package/dist/features/environment/InstanceDrawer/queries.esm.js.map +1 -0
- package/dist/features/environment/InstanceDrawer/tabs/ConfigTab.esm.js +170 -0
- package/dist/features/environment/InstanceDrawer/tabs/ConfigTab.esm.js.map +1 -0
- package/dist/features/environment/InstanceDrawer/tabs/DependenciesTab.esm.js +413 -0
- package/dist/features/environment/InstanceDrawer/tabs/DependenciesTab.esm.js.map +1 -0
- package/dist/features/environment/InstanceDrawer/tabs/DeploymentLogsPanel.esm.js +191 -0
- package/dist/features/environment/InstanceDrawer/tabs/DeploymentLogsPanel.esm.js.map +1 -0
- package/dist/features/environment/InstanceDrawer/tabs/DeploymentReadOnlyActions.esm.js +63 -0
- package/dist/features/environment/InstanceDrawer/tabs/DeploymentReadOnlyActions.esm.js.map +1 -0
- package/dist/features/environment/InstanceDrawer/tabs/GuideTab.esm.js +48 -0
- package/dist/features/environment/InstanceDrawer/tabs/GuideTab.esm.js.map +1 -0
- package/dist/features/environment/InstanceDrawer/tabs/HistoryTab.esm.js +446 -0
- package/dist/features/environment/InstanceDrawer/tabs/HistoryTab.esm.js.map +1 -0
- package/dist/features/environment/InstanceDrawer/tabs/MonitorTab.esm.js +146 -0
- package/dist/features/environment/InstanceDrawer/tabs/MonitorTab.esm.js.map +1 -0
- package/dist/features/environment/InstanceDrawer/tabs/OverviewTab.esm.js +572 -0
- package/dist/features/environment/InstanceDrawer/tabs/OverviewTab.esm.js.map +1 -0
- package/dist/features/environment/InstanceDrawer/tabs/ResourcesTab.esm.js +471 -0
- package/dist/features/environment/InstanceDrawer/tabs/ResourcesTab.esm.js.map +1 -0
- package/dist/features/environment/InstanceDrawer/tabs/SecretsTab.esm.js +109 -0
- package/dist/features/environment/InstanceDrawer/tabs/SecretsTab.esm.js.map +1 -0
- package/dist/features/environment/InstanceDrawer/tabs/ViewDeploymentDetails.esm.js +384 -0
- package/dist/features/environment/InstanceDrawer/tabs/ViewDeploymentDetails.esm.js.map +1 -0
- package/dist/features/environment/InstanceDrawer/tabs/flattenParams.esm.js +23 -0
- package/dist/features/environment/InstanceDrawer/tabs/flattenParams.esm.js.map +1 -0
- package/dist/features/environment/InstanceDrawer/useInstanceApiQuery.esm.js +6 -0
- package/dist/features/environment/InstanceDrawer/useInstanceApiQuery.esm.js.map +1 -0
- package/dist/features/environment/InstanceDrawer/useOverflowMeasure.esm.js +55 -0
- package/dist/features/environment/InstanceDrawer/useOverflowMeasure.esm.js.map +1 -0
- package/dist/features/environment/InstanceDrawer/useResizableWidth.esm.js +44 -0
- package/dist/features/environment/InstanceDrawer/useResizableWidth.esm.js.map +1 -0
- package/dist/features/environment/components/InstanceStatusPill.esm.js +54 -0
- package/dist/features/environment/components/InstanceStatusPill.esm.js.map +1 -0
- package/dist/features/environment/graph/Diagram.esm.js +143 -0
- package/dist/features/environment/graph/Diagram.esm.js.map +1 -0
- package/dist/features/environment/graph/DiagramNode.constants.esm.js +5 -0
- package/dist/features/environment/graph/DiagramNode.constants.esm.js.map +1 -0
- package/dist/features/environment/graph/DiagramNode.esm.js +221 -0
- package/dist/features/environment/graph/DiagramNode.esm.js.map +1 -0
- package/dist/features/environment/graph/NodeMeta.esm.js +182 -0
- package/dist/features/environment/graph/NodeMeta.esm.js.map +1 -0
- package/dist/features/environment/graph/NodeVersionBadges.esm.js +150 -0
- package/dist/features/environment/graph/NodeVersionBadges.esm.js.map +1 -0
- package/dist/features/environment/graph/diagramFactory.esm.js +151 -0
- package/dist/features/environment/graph/diagramFactory.esm.js.map +1 -0
- package/dist/features/environment/graph/handles/ExpandableHandleWrapper.esm.js +174 -0
- package/dist/features/environment/graph/handles/ExpandableHandleWrapper.esm.js.map +1 -0
- package/dist/features/environment/graph/handles/NodeHandle.esm.js +45 -0
- package/dist/features/environment/graph/handles/NodeHandle.esm.js.map +1 -0
- package/dist/features/environment/graph/handles/NodeHandleTooltip.esm.js +134 -0
- package/dist/features/environment/graph/handles/NodeHandleTooltip.esm.js.map +1 -0
- package/dist/features/environment/graph/handles/handleTypes.esm.js +170 -0
- package/dist/features/environment/graph/handles/handleTypes.esm.js.map +1 -0
- package/dist/features/environment/graph/handles/useAnimationFrameSync.esm.js +19 -0
- package/dist/features/environment/graph/handles/useAnimationFrameSync.esm.js.map +1 -0
- package/dist/features/environment/graph/handles/useRadialPositions.esm.js +37 -0
- package/dist/features/environment/graph/handles/useRadialPositions.esm.js.map +1 -0
- package/dist/features/environment/graph/handles/useTransitionLifecycle.esm.js +19 -0
- package/dist/features/environment/graph/handles/useTransitionLifecycle.esm.js.map +1 -0
- package/dist/features/environment/graph/hasUndeployedPlan.esm.js +43 -0
- package/dist/features/environment/graph/hasUndeployedPlan.esm.js.map +1 -0
- package/dist/features/environment/graph/queries.esm.js +103 -0
- package/dist/features/environment/graph/queries.esm.js.map +1 -0
- package/dist/features/environment/graph/useDiagramSnapshot.esm.js +43 -0
- package/dist/features/environment/graph/useDiagramSnapshot.esm.js.map +1 -0
- package/dist/features/environment/realtime/RealtimeProvider.esm.js +43 -0
- package/dist/features/environment/realtime/RealtimeProvider.esm.js.map +1 -0
- package/dist/features/environment/realtime/queries.esm.js +76 -0
- package/dist/features/environment/realtime/queries.esm.js.map +1 -0
- package/dist/features/environment/realtime/useLiveRelayQuery.esm.js +36 -0
- package/dist/features/environment/realtime/useLiveRelayQuery.esm.js.map +1 -0
- package/dist/features/project/ProjectDetailsPage.esm.js +101 -0
- package/dist/features/project/ProjectDetailsPage.esm.js.map +1 -0
- package/dist/features/project/tabs/ComponentsTab.esm.js +149 -0
- package/dist/features/project/tabs/ComponentsTab.esm.js.map +1 -0
- package/dist/features/project/tabs/EnvStatus.esm.js +149 -0
- package/dist/features/project/tabs/EnvStatus.esm.js.map +1 -0
- package/dist/features/project/tabs/EnvironmentsTab.esm.js +199 -0
- package/dist/features/project/tabs/EnvironmentsTab.esm.js.map +1 -0
- package/dist/features/project/tabs/OverviewTab.esm.js +420 -0
- package/dist/features/project/tabs/OverviewTab.esm.js.map +1 -0
- package/dist/features/projects/ProjectsListPage.esm.js +50 -0
- package/dist/features/projects/ProjectsListPage.esm.js.map +1 -0
- package/dist/features/projects/ProjectsListPageLazy.esm.js +12 -0
- package/dist/features/projects/ProjectsListPageLazy.esm.js.map +1 -0
- package/dist/features/projects/projectColumns.esm.js +38 -0
- package/dist/features/projects/projectColumns.esm.js.map +1 -0
- package/dist/features/projects/useProjects.esm.js +48 -0
- package/dist/features/projects/useProjects.esm.js.map +1 -0
- package/dist/features/repo/DeploymentLogsDrawer.esm.js +213 -0
- package/dist/features/repo/DeploymentLogsDrawer.esm.js.map +1 -0
- package/dist/features/repo/DeploymentLogsDrawer.loading.esm.js +43 -0
- package/dist/features/repo/DeploymentLogsDrawer.loading.esm.js.map +1 -0
- package/dist/features/repo/FileTree.esm.js +179 -0
- package/dist/features/repo/FileTree.esm.js.map +1 -0
- package/dist/features/repo/FileViewer.esm.js +115 -0
- package/dist/features/repo/FileViewer.esm.js.map +1 -0
- package/dist/features/repo/FileViewer.helpers.esm.js +54 -0
- package/dist/features/repo/FileViewer.helpers.esm.js.map +1 -0
- package/dist/features/repo/RepoDetailsPage.esm.js +127 -0
- package/dist/features/repo/RepoDetailsPage.esm.js.map +1 -0
- package/dist/features/repo/RepoEmptyState.esm.js +58 -0
- package/dist/features/repo/RepoEmptyState.esm.js.map +1 -0
- package/dist/features/repo/RepoNoVersionsState.esm.js +29 -0
- package/dist/features/repo/RepoNoVersionsState.esm.js.map +1 -0
- package/dist/features/repo/RepoTabHeader.esm.js +30 -0
- package/dist/features/repo/RepoTabHeader.esm.js.map +1 -0
- package/dist/features/repo/RepoTabLayout.esm.js +18 -0
- package/dist/features/repo/RepoTabLayout.esm.js.map +1 -0
- package/dist/features/repo/RepoVersionSelect.esm.js +176 -0
- package/dist/features/repo/RepoVersionSelect.esm.js.map +1 -0
- package/dist/features/repo/ViewDeploymentDetailsDialog.esm.js +427 -0
- package/dist/features/repo/ViewDeploymentDetailsDialog.esm.js.map +1 -0
- package/dist/features/repo/deploymentHelpers.esm.js +74 -0
- package/dist/features/repo/deploymentHelpers.esm.js.map +1 -0
- package/dist/features/repo/fileTreeHelpers.esm.js +45 -0
- package/dist/features/repo/fileTreeHelpers.esm.js.map +1 -0
- package/dist/features/repo/flattenParams.esm.js +23 -0
- package/dist/features/repo/flattenParams.esm.js.map +1 -0
- package/dist/features/repo/queries.esm.js +239 -0
- package/dist/features/repo/queries.esm.js.map +1 -0
- package/dist/features/repo/repoFilter.esm.js +9 -0
- package/dist/features/repo/repoFilter.esm.js.map +1 -0
- package/dist/features/repo/repoTabs.esm.js +22 -0
- package/dist/features/repo/repoTabs.esm.js.map +1 -0
- package/dist/features/repo/resolveVersion.esm.js +22 -0
- package/dist/features/repo/resolveVersion.esm.js.map +1 -0
- package/dist/features/repo/tabs/DeploymentRow.esm.js +201 -0
- package/dist/features/repo/tabs/DeploymentRow.esm.js.map +1 -0
- package/dist/features/repo/tabs/DeploymentsTab.esm.js +188 -0
- package/dist/features/repo/tabs/DeploymentsTab.esm.js.map +1 -0
- package/dist/features/repo/tabs/DeploymentsTab.helpers.esm.js +46 -0
- package/dist/features/repo/tabs/DeploymentsTab.helpers.esm.js.map +1 -0
- package/dist/features/repo/tabs/DeploymentsTab.loading.esm.js +37 -0
- package/dist/features/repo/tabs/DeploymentsTab.loading.esm.js.map +1 -0
- package/dist/features/repo/tabs/FilesTab.esm.js +142 -0
- package/dist/features/repo/tabs/FilesTab.esm.js.map +1 -0
- package/dist/features/repo/tabs/InstanceRow.esm.js +121 -0
- package/dist/features/repo/tabs/InstanceRow.esm.js.map +1 -0
- package/dist/features/repo/tabs/InstancesTab.esm.js +147 -0
- package/dist/features/repo/tabs/InstancesTab.esm.js.map +1 -0
- package/dist/features/repo/tabs/InstancesTab.helpers.esm.js +44 -0
- package/dist/features/repo/tabs/InstancesTab.helpers.esm.js.map +1 -0
- package/dist/features/repo/tabs/InstancesTab.loading.esm.js +33 -0
- package/dist/features/repo/tabs/InstancesTab.loading.esm.js.map +1 -0
- package/dist/features/repo/tabs/OverviewTab.esm.js +77 -0
- package/dist/features/repo/tabs/OverviewTab.esm.js.map +1 -0
- package/dist/features/repo/tabs/PermissionsTab.esm.js +56 -0
- package/dist/features/repo/tabs/PermissionsTab.esm.js.map +1 -0
- package/dist/features/repo/tabs/VersionsTab.esm.js +152 -0
- package/dist/features/repo/tabs/VersionsTab.esm.js.map +1 -0
- package/dist/features/repo/useInfiniteRelayList.esm.js +92 -0
- package/dist/features/repo/useInfiniteRelayList.esm.js.map +1 -0
- package/dist/features/repo/useInfiniteScroll.esm.js +21 -0
- package/dist/features/repo/useInfiniteScroll.esm.js.map +1 -0
- package/dist/features/repos/ReposListPage.esm.js +53 -0
- package/dist/features/repos/ReposListPage.esm.js.map +1 -0
- package/dist/features/repos/queries.esm.js +40 -0
- package/dist/features/repos/queries.esm.js.map +1 -0
- package/dist/features/repos/repoColumns.esm.js +121 -0
- package/dist/features/repos/repoColumns.esm.js.map +1 -0
- package/dist/features/repos/useRepos.esm.js +22 -0
- package/dist/features/repos/useRepos.esm.js.map +1 -0
- package/dist/features/resource/OriginChip.esm.js +42 -0
- package/dist/features/resource/OriginChip.esm.js.map +1 -0
- package/dist/features/resource/ResourceDetailsPage.esm.js +167 -0
- package/dist/features/resource/ResourceDetailsPage.esm.js.map +1 -0
- package/dist/features/resource/queries.esm.js +141 -0
- package/dist/features/resource/queries.esm.js.map +1 -0
- package/dist/features/resource/tabs/GeneralTab.esm.js +247 -0
- package/dist/features/resource/tabs/GeneralTab.esm.js.map +1 -0
- package/dist/features/resource/tabs/GeneralTab.loading.esm.js +76 -0
- package/dist/features/resource/tabs/GeneralTab.loading.esm.js.map +1 -0
- package/dist/features/resource/tabs/PermissionsTab.esm.js +57 -0
- package/dist/features/resource/tabs/PermissionsTab.esm.js.map +1 -0
- package/dist/features/resource/tabs/SettingsTabLayout.esm.js +18 -0
- package/dist/features/resource/tabs/SettingsTabLayout.esm.js.map +1 -0
- package/dist/features/resource/tabs/TabHeader.esm.js +30 -0
- package/dist/features/resource/tabs/TabHeader.esm.js.map +1 -0
- package/dist/features/resource/tabs/UsagePanel.esm.js +35 -0
- package/dist/features/resource/tabs/UsagePanel.esm.js.map +1 -0
- package/dist/features/resource/tabs/UsageTab.esm.js +91 -0
- package/dist/features/resource/tabs/UsageTab.esm.js.map +1 -0
- package/dist/features/resource/tabs/UsageTab.helpers.esm.js +168 -0
- package/dist/features/resource/tabs/UsageTab.helpers.esm.js.map +1 -0
- package/dist/features/resources/ResourcesEmptyState.esm.js +148 -0
- package/dist/features/resources/ResourcesEmptyState.esm.js.map +1 -0
- package/dist/features/resources/ResourcesListPage.esm.js +115 -0
- package/dist/features/resources/ResourcesListPage.esm.js.map +1 -0
- package/dist/features/resources/queries.esm.js +50 -0
- package/dist/features/resources/queries.esm.js.map +1 -0
- package/dist/features/resources/resourceColumns.esm.js +158 -0
- package/dist/features/resources/resourceColumns.esm.js.map +1 -0
- package/dist/features/resources/resourceConstants.esm.js +7 -0
- package/dist/features/resources/resourceConstants.esm.js.map +1 -0
- package/dist/features/resources/toResourceRow.esm.js +29 -0
- package/dist/features/resources/toResourceRow.esm.js.map +1 -0
- package/dist/hooks/useAuthedSvg.esm.js +34 -0
- package/dist/hooks/useAuthedSvg.esm.js.map +1 -0
- package/dist/hooks/useCursorPagination.esm.js +40 -0
- package/dist/hooks/useCursorPagination.esm.js.map +1 -0
- package/dist/hooks/useMassdriverSubscription.esm.js +61 -0
- package/dist/hooks/useMassdriverSubscription.esm.js.map +1 -0
- package/dist/hooks/usePaginatedRelayQuery.esm.js +68 -0
- package/dist/hooks/usePaginatedRelayQuery.esm.js.map +1 -0
- package/dist/index.d.ts +256 -0
- package/dist/index.esm.js +8 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/internalRoutes.esm.js +29 -0
- package/dist/internalRoutes.esm.js.map +1 -0
- package/dist/plugin.esm.js +57 -0
- package/dist/plugin.esm.js.map +1 -0
- package/dist/queries.esm.js +54 -0
- package/dist/queries.esm.js.map +1 -0
- package/dist/routes.esm.js +6 -0
- package/dist/routes.esm.js.map +1 -0
- package/dist/shell/MassdriverHeader.esm.js +37 -0
- package/dist/shell/MassdriverHeader.esm.js.map +1 -0
- package/dist/shell/MassdriverShell.esm.js +30 -0
- package/dist/shell/MassdriverShell.esm.js.map +1 -0
- package/dist/theme/MassdriverThemeScope.esm.js +30 -0
- package/dist/theme/MassdriverThemeScope.esm.js.map +1 -0
- package/dist/theme/ThemeModeContext.esm.js +35 -0
- package/dist/theme/ThemeModeContext.esm.js.map +1 -0
- package/dist/theme/muiClassNameAudit.esm.js +11 -0
- package/dist/theme/muiClassNameAudit.esm.js.map +1 -0
- package/dist/useInstances.esm.js +39 -0
- package/dist/useInstances.esm.js.map +1 -0
- package/dist/utils/attributes.esm.js +28 -0
- package/dist/utils/attributes.esm.js.map +1 -0
- package/dist/utils/conditions.esm.js +20 -0
- package/dist/utils/conditions.esm.js.map +1 -0
- package/dist/utils/formatRelativeTime.esm.js +40 -0
- package/dist/utils/formatRelativeTime.esm.js.map +1 -0
- package/dist/utils/instanceStatuses.esm.js +74 -0
- package/dist/utils/instanceStatuses.esm.js.map +1 -0
- package/package.json +92 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
2
|
+
import { useApi } from '@backstage/frontend-plugin-api';
|
|
3
|
+
import { massdriverApiRef } from '../../../api.esm.js';
|
|
4
|
+
import { useRealtimeRevision } from './RealtimeProvider.esm.js';
|
|
5
|
+
|
|
6
|
+
const useLiveRelayQuery = (query, variables) => {
|
|
7
|
+
const api = useApi(massdriverApiRef);
|
|
8
|
+
const revision = useRealtimeRevision();
|
|
9
|
+
const [state, setState] = useState({ identity: "" });
|
|
10
|
+
const skip = variables === null;
|
|
11
|
+
const identity = `${query}|${JSON.stringify(variables)}`;
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
if (skip) return void 0;
|
|
14
|
+
let cancelled = false;
|
|
15
|
+
api.query(query, variables).then(
|
|
16
|
+
(value) => {
|
|
17
|
+
if (!cancelled) setState({ identity, value });
|
|
18
|
+
},
|
|
19
|
+
(error) => {
|
|
20
|
+
if (!cancelled) setState({ identity, error });
|
|
21
|
+
}
|
|
22
|
+
);
|
|
23
|
+
return () => {
|
|
24
|
+
cancelled = true;
|
|
25
|
+
};
|
|
26
|
+
}, [api, query, identity, revision, skip]);
|
|
27
|
+
const fresh = state.identity === identity;
|
|
28
|
+
return {
|
|
29
|
+
value: !skip && fresh ? state.value : void 0,
|
|
30
|
+
error: !skip && fresh ? state.error : void 0,
|
|
31
|
+
loading: !skip && !fresh
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export { useLiveRelayQuery };
|
|
36
|
+
//# sourceMappingURL=useLiveRelayQuery.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useLiveRelayQuery.esm.js","sources":["../../../../src/features/environment/realtime/useLiveRelayQuery.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport { useApi } from '@backstage/frontend-plugin-api';\nimport { massdriverApiRef } from '../../../api';\nimport { useRealtimeRevision } from './RealtimeProvider';\n\ninterface LiveQueryState<T> {\n identity: string;\n value?: T;\n error?: Error;\n}\n\n/**\n * Relay query that stays live via the environment's realtime revision, with two\n * distinct refetch behaviors:\n *\n * - **Identity change** (query/variables): the previous result is dropped and\n * `loading` goes true — a different entity is being loaded, show a loader.\n * - **Revision bump** (realtime event): the previous result stays rendered and\n * swaps atomically when fresh data lands — never a loading flash. This is the\n * plugin's analogue of the web app's \"no skeleton flicker on subscription\n * refetch\" rule (see .claude/rules/realtime.md).\n *\n * Pass `variables: null` to skip (returns `{ loading: false }` with no value).\n */\nexport const useLiveRelayQuery = <T>(\n query: string,\n variables: Record<string, unknown> | null,\n): { value?: T; error?: Error; loading: boolean } => {\n const api = useApi(massdriverApiRef);\n const revision = useRealtimeRevision();\n const [state, setState] = useState<LiveQueryState<T>>({ identity: '' });\n\n const skip = variables === null;\n const identity = `${query}|${JSON.stringify(variables)}`;\n\n useEffect(() => {\n if (skip) return undefined;\n let cancelled = false;\n api.query(query, variables).then(\n value => {\n if (!cancelled) setState({ identity, value: value as T });\n },\n error => {\n if (!cancelled) setState({ identity, error: error as Error });\n },\n );\n return () => {\n cancelled = true;\n };\n // `variables` participates by value through `identity`.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [api, query, identity, revision, skip]);\n\n // A result only counts once it matches the current identity; until then the\n // hook is loading and stale state is hidden. Revision bumps keep the identity\n // (and therefore the rendered value) intact while the refetch is in flight.\n const fresh = state.identity === identity;\n return {\n value: !skip && fresh ? state.value : undefined,\n error: !skip && fresh ? state.error : undefined,\n loading: !skip && !fresh,\n };\n};\n\nexport default useLiveRelayQuery;\n"],"names":[],"mappings":";;;;;AAwBO,MAAM,iBAAA,GAAoB,CAC/B,KAAA,EACA,SAAA,KACmD;AACnD,EAAA,MAAM,GAAA,GAAM,OAAO,gBAAgB,CAAA;AACnC,EAAA,MAAM,WAAW,mBAAA,EAAoB;AACrC,EAAA,MAAM,CAAC,OAAO,QAAQ,CAAA,GAAI,SAA4B,EAAE,QAAA,EAAU,IAAI,CAAA;AAEtE,EAAA,MAAM,OAAO,SAAA,KAAc,IAAA;AAC3B,EAAA,MAAM,WAAW,CAAA,EAAG,KAAK,IAAI,IAAA,CAAK,SAAA,CAAU,SAAS,CAAC,CAAA,CAAA;AAEtD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,MAAM,OAAO,MAAA;AACjB,IAAA,IAAI,SAAA,GAAY,KAAA;AAChB,IAAA,GAAA,CAAI,KAAA,CAAM,KAAA,EAAO,SAAS,CAAA,CAAE,IAAA;AAAA,MAC1B,CAAA,KAAA,KAAS;AACP,QAAA,IAAI,CAAC,SAAA,EAAW,QAAA,CAAS,EAAE,QAAA,EAAU,OAAmB,CAAA;AAAA,MAC1D,CAAA;AAAA,MACA,CAAA,KAAA,KAAS;AACP,QAAA,IAAI,CAAC,SAAA,EAAW,QAAA,CAAS,EAAE,QAAA,EAAU,OAAuB,CAAA;AAAA,MAC9D;AAAA,KACF;AACA,IAAA,OAAO,MAAM;AACX,MAAA,SAAA,GAAY,IAAA;AAAA,IACd,CAAA;AAAA,EAGF,GAAG,CAAC,GAAA,EAAK,OAAO,QAAA,EAAU,QAAA,EAAU,IAAI,CAAC,CAAA;AAKzC,EAAA,MAAM,KAAA,GAAQ,MAAM,QAAA,KAAa,QAAA;AACjC,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,CAAC,IAAA,IAAQ,KAAA,GAAQ,MAAM,KAAA,GAAQ,MAAA;AAAA,IACtC,KAAA,EAAO,CAAC,IAAA,IAAQ,KAAA,GAAQ,MAAM,KAAA,GAAQ,MAAA;AAAA,IACtC,OAAA,EAAS,CAAC,IAAA,IAAQ,CAAC;AAAA,GACrB;AACF;;;;"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import { useApi } from '@backstage/frontend-plugin-api';
|
|
3
|
+
import { projectUrl } from '@massdriver/backstage-plugin-common';
|
|
4
|
+
import Box from '@massdriver/ui/Box';
|
|
5
|
+
import PageTabs from '@massdriver/ui/PageTabs';
|
|
6
|
+
import stylin from '@massdriver/ui/stylin';
|
|
7
|
+
import useAsync from 'react-use/esm/useAsync';
|
|
8
|
+
import { useParams } from 'react-router-dom';
|
|
9
|
+
import { massdriverApiRef } from '../../api.esm.js';
|
|
10
|
+
import { NotFound } from '../../components/NotFound.esm.js';
|
|
11
|
+
import { OpenInMassdriverButton } from '../../components/OpenInMassdriverButton.esm.js';
|
|
12
|
+
import { PageLayout } from '../../components/PageLayout.esm.js';
|
|
13
|
+
import { RouterLinkAdapter } from '../../components/RouterLinkAdapter.esm.js';
|
|
14
|
+
import { internalRoutes } from '../../internalRoutes.esm.js';
|
|
15
|
+
import { ComponentsTab } from './tabs/ComponentsTab.esm.js';
|
|
16
|
+
import { EnvironmentsTab } from './tabs/EnvironmentsTab.esm.js';
|
|
17
|
+
import { OverviewTab } from './tabs/OverviewTab.esm.js';
|
|
18
|
+
|
|
19
|
+
const TABS = [
|
|
20
|
+
{ id: "overview", label: "Overview" },
|
|
21
|
+
{ id: "components", label: "Components" },
|
|
22
|
+
{ id: "environments", label: "Environments" }
|
|
23
|
+
];
|
|
24
|
+
const PANELS = {
|
|
25
|
+
overview: OverviewTab,
|
|
26
|
+
components: ComponentsTab,
|
|
27
|
+
environments: EnvironmentsTab
|
|
28
|
+
};
|
|
29
|
+
const HEADER_QUERY = `
|
|
30
|
+
query MassdriverProjectHeader($organizationId: ID!, $id: ID!) {
|
|
31
|
+
project(organizationId: $organizationId, id: $id) {
|
|
32
|
+
id
|
|
33
|
+
name
|
|
34
|
+
description
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
`;
|
|
38
|
+
const ProjectDetailsPage = () => {
|
|
39
|
+
const api = useApi(massdriverApiRef);
|
|
40
|
+
const { projectId = "", tab } = useParams();
|
|
41
|
+
const activeTab = TABS.some((entry) => entry.id === tab) ? tab : "overview";
|
|
42
|
+
const {
|
|
43
|
+
value: project,
|
|
44
|
+
loading,
|
|
45
|
+
error
|
|
46
|
+
} = useAsync(async () => {
|
|
47
|
+
const data = await api.query(HEADER_QUERY, { id: projectId });
|
|
48
|
+
return data.project;
|
|
49
|
+
}, [api, projectId]);
|
|
50
|
+
if (!loading && !error && !project) {
|
|
51
|
+
return /* @__PURE__ */ jsx(
|
|
52
|
+
NotFound,
|
|
53
|
+
{
|
|
54
|
+
title: "Project not found",
|
|
55
|
+
message: "This project doesn't exist or you don't have access to it."
|
|
56
|
+
}
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
const tabs = TABS.map((entry) => ({
|
|
60
|
+
...entry,
|
|
61
|
+
href: internalRoutes.projectTab(projectId, entry.id)
|
|
62
|
+
}));
|
|
63
|
+
const appProjectUrl = projectUrl(api.appUrl, api.organizationId, projectId);
|
|
64
|
+
return /* @__PURE__ */ jsx(
|
|
65
|
+
PageLayout,
|
|
66
|
+
{
|
|
67
|
+
title: project?.name ?? "",
|
|
68
|
+
description: project?.description,
|
|
69
|
+
headerActions: /* @__PURE__ */ jsxs(HeaderActions, { children: [
|
|
70
|
+
/* @__PURE__ */ jsx(OpenInMassdriverButton, { url: appProjectUrl, variant: "outlined", children: "Open in Massdriver" }),
|
|
71
|
+
/* @__PURE__ */ jsx(
|
|
72
|
+
OpenInMassdriverButton,
|
|
73
|
+
{
|
|
74
|
+
url: `${appProjectUrl}?cloneProject=true`,
|
|
75
|
+
variant: "outlined",
|
|
76
|
+
children: "Clone Project"
|
|
77
|
+
}
|
|
78
|
+
)
|
|
79
|
+
] }),
|
|
80
|
+
flush: true,
|
|
81
|
+
children: /* @__PURE__ */ jsx(
|
|
82
|
+
PageTabs,
|
|
83
|
+
{
|
|
84
|
+
orientation: "vertical",
|
|
85
|
+
tabs,
|
|
86
|
+
panels: PANELS,
|
|
87
|
+
activeTab,
|
|
88
|
+
panelProps: { projectId },
|
|
89
|
+
LinkComponent: RouterLinkAdapter
|
|
90
|
+
}
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
);
|
|
94
|
+
};
|
|
95
|
+
const HeaderActions = stylin(Box)(({ theme }) => ({
|
|
96
|
+
display: "flex",
|
|
97
|
+
gap: theme.spacing(1.5)
|
|
98
|
+
}));
|
|
99
|
+
|
|
100
|
+
export { ProjectDetailsPage };
|
|
101
|
+
//# sourceMappingURL=ProjectDetailsPage.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProjectDetailsPage.esm.js","sources":["../../../src/features/project/ProjectDetailsPage.tsx"],"sourcesContent":["import { useApi } from '@backstage/frontend-plugin-api';\nimport { projectUrl } from '@massdriver/backstage-plugin-common';\nimport Box from '@massdriver/ui/Box';\nimport PageTabs from '@massdriver/ui/PageTabs';\nimport stylin from '@massdriver/ui/stylin';\nimport useAsync from 'react-use/esm/useAsync';\nimport { useParams } from 'react-router-dom';\nimport { massdriverApiRef } from '../../api';\nimport { NotFound } from '../../components/NotFound';\nimport { OpenInMassdriverButton } from '../../components/OpenInMassdriverButton';\nimport { PageLayout } from '../../components/PageLayout';\nimport { RouterLinkAdapter } from '../../components/RouterLinkAdapter';\nimport { internalRoutes } from '../../internalRoutes';\nimport { ComponentsTab } from './tabs/ComponentsTab';\nimport { EnvironmentsTab } from './tabs/EnvironmentsTab';\nimport { OverviewTab } from './tabs/OverviewTab';\n\nconst TABS = [\n { id: 'overview', label: 'Overview' },\n { id: 'components', label: 'Components' },\n { id: 'environments', label: 'Environments' },\n];\n\nconst PANELS: Record<string, (props: { projectId: string }) => JSX.Element> = {\n overview: OverviewTab,\n components: ComponentsTab,\n environments: EnvironmentsTab,\n};\n\nconst HEADER_QUERY = `\n query MassdriverProjectHeader($organizationId: ID!, $id: ID!) {\n project(organizationId: $organizationId, id: $id) {\n id\n name\n description\n }\n }\n`;\n\n/** Read-only project details: vertical side-tabs mirroring the web app. */\nexport const ProjectDetailsPage = () => {\n const api = useApi(massdriverApiRef);\n const { projectId = '', tab } = useParams();\n const activeTab = TABS.some(entry => entry.id === tab) ? tab! : 'overview';\n\n const {\n value: project,\n loading,\n error,\n } = useAsync(async () => {\n const data = (await api.query(HEADER_QUERY, { id: projectId })) as {\n project: { id: string; name?: string; description?: string } | null;\n };\n return data.project;\n }, [api, projectId]);\n\n if (!loading && !error && !project) {\n return (\n <NotFound\n title=\"Project not found\"\n message=\"This project doesn't exist or you don't have access to it.\"\n />\n );\n }\n\n const tabs = TABS.map(entry => ({\n ...entry,\n href: internalRoutes.projectTab(projectId, entry.id),\n }));\n\n const appProjectUrl = projectUrl(api.appUrl, api.organizationId, projectId);\n\n return (\n <PageLayout\n title={project?.name ?? ''}\n description={project?.description}\n headerActions={\n <HeaderActions>\n <OpenInMassdriverButton url={appProjectUrl} variant=\"outlined\">\n Open in Massdriver\n </OpenInMassdriverButton>\n <OpenInMassdriverButton\n url={`${appProjectUrl}?cloneProject=true`}\n variant=\"outlined\"\n >\n Clone Project\n </OpenInMassdriverButton>\n </HeaderActions>\n }\n flush\n >\n <PageTabs\n orientation=\"vertical\"\n tabs={tabs}\n panels={PANELS}\n activeTab={activeTab}\n panelProps={{ projectId }}\n LinkComponent={RouterLinkAdapter}\n />\n </PageLayout>\n );\n};\n\nconst HeaderActions = stylin(Box)(({ theme }: { theme: any }) => ({\n display: 'flex',\n gap: theme.spacing(1.5),\n}));\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
2
|
+
import { useApi } from '@backstage/frontend-plugin-api';
|
|
3
|
+
import { parseInstanceId } from '@massdriver/backstage-plugin-common';
|
|
4
|
+
import Alert from '@massdriver/ui/Alert';
|
|
5
|
+
import Box from '@massdriver/ui/Box';
|
|
6
|
+
import DataList, { col } from '@massdriver/ui/DataList';
|
|
7
|
+
import IconTile from '@massdriver/ui/IconTile';
|
|
8
|
+
import Stack from '@massdriver/ui/Stack';
|
|
9
|
+
import Typography from '@massdriver/ui/Typography';
|
|
10
|
+
import ExtensionIcon from '@massdriver/ui/icons/ExtensionIcon';
|
|
11
|
+
import stylin from '@massdriver/ui/stylin';
|
|
12
|
+
import useAsync from 'react-use/esm/useAsync';
|
|
13
|
+
import { massdriverApiRef } from '../../../api.esm.js';
|
|
14
|
+
import { buildAttributesColumn, Code } from '../../../components/AttributesColumn.esm.js';
|
|
15
|
+
import { internalRoutes } from '../../../internalRoutes.esm.js';
|
|
16
|
+
import { EnvStatusStrip } from './EnvStatus.esm.js';
|
|
17
|
+
|
|
18
|
+
const COMPONENTS_QUERY = `
|
|
19
|
+
query MassdriverProjectComponents($organizationId: ID!, $id: ID!) {
|
|
20
|
+
project(organizationId: $organizationId, id: $id) {
|
|
21
|
+
id
|
|
22
|
+
components {
|
|
23
|
+
id
|
|
24
|
+
name
|
|
25
|
+
description
|
|
26
|
+
attributes
|
|
27
|
+
effectiveAttributes
|
|
28
|
+
ociRepo { id name icon }
|
|
29
|
+
instances(cursor: { limit: 100 }) {
|
|
30
|
+
items {
|
|
31
|
+
id
|
|
32
|
+
status
|
|
33
|
+
deployedVersion
|
|
34
|
+
resolvedVersion
|
|
35
|
+
availableUpgrade
|
|
36
|
+
environment { id name }
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
`;
|
|
43
|
+
const ComponentsTab = ({ projectId }) => {
|
|
44
|
+
const api = useApi(massdriverApiRef);
|
|
45
|
+
const { value, loading, error } = useAsync(async () => {
|
|
46
|
+
const data = await api.query(COMPONENTS_QUERY, { id: projectId });
|
|
47
|
+
return data.project?.components ?? [];
|
|
48
|
+
}, [api, projectId]);
|
|
49
|
+
const rows = (value ?? []).map((component) => ({
|
|
50
|
+
...component,
|
|
51
|
+
typeName: component.ociRepo?.name,
|
|
52
|
+
instances: (component.instances?.items ?? []).filter(
|
|
53
|
+
Boolean
|
|
54
|
+
)
|
|
55
|
+
}));
|
|
56
|
+
const getInstanceUrl = (instance) => {
|
|
57
|
+
if (!instance.environment?.id || !instance.id) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
const { scopedEnvironmentId, scopedComponentId } = parseInstanceId(
|
|
61
|
+
instance.id
|
|
62
|
+
);
|
|
63
|
+
return internalRoutes.instance(
|
|
64
|
+
projectId,
|
|
65
|
+
scopedEnvironmentId,
|
|
66
|
+
scopedComponentId
|
|
67
|
+
);
|
|
68
|
+
};
|
|
69
|
+
const columns = [
|
|
70
|
+
col.custom(
|
|
71
|
+
"name",
|
|
72
|
+
"Name",
|
|
73
|
+
(_value, row) => /* @__PURE__ */ jsxs(NameCell, { children: [
|
|
74
|
+
/* @__PURE__ */ jsx(
|
|
75
|
+
IconTile,
|
|
76
|
+
{
|
|
77
|
+
src: row.ociRepo?.icon,
|
|
78
|
+
alt: row.ociRepo?.name,
|
|
79
|
+
size: "small",
|
|
80
|
+
fallback: /* @__PURE__ */ jsx(ExtensionIcon, {})
|
|
81
|
+
}
|
|
82
|
+
),
|
|
83
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", children: row.name })
|
|
84
|
+
] }),
|
|
85
|
+
{ flex: 2, minWidth: 220, searchable: true }
|
|
86
|
+
),
|
|
87
|
+
col.text("description", "Description", {
|
|
88
|
+
flex: 2,
|
|
89
|
+
minWidth: 200,
|
|
90
|
+
sortable: false,
|
|
91
|
+
searchable: true
|
|
92
|
+
}),
|
|
93
|
+
col.text("typeName", "Bundle Type", {
|
|
94
|
+
flex: 1,
|
|
95
|
+
minWidth: 160,
|
|
96
|
+
sortable: false
|
|
97
|
+
}),
|
|
98
|
+
buildAttributesColumn({
|
|
99
|
+
directText: "Key-value attributes assigned directly to this component. Attributes cascade to instances of the component across all environments.",
|
|
100
|
+
effectiveText: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
101
|
+
"The full attribute map the authorization system evaluates policies against for this component \u2014 the component's own user attributes plus auto-injected ",
|
|
102
|
+
/* @__PURE__ */ jsx(Code, { children: "md-*" }),
|
|
103
|
+
" system attributes."
|
|
104
|
+
] })
|
|
105
|
+
}),
|
|
106
|
+
col.custom(
|
|
107
|
+
"status",
|
|
108
|
+
"Status across environments",
|
|
109
|
+
(_value, row) => /* @__PURE__ */ jsx(
|
|
110
|
+
EnvStatusStrip,
|
|
111
|
+
{
|
|
112
|
+
instances: row.instances,
|
|
113
|
+
getInstanceUrl
|
|
114
|
+
}
|
|
115
|
+
),
|
|
116
|
+
{ flex: 3, minWidth: 280, sortable: false, searchable: false }
|
|
117
|
+
)
|
|
118
|
+
];
|
|
119
|
+
return /* @__PURE__ */ jsxs(Wrapper, { children: [
|
|
120
|
+
/* @__PURE__ */ jsx(Stack, { direction: "row", justifyContent: "space-between", alignItems: "center", children: /* @__PURE__ */ jsx(Typography, { variant: "h6", children: "Components" }) }),
|
|
121
|
+
error ? /* @__PURE__ */ jsx(Alert, { severity: "error", children: String(error.message ?? error) }) : /* @__PURE__ */ jsx(
|
|
122
|
+
DataList,
|
|
123
|
+
{
|
|
124
|
+
rows,
|
|
125
|
+
columns,
|
|
126
|
+
loading,
|
|
127
|
+
emptyMessage: "No components in this project yet.",
|
|
128
|
+
variant: "outlined"
|
|
129
|
+
}
|
|
130
|
+
)
|
|
131
|
+
] });
|
|
132
|
+
};
|
|
133
|
+
const Wrapper = stylin(Box)(({ theme }) => ({
|
|
134
|
+
padding: theme.spacing(4),
|
|
135
|
+
maxWidth: 1400,
|
|
136
|
+
mx: "auto",
|
|
137
|
+
width: "100%",
|
|
138
|
+
display: "flex",
|
|
139
|
+
flexDirection: "column",
|
|
140
|
+
gap: theme.spacing(2)
|
|
141
|
+
}));
|
|
142
|
+
const NameCell = stylin(Box)(({ theme }) => ({
|
|
143
|
+
display: "flex",
|
|
144
|
+
alignItems: "center",
|
|
145
|
+
gap: theme.spacing(1)
|
|
146
|
+
}));
|
|
147
|
+
|
|
148
|
+
export { ComponentsTab };
|
|
149
|
+
//# sourceMappingURL=ComponentsTab.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ComponentsTab.esm.js","sources":["../../../../src/features/project/tabs/ComponentsTab.tsx"],"sourcesContent":["import { useApi } from '@backstage/frontend-plugin-api';\nimport { parseInstanceId } from '@massdriver/backstage-plugin-common';\nimport Alert from '@massdriver/ui/Alert';\nimport Box from '@massdriver/ui/Box';\nimport { col } from '@massdriver/ui/DataList';\nimport DataList from '@massdriver/ui/DataList';\nimport IconTile from '@massdriver/ui/IconTile';\nimport Stack from '@massdriver/ui/Stack';\nimport Typography from '@massdriver/ui/Typography';\nimport ExtensionIcon from '@massdriver/ui/icons/ExtensionIcon';\nimport stylin from '@massdriver/ui/stylin';\nimport useAsync from 'react-use/esm/useAsync';\nimport { massdriverApiRef } from '../../../api';\nimport {\n buildAttributesColumn,\n Code,\n} from '../../../components/AttributesColumn';\nimport { internalRoutes } from '../../../internalRoutes';\nimport { EnvInstance, EnvStatusStrip } from './EnvStatus';\n\ninterface ComponentRow {\n id: string;\n name: string;\n description?: string | null;\n attributes?: unknown;\n effectiveAttributes?: unknown;\n ociRepo?: { id: string; name?: string; icon?: string } | null;\n typeName?: string;\n instances: EnvInstance[];\n}\n\nconst COMPONENTS_QUERY = `\n query MassdriverProjectComponents($organizationId: ID!, $id: ID!) {\n project(organizationId: $organizationId, id: $id) {\n id\n components {\n id\n name\n description\n attributes\n effectiveAttributes\n ociRepo { id name icon }\n instances(cursor: { limit: 100 }) {\n items {\n id\n status\n deployedVersion\n resolvedVersion\n availableUpgrade\n environment { id name }\n }\n }\n }\n }\n }\n`;\n\n/** Read-only Components tab: components with status across environments. */\nexport const ComponentsTab = ({ projectId }: { projectId: string }) => {\n const api = useApi(massdriverApiRef);\n const { value, loading, error } = useAsync(async () => {\n const data = (await api.query(COMPONENTS_QUERY, { id: projectId })) as {\n project: {\n components?: Array<{\n id: string;\n name: string;\n description?: string | null;\n attributes?: unknown;\n effectiveAttributes?: unknown;\n ociRepo?: { id: string; name?: string; icon?: string } | null;\n instances?: { items?: (EnvInstance | null)[] | null };\n }> | null;\n } | null;\n };\n return data.project?.components ?? [];\n }, [api, projectId]);\n\n const rows: ComponentRow[] = (value ?? []).map(component => ({\n ...component,\n typeName: component.ociRepo?.name,\n instances: (component.instances?.items ?? []).filter(\n Boolean,\n ) as EnvInstance[],\n }));\n\n const getInstanceUrl = (instance: EnvInstance): string | null => {\n if (!instance.environment?.id || !instance.id) {\n return null;\n }\n const { scopedEnvironmentId, scopedComponentId } = parseInstanceId(\n instance.id,\n );\n return internalRoutes.instance(\n projectId,\n scopedEnvironmentId,\n scopedComponentId,\n );\n };\n\n const columns = [\n col.custom(\n 'name',\n 'Name',\n (_value: unknown, row: ComponentRow) => (\n <NameCell>\n <IconTile\n src={row.ociRepo?.icon}\n alt={row.ociRepo?.name}\n size=\"small\"\n fallback={<ExtensionIcon />}\n />\n <Typography variant=\"body2\">{row.name}</Typography>\n </NameCell>\n ),\n { flex: 2, minWidth: 220, searchable: true },\n ),\n col.text('description', 'Description', {\n flex: 2,\n minWidth: 200,\n sortable: false,\n searchable: true,\n }),\n col.text('typeName', 'Bundle Type', {\n flex: 1,\n minWidth: 160,\n sortable: false,\n }),\n buildAttributesColumn({\n directText:\n 'Key-value attributes assigned directly to this component. Attributes cascade to instances of the component across all environments.',\n effectiveText: (\n <>\n The full attribute map the authorization system evaluates policies\n against for this component — the component's own user attributes plus\n auto-injected <Code>md-*</Code> system attributes.\n </>\n ),\n }),\n col.custom(\n 'status',\n 'Status across environments',\n (_value: unknown, row: ComponentRow) => (\n <EnvStatusStrip\n instances={row.instances}\n getInstanceUrl={getInstanceUrl}\n />\n ),\n { flex: 3, minWidth: 280, sortable: false, searchable: false },\n ),\n ];\n\n return (\n <Wrapper>\n <Stack direction=\"row\" justifyContent=\"space-between\" alignItems=\"center\">\n <Typography variant=\"h6\">Components</Typography>\n </Stack>\n {error ? (\n <Alert severity=\"error\">{String(error.message ?? error)}</Alert>\n ) : (\n <DataList\n rows={rows}\n columns={columns}\n loading={loading}\n emptyMessage=\"No components in this project yet.\"\n variant=\"outlined\"\n />\n )}\n </Wrapper>\n );\n};\n\nconst Wrapper = stylin(Box)(({ theme }: { theme: any }) => ({\n padding: theme.spacing(4),\n maxWidth: 1400,\n mx: 'auto',\n width: '100%',\n display: 'flex',\n flexDirection: 'column',\n gap: theme.spacing(2),\n}));\n\nconst NameCell = stylin(Box)(({ theme }: { theme: any }) => ({\n display: 'flex',\n alignItems: 'center',\n gap: theme.spacing(1),\n}));\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import Box from '@massdriver/ui/Box';
|
|
3
|
+
import Tooltip from '@massdriver/ui/Tooltip';
|
|
4
|
+
import Typography from '@massdriver/ui/Typography';
|
|
5
|
+
import stylin from '@massdriver/ui/stylin';
|
|
6
|
+
import { instanceStatusColors } from '@massdriver/ui/theme';
|
|
7
|
+
import { RouterLinkAdapter } from '../../../components/RouterLinkAdapter.esm.js';
|
|
8
|
+
|
|
9
|
+
const STATUS_LABELS = {
|
|
10
|
+
INITIALIZED: "Not deployed yet",
|
|
11
|
+
PROVISIONED: "Provisioned",
|
|
12
|
+
DECOMMISSIONED: "Decommissioned",
|
|
13
|
+
FAILED: "Failed",
|
|
14
|
+
EXTERNAL: "External"
|
|
15
|
+
};
|
|
16
|
+
const labelFor = (status) => (status && STATUS_LABELS[status]) ?? status ?? "Unknown";
|
|
17
|
+
const colorFor = (status) => (status && instanceStatusColors[status]) ?? instanceStatusColors.INITIALIZED;
|
|
18
|
+
const EnvStatusStrip = ({
|
|
19
|
+
instances,
|
|
20
|
+
getInstanceUrl
|
|
21
|
+
}) => {
|
|
22
|
+
if (!instances || instances.length === 0) {
|
|
23
|
+
return /* @__PURE__ */ jsx(EmptyText, { variant: "caption", color: "text.secondary", children: "Not deployed in any environment" });
|
|
24
|
+
}
|
|
25
|
+
return /* @__PURE__ */ jsx(Strip, { children: instances.map((instance) => /* @__PURE__ */ jsx(
|
|
26
|
+
EnvStatusChip,
|
|
27
|
+
{
|
|
28
|
+
instance,
|
|
29
|
+
href: getInstanceUrl?.(instance) ?? null
|
|
30
|
+
},
|
|
31
|
+
instance.id
|
|
32
|
+
)) });
|
|
33
|
+
};
|
|
34
|
+
const EnvStatusChip = ({
|
|
35
|
+
instance,
|
|
36
|
+
href
|
|
37
|
+
}) => {
|
|
38
|
+
const color = colorFor(instance.status);
|
|
39
|
+
const versionLabel = instance.deployedVersion ?? "\u2014";
|
|
40
|
+
const showResolved = instance.resolvedVersion && instance.resolvedVersion !== instance.deployedVersion;
|
|
41
|
+
const tooltipRows = [
|
|
42
|
+
instance.environment?.name && {
|
|
43
|
+
label: "Environment",
|
|
44
|
+
value: instance.environment.name
|
|
45
|
+
},
|
|
46
|
+
{ label: "Status", value: labelFor(instance.status) },
|
|
47
|
+
{
|
|
48
|
+
label: "Deployed",
|
|
49
|
+
value: instance.deployedVersion ? `v${instance.deployedVersion}` : "Not deployed"
|
|
50
|
+
},
|
|
51
|
+
showResolved && {
|
|
52
|
+
label: "Resolves to",
|
|
53
|
+
value: `v${instance.resolvedVersion}`
|
|
54
|
+
},
|
|
55
|
+
instance.availableUpgrade && {
|
|
56
|
+
label: "Upgrade available",
|
|
57
|
+
value: `v${instance.availableUpgrade}`
|
|
58
|
+
}
|
|
59
|
+
].filter(Boolean);
|
|
60
|
+
const content = /* @__PURE__ */ jsxs(Chip, { interactive: Boolean(href), children: [
|
|
61
|
+
/* @__PURE__ */ jsx(Dot, { color }),
|
|
62
|
+
/* @__PURE__ */ jsx(Name, { variant: "caption", children: instance.environment?.name }),
|
|
63
|
+
/* @__PURE__ */ jsx(Version, { variant: "caption", children: versionLabel })
|
|
64
|
+
] });
|
|
65
|
+
return /* @__PURE__ */ jsx(
|
|
66
|
+
Tooltip,
|
|
67
|
+
{
|
|
68
|
+
arrow: true,
|
|
69
|
+
enterDelay: 400,
|
|
70
|
+
placement: "top",
|
|
71
|
+
slotProps: { tooltip: { sx: { maxWidth: 260 } } },
|
|
72
|
+
title: /* @__PURE__ */ jsx(TooltipBody, { children: tooltipRows.map((row) => /* @__PURE__ */ jsxs(TooltipRow, { children: [
|
|
73
|
+
/* @__PURE__ */ jsx(TooltipLabel, { children: row.label }),
|
|
74
|
+
/* @__PURE__ */ jsx(TooltipValue, { children: row.value })
|
|
75
|
+
] }, row.label)) }),
|
|
76
|
+
children: href ? /* @__PURE__ */ jsx(ChipLink, { href, children: content }) : content
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
};
|
|
80
|
+
const Strip = stylin(Box)(({ theme }) => ({
|
|
81
|
+
display: "flex",
|
|
82
|
+
flexWrap: "wrap",
|
|
83
|
+
gap: theme.spacing(0.75),
|
|
84
|
+
alignItems: "center"
|
|
85
|
+
}));
|
|
86
|
+
const EmptyText = stylin(Typography)(({ theme }) => ({
|
|
87
|
+
fontStyle: "italic",
|
|
88
|
+
paddingTop: theme.spacing(0.5),
|
|
89
|
+
paddingBottom: theme.spacing(0.5)
|
|
90
|
+
}));
|
|
91
|
+
const ChipLink = stylin(RouterLinkAdapter)({ textDecoration: "none" });
|
|
92
|
+
const Chip = stylin(Box, ["interactive"])(
|
|
93
|
+
({ theme, interactive }) => ({
|
|
94
|
+
display: "inline-flex",
|
|
95
|
+
alignItems: "center",
|
|
96
|
+
gap: theme.spacing(0.5),
|
|
97
|
+
padding: `${theme.spacing(0.25)} ${theme.spacing(1)}`,
|
|
98
|
+
borderRadius: theme.custom.general.borderRadiusSm,
|
|
99
|
+
backgroundColor: theme.palette.background.field,
|
|
100
|
+
border: `1px solid ${theme.palette.divider}`,
|
|
101
|
+
textDecoration: "none",
|
|
102
|
+
transition: "background-color 120ms ease, border-color 120ms ease",
|
|
103
|
+
...interactive && {
|
|
104
|
+
cursor: "pointer",
|
|
105
|
+
"&:hover": {
|
|
106
|
+
backgroundColor: theme.palette.action.hover,
|
|
107
|
+
borderColor: theme.palette.text.secondary
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
})
|
|
111
|
+
);
|
|
112
|
+
const Dot = stylin("span", ["color"])(({ color }) => ({
|
|
113
|
+
width: 8,
|
|
114
|
+
height: 8,
|
|
115
|
+
borderRadius: "50%",
|
|
116
|
+
flexShrink: 0,
|
|
117
|
+
backgroundColor: color
|
|
118
|
+
}));
|
|
119
|
+
const Name = stylin(Typography)(({ theme }) => ({
|
|
120
|
+
color: theme.palette.text.primary,
|
|
121
|
+
fontWeight: theme.typography.fontWeightMedium
|
|
122
|
+
}));
|
|
123
|
+
const Version = stylin(Typography)(({ theme }) => ({
|
|
124
|
+
color: theme.palette.text.secondary,
|
|
125
|
+
fontFamily: theme.typography.fontFamilyMono
|
|
126
|
+
}));
|
|
127
|
+
const TooltipBody = stylin(Box)(({ theme }) => ({
|
|
128
|
+
display: "flex",
|
|
129
|
+
flexDirection: "column",
|
|
130
|
+
gap: theme.spacing(0.25)
|
|
131
|
+
}));
|
|
132
|
+
const TooltipRow = stylin(Box)(({ theme }) => ({
|
|
133
|
+
display: "flex",
|
|
134
|
+
gap: theme.spacing(1),
|
|
135
|
+
fontSize: 11,
|
|
136
|
+
lineHeight: 1.4
|
|
137
|
+
}));
|
|
138
|
+
const TooltipLabel = stylin("span")({
|
|
139
|
+
fontWeight: 600,
|
|
140
|
+
color: "inherit",
|
|
141
|
+
opacity: 0.75
|
|
142
|
+
});
|
|
143
|
+
const TooltipValue = stylin("span")(({ theme }) => ({
|
|
144
|
+
color: "inherit",
|
|
145
|
+
fontFamily: theme.typography.fontFamilyMono
|
|
146
|
+
}));
|
|
147
|
+
|
|
148
|
+
export { EnvStatusStrip };
|
|
149
|
+
//# sourceMappingURL=EnvStatus.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EnvStatus.esm.js","sources":["../../../../src/features/project/tabs/EnvStatus.tsx"],"sourcesContent":["import Box from '@massdriver/ui/Box';\nimport Tooltip from '@massdriver/ui/Tooltip';\nimport Typography from '@massdriver/ui/Typography';\nimport stylin from '@massdriver/ui/stylin';\nimport { instanceStatusColors } from '@massdriver/ui/theme';\nimport { RouterLinkAdapter } from '../../../components/RouterLinkAdapter';\n\nexport interface EnvInstance {\n id: string;\n status?: string | null;\n deployedVersion?: string | null;\n resolvedVersion?: string | null;\n availableUpgrade?: string | null;\n environment?: { id: string; name?: string | null } | null;\n}\n\nconst STATUS_LABELS: Record<string, string> = {\n INITIALIZED: 'Not deployed yet',\n PROVISIONED: 'Provisioned',\n DECOMMISSIONED: 'Decommissioned',\n FAILED: 'Failed',\n EXTERNAL: 'External',\n};\n\nconst labelFor = (status?: string | null) =>\n (status && STATUS_LABELS[status]) ?? status ?? 'Unknown';\nconst colorFor = (status?: string | null) =>\n (status && instanceStatusColors[status]) ?? instanceStatusColors.INITIALIZED;\n\n/** Chips showing an instance's status per environment (mirrors the web app). */\nexport const EnvStatusStrip = ({\n instances,\n getInstanceUrl,\n}: {\n instances?: EnvInstance[] | null;\n getInstanceUrl?: (instance: EnvInstance) => string | null;\n}) => {\n if (!instances || instances.length === 0) {\n return (\n <EmptyText variant=\"caption\" color=\"text.secondary\">\n Not deployed in any environment\n </EmptyText>\n );\n }\n return (\n <Strip>\n {instances.map(instance => (\n <EnvStatusChip\n key={instance.id}\n instance={instance}\n href={getInstanceUrl?.(instance) ?? null}\n />\n ))}\n </Strip>\n );\n};\n\nconst EnvStatusChip = ({\n instance,\n href,\n}: {\n instance: EnvInstance;\n href: string | null;\n}) => {\n const color = colorFor(instance.status);\n const versionLabel = instance.deployedVersion ?? '—';\n const showResolved =\n instance.resolvedVersion &&\n instance.resolvedVersion !== instance.deployedVersion;\n\n const tooltipRows = [\n instance.environment?.name && {\n label: 'Environment',\n value: instance.environment.name,\n },\n { label: 'Status', value: labelFor(instance.status) },\n {\n label: 'Deployed',\n value: instance.deployedVersion\n ? `v${instance.deployedVersion}`\n : 'Not deployed',\n },\n showResolved && {\n label: 'Resolves to',\n value: `v${instance.resolvedVersion}`,\n },\n instance.availableUpgrade && {\n label: 'Upgrade available',\n value: `v${instance.availableUpgrade}`,\n },\n ].filter(Boolean) as { label: string; value: string }[];\n\n const content = (\n <Chip interactive={Boolean(href)}>\n <Dot color={color} />\n <Name variant=\"caption\">{instance.environment?.name}</Name>\n <Version variant=\"caption\">{versionLabel}</Version>\n </Chip>\n );\n\n return (\n <Tooltip\n arrow\n enterDelay={400}\n placement=\"top\"\n slotProps={{ tooltip: { sx: { maxWidth: 260 } } }}\n title={\n <TooltipBody>\n {tooltipRows.map(row => (\n <TooltipRow key={row.label}>\n <TooltipLabel>{row.label}</TooltipLabel>\n <TooltipValue>{row.value}</TooltipValue>\n </TooltipRow>\n ))}\n </TooltipBody>\n }\n >\n {href ? <ChipLink href={href}>{content}</ChipLink> : content}\n </Tooltip>\n );\n};\n\nconst Strip = stylin(Box)(({ theme }: { theme: any }) => ({\n display: 'flex',\n flexWrap: 'wrap',\n gap: theme.spacing(0.75),\n alignItems: 'center',\n}));\n\nconst EmptyText = stylin(Typography)(({ theme }: { theme: any }) => ({\n fontStyle: 'italic',\n paddingTop: theme.spacing(0.5),\n paddingBottom: theme.spacing(0.5),\n}));\n\nconst ChipLink = stylin(RouterLinkAdapter)({ textDecoration: 'none' });\n\nconst Chip = stylin(Box, ['interactive'])(\n ({ theme, interactive }: { theme: any; interactive: boolean }) => ({\n display: 'inline-flex',\n alignItems: 'center',\n gap: theme.spacing(0.5),\n padding: `${theme.spacing(0.25)} ${theme.spacing(1)}`,\n borderRadius: theme.custom.general.borderRadiusSm,\n backgroundColor: theme.palette.background.field,\n border: `1px solid ${theme.palette.divider}`,\n textDecoration: 'none',\n transition: 'background-color 120ms ease, border-color 120ms ease',\n ...(interactive && {\n cursor: 'pointer',\n '&:hover': {\n backgroundColor: theme.palette.action.hover,\n borderColor: theme.palette.text.secondary,\n },\n }),\n }),\n);\n\nconst Dot = stylin('span', ['color'])(({ color }: { color: string }) => ({\n width: 8,\n height: 8,\n borderRadius: '50%',\n flexShrink: 0,\n backgroundColor: color,\n}));\n\nconst Name = stylin(Typography)(({ theme }: { theme: any }) => ({\n color: theme.palette.text.primary,\n fontWeight: theme.typography.fontWeightMedium,\n}));\n\nconst Version = stylin(Typography)(({ theme }: { theme: any }) => ({\n color: theme.palette.text.secondary,\n fontFamily: theme.typography.fontFamilyMono,\n}));\n\nconst TooltipBody = stylin(Box)(({ theme }: { theme: any }) => ({\n display: 'flex',\n flexDirection: 'column',\n gap: theme.spacing(0.25),\n}));\n\nconst TooltipRow = stylin(Box)(({ theme }: { theme: any }) => ({\n display: 'flex',\n gap: theme.spacing(1),\n fontSize: 11,\n lineHeight: 1.4,\n}));\n\nconst TooltipLabel = stylin('span')({\n fontWeight: 600,\n color: 'inherit',\n opacity: 0.75,\n});\n\nconst TooltipValue = stylin('span')(({ theme }: { theme: any }) => ({\n color: 'inherit',\n fontFamily: theme.typography.fontFamilyMono,\n}));\n"],"names":[],"mappings":"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"}
|