@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,92 @@
|
|
|
1
|
+
import { useApi } from '@backstage/frontend-plugin-api';
|
|
2
|
+
import { useRef, useState, useCallback, useEffect } from 'react';
|
|
3
|
+
import { massdriverApiRef } from '../../api.esm.js';
|
|
4
|
+
|
|
5
|
+
const useInfiniteRelayList = (query, {
|
|
6
|
+
responseKey,
|
|
7
|
+
variables,
|
|
8
|
+
pageSize = 20,
|
|
9
|
+
skip = false
|
|
10
|
+
}) => {
|
|
11
|
+
const api = useApi(massdriverApiRef);
|
|
12
|
+
const variablesRef = useRef(variables);
|
|
13
|
+
variablesRef.current = variables;
|
|
14
|
+
const path = Array.isArray(responseKey) ? responseKey : [responseKey];
|
|
15
|
+
const resetKey = JSON.stringify({
|
|
16
|
+
query,
|
|
17
|
+
variables: variables ?? null,
|
|
18
|
+
skip
|
|
19
|
+
});
|
|
20
|
+
const [items, setItems] = useState([]);
|
|
21
|
+
const [nextCursor, setNextCursor] = useState(null);
|
|
22
|
+
const [loading, setLoading] = useState(false);
|
|
23
|
+
const [loadingMore, setLoadingMore] = useState(false);
|
|
24
|
+
const [error, setError] = useState(void 0);
|
|
25
|
+
const fetchingRef = useRef(false);
|
|
26
|
+
const requestIdRef = useRef(0);
|
|
27
|
+
const runFetch = useCallback(
|
|
28
|
+
async (cursorNext, mode) => {
|
|
29
|
+
fetchingRef.current = true;
|
|
30
|
+
const requestId = ++requestIdRef.current;
|
|
31
|
+
if (mode === "initial") setLoading(true);
|
|
32
|
+
else setLoadingMore(true);
|
|
33
|
+
setError(void 0);
|
|
34
|
+
try {
|
|
35
|
+
const data = await api.query(query, {
|
|
36
|
+
...variablesRef.current ?? {},
|
|
37
|
+
cursor: {
|
|
38
|
+
limit: pageSize,
|
|
39
|
+
...cursorNext ? { next: cursorNext } : {}
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
if (requestId !== requestIdRef.current) return;
|
|
43
|
+
const page = path.reduce(
|
|
44
|
+
(node, key) => node?.[key],
|
|
45
|
+
data
|
|
46
|
+
);
|
|
47
|
+
const pageItems = (page?.items ?? []).filter(Boolean);
|
|
48
|
+
setItems(
|
|
49
|
+
(prev) => mode === "initial" ? pageItems : [...prev, ...pageItems]
|
|
50
|
+
);
|
|
51
|
+
setNextCursor(page?.cursor?.next ?? null);
|
|
52
|
+
} catch (caught) {
|
|
53
|
+
if (requestId !== requestIdRef.current) return;
|
|
54
|
+
setError(caught);
|
|
55
|
+
} finally {
|
|
56
|
+
if (requestId === requestIdRef.current) {
|
|
57
|
+
if (mode === "initial") setLoading(false);
|
|
58
|
+
else setLoadingMore(false);
|
|
59
|
+
}
|
|
60
|
+
fetchingRef.current = false;
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
// path is derived from responseKey, which is part of resetKey.
|
|
64
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
65
|
+
[api, query, pageSize, resetKey]
|
|
66
|
+
);
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
setItems([]);
|
|
69
|
+
setNextCursor(null);
|
|
70
|
+
if (skip) {
|
|
71
|
+
setLoading(false);
|
|
72
|
+
setLoadingMore(false);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
runFetch(null, "initial");
|
|
76
|
+
}, [resetKey]);
|
|
77
|
+
const onLoadMore = useCallback(() => {
|
|
78
|
+
if (!nextCursor || fetchingRef.current || loading || loadingMore) return;
|
|
79
|
+
runFetch(nextCursor, "more");
|
|
80
|
+
}, [nextCursor, loading, loadingMore, runFetch]);
|
|
81
|
+
return {
|
|
82
|
+
items,
|
|
83
|
+
loading,
|
|
84
|
+
loadingMore,
|
|
85
|
+
error,
|
|
86
|
+
hasMore: Boolean(nextCursor),
|
|
87
|
+
onLoadMore
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export { useInfiniteRelayList };
|
|
92
|
+
//# sourceMappingURL=useInfiniteRelayList.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useInfiniteRelayList.esm.js","sources":["../../../src/features/repo/useInfiniteRelayList.ts"],"sourcesContent":["import { useApi } from '@backstage/frontend-plugin-api';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { massdriverApiRef } from '../../api';\n\ninterface RelayPage<T> {\n items?: (T | null)[] | null;\n cursor?: { next?: string | null } | null;\n}\n\nexport interface InfiniteRelayResult<T> {\n items: T[];\n loading: boolean;\n loadingMore: boolean;\n error?: Error;\n hasMore: boolean;\n onLoadMore: () => void;\n}\n\n/**\n * Feature-local equivalent of the web app's `useInfiniteQuery` for the relay:\n * accumulates cursor pages into one growing list (`onLoadMore` appends the next\n * page). The accumulated list resets whenever the query inputs (variables/skip)\n * change, so a filter or sort change starts a fresh list. Page size defaults to\n * 20. Mirrors the web's Apollo `useInfiniteQuery` return shape\n * (`items`/`loading`/`loadingMore`/`error`/`hasMore`/`onLoadMore`).\n */\nexport const useInfiniteRelayList = <T>(\n query: string,\n {\n responseKey,\n variables,\n pageSize = 20,\n skip = false,\n }: {\n /** Key of the paginated page in the response; an array walks a nested path. */\n responseKey: string | string[];\n variables?: Record<string, unknown>;\n pageSize?: number;\n skip?: boolean;\n },\n): InfiniteRelayResult<T> => {\n const api = useApi(massdriverApiRef);\n\n // Latest values read inside the async fetch without widening its deps — the\n // effect keys off `resetKey` (a stable serialization) instead.\n const variablesRef = useRef(variables);\n variablesRef.current = variables;\n const path = Array.isArray(responseKey) ? responseKey : [responseKey];\n\n const resetKey = JSON.stringify({\n query,\n variables: variables ?? null,\n skip,\n });\n\n const [items, setItems] = useState<T[]>([]);\n const [nextCursor, setNextCursor] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n const [loadingMore, setLoadingMore] = useState(false);\n const [error, setError] = useState<Error | undefined>(undefined);\n\n const fetchingRef = useRef(false);\n const requestIdRef = useRef(0);\n\n const runFetch = useCallback(\n async (cursorNext: string | null, mode: 'initial' | 'more') => {\n fetchingRef.current = true;\n const requestId = ++requestIdRef.current;\n if (mode === 'initial') setLoading(true);\n else setLoadingMore(true);\n setError(undefined);\n try {\n const data = (await api.query(query, {\n ...(variablesRef.current ?? {}),\n cursor: {\n limit: pageSize,\n ...(cursorNext ? { next: cursorNext } : {}),\n },\n })) as Record<string, unknown>;\n // A newer fetch superseded this one (filters changed mid-flight); drop it.\n if (requestId !== requestIdRef.current) return;\n const page = path.reduce<unknown>(\n (node, key) =>\n (node as Record<string, unknown> | null | undefined)?.[key],\n data,\n ) as RelayPage<T> | undefined;\n const pageItems = (page?.items ?? []).filter(Boolean) as T[];\n setItems(prev =>\n mode === 'initial' ? pageItems : [...prev, ...pageItems],\n );\n setNextCursor(page?.cursor?.next ?? null);\n } catch (caught) {\n if (requestId !== requestIdRef.current) return;\n setError(caught as Error);\n } finally {\n if (requestId === requestIdRef.current) {\n if (mode === 'initial') setLoading(false);\n else setLoadingMore(false);\n }\n fetchingRef.current = false;\n }\n },\n // path is derived from responseKey, which is part of resetKey.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [api, query, pageSize, resetKey],\n );\n\n // Reset and re-fetch from the first page whenever the query inputs change.\n useEffect(() => {\n setItems([]);\n setNextCursor(null);\n if (skip) {\n setLoading(false);\n setLoadingMore(false);\n return;\n }\n runFetch(null, 'initial');\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [resetKey]);\n\n const onLoadMore = useCallback(() => {\n if (!nextCursor || fetchingRef.current || loading || loadingMore) return;\n runFetch(nextCursor, 'more');\n }, [nextCursor, loading, loadingMore, runFetch]);\n\n return {\n items,\n loading,\n loadingMore,\n error,\n hasMore: Boolean(nextCursor),\n onLoadMore,\n };\n};\n\nexport default useInfiniteRelayList;\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
const useInfiniteScroll = ({
|
|
4
|
+
onLoadMore,
|
|
5
|
+
hasMore,
|
|
6
|
+
loading
|
|
7
|
+
}) => {
|
|
8
|
+
const [sentinel, setSentinel] = useState(null);
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
if (!sentinel || !hasMore || loading) return void 0;
|
|
11
|
+
const observer = new IntersectionObserver((entries) => {
|
|
12
|
+
if (entries[0].isIntersecting) onLoadMore();
|
|
13
|
+
});
|
|
14
|
+
observer.observe(sentinel);
|
|
15
|
+
return () => observer.disconnect();
|
|
16
|
+
}, [sentinel, hasMore, loading, onLoadMore]);
|
|
17
|
+
return setSentinel;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export { useInfiniteScroll };
|
|
21
|
+
//# sourceMappingURL=useInfiniteScroll.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useInfiniteScroll.esm.js","sources":["../../../src/features/repo/useInfiniteScroll.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\n\n// Ported from apps/web/shared/hooks/useInfiniteScroll.js. Returns a ref-setter;\n// attach it to a 1px sentinel at the bottom of a scrollable list and it fires\n// `onLoadMore` when the sentinel scrolls into view.\nexport const useInfiniteScroll = ({\n onLoadMore,\n hasMore,\n loading,\n}: {\n onLoadMore: () => void;\n hasMore: boolean;\n loading: boolean;\n}) => {\n const [sentinel, setSentinel] = useState<Element | null>(null);\n\n useEffect(() => {\n if (!sentinel || !hasMore || loading) return undefined;\n\n const observer = new IntersectionObserver(entries => {\n if (entries[0].isIntersecting) onLoadMore();\n });\n\n observer.observe(sentinel);\n return () => observer.disconnect();\n }, [sentinel, hasMore, loading, onLoadMore]);\n\n return setSentinel;\n};\n\nexport default useInfiniteScroll;\n"],"names":[],"mappings":";;AAKO,MAAM,oBAAoB,CAAC;AAAA,EAChC,UAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF,CAAA,KAIM;AACJ,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAI,SAAyB,IAAI,CAAA;AAE7D,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,QAAA,IAAY,CAAC,OAAA,IAAW,SAAS,OAAO,MAAA;AAE7C,IAAA,MAAM,QAAA,GAAW,IAAI,oBAAA,CAAqB,CAAA,OAAA,KAAW;AACnD,MAAA,IAAI,OAAA,CAAQ,CAAC,CAAA,CAAE,cAAA,EAAgB,UAAA,EAAW;AAAA,IAC5C,CAAC,CAAA;AAED,IAAA,QAAA,CAAS,QAAQ,QAAQ,CAAA;AACzB,IAAA,OAAO,MAAM,SAAS,UAAA,EAAW;AAAA,EACnC,GAAG,CAAC,QAAA,EAAU,OAAA,EAAS,OAAA,EAAS,UAAU,CAAC,CAAA;AAE3C,EAAA,OAAO,WAAA;AACT;;;;"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { useApi } from '@backstage/frontend-plugin-api';
|
|
3
|
+
import { reposUrl } from '@massdriver/backstage-plugin-common';
|
|
4
|
+
import Alert from '@massdriver/ui/Alert';
|
|
5
|
+
import DataList from '@massdriver/ui/DataList';
|
|
6
|
+
import { massdriverApiRef } from '../../api.esm.js';
|
|
7
|
+
import { OpenInMassdriverButton } from '../../components/OpenInMassdriverButton.esm.js';
|
|
8
|
+
import { PageLayout } from '../../components/PageLayout.esm.js';
|
|
9
|
+
import { buildRepoColumns } from './repoColumns.esm.js';
|
|
10
|
+
import { useReposPaginated, toRepoRow } from './useRepos.esm.js';
|
|
11
|
+
|
|
12
|
+
const ReposListPage = () => {
|
|
13
|
+
const api = useApi(massdriverApiRef);
|
|
14
|
+
const { items, loading, error, hasMore, dataListParams } = useReposPaginated();
|
|
15
|
+
const columns = buildRepoColumns({
|
|
16
|
+
appUrl: api.appUrl,
|
|
17
|
+
organizationId: api.organizationId
|
|
18
|
+
});
|
|
19
|
+
const rows = items.map(toRepoRow);
|
|
20
|
+
const hasSearch = Boolean(dataListParams.state?.search);
|
|
21
|
+
const emptyMessage = hasSearch ? "No repositories match your search." : "This organization has no repositories.";
|
|
22
|
+
return /* @__PURE__ */ jsx(
|
|
23
|
+
PageLayout,
|
|
24
|
+
{
|
|
25
|
+
title: "Repositories",
|
|
26
|
+
description: "Repositories are the basic building blocks of infrastructure, applications, and architectures in Massdriver.",
|
|
27
|
+
actions: /* @__PURE__ */ jsx(
|
|
28
|
+
OpenInMassdriverButton,
|
|
29
|
+
{
|
|
30
|
+
url: `${reposUrl(api.appUrl, api.organizationId)}?createOciRepo=true`,
|
|
31
|
+
children: "New Repository"
|
|
32
|
+
}
|
|
33
|
+
),
|
|
34
|
+
children: error ? /* @__PURE__ */ jsx(Alert, { severity: "error", children: String(error.message ?? error) }) : /* @__PURE__ */ jsx(
|
|
35
|
+
DataList,
|
|
36
|
+
{
|
|
37
|
+
rows,
|
|
38
|
+
columns,
|
|
39
|
+
loading,
|
|
40
|
+
serverSide: true,
|
|
41
|
+
searchable: true,
|
|
42
|
+
hasMore,
|
|
43
|
+
variant: "outlined",
|
|
44
|
+
emptyMessage,
|
|
45
|
+
...dataListParams
|
|
46
|
+
}
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export { ReposListPage };
|
|
53
|
+
//# sourceMappingURL=ReposListPage.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReposListPage.esm.js","sources":["../../../src/features/repos/ReposListPage.tsx"],"sourcesContent":["import { useApi } from '@backstage/frontend-plugin-api';\nimport { reposUrl } from '@massdriver/backstage-plugin-common';\nimport Alert from '@massdriver/ui/Alert';\nimport DataList from '@massdriver/ui/DataList';\nimport { massdriverApiRef } from '../../api';\nimport { OpenInMassdriverButton } from '../../components/OpenInMassdriverButton';\nimport { PageLayout } from '../../components/PageLayout';\nimport { buildRepoColumns } from './repoColumns';\nimport { toRepoRow, useReposPaginated } from './useRepos';\n\n// Ported from apps/web/features/repos/pages/ReposPage.js +\n// sections/ReposList/. The web app's \"New repository\" button opens a dialog\n// driven by the `createOciRepo` URL param; here it deep-links out to Massdriver\n// with that param set (read-only parity).\nexport const ReposListPage = () => {\n const api = useApi(massdriverApiRef);\n const { items, loading, error, hasMore, dataListParams } =\n useReposPaginated();\n const columns = buildRepoColumns({\n appUrl: api.appUrl,\n organizationId: api.organizationId,\n });\n const rows = items.map(toRepoRow);\n const hasSearch = Boolean(dataListParams.state?.search);\n const emptyMessage = hasSearch\n ? 'No repositories match your search.'\n : 'This organization has no repositories.';\n\n return (\n <PageLayout\n title=\"Repositories\"\n description=\"Repositories are the basic building blocks of infrastructure, applications, and architectures in Massdriver.\"\n actions={\n <OpenInMassdriverButton\n url={`${reposUrl(api.appUrl, api.organizationId)}?createOciRepo=true`}\n >\n New Repository\n </OpenInMassdriverButton>\n }\n >\n {error ? (\n <Alert severity=\"error\">{String(error.message ?? error)}</Alert>\n ) : (\n <DataList\n rows={rows}\n columns={columns}\n loading={loading}\n serverSide\n searchable\n hasMore={hasMore}\n variant=\"outlined\"\n emptyMessage={emptyMessage}\n {...dataListParams}\n />\n )}\n </PageLayout>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;AAcO,MAAM,gBAAgB,MAAM;AACjC,EAAA,MAAM,GAAA,GAAM,OAAO,gBAAgB,CAAA;AACnC,EAAA,MAAM,EAAE,KAAA,EAAO,OAAA,EAAS,OAAO,OAAA,EAAS,cAAA,KACtC,iBAAA,EAAkB;AACpB,EAAA,MAAM,UAAU,gBAAA,CAAiB;AAAA,IAC/B,QAAQ,GAAA,CAAI,MAAA;AAAA,IACZ,gBAAgB,GAAA,CAAI;AAAA,GACrB,CAAA;AACD,EAAA,MAAM,IAAA,GAAO,KAAA,CAAM,GAAA,CAAI,SAAS,CAAA;AAChC,EAAA,MAAM,SAAA,GAAY,OAAA,CAAQ,cAAA,CAAe,KAAA,EAAO,MAAM,CAAA;AACtD,EAAA,MAAM,YAAA,GAAe,YACjB,oCAAA,GACA,wCAAA;AAEJ,EAAA,uBACE,GAAA;AAAA,IAAC,UAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAM,cAAA;AAAA,MACN,WAAA,EAAY,8GAAA;AAAA,MACZ,OAAA,kBACE,GAAA;AAAA,QAAC,sBAAA;AAAA,QAAA;AAAA,UACC,KAAK,CAAA,EAAG,QAAA,CAAS,IAAI,MAAA,EAAQ,GAAA,CAAI,cAAc,CAAC,CAAA,mBAAA,CAAA;AAAA,UACjD,QAAA,EAAA;AAAA;AAAA,OAED;AAAA,MAGD,QAAA,EAAA,KAAA,mBACC,GAAA,CAAC,KAAA,EAAA,EAAM,QAAA,EAAS,OAAA,EAAS,iBAAO,KAAA,CAAM,OAAA,IAAW,KAAK,CAAA,EAAE,CAAA,mBAExD,GAAA;AAAA,QAAC,QAAA;AAAA,QAAA;AAAA,UACC,IAAA;AAAA,UACA,OAAA;AAAA,UACA,OAAA;AAAA,UACA,UAAA,EAAU,IAAA;AAAA,UACV,UAAA,EAAU,IAAA;AAAA,UACV,OAAA;AAAA,UACA,OAAA,EAAQ,UAAA;AAAA,UACR,YAAA;AAAA,UACC,GAAG;AAAA;AAAA;AACN;AAAA,GAEJ;AAEJ;;;;"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const OCI_REPOS_LIST_QUERY = `
|
|
2
|
+
query MassdriverOciReposList(
|
|
3
|
+
$organizationId: ID!
|
|
4
|
+
$filter: OciReposFilter
|
|
5
|
+
$sort: OciReposSort
|
|
6
|
+
$cursor: Cursor
|
|
7
|
+
) {
|
|
8
|
+
ociRepos(
|
|
9
|
+
organizationId: $organizationId
|
|
10
|
+
filter: $filter
|
|
11
|
+
sort: $sort
|
|
12
|
+
cursor: $cursor
|
|
13
|
+
) {
|
|
14
|
+
cursor {
|
|
15
|
+
next
|
|
16
|
+
previous
|
|
17
|
+
}
|
|
18
|
+
items {
|
|
19
|
+
id
|
|
20
|
+
name
|
|
21
|
+
createdAt
|
|
22
|
+
updatedAt
|
|
23
|
+
description
|
|
24
|
+
icon
|
|
25
|
+
sourceUrl
|
|
26
|
+
attributes
|
|
27
|
+
effectiveAttributes
|
|
28
|
+
tags(sort: { field: VERSION, order: DESC }, cursor: { limit: 1 }) {
|
|
29
|
+
items {
|
|
30
|
+
tag
|
|
31
|
+
createdAt
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
`;
|
|
38
|
+
|
|
39
|
+
export { OCI_REPOS_LIST_QUERY };
|
|
40
|
+
//# sourceMappingURL=queries.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queries.esm.js","sources":["../../../src/features/repos/queries.ts"],"sourcesContent":["// Ported from apps/web/features/repos/hooks/useOciReposQuery.js (OCI_REPOS_QUERY).\n// Operation renamed to MassdriverOciReposList; $organizationId is declared but\n// never passed — the relay injects it.\nexport const OCI_REPOS_LIST_QUERY = `\n query MassdriverOciReposList(\n $organizationId: ID!\n $filter: OciReposFilter\n $sort: OciReposSort\n $cursor: Cursor\n ) {\n ociRepos(\n organizationId: $organizationId\n filter: $filter\n sort: $sort\n cursor: $cursor\n ) {\n cursor {\n next\n previous\n }\n items {\n id\n name\n createdAt\n updatedAt\n description\n icon\n sourceUrl\n attributes\n effectiveAttributes\n tags(sort: { field: VERSION, order: DESC }, cursor: { limit: 1 }) {\n items {\n tag\n createdAt\n }\n }\n }\n }\n }\n`;\n"],"names":[],"mappings":"AAGO,MAAM,oBAAA,GAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;;"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
2
|
+
import Box from '@massdriver/ui/Box';
|
|
3
|
+
import { col } from '@massdriver/ui/DataList';
|
|
4
|
+
import stylin from '@massdriver/ui/stylin';
|
|
5
|
+
import DeleteOutlineIcon from '@massdriver/ui/icons/DeleteOutlineIcon';
|
|
6
|
+
import EditIcon from '@massdriver/ui/icons/EditIcon';
|
|
7
|
+
import ExtensionIcon from '@massdriver/ui/icons/ExtensionIcon';
|
|
8
|
+
import OpenInNewIcon from '@massdriver/ui/icons/OpenInNewIcon';
|
|
9
|
+
import { reposUrl } from '@massdriver/backstage-plugin-common';
|
|
10
|
+
import { AuthedIcon } from '../../components/AuthedIcon.esm.js';
|
|
11
|
+
import { buildAttributesColumn, Code } from '../../components/AttributesColumn.esm.js';
|
|
12
|
+
import { RouterLinkAdapter } from '../../components/RouterLinkAdapter.esm.js';
|
|
13
|
+
import { formatAbsoluteTime } from '../../utils/formatRelativeTime.esm.js';
|
|
14
|
+
import { internalRoutes } from '../../internalRoutes.esm.js';
|
|
15
|
+
|
|
16
|
+
const buildRepoColumns = ({
|
|
17
|
+
appUrl,
|
|
18
|
+
organizationId
|
|
19
|
+
}) => [
|
|
20
|
+
col.custom(
|
|
21
|
+
"name",
|
|
22
|
+
"Name",
|
|
23
|
+
(value, row) => /* @__PURE__ */ jsxs(NameCell, { children: [
|
|
24
|
+
/* @__PURE__ */ jsx(
|
|
25
|
+
AuthedIcon,
|
|
26
|
+
{
|
|
27
|
+
url: row.icon,
|
|
28
|
+
alt: value,
|
|
29
|
+
size: "small",
|
|
30
|
+
fallback: /* @__PURE__ */ jsx(FallbackIcon, {})
|
|
31
|
+
}
|
|
32
|
+
),
|
|
33
|
+
/* @__PURE__ */ jsx(
|
|
34
|
+
NameLink,
|
|
35
|
+
{
|
|
36
|
+
component: RouterLinkAdapter,
|
|
37
|
+
href: internalRoutes.repository(row.id),
|
|
38
|
+
children: value || "--"
|
|
39
|
+
}
|
|
40
|
+
)
|
|
41
|
+
] }),
|
|
42
|
+
{ flex: 2, minWidth: 200, sortable: true, searchable: true }
|
|
43
|
+
),
|
|
44
|
+
col.text("description", "Description", {
|
|
45
|
+
flex: 3,
|
|
46
|
+
minWidth: 150,
|
|
47
|
+
sortable: false
|
|
48
|
+
}),
|
|
49
|
+
buildAttributesColumn({
|
|
50
|
+
directText: "Key-value attributes assigned directly to this repository. Attributes cascade to bundles published from this repo.",
|
|
51
|
+
effectiveText: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
52
|
+
"The full attribute map the authorization system evaluates policies against for this repository \u2014 the repo's own user attributes plus auto-injected ",
|
|
53
|
+
/* @__PURE__ */ jsx(Code, { children: "md-*" }),
|
|
54
|
+
" system attributes."
|
|
55
|
+
] })
|
|
56
|
+
}),
|
|
57
|
+
col.text("latestVersion", "Latest Version", {
|
|
58
|
+
flex: 1,
|
|
59
|
+
minWidth: 120,
|
|
60
|
+
sortable: false,
|
|
61
|
+
searchable: false
|
|
62
|
+
}),
|
|
63
|
+
col.text("updatedAt", "Updated", {
|
|
64
|
+
flex: 1,
|
|
65
|
+
minWidth: 150,
|
|
66
|
+
sortable: false,
|
|
67
|
+
searchable: false,
|
|
68
|
+
tooltip: (_value, row) => formatAbsoluteTime(row.updatedAtRaw)
|
|
69
|
+
}),
|
|
70
|
+
col.actions([
|
|
71
|
+
{
|
|
72
|
+
// "View source code" is a read link — allowed under read-only parity.
|
|
73
|
+
icon: /* @__PURE__ */ jsx(OpenInNewIcon, { fontSize: "small" }),
|
|
74
|
+
tooltip: (_row, { disabled }) => disabled ? "Source code not available" : "View source code",
|
|
75
|
+
href: (row) => row.sourceUrl,
|
|
76
|
+
target: "_blank",
|
|
77
|
+
rel: "noopener noreferrer",
|
|
78
|
+
disabled: (row) => !row.sourceUrl
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
icon: /* @__PURE__ */ jsx(EditIcon, { fontSize: "small" }),
|
|
82
|
+
tooltip: "Edit in Massdriver",
|
|
83
|
+
href: (row) => `${reposUrl(appUrl, organizationId)}?editOciRepo=${encodeURIComponent(
|
|
84
|
+
row.id
|
|
85
|
+
)}`,
|
|
86
|
+
target: "_blank",
|
|
87
|
+
rel: "noopener noreferrer"
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
icon: /* @__PURE__ */ jsx(DeleteOutlineIcon, { fontSize: "small" }),
|
|
91
|
+
tooltip: "Delete in Massdriver",
|
|
92
|
+
href: (row) => `${reposUrl(appUrl, organizationId)}?deleteOciRepo=${encodeURIComponent(
|
|
93
|
+
row.id
|
|
94
|
+
)}`,
|
|
95
|
+
target: "_blank",
|
|
96
|
+
rel: "noopener noreferrer",
|
|
97
|
+
color: "error"
|
|
98
|
+
}
|
|
99
|
+
])
|
|
100
|
+
];
|
|
101
|
+
const NameCell = stylin(Box)(({ theme }) => ({
|
|
102
|
+
display: "flex",
|
|
103
|
+
alignItems: "center",
|
|
104
|
+
gap: theme.spacing(1.5),
|
|
105
|
+
minWidth: 0
|
|
106
|
+
}));
|
|
107
|
+
const FallbackIcon = stylin(ExtensionIcon)({
|
|
108
|
+
fontSize: 18
|
|
109
|
+
});
|
|
110
|
+
const NameLink = stylin(Box)({
|
|
111
|
+
color: "inherit",
|
|
112
|
+
textDecoration: "none",
|
|
113
|
+
whiteSpace: "nowrap",
|
|
114
|
+
overflow: "hidden",
|
|
115
|
+
textOverflow: "ellipsis",
|
|
116
|
+
minWidth: 0,
|
|
117
|
+
"&:hover": { textDecoration: "underline" }
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
export { buildRepoColumns };
|
|
121
|
+
//# sourceMappingURL=repoColumns.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repoColumns.esm.js","sources":["../../../src/features/repos/repoColumns.tsx"],"sourcesContent":["import Box from '@massdriver/ui/Box';\nimport { col } from '@massdriver/ui/DataList';\nimport stylin from '@massdriver/ui/stylin';\nimport DeleteOutlineIcon from '@massdriver/ui/icons/DeleteOutlineIcon';\nimport EditIcon from '@massdriver/ui/icons/EditIcon';\nimport ExtensionIcon from '@massdriver/ui/icons/ExtensionIcon';\nimport OpenInNewIcon from '@massdriver/ui/icons/OpenInNewIcon';\nimport { reposUrl } from '@massdriver/backstage-plugin-common';\nimport AuthedIcon from '../../components/AuthedIcon';\nimport { buildAttributesColumn, Code } from '../../components/AttributesColumn';\nimport { RouterLinkAdapter } from '../../components/RouterLinkAdapter';\nimport { formatAbsoluteTime } from '../../utils/formatRelativeTime';\nimport { internalRoutes } from '../../internalRoutes';\nimport type { RepoRow } from './useRepos';\n\n// Ported from apps/web/features/repos/utils/repoColumns.js (buildRepoColumns).\n// The repo's brand icon (`repo.icon`, an auth-guarded SVG URL) is fetched\n// through the backend content proxy by AuthedIcon, exactly like the web app.\n// Edit/Delete mutate, so they deep-link into the web app's dialogs via the\n// same `?editOciRepo=` / `?deleteOciRepo=` URL params the app's list uses.\nexport const buildRepoColumns = ({\n appUrl,\n organizationId,\n}: {\n appUrl: string;\n organizationId: string;\n}) => [\n col.custom(\n 'name',\n 'Name',\n (value: string, row: RepoRow) => (\n <NameCell>\n <AuthedIcon\n url={row.icon}\n alt={value}\n size=\"small\"\n fallback={<FallbackIcon />}\n />\n <NameLink\n component={RouterLinkAdapter}\n href={internalRoutes.repository(row.id)}\n >\n {value || '--'}\n </NameLink>\n </NameCell>\n ),\n { flex: 2, minWidth: 200, sortable: true, searchable: true },\n ),\n col.text('description', 'Description', {\n flex: 3,\n minWidth: 150,\n sortable: false,\n }),\n buildAttributesColumn({\n directText:\n 'Key-value attributes assigned directly to this repository. Attributes cascade to bundles published from this repo.',\n effectiveText: (\n <>\n The full attribute map the authorization system evaluates policies\n against for this repository — the repo's own user attributes plus\n auto-injected <Code>md-*</Code> system attributes.\n </>\n ),\n }),\n col.text('latestVersion', 'Latest Version', {\n flex: 1,\n minWidth: 120,\n sortable: false,\n searchable: false,\n }),\n col.text('updatedAt', 'Updated', {\n flex: 1,\n minWidth: 150,\n sortable: false,\n searchable: false,\n tooltip: (_value: unknown, row: RepoRow) =>\n formatAbsoluteTime(row.updatedAtRaw),\n }),\n col.actions([\n {\n // \"View source code\" is a read link — allowed under read-only parity.\n icon: <OpenInNewIcon fontSize=\"small\" />,\n tooltip: (_row: RepoRow, { disabled }: { disabled: boolean }) =>\n disabled ? 'Source code not available' : 'View source code',\n href: (row: RepoRow) => row.sourceUrl,\n target: '_blank',\n rel: 'noopener noreferrer',\n disabled: (row: RepoRow) => !row.sourceUrl,\n },\n {\n icon: <EditIcon fontSize=\"small\" />,\n tooltip: 'Edit in Massdriver',\n href: (row: RepoRow) =>\n `${reposUrl(appUrl, organizationId)}?editOciRepo=${encodeURIComponent(\n row.id,\n )}`,\n target: '_blank',\n rel: 'noopener noreferrer',\n },\n {\n icon: <DeleteOutlineIcon fontSize=\"small\" />,\n tooltip: 'Delete in Massdriver',\n href: (row: RepoRow) =>\n `${reposUrl(appUrl, organizationId)}?deleteOciRepo=${encodeURIComponent(\n row.id,\n )}`,\n target: '_blank',\n rel: 'noopener noreferrer',\n color: 'error',\n },\n ]),\n];\n\nconst NameCell = stylin(Box)(({ theme }: { theme: any }) => ({\n display: 'flex',\n alignItems: 'center',\n gap: theme.spacing(1.5),\n minWidth: 0,\n}));\n\nconst FallbackIcon = stylin(ExtensionIcon)({\n fontSize: 18,\n});\n\nconst NameLink = stylin(Box)({\n color: 'inherit',\n textDecoration: 'none',\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n minWidth: 0,\n '&:hover': { textDecoration: 'underline' },\n});\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { usePaginatedRelayQuery } from '../../hooks/usePaginatedRelayQuery.esm.js';
|
|
2
|
+
import { formatRelativeTime } from '../../utils/formatRelativeTime.esm.js';
|
|
3
|
+
import { OCI_REPOS_LIST_QUERY } from './queries.esm.js';
|
|
4
|
+
|
|
5
|
+
const toRepoRow = (repo) => ({
|
|
6
|
+
...repo,
|
|
7
|
+
name: repo.name || "",
|
|
8
|
+
icon: repo.icon ?? null,
|
|
9
|
+
description: repo.description ?? null,
|
|
10
|
+
latestVersion: repo.tags?.items?.[0]?.tag ? `v${repo.tags.items[0].tag}` : null,
|
|
11
|
+
updatedAtRaw: repo.updatedAt,
|
|
12
|
+
updatedAt: formatRelativeTime(repo.updatedAt)
|
|
13
|
+
});
|
|
14
|
+
const useReposPaginated = () => usePaginatedRelayQuery(OCI_REPOS_LIST_QUERY, {
|
|
15
|
+
responseKey: "ociRepos",
|
|
16
|
+
sortFieldMap: { name: "NAME", createdAt: "CREATED_AT" },
|
|
17
|
+
defaultSort: { field: "name", direction: "asc" },
|
|
18
|
+
pageSize: 20
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
export { toRepoRow, useReposPaginated };
|
|
22
|
+
//# sourceMappingURL=useRepos.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useRepos.esm.js","sources":["../../../src/features/repos/useRepos.ts"],"sourcesContent":["import {\n PaginatedResult,\n usePaginatedRelayQuery,\n} from '../../hooks/usePaginatedRelayQuery';\nimport { formatRelativeTime } from '../../utils/formatRelativeTime';\nimport { OCI_REPOS_LIST_QUERY } from './queries';\n\n/** A repository as returned by the API (mirrors the web app's selection). */\nexport interface RepoListItem {\n id: string;\n name: string;\n description?: string | null;\n icon?: string | null;\n sourceUrl?: string | null;\n attributes?: unknown;\n effectiveAttributes?: unknown;\n createdAt?: string | null;\n updatedAt?: string | null;\n tags?: { items?: Array<{ tag: string; createdAt?: string } | null> } | null;\n}\n\n/** A repository row as rendered in the DataList (mirrors the web `toRepoRow`). */\nexport interface RepoRow extends RepoListItem {\n name: string;\n description: string | null;\n latestVersion: string | null;\n updatedAt: string;\n updatedAtRaw?: string | null;\n}\n\n/** Transform a raw repo into a display row. Mirrors `toRepoRow` in repoColumns.js. */\nexport const toRepoRow = (repo: RepoListItem): RepoRow => ({\n ...repo,\n name: repo.name || '',\n icon: repo.icon ?? null,\n description: repo.description ?? null,\n latestVersion: repo.tags?.items?.[0]?.tag\n ? `v${repo.tags.items[0].tag}`\n : null,\n updatedAtRaw: repo.updatedAt,\n updatedAt: formatRelativeTime(repo.updatedAt),\n});\n\n/** Server-side, cursor-paginated repositories list (matches the web app). */\nexport const useReposPaginated = (): PaginatedResult<RepoListItem> =>\n usePaginatedRelayQuery<RepoListItem>(OCI_REPOS_LIST_QUERY, {\n responseKey: 'ociRepos',\n sortFieldMap: { name: 'NAME', createdAt: 'CREATED_AT' },\n defaultSort: { field: 'name', direction: 'asc' },\n pageSize: 20,\n });\n"],"names":[],"mappings":";;;;AA+BO,MAAM,SAAA,GAAY,CAAC,IAAA,MAAiC;AAAA,EACzD,GAAG,IAAA;AAAA,EACH,IAAA,EAAM,KAAK,IAAA,IAAQ,EAAA;AAAA,EACnB,IAAA,EAAM,KAAK,IAAA,IAAQ,IAAA;AAAA,EACnB,WAAA,EAAa,KAAK,WAAA,IAAe,IAAA;AAAA,EACjC,aAAA,EAAe,IAAA,CAAK,IAAA,EAAM,KAAA,GAAQ,CAAC,CAAA,EAAG,GAAA,GAClC,CAAA,CAAA,EAAI,IAAA,CAAK,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA,CAAE,GAAG,CAAA,CAAA,GAC1B,IAAA;AAAA,EACJ,cAAc,IAAA,CAAK,SAAA;AAAA,EACnB,SAAA,EAAW,kBAAA,CAAmB,IAAA,CAAK,SAAS;AAC9C,CAAA;AAGO,MAAM,iBAAA,GAAoB,MAC/B,sBAAA,CAAqC,oBAAA,EAAsB;AAAA,EACzD,WAAA,EAAa,UAAA;AAAA,EACb,YAAA,EAAc,EAAE,IAAA,EAAM,MAAA,EAAQ,WAAW,YAAA,EAAa;AAAA,EACtD,WAAA,EAAa,EAAE,KAAA,EAAO,MAAA,EAAQ,WAAW,KAAA,EAAM;AAAA,EAC/C,QAAA,EAAU;AACZ,CAAC;;;;"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import Chip from '@massdriver/ui/Chip';
|
|
3
|
+
import stylin from '@massdriver/ui/stylin';
|
|
4
|
+
import { chipClasses } from '@mui/material/Chip';
|
|
5
|
+
import '@mui/material/Drawer';
|
|
6
|
+
import '@mui/material/OutlinedInput';
|
|
7
|
+
import '@mui/material/Select';
|
|
8
|
+
import '@mui/material/ToggleButton';
|
|
9
|
+
|
|
10
|
+
const ORIGIN_LABELS = {
|
|
11
|
+
IMPORTED: "Imported",
|
|
12
|
+
PROVISIONED: "Provisioned"
|
|
13
|
+
};
|
|
14
|
+
const OriginChip = ({ origin }) => {
|
|
15
|
+
const provisioned = origin === "PROVISIONED";
|
|
16
|
+
return /* @__PURE__ */ jsx(
|
|
17
|
+
StyledChip,
|
|
18
|
+
{
|
|
19
|
+
size: "small",
|
|
20
|
+
label: ORIGIN_LABELS[origin ?? ""] ?? origin,
|
|
21
|
+
provisioned
|
|
22
|
+
}
|
|
23
|
+
);
|
|
24
|
+
};
|
|
25
|
+
const StyledChip = stylin(Chip, ["provisioned"])(
|
|
26
|
+
({ theme, provisioned }) => ({
|
|
27
|
+
height: 20,
|
|
28
|
+
fontSize: "0.6875rem",
|
|
29
|
+
fontWeight: 600,
|
|
30
|
+
letterSpacing: "0.03em",
|
|
31
|
+
textTransform: "uppercase",
|
|
32
|
+
borderRadius: "4px",
|
|
33
|
+
backgroundColor: provisioned ? theme.palette.info.lighter : theme.palette.success.lighter,
|
|
34
|
+
color: provisioned ? theme.palette.info.dark : theme.palette.success.dark,
|
|
35
|
+
[`& .${chipClasses.label}`]: {
|
|
36
|
+
padding: theme.spacing(0, 0.75)
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
export { OriginChip };
|
|
42
|
+
//# sourceMappingURL=OriginChip.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OriginChip.esm.js","sources":["../../../src/features/resource/OriginChip.tsx"],"sourcesContent":["import Chip from '@massdriver/ui/Chip';\nimport stylin from '@massdriver/ui/stylin';\nimport { chipClasses } from '../../theme/muiClasses';\n\n// Ported from apps/web/features/resources/sections/GeneralTab/GeneralTab.view.js\n// (the OriginChip styled component + ORIGIN_LABELS).\n\nconst ORIGIN_LABELS: Record<string, string> = {\n IMPORTED: 'Imported',\n PROVISIONED: 'Provisioned',\n};\n\n/** Small uppercase status chip: provisioned reads info, imported reads success. */\nexport const OriginChip = ({ origin }: { origin?: string | null }) => {\n const provisioned = origin === 'PROVISIONED';\n return (\n <StyledChip\n size=\"small\"\n label={ORIGIN_LABELS[origin ?? ''] ?? origin}\n provisioned={provisioned}\n />\n );\n};\n\nexport default OriginChip;\n\nconst StyledChip = stylin(Chip, ['provisioned'])(\n ({ theme, provisioned }: { theme: any; provisioned: boolean }) => ({\n height: 20,\n fontSize: '0.6875rem',\n fontWeight: 600,\n letterSpacing: '0.03em',\n textTransform: 'uppercase',\n borderRadius: '4px',\n backgroundColor: provisioned\n ? theme.palette.info.lighter\n : theme.palette.success.lighter,\n color: provisioned ? theme.palette.info.dark : theme.palette.success.dark,\n [`& .${chipClasses.label}`]: {\n padding: theme.spacing(0, 0.75),\n },\n }),\n);\n"],"names":[],"mappings":";;;;;;;;;AAOA,MAAM,aAAA,GAAwC;AAAA,EAC5C,QAAA,EAAU,UAAA;AAAA,EACV,WAAA,EAAa;AACf,CAAA;AAGO,MAAM,UAAA,GAAa,CAAC,EAAE,MAAA,EAAO,KAAkC;AACpE,EAAA,MAAM,cAAc,MAAA,KAAW,aAAA;AAC/B,EAAA,uBACE,GAAA;AAAA,IAAC,UAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAK,OAAA;AAAA,MACL,KAAA,EAAO,aAAA,CAAc,MAAA,IAAU,EAAE,CAAA,IAAK,MAAA;AAAA,MACtC;AAAA;AAAA,GACF;AAEJ;AAIA,MAAM,UAAA,GAAa,MAAA,CAAO,IAAA,EAAM,CAAC,aAAa,CAAC,CAAA;AAAA,EAC7C,CAAC,EAAE,KAAA,EAAO,WAAA,EAAY,MAA6C;AAAA,IACjE,MAAA,EAAQ,EAAA;AAAA,IACR,QAAA,EAAU,WAAA;AAAA,IACV,UAAA,EAAY,GAAA;AAAA,IACZ,aAAA,EAAe,QAAA;AAAA,IACf,aAAA,EAAe,WAAA;AAAA,IACf,YAAA,EAAc,KAAA;AAAA,IACd,eAAA,EAAiB,cACb,KAAA,CAAM,OAAA,CAAQ,KAAK,OAAA,GACnB,KAAA,CAAM,QAAQ,OAAA,CAAQ,OAAA;AAAA,IAC1B,KAAA,EAAO,cAAc,KAAA,CAAM,OAAA,CAAQ,KAAK,IAAA,GAAO,KAAA,CAAM,QAAQ,OAAA,CAAQ,IAAA;AAAA,IACrE,CAAC,CAAA,GAAA,EAAM,WAAA,CAAY,KAAK,EAAE,GAAG;AAAA,MAC3B,OAAA,EAAS,KAAA,CAAM,OAAA,CAAQ,CAAA,EAAG,IAAI;AAAA;AAChC,GACF;AACF,CAAA;;;;"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import { useApi } from '@backstage/frontend-plugin-api';
|
|
3
|
+
import { resourceUrl } from '@massdriver/backstage-plugin-common';
|
|
4
|
+
import Box from '@massdriver/ui/Box';
|
|
5
|
+
import IconButton from '@massdriver/ui/IconButton';
|
|
6
|
+
import IconTile from '@massdriver/ui/IconTile';
|
|
7
|
+
import PageTabs from '@massdriver/ui/PageTabs';
|
|
8
|
+
import Tooltip from '@massdriver/ui/Tooltip';
|
|
9
|
+
import DeleteIcon from '@massdriver/ui/icons/DeleteIcon';
|
|
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 { useParams } from 'react-router-dom';
|
|
14
|
+
import { massdriverApiRef } from '../../api.esm.js';
|
|
15
|
+
import { DisabledAction } from '../../components/DisabledAction.esm.js';
|
|
16
|
+
import { NotFound } from '../../components/NotFound.esm.js';
|
|
17
|
+
import { OpenInMassdriverButton } from '../../components/OpenInMassdriverButton.esm.js';
|
|
18
|
+
import { PageLayout } from '../../components/PageLayout.esm.js';
|
|
19
|
+
import { RouterLinkAdapter } from '../../components/RouterLinkAdapter.esm.js';
|
|
20
|
+
import { internalRoutes } from '../../internalRoutes.esm.js';
|
|
21
|
+
import { PROVISIONED_EDIT_TOOLTIP, PROVISIONED_DELETE_TOOLTIP } from '../resources/resourceConstants.esm.js';
|
|
22
|
+
import { RESOURCE_HEADER_QUERY } from './queries.esm.js';
|
|
23
|
+
import { GeneralTab } from './tabs/GeneralTab.esm.js';
|
|
24
|
+
import { PermissionsTab } from './tabs/PermissionsTab.esm.js';
|
|
25
|
+
import { UsageTab } from './tabs/UsageTab.esm.js';
|
|
26
|
+
|
|
27
|
+
const DELETE_TOOLTIP = "Delete in Massdriver";
|
|
28
|
+
const TABS = [
|
|
29
|
+
{ id: "general", label: "General" },
|
|
30
|
+
{ id: "usage", label: "Usage" },
|
|
31
|
+
{ id: "permissions", label: "Permissions" }
|
|
32
|
+
];
|
|
33
|
+
const PANELS = {
|
|
34
|
+
general: GeneralTab,
|
|
35
|
+
usage: UsageTab,
|
|
36
|
+
permissions: PermissionsTab
|
|
37
|
+
};
|
|
38
|
+
const ResourceDetailsPage = () => {
|
|
39
|
+
const api = useApi(massdriverApiRef);
|
|
40
|
+
const { resourceId: rawResourceId = "", tab } = useParams();
|
|
41
|
+
const resourceId = decodeURIComponent(rawResourceId);
|
|
42
|
+
const activeTab = TABS.some((entry) => entry.id === tab) ? tab : "general";
|
|
43
|
+
const {
|
|
44
|
+
value: resource,
|
|
45
|
+
loading,
|
|
46
|
+
error
|
|
47
|
+
} = useAsync(async () => {
|
|
48
|
+
const data = await api.query(RESOURCE_HEADER_QUERY, {
|
|
49
|
+
id: resourceId
|
|
50
|
+
});
|
|
51
|
+
return data.resource;
|
|
52
|
+
}, [api, resourceId]);
|
|
53
|
+
if (!loading && !error && !resource) {
|
|
54
|
+
return /* @__PURE__ */ jsx(
|
|
55
|
+
NotFound,
|
|
56
|
+
{
|
|
57
|
+
title: "Resource not found",
|
|
58
|
+
message: "This resource doesn't exist or you don't have access to it."
|
|
59
|
+
}
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
const isProvisioned = resource?.origin === "PROVISIONED";
|
|
63
|
+
const tabs = TABS.map((entry) => ({
|
|
64
|
+
...entry,
|
|
65
|
+
href: internalRoutes.resourceTab(resourceId, entry.id)
|
|
66
|
+
}));
|
|
67
|
+
const titleNode = resource ? /* @__PURE__ */ jsxs(TitleRow, { children: [
|
|
68
|
+
/* @__PURE__ */ jsx(
|
|
69
|
+
IconTile,
|
|
70
|
+
{
|
|
71
|
+
src: resource.resourceType?.icon,
|
|
72
|
+
alt: resource.resourceType?.name,
|
|
73
|
+
size: "medium",
|
|
74
|
+
fallback: /* @__PURE__ */ jsx(ExtensionIcon, {})
|
|
75
|
+
}
|
|
76
|
+
),
|
|
77
|
+
/* @__PURE__ */ jsx(TitleText, { children: resource.name })
|
|
78
|
+
] }) : "";
|
|
79
|
+
return /* @__PURE__ */ jsx(
|
|
80
|
+
PageLayout,
|
|
81
|
+
{
|
|
82
|
+
title: titleNode,
|
|
83
|
+
description: resource?.resourceType?.name,
|
|
84
|
+
headerActions: resource ? /* @__PURE__ */ jsxs(HeaderActions, { children: [
|
|
85
|
+
/* @__PURE__ */ jsx(
|
|
86
|
+
OpenInMassdriverButton,
|
|
87
|
+
{
|
|
88
|
+
url: resourceUrl(api.appUrl, api.organizationId, resourceId),
|
|
89
|
+
variant: "outlined",
|
|
90
|
+
children: "Open in Massdriver"
|
|
91
|
+
}
|
|
92
|
+
),
|
|
93
|
+
isProvisioned ? /* @__PURE__ */ jsx(DisabledAction, { label: "Edit", tooltip: PROVISIONED_EDIT_TOOLTIP }) : /* @__PURE__ */ jsx(
|
|
94
|
+
OpenInMassdriverButton,
|
|
95
|
+
{
|
|
96
|
+
url: resourceUrl(api.appUrl, api.organizationId, resourceId),
|
|
97
|
+
variant: "outlined",
|
|
98
|
+
children: "Edit"
|
|
99
|
+
}
|
|
100
|
+
),
|
|
101
|
+
/* @__PURE__ */ jsx(
|
|
102
|
+
Tooltip,
|
|
103
|
+
{
|
|
104
|
+
title: isProvisioned ? PROVISIONED_DELETE_TOOLTIP : DELETE_TOOLTIP,
|
|
105
|
+
arrow: true,
|
|
106
|
+
placement: "top",
|
|
107
|
+
children: /* @__PURE__ */ jsx(ButtonWrap, { children: /* @__PURE__ */ jsx(
|
|
108
|
+
DangerIconButton,
|
|
109
|
+
{
|
|
110
|
+
"aria-label": "Delete resource",
|
|
111
|
+
disabled: isProvisioned,
|
|
112
|
+
...isProvisioned ? {} : {
|
|
113
|
+
href: resourceUrl(
|
|
114
|
+
api.appUrl,
|
|
115
|
+
api.organizationId,
|
|
116
|
+
resourceId
|
|
117
|
+
),
|
|
118
|
+
target: "_blank",
|
|
119
|
+
rel: "noopener noreferrer"
|
|
120
|
+
},
|
|
121
|
+
children: /* @__PURE__ */ jsx(DeleteIcon, {})
|
|
122
|
+
}
|
|
123
|
+
) })
|
|
124
|
+
}
|
|
125
|
+
)
|
|
126
|
+
] }) : null,
|
|
127
|
+
flush: true,
|
|
128
|
+
children: /* @__PURE__ */ jsx(
|
|
129
|
+
PageTabs,
|
|
130
|
+
{
|
|
131
|
+
orientation: "vertical",
|
|
132
|
+
tabs,
|
|
133
|
+
panels: PANELS,
|
|
134
|
+
activeTab,
|
|
135
|
+
panelProps: { resourceId, resourceOrigin: resource?.origin },
|
|
136
|
+
LinkComponent: RouterLinkAdapter
|
|
137
|
+
}
|
|
138
|
+
)
|
|
139
|
+
}
|
|
140
|
+
);
|
|
141
|
+
};
|
|
142
|
+
const TitleRow = stylin("span")(({ theme }) => ({
|
|
143
|
+
display: "inline-flex",
|
|
144
|
+
alignItems: "center",
|
|
145
|
+
gap: theme.spacing(1.5),
|
|
146
|
+
minWidth: 0
|
|
147
|
+
}));
|
|
148
|
+
const TitleText = stylin("span")({
|
|
149
|
+
minWidth: 0,
|
|
150
|
+
wordBreak: "break-word"
|
|
151
|
+
});
|
|
152
|
+
const HeaderActions = stylin(Box)(({ theme }) => ({
|
|
153
|
+
display: "flex",
|
|
154
|
+
alignItems: "center",
|
|
155
|
+
gap: theme.spacing(1)
|
|
156
|
+
}));
|
|
157
|
+
const ButtonWrap = stylin("span")({
|
|
158
|
+
display: "inline-flex"
|
|
159
|
+
});
|
|
160
|
+
const DangerIconButton = stylin(IconButton)(({ theme }) => ({
|
|
161
|
+
"&:hover:not(:disabled)": {
|
|
162
|
+
color: theme.palette.error.main
|
|
163
|
+
}
|
|
164
|
+
}));
|
|
165
|
+
|
|
166
|
+
export { ResourceDetailsPage };
|
|
167
|
+
//# sourceMappingURL=ResourceDetailsPage.esm.js.map
|