Skip to content

Commit

Permalink
feat(ws): Add popup to Workspace data vol column in workspaces table (#…
Browse files Browse the repository at this point in the history
…160)

Signed-off-by: Elay Aharoni (EXT-Nokia) <[email protected]>
Co-authored-by: Elay Aharoni (EXT-Nokia) <[email protected]>
  • Loading branch information
ElayAharoni and Elay Aharoni (EXT-Nokia) authored Jan 13, 2025
1 parent 57fc8b1 commit 249a456
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 20 deletions.
74 changes: 74 additions & 0 deletions workspaces/frontend/src/app/pages/Workspaces/DataVolumesList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import {
ClipboardCopy,
ClipboardCopyVariant,
Content,
Flex,
FlexItem,
List,
ListItem,
Stack,
StackItem,
Tooltip,
} from '@patternfly/react-core';
import { DatabaseIcon, LockedIcon } from '@patternfly/react-icons';
import * as React from 'react';
import { Workspace } from '~/shared/types';

interface DataVolumesListProps {
workspace: Workspace;
}

export const DataVolumesList: React.FC<DataVolumesListProps> = ({ workspace }) => {
const workspaceDataVol = workspace.podTemplate.volumes.data;

const singleDataVolRenderer = (data: {
pvcName: string;
mountPath: string;
readOnly: boolean;
}) => (
<Flex
gap={{ default: 'gapSm' }}
alignItems={{ default: 'alignItemsFlexStart' }}
flexWrap={{ default: 'nowrap' }}
>
<FlexItem>
<DatabaseIcon />
</FlexItem>
<FlexItem>
<Content>
{data.pvcName}
{data.readOnly && (
<Tooltip content="Data is readonly">
<LockedIcon style={{ marginLeft: '5px' }} />
</Tooltip>
)}
</Content>
<Stack>
<StackItem>
<Content component="small">
Mount path:{' '}
<ClipboardCopy variant={ClipboardCopyVariant.inlineCompact}>
{data.mountPath}
</ClipboardCopy>
</Content>
</StackItem>
</Stack>
</FlexItem>
</Flex>
);

return (
<Stack hasGutter>
<StackItem>
<strong data-testid="notebook-storage-bar-title">Cluster storage</strong>
</StackItem>
<StackItem>
<List isPlain>
{workspaceDataVol.map((data, index) => (
<ListItem key={`data-vol-${index}`}>{singleDataVolRenderer(data)}</ListItem>
))}
</List>
</StackItem>
</Stack>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import * as React from 'react';
import { ExpandableRowContent, Td, Tr } from '@patternfly/react-table';
import { Workspace, WorkspacesColumnNames } from '~/shared/types';
import { DataVolumesList } from '~/app/pages/Workspaces/DataVolumesList';

interface ExpandedWorkspaceRowProps {
workspace: Workspace;
columnNames: WorkspacesColumnNames;
}

export const ExpandedWorkspaceRow: React.FC<ExpandedWorkspaceRowProps> = ({
workspace,
columnNames,
}) => {
const renderExpandedData = () =>
Object.keys(columnNames).map((colName) => {
switch (colName) {
case 'name':
return (
<Td noPadding colSpan={1}>
<ExpandableRowContent>
<DataVolumesList workspace={workspace} />
</ExpandableRowContent>
</Td>
);
default:
return <Td />;
}
});

return (
<Tr>
<Td />
{renderExpandedData()}
</Tr>
);
};
64 changes: 44 additions & 20 deletions workspaces/frontend/src/app/pages/Workspaces/Workspaces.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ import {
IActions,
} from '@patternfly/react-table';
import { FilterIcon } from '@patternfly/react-icons';
import { Workspace, WorkspaceState } from 'shared/types';
import { Workspace, WorkspacesColumnNames, WorkspaceState } from '~/shared/types';

import { ExpandedWorkspaceRow } from '~/app/pages/Workspaces/ExpandedWorkspaceRow';
import { formatRam } from 'shared/utilities/WorkspaceResources';

export const Workspaces: React.FunctionComponent = () => {
Expand All @@ -54,7 +56,12 @@ export const Workspaces: React.FunctionComponent = () => {
home: '/home',
data: [
{
pvcName: 'data',
pvcName: 'Volume-1',
mountPath: '/data',
readOnly: true,
},
{
pvcName: 'Volume-2',
mountPath: '/data',
readOnly: false,
},
Expand Down Expand Up @@ -95,7 +102,7 @@ export const Workspaces: React.FunctionComponent = () => {
home: '/home',
data: [
{
pvcName: 'data',
pvcName: 'PVC-1',
mountPath: '/data',
readOnly: false,
},
Expand Down Expand Up @@ -126,14 +133,13 @@ export const Workspaces: React.FunctionComponent = () => {
];

// Table columns
const columnNames = {
const columnNames: WorkspacesColumnNames = {
name: 'Name',
kind: 'Kind',
image: 'Image',
podConfig: 'Pod Config',
state: 'State',
homeVol: 'Home Vol',
dataVol: 'Data Vol',
cpu: 'CPU',
ram: 'Memory',
lastActivity: 'Last Activity',
Expand All @@ -147,6 +153,18 @@ export const Workspaces: React.FunctionComponent = () => {
const attributeContainerRef = React.useRef<HTMLDivElement | null>(null);

const [searchValue, setSearchValue] = React.useState('');
const [expandedWorkspacesNames, setExpandedWorkspacesNames] = React.useState<string[]>([]);

const setWorkspaceExpanded = (workspace: Workspace, isExpanding = true) =>
setExpandedWorkspacesNames((prevExpanded) => {
const newExpandedWorkspacesNames = prevExpanded.filter((wsName) => wsName !== workspace.name);
return isExpanding
? [...newExpandedWorkspacesNames, workspace.name]
: newExpandedWorkspacesNames;
});

const isWorkspaceExpanded = (workspace: Workspace) =>
expandedWorkspacesNames.includes(workspace.name);

const searchInput = (
<SearchInput
Expand Down Expand Up @@ -322,19 +340,18 @@ export const Workspaces: React.FunctionComponent = () => {
const [activeSortDirection, setActiveSortDirection] = React.useState<'asc' | 'desc' | null>(null);

const getSortableRowValues = (workspace: Workspace): (string | number)[] => {
const { name, kind, image, podConfig, state, homeVol, dataVol, cpu, ram, lastActivity } = {
const { name, kind, image, podConfig, state, homeVol, cpu, ram, lastActivity } = {
name: workspace.name,
kind: workspace.kind,
image: workspace.options.imageConfig,
podConfig: workspace.options.podConfig,
state: WorkspaceState[workspace.status.state],
homeVol: workspace.podTemplate.volumes.home,
dataVol: workspace.podTemplate.volumes.data[0].pvcName || '',
cpu: workspace.cpu,
ram: workspace.ram,
lastActivity: workspace.status.activity.lastActivity,
};
return [name, kind, image, podConfig, state, homeVol, dataVol, cpu, ram, lastActivity];
return [name, kind, image, podConfig, state, homeVol, cpu, ram, lastActivity];
};

let sortedWorkspaces = filteredWorkspaces;
Expand Down Expand Up @@ -438,26 +455,33 @@ export const Workspaces: React.FunctionComponent = () => {
<Table aria-label="Sortable table" ouiaId="SortableTable">
<Thead>
<Tr>
<Th />
<Th sort={getSortParams(0)}>{columnNames.name}</Th>
<Th sort={getSortParams(1)}>{columnNames.kind}</Th>
<Th sort={getSortParams(2)}>{columnNames.image}</Th>
<Th sort={getSortParams(3)}>{columnNames.podConfig}</Th>
<Th sort={getSortParams(4)}>{columnNames.state}</Th>
<Th sort={getSortParams(5)}>{columnNames.homeVol}</Th>
<Th sort={getSortParams(6)}>{columnNames.dataVol}</Th>
<Th sort={getSortParams(7)} info={{ tooltip: 'Workspace CPU usage' }}>
<Th sort={getSortParams(6)} info={{ tooltip: 'Workspace CPU usage' }}>
{columnNames.cpu}
</Th>
<Th sort={getSortParams(8)} info={{ tooltip: 'Workspace memory usage' }}>
<Th sort={getSortParams(7)} info={{ tooltip: 'Workspace memory usage' }}>
{columnNames.ram}
</Th>
<Th sort={getSortParams(9)}>{columnNames.lastActivity}</Th>
<Th sort={getSortParams(8)}>{columnNames.lastActivity}</Th>
<Th screenReaderText="Primary action" />
</Tr>
</Thead>
<Tbody>
{sortedWorkspaces.map((workspace, rowIndex) => (
<Tr key={rowIndex}>
{sortedWorkspaces.map((workspace, rowIndex) => (
<Tbody key={rowIndex} isExpanded={isWorkspaceExpanded(workspace)}>
<Tr>
<Td
expand={{
rowIndex,
isExpanded: isWorkspaceExpanded(workspace),
onToggle: () => setWorkspaceExpanded(workspace, !isWorkspaceExpanded(workspace)),
}}
/>
<Td dataLabel={columnNames.name}>{workspace.name}</Td>
<Td dataLabel={columnNames.kind}>{workspace.kind}</Td>
<Td dataLabel={columnNames.image}>{workspace.options.imageConfig}</Td>
Expand All @@ -468,9 +492,6 @@ export const Workspaces: React.FunctionComponent = () => {
</Label>
</Td>
<Td dataLabel={columnNames.homeVol}>{workspace.podTemplate.volumes.home}</Td>
<Td dataLabel={columnNames.dataVol}>
{workspace.podTemplate.volumes.data[0].pvcName || ''}
</Td>
<Td dataLabel={columnNames.cpu}>{`${workspace.cpu}%`}</Td>
<Td dataLabel={columnNames.ram}>{formatRam(workspace.ram)}</Td>
<Td dataLabel={columnNames.lastActivity}>
Expand All @@ -485,8 +506,11 @@ export const Workspaces: React.FunctionComponent = () => {
<ActionsColumn items={defaultActions(workspace)} />
</Td>
</Tr>
))}
</Tbody>
{isWorkspaceExpanded(workspace) && (
<ExpandedWorkspaceRow workspace={workspace} columnNames={columnNames} />
)}
</Tbody>
))}
</Table>
<Pagination
itemCount={333}
Expand Down
12 changes: 12 additions & 0 deletions workspaces/frontend/src/shared/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,15 @@ export interface Workspace {
};
status: WorkspaceStatus;
}

export type WorkspacesColumnNames = {
name: string;
kind: string;
image: string;
podConfig: string;
state: string;
homeVol: string;
cpu: string;
ram: string;
lastActivity: string;
};

0 comments on commit 249a456

Please sign in to comment.