feat(ws): Make Workspace Kind drawer resizable and add table view to WS kind details (#483)
Signed-off-by: Charles Thao <cthao@redhat.com>
This commit is contained in:
parent
13a66aef2b
commit
de0e5c4356
|
@ -45,7 +45,7 @@ export const WorkspaceKindDetails: React.FunctionComponent<WorkspaceKindDetailsP
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DrawerPanelContent data-testid="workspaceDetails">
|
<DrawerPanelContent minSize="45%" isResizable data-testid="workspaceDetails">
|
||||||
<DrawerHead>
|
<DrawerHead>
|
||||||
<Title headingLevel="h6">{workspaceKind.name}</Title>
|
<Title headingLevel="h6">{workspaceKind.name}</Title>
|
||||||
<DrawerActions>
|
<DrawerActions>
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Button, List, ListItem } from '@patternfly/react-core';
|
|
||||||
import { WorkspaceKind } from '~/shared/api/backendApiTypes';
|
import { WorkspaceKind } from '~/shared/api/backendApiTypes';
|
||||||
import { WorkspaceCountPerKind } from '~/app/hooks/useWorkspaceCountPerKind';
|
import { WorkspaceCountPerKind } from '~/app/hooks/useWorkspaceCountPerKind';
|
||||||
import { useTypedNavigate } from '~/app/routerHelper';
|
import { WorkspaceKindDetailsTable } from './WorkspaceKindDetailsTable';
|
||||||
|
|
||||||
type WorkspaceDetailsImagesProps = {
|
type WorkspaceDetailsImagesProps = {
|
||||||
workspaceKind: WorkspaceKind;
|
workspaceKind: WorkspaceKind;
|
||||||
|
@ -12,37 +11,21 @@ type WorkspaceDetailsImagesProps = {
|
||||||
export const WorkspaceKindDetailsImages: React.FunctionComponent<WorkspaceDetailsImagesProps> = ({
|
export const WorkspaceKindDetailsImages: React.FunctionComponent<WorkspaceDetailsImagesProps> = ({
|
||||||
workspaceKind,
|
workspaceKind,
|
||||||
workspaceCountPerKind,
|
workspaceCountPerKind,
|
||||||
}) => {
|
}) => (
|
||||||
const navigate = useTypedNavigate();
|
<WorkspaceKindDetailsTable
|
||||||
|
rows={workspaceKind.podTemplate.options.imageConfig.values.map((image) => ({
|
||||||
return (
|
id: image.id,
|
||||||
<List isPlain>
|
displayName: image.displayName,
|
||||||
{workspaceKind.podTemplate.options.imageConfig.values.map((image, rowIndex) => (
|
kindName: workspaceKind.name,
|
||||||
<ListItem key={rowIndex}>
|
workspaceCountRouteState: {
|
||||||
{image.displayName}:{' '}
|
imageId: image.id,
|
||||||
<Button
|
},
|
||||||
variant="link"
|
workspaceCount:
|
||||||
isInline
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
className="workspace-kind-summary-button"
|
workspaceCountPerKind[workspaceKind.name]
|
||||||
onClick={() =>
|
? workspaceCountPerKind[workspaceKind.name].countByImage[image.id] ?? 0
|
||||||
navigate('workspaceKindSummary', {
|
: 0,
|
||||||
params: { kind: workspaceKind.name },
|
}))}
|
||||||
state: {
|
tableKind="image"
|
||||||
imageId: image.id,
|
/>
|
||||||
},
|
);
|
||||||
})
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
||||||
workspaceCountPerKind[workspaceKind.name]
|
|
||||||
? workspaceCountPerKind[workspaceKind.name].countByImage[image.id] ?? 0
|
|
||||||
: 0
|
|
||||||
}
|
|
||||||
{' Workspaces'}
|
|
||||||
</Button>
|
|
||||||
</ListItem>
|
|
||||||
))}
|
|
||||||
</List>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Button, List, ListItem } from '@patternfly/react-core';
|
|
||||||
import { WorkspaceKind } from '~/shared/api/backendApiTypes';
|
import { WorkspaceKind } from '~/shared/api/backendApiTypes';
|
||||||
import { WorkspaceCountPerKind } from '~/app/hooks/useWorkspaceCountPerKind';
|
import { WorkspaceCountPerKind } from '~/app/hooks/useWorkspaceCountPerKind';
|
||||||
import { useTypedNavigate } from '~/app/routerHelper';
|
import { WorkspaceKindDetailsTable } from './WorkspaceKindDetailsTable';
|
||||||
|
|
||||||
type WorkspaceDetailsNamespacesProps = {
|
type WorkspaceDetailsNamespacesProps = {
|
||||||
workspaceKind: WorkspaceKind;
|
workspaceKind: WorkspaceKind;
|
||||||
|
@ -11,42 +10,25 @@ type WorkspaceDetailsNamespacesProps = {
|
||||||
|
|
||||||
export const WorkspaceKindDetailsNamespaces: React.FunctionComponent<
|
export const WorkspaceKindDetailsNamespaces: React.FunctionComponent<
|
||||||
WorkspaceDetailsNamespacesProps
|
WorkspaceDetailsNamespacesProps
|
||||||
> = ({ workspaceKind, workspaceCountPerKind }) => {
|
> = ({ workspaceKind, workspaceCountPerKind }) => (
|
||||||
const navigate = useTypedNavigate();
|
<WorkspaceKindDetailsTable
|
||||||
|
rows={Object.keys(
|
||||||
return (
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
<List isPlain>
|
workspaceCountPerKind[workspaceKind.name]
|
||||||
{Object.keys(
|
? workspaceCountPerKind[workspaceKind.name].countByNamespace
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
: [],
|
||||||
workspaceCountPerKind[workspaceKind.name]
|
).map((namespace, rowIndex) => ({
|
||||||
? workspaceCountPerKind[workspaceKind.name].countByNamespace
|
id: String(rowIndex),
|
||||||
: [],
|
displayName: namespace,
|
||||||
).map((namespace, rowIndex) => (
|
kindName: workspaceKind.name,
|
||||||
<ListItem key={rowIndex}>
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
{namespace}:{' '}
|
workspaceCount: workspaceCountPerKind[workspaceKind.name]
|
||||||
<Button
|
? workspaceCountPerKind[workspaceKind.name].countByNamespace[namespace]
|
||||||
variant="link"
|
: 0,
|
||||||
className="workspace-kind-summary-button"
|
workspaceCountRouteState: {
|
||||||
isInline
|
namespace,
|
||||||
onClick={() =>
|
},
|
||||||
navigate('workspaceKindSummary', {
|
}))}
|
||||||
params: { kind: workspaceKind.name },
|
tableKind="namespace"
|
||||||
state: {
|
/>
|
||||||
namespace,
|
);
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
||||||
workspaceCountPerKind[workspaceKind.name]
|
|
||||||
? workspaceCountPerKind[workspaceKind.name].countByNamespace[namespace]
|
|
||||||
: 0
|
|
||||||
}
|
|
||||||
{' Workspaces'}
|
|
||||||
</Button>
|
|
||||||
</ListItem>
|
|
||||||
))}
|
|
||||||
</List>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Button, List, ListItem } from '@patternfly/react-core';
|
|
||||||
import { WorkspaceKind } from '~/shared/api/backendApiTypes';
|
import { WorkspaceKind } from '~/shared/api/backendApiTypes';
|
||||||
import { WorkspaceCountPerKind } from '~/app/hooks/useWorkspaceCountPerKind';
|
import { WorkspaceCountPerKind } from '~/app/hooks/useWorkspaceCountPerKind';
|
||||||
import { useTypedNavigate } from '~/app/routerHelper';
|
import { WorkspaceKindDetailsTable } from './WorkspaceKindDetailsTable';
|
||||||
|
|
||||||
type WorkspaceDetailsPodConfigsProps = {
|
type WorkspaceDetailsPodConfigsProps = {
|
||||||
workspaceKind: WorkspaceKind;
|
workspaceKind: WorkspaceKind;
|
||||||
|
@ -11,37 +10,20 @@ type WorkspaceDetailsPodConfigsProps = {
|
||||||
|
|
||||||
export const WorkspaceKindDetailsPodConfigs: React.FunctionComponent<
|
export const WorkspaceKindDetailsPodConfigs: React.FunctionComponent<
|
||||||
WorkspaceDetailsPodConfigsProps
|
WorkspaceDetailsPodConfigsProps
|
||||||
> = ({ workspaceKind, workspaceCountPerKind }) => {
|
> = ({ workspaceKind, workspaceCountPerKind }) => (
|
||||||
const navigate = useTypedNavigate();
|
<WorkspaceKindDetailsTable
|
||||||
|
rows={workspaceKind.podTemplate.options.podConfig.values.map((podConfig) => ({
|
||||||
return (
|
id: podConfig.id,
|
||||||
<List isPlain>
|
displayName: podConfig.displayName,
|
||||||
{workspaceKind.podTemplate.options.podConfig.values.map((podConfig, rowIndex) => (
|
kindName: workspaceKind.name,
|
||||||
<ListItem key={rowIndex}>
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
{podConfig.displayName}:{' '}
|
workspaceCount: workspaceCountPerKind[workspaceKind.name]
|
||||||
<Button
|
? workspaceCountPerKind[workspaceKind.name].countByPodConfig[podConfig.id] ?? 0
|
||||||
variant="link"
|
: 0,
|
||||||
className="workspace-kind-summary-button"
|
workspaceCountRouteState: {
|
||||||
isInline
|
podConfigId: podConfig.id,
|
||||||
onClick={() =>
|
},
|
||||||
navigate('workspaceKindSummary', {
|
}))}
|
||||||
params: { kind: workspaceKind.name },
|
tableKind="podConfig"
|
||||||
state: {
|
/>
|
||||||
podConfigId: podConfig.id,
|
);
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
||||||
workspaceCountPerKind[workspaceKind.name]
|
|
||||||
? workspaceCountPerKind[workspaceKind.name].countByPodConfig[podConfig.id] ?? 0
|
|
||||||
: 0
|
|
||||||
}
|
|
||||||
{' Workspaces'}
|
|
||||||
</Button>
|
|
||||||
</ListItem>
|
|
||||||
))}
|
|
||||||
</List>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
import React, { useMemo, useState } from 'react';
|
||||||
|
import { Table, Thead, Tr, Td, Tbody, Th } from '@patternfly/react-table';
|
||||||
|
import { Button, Content, Pagination, PaginationVariant } from '@patternfly/react-core';
|
||||||
|
import { useTypedNavigate } from '~/app/routerHelper';
|
||||||
|
import { RouteStateMap } from '~/app/routes';
|
||||||
|
|
||||||
|
export interface WorkspaceKindDetailsTableRow {
|
||||||
|
id: string;
|
||||||
|
displayName: string;
|
||||||
|
kindName: string;
|
||||||
|
workspaceCount: number;
|
||||||
|
workspaceCountRouteState: RouteStateMap['workspaceKindSummary'];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WorkspaceKindDetailsTableProps {
|
||||||
|
rows: WorkspaceKindDetailsTableRow[];
|
||||||
|
tableKind: 'image' | 'podConfig' | 'namespace';
|
||||||
|
}
|
||||||
|
|
||||||
|
export const WorkspaceKindDetailsTable: React.FC<WorkspaceKindDetailsTableProps> = ({
|
||||||
|
rows,
|
||||||
|
tableKind,
|
||||||
|
}) => {
|
||||||
|
const navigate = useTypedNavigate();
|
||||||
|
|
||||||
|
const [page, setPage] = useState(1);
|
||||||
|
const [perPage, setPerPage] = useState(10);
|
||||||
|
const rowPages = useMemo(() => {
|
||||||
|
const pages = [];
|
||||||
|
for (let i = 0; i < rows.length; i += perPage) {
|
||||||
|
pages.push(rows.slice(i, i + perPage));
|
||||||
|
}
|
||||||
|
return pages;
|
||||||
|
}, [perPage, rows]);
|
||||||
|
|
||||||
|
const onSetPage = (
|
||||||
|
_event: React.MouseEvent | React.KeyboardEvent | MouseEvent,
|
||||||
|
newPage: number,
|
||||||
|
) => {
|
||||||
|
setPage(newPage);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onPerPageSelect = (
|
||||||
|
_event: React.MouseEvent | React.KeyboardEvent | MouseEvent,
|
||||||
|
newPerPage: number,
|
||||||
|
newPage: number,
|
||||||
|
) => {
|
||||||
|
setPerPage(newPerPage);
|
||||||
|
setPage(newPage);
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Content>
|
||||||
|
<Table aria-label={`workspace-kind-details-${tableKind}`}>
|
||||||
|
<Thead>
|
||||||
|
<Tr>
|
||||||
|
<Th>Name</Th>
|
||||||
|
<Th>Workspaces</Th>
|
||||||
|
</Tr>
|
||||||
|
</Thead>
|
||||||
|
<Tbody>
|
||||||
|
{rowPages[page - 1].map((row) => (
|
||||||
|
<Tr key={row.id}>
|
||||||
|
<Td>{row.displayName}</Td>
|
||||||
|
<Td>
|
||||||
|
<Button
|
||||||
|
variant="link"
|
||||||
|
isInline
|
||||||
|
className="workspace-kind-summary-button"
|
||||||
|
onClick={() =>
|
||||||
|
navigate('workspaceKindSummary', {
|
||||||
|
params: { kind: row.kindName },
|
||||||
|
state: row.workspaceCountRouteState,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{row.workspaceCount} Workspaces
|
||||||
|
</Button>
|
||||||
|
</Td>
|
||||||
|
</Tr>
|
||||||
|
))}
|
||||||
|
</Tbody>
|
||||||
|
</Table>
|
||||||
|
<Pagination
|
||||||
|
itemCount={rows.length}
|
||||||
|
widgetId="pagination-bottom"
|
||||||
|
perPage={perPage}
|
||||||
|
page={page}
|
||||||
|
variant={PaginationVariant.bottom}
|
||||||
|
isCompact
|
||||||
|
onSetPage={onSetPage}
|
||||||
|
onPerPageSelect={onPerPageSelect}
|
||||||
|
/>
|
||||||
|
</Content>
|
||||||
|
);
|
||||||
|
};
|
Loading…
Reference in New Issue