feat(ws): added images tab to workspace kind details (#398)

* feat(ws): added images tab to workspace kind details

Signed-off-by: paulovmr <832830+paulovmr@users.noreply.github.com>

* feat(ws): added images tab to workspace kind details

Signed-off-by: paulovmr <832830+paulovmr@users.noreply.github.com>

* feat(ws): added images tab to workspace kind details

Signed-off-by: paulovmr <832830+paulovmr@users.noreply.github.com>

---------

Signed-off-by: paulovmr <832830+paulovmr@users.noreply.github.com>
This commit is contained in:
Paulo Rego 2025-06-02 14:47:23 -03:00 committed by GitHub
parent d668eb83c7
commit 83caeff57c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 95 additions and 9 deletions

View File

@ -1,8 +1,12 @@
import * as React from 'react';
import { useNotebookAPI } from '~/app/hooks/useNotebookAPI';
import { Workspace, WorkspaceKind } from '~/shared/api/backendApiTypes';
import { WorkspaceCountPerKindImagePodConfig } from '~/app/types';
type WorkspaceCountPerKind = Record<WorkspaceKind['name'], number>;
export type WorkspaceCountPerKind = Record<
WorkspaceKind['name'],
WorkspaceCountPerKindImagePodConfig
>;
export const useWorkspaceCountPerKind = (): WorkspaceCountPerKind => {
const { api } = useNotebookAPI();
@ -14,7 +18,25 @@ export const useWorkspaceCountPerKind = (): WorkspaceCountPerKind => {
React.useEffect(() => {
api.listAllWorkspaces({}).then((workspaces) => {
const countPerKind = workspaces.reduce((acc: WorkspaceCountPerKind, workspace: Workspace) => {
acc[workspace.workspaceKind.name] = (acc[workspace.workspaceKind.name] || 0) + 1;
acc[workspace.workspaceKind.name] = acc[workspace.workspaceKind.name] ?? {
count: 0,
countByImage: {},
countByPodConfig: {},
};
acc[workspace.workspaceKind.name].count =
(acc[workspace.workspaceKind.name].count || 0) + 1;
acc[workspace.workspaceKind.name].countByImage[
workspace.podTemplate.options.imageConfig.current.id
] =
(acc[workspace.workspaceKind.name].countByImage[
workspace.podTemplate.options.imageConfig.current.id
] || 0) + 1;
acc[workspace.workspaceKind.name].countByPodConfig[
workspace.podTemplate.options.podConfig.current.id
] =
(acc[workspace.workspaceKind.name].countByPodConfig[
workspace.podTemplate.options.podConfig.current.id
] || 0) + 1;
return acc;
}, {});
setWorkspaceCountPerKind(countPerKind);

View File

@ -87,7 +87,8 @@ export const WorkspaceKinds: React.FunctionComponent = () => {
name: workspaceKind.name,
description: workspaceKind.description,
deprecated: workspaceKind.deprecated,
numOfWorkspaces: workspaceCountPerKind[workspaceKind.name] ?? 0,
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
numOfWorkspaces: workspaceCountPerKind[workspaceKind.name]?.count ?? 0,
};
return [icon, name, description, deprecated, numberOfWorkspaces];
},
@ -433,6 +434,7 @@ export const WorkspaceKinds: React.FunctionComponent = () => {
{selectedWorkspaceKind && (
<WorkspaceKindDetails
workspaceKind={selectedWorkspaceKind}
workspaceCountPerKind={workspaceCountPerKind}
onCloseClick={() => setSelectedWorkspaceKind(null)}
/>
)}
@ -580,7 +582,10 @@ export const WorkspaceKinds: React.FunctionComponent = () => {
)}
</Td>
<Td dataLabel={columns.numberOfWorkspaces.name}>
{workspaceCountPerKind[workspaceKind.name] ?? 0}
{
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
workspaceCountPerKind[workspaceKind.name]?.count ?? 0
}
</Td>
<Td isActionCell data-testid="action-column">

View File

@ -13,15 +13,19 @@ import {
TabContent,
} from '@patternfly/react-core';
import { WorkspaceKind } from '~/shared/api/backendApiTypes';
import { WorkspaceDetailsOverview } from './WorkspaceDetailsOverview';
import { WorkspaceCountPerKind } from '~/app/hooks/useWorkspaceCountPerKind';
import { WorkspaceKindDetailsOverview } from './WorkspaceKindDetailsOverview';
import { WorkspaceKindDetailsImages } from './WorkspaceKindDetailsImages';
type WorkspaceKindDetailsProps = {
workspaceKind: WorkspaceKind;
workspaceCountPerKind: WorkspaceCountPerKind;
onCloseClick: React.MouseEventHandler;
};
export const WorkspaceKindDetails: React.FunctionComponent<WorkspaceKindDetailsProps> = ({
workspaceKind,
workspaceCountPerKind,
onCloseClick,
}) => {
const [activeTabKey, setActiveTabKey] = React.useState<string | number>(0);
@ -50,6 +54,12 @@ export const WorkspaceKindDetails: React.FunctionComponent<WorkspaceKindDetailsP
tabContentId="overviewTabContent"
aria-label="Overview"
/>
<Tab
eventKey={1}
title={<TabTitleText>Images</TabTitleText>}
tabContentId="imagesTabContent"
aria-label="Images"
/>
</Tabs>
</DrawerPanelBody>
@ -62,7 +72,21 @@ export const WorkspaceKindDetails: React.FunctionComponent<WorkspaceKindDetailsP
hidden={activeTabKey !== 0}
>
<TabContentBody hasPadding>
<WorkspaceDetailsOverview workspaceKind={workspaceKind} />
<WorkspaceKindDetailsOverview workspaceKind={workspaceKind} />
</TabContentBody>
</TabContent>
<TabContent
key={1}
eventKey={1}
id="imagesTabContent"
activeKey={activeTabKey}
hidden={activeTabKey !== 1}
>
<TabContentBody hasPadding>
<WorkspaceKindDetailsImages
workspaceKind={workspaceKind}
workspaceCountPerKind={workspaceCountPerKind}
/>
</TabContentBody>
</TabContent>
</DrawerPanelBody>

View File

@ -0,0 +1,29 @@
import React from 'react';
import { List, ListItem } from '@patternfly/react-core';
import { WorkspaceKind } from '~/shared/api/backendApiTypes';
import { WorkspaceCountPerKind } from '~/app/hooks/useWorkspaceCountPerKind';
type WorkspaceDetailsImagesProps = {
workspaceKind: WorkspaceKind;
workspaceCountPerKind: WorkspaceCountPerKind;
};
export const WorkspaceKindDetailsImages: React.FunctionComponent<WorkspaceDetailsImagesProps> = ({
workspaceKind,
workspaceCountPerKind,
}) => (
<List isPlain>
{workspaceKind.podTemplate.options.imageConfig.values.map((image, rowIndex) => (
<ListItem key={rowIndex}>
{image.displayName}:{' '}
{
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
workspaceCountPerKind[workspaceKind.name]
? workspaceCountPerKind[workspaceKind.name].countByImage[image.id]
: 0
}
{' Workspaces'}
</ListItem>
))}
</List>
);

View File

@ -13,9 +13,9 @@ type WorkspaceDetailsOverviewProps = {
workspaceKind: WorkspaceKind;
};
export const WorkspaceDetailsOverview: React.FunctionComponent<WorkspaceDetailsOverviewProps> = ({
workspaceKind,
}) => (
export const WorkspaceKindDetailsOverview: React.FunctionComponent<
WorkspaceDetailsOverviewProps
> = ({ workspaceKind }) => (
<DescriptionList isHorizontal>
<DescriptionListGroup>
<DescriptionListTerm>Name</DescriptionListTerm>

View File

@ -46,3 +46,9 @@ export interface WorkspaceFormData {
podConfig: WorkspacePodConfigValue | undefined;
properties: WorkspaceFormProperties;
}
export interface WorkspaceCountPerKindImagePodConfig {
count: number;
countByImage: Record<WorkspaceImageConfigValue['id'], number>;
countByPodConfig: Record<WorkspacePodConfigValue['id'], number>;
}