Skip to content

Commit f8aa5bc

Browse files
committed
fix(ws): updates to table columns
Signed-off-by: Jenny <[email protected]> add icon to workspaceKindsColumns interface fix(ws): Update table with expandable variant and fix styles fix secondary border in menu toggle fix menu toggle expanded text color and update icon to use status prop remove unused files add cluster storage description list group Signed-off-by: Jenny <[email protected]> Add title and packages revert form label styling, revert homeVol column fix linting fix lint Signed-off-by: Jenny <[email protected]> Add PR code suggestions, remove unused interfaces Signed-off-by: Jenny <[email protected]> remove unused import Signed-off-by: Jenny <[email protected]> fix filterWorkspacesTest
1 parent ca8e94c commit f8aa5bc

File tree

11 files changed

+476
-255
lines changed

11 files changed

+476
-255
lines changed

workspaces/frontend/src/__tests__/cypress/cypress/tests/mocked/workspaces/filterWorkspacesTest.cy.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,16 @@ describe('Application', () => {
3232
it('filter rows with multiple filters', () => {
3333
home.visit();
3434
useFilter('name', 'Name', 'My');
35-
useFilter('podConfig', 'Pod Config', 'Tiny');
36-
cy.get("[id$='workspaces-table-content']").find('tr').should('have.length', 1);
35+
cy.get("[id$='workspaces-table-content']").find('tr').should('have.length', 2);
3736
cy.get("[id$='workspaces-table-row-1']").contains('My First Jupyter Notebook');
3837
});
3938

4039
it('filter rows with multiple filters and remove one', () => {
4140
home.visit();
4241
useFilter('name', 'Name', 'My');
43-
useFilter('podConfig', 'Pod Config', 'Tiny');
44-
cy.get("[id$='workspaces-table-content']").find('tr').should('have.length', 1);
42+
cy.get("[id$='workspaces-table-content']").find('tr').should('have.length', 2);
4543
cy.get("[id$='workspaces-table-row-1']").contains('My First Jupyter Notebook');
46-
cy.get("[class$='pf-v6-c-label-group__close']").eq(1).click();
44+
cy.get("[class$='pf-v6-c-label-group__close']").first().click();
4745
cy.get("[class$='pf-v6-c-toolbar__group']").should('not.contain', 'Pod Config');
4846
cy.get("[id$='workspaces-table-content']").find('tr').should('have.length', 2);
4947
cy.get("[id$='workspaces-table-row-1']").contains('My First Jupyter Notebook');
@@ -53,8 +51,7 @@ describe('Application', () => {
5351
it('filter rows with multiple filters and remove all', () => {
5452
home.visit();
5553
useFilter('name', 'Name', 'My');
56-
useFilter('podConfig', 'Pod Config', 'Tiny');
57-
cy.get("[id$='workspaces-table-content']").find('tr').should('have.length', 1);
54+
cy.get("[id$='workspaces-table-content']").find('tr').should('have.length', 2);
5855
cy.get("[id$='workspaces-table-row-1']").contains('My First Jupyter Notebook');
5956
cy.get('*').contains('Clear all filters').click();
6057
cy.get("[class$='pf-v6-c-toolbar__group']").should('not.contain', 'Pod Config');

workspaces/frontend/src/app/components/WorkspaceTable.tsx

Lines changed: 217 additions & 176 deletions
Large diffs are not rendered by default.

workspaces/frontend/src/app/pages/WorkspaceKinds/summary/WorkspaceKindSummary.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ const WorkspaceKindSummary: React.FC = () => {
9292
ref={workspaceTableRef}
9393
workspaces={workspaces}
9494
canCreateWorkspaces={false}
95-
hiddenColumns={['connect', 'kind', 'homeVol']}
95+
hiddenColumns={['connect', 'kind']}
9696
rowActions={tableRowActions}
9797
/>
9898
</StackItem>

workspaces/frontend/src/app/pages/Workspaces/DataVolumesList.tsx

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@ import {
33
ClipboardCopy,
44
ClipboardCopyVariant,
55
Content,
6+
DescriptionList,
7+
DescriptionListGroup,
8+
DescriptionListTerm,
9+
DescriptionListDescription,
610
Flex,
711
FlexItem,
812
List,
913
ListItem,
10-
Stack,
11-
StackItem,
1214
Tooltip,
1315
} from '@patternfly/react-core';
1416
import { DatabaseIcon, LockedIcon } from '@patternfly/react-icons';
@@ -43,32 +45,30 @@ export const DataVolumesList: React.FC<DataVolumesListProps> = ({ workspace }) =
4345
</Tooltip>
4446
)}
4547
</Content>
46-
<Stack>
47-
<StackItem>
48-
<Content component="small">
49-
Mount path:{' '}
50-
<ClipboardCopy variant={ClipboardCopyVariant.inlineCompact}>
51-
{data.mountPath}
52-
</ClipboardCopy>
53-
</Content>
54-
</StackItem>
55-
</Stack>
48+
<Content component="small">
49+
Mount path:{' '}
50+
<ClipboardCopy variant={ClipboardCopyVariant.inlineCompact}>
51+
{data.mountPath}
52+
</ClipboardCopy>
53+
</Content>
5654
</FlexItem>
5755
</Flex>
5856
);
5957

6058
return (
61-
<Stack hasGutter>
62-
<StackItem>
63-
<strong data-testid="notebook-storage-bar-title">Cluster storage</strong>
64-
</StackItem>
65-
<StackItem>
66-
<List isPlain>
67-
{workspaceDataVol.map((data, index) => (
68-
<ListItem key={`data-vol-${index}`}>{singleDataVolRenderer(data)}</ListItem>
69-
))}
70-
</List>
71-
</StackItem>
72-
</Stack>
59+
<DescriptionList>
60+
<DescriptionListGroup>
61+
<DescriptionListTerm data-testid="notebook-storage-bar-title">
62+
Cluster storage
63+
</DescriptionListTerm>
64+
<DescriptionListDescription>
65+
<List isPlain>
66+
{workspaceDataVol.map((data, index) => (
67+
<ListItem key={`data-vol-${index}`}>{singleDataVolRenderer(data)}</ListItem>
68+
))}
69+
</List>
70+
</DescriptionListDescription>
71+
</DescriptionListGroup>
72+
</DescriptionList>
7373
);
7474
};
Lines changed: 67 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,86 @@
11
import React from 'react';
2-
import { ExpandableRowContent, Td, Tr } from '@patternfly/react-table';
2+
import { Tr, Td, ExpandableRowContent } from '@patternfly/react-table';
33
import { Workspace } from '~/shared/api/backendApiTypes';
4-
import { DataVolumesList } from '~/app/pages/Workspaces/DataVolumesList';
5-
import { WorkspaceTableColumnKeys } from '~/app/components/WorkspaceTable';
4+
import { WorkspaceStorage } from './WorkspaceStorage';
5+
import { WorkspacePackageDetails } from './WorkspacePackageDetails';
6+
import { WorkspaceConfigDetails } from './WorkspaceConfigDetails';
7+
8+
// Import the type from WorkspaceTable
9+
export type WorkspaceTableColumnKeys =
10+
| 'name'
11+
| 'kind'
12+
| 'namespace'
13+
| 'image'
14+
| 'state'
15+
| 'gpu'
16+
| 'idleGpu'
17+
| 'lastActivity'
18+
| 'connect'
19+
| 'actions';
620

721
interface ExpandedWorkspaceRowProps {
822
workspace: Workspace;
9-
columnKeys: WorkspaceTableColumnKeys[];
23+
visibleColumnKeys: WorkspaceTableColumnKeys[];
24+
canExpandRows: boolean;
1025
}
1126

1227
export const ExpandedWorkspaceRow: React.FC<ExpandedWorkspaceRowProps> = ({
1328
workspace,
14-
columnKeys,
29+
visibleColumnKeys,
30+
canExpandRows,
1531
}) => {
16-
const renderExpandedData = () =>
17-
columnKeys.map((colKey, index) => {
18-
switch (colKey) {
19-
case 'name':
32+
// Calculate total number of columns (including expand column if present)
33+
const totalColumns = visibleColumnKeys.length + (canExpandRows ? 1 : 0);
34+
35+
// Find the positions where we want to show our content
36+
// We'll show storage in the first content column, package details in the second,
37+
// and config details in the third
38+
const getColumnIndex = (columnKey: WorkspaceTableColumnKeys) => {
39+
const baseIndex = canExpandRows ? 1 : 0; // Account for expand column
40+
return baseIndex + visibleColumnKeys.indexOf(columnKey);
41+
};
42+
43+
const storageColumnIndex = visibleColumnKeys.includes('name') ? getColumnIndex('name') : 1;
44+
const configColumnIndex = visibleColumnKeys.includes('image') ? getColumnIndex('image') : 2;
45+
const packageColumnIndex = visibleColumnKeys.includes('kind') ? getColumnIndex('kind') : 3;
46+
47+
return (
48+
<Tr isExpanded>
49+
{/* Render cells for each column */}
50+
{Array.from({ length: totalColumns }, (_, index) => {
51+
if (index === storageColumnIndex) {
2052
return (
21-
<Td noPadding colSpan={1} key={colKey}>
53+
<Td key={`storage-${index}`} dataLabel="Storage">
2254
<ExpandableRowContent>
23-
<DataVolumesList workspace={workspace} />
55+
<WorkspaceStorage workspace={workspace} />
2456
</ExpandableRowContent>
2557
</Td>
2658
);
27-
default:
28-
return <Td key={index} />;
29-
}
30-
});
59+
}
3160

32-
return (
33-
<Tr>
34-
<Td />
35-
{renderExpandedData()}
61+
if (index === packageColumnIndex) {
62+
return (
63+
<Td key={`package-${index}`}>
64+
<ExpandableRowContent>
65+
<WorkspacePackageDetails workspace={workspace} />
66+
</ExpandableRowContent>
67+
</Td>
68+
);
69+
}
70+
71+
if (index === configColumnIndex) {
72+
return (
73+
<Td key={`config-${index}`}>
74+
<ExpandableRowContent>
75+
<WorkspaceConfigDetails workspace={workspace} />
76+
</ExpandableRowContent>
77+
</Td>
78+
);
79+
}
80+
81+
// Empty cell for all other columns
82+
return <Td key={`empty-${index}`} />;
83+
})}
3684
</Tr>
3785
);
3886
};
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import * as React from 'react';
2+
import {
3+
DescriptionList,
4+
DescriptionListTerm,
5+
DescriptionListGroup,
6+
DescriptionListDescription,
7+
} from '@patternfly/react-core';
8+
import { Workspace } from '~/shared/api/backendApiTypes';
9+
import { formatResourceFromWorkspace } from '~/shared/utilities/WorkspaceUtils';
10+
11+
interface WorkspaceConfigDetailsProps {
12+
workspace: Workspace;
13+
}
14+
15+
export const WorkspaceConfigDetails: React.FC<WorkspaceConfigDetailsProps> = ({ workspace }) => (
16+
<DescriptionList>
17+
<DescriptionListGroup>
18+
<DescriptionListTerm>Pod config</DescriptionListTerm>
19+
<DescriptionListDescription>
20+
{workspace.podTemplate.options.podConfig.current.displayName}
21+
</DescriptionListDescription>
22+
</DescriptionListGroup>
23+
<DescriptionListGroup>
24+
<DescriptionListTerm>CPU</DescriptionListTerm>
25+
<DescriptionListDescription>
26+
{formatResourceFromWorkspace(workspace, 'cpu')}
27+
</DescriptionListDescription>
28+
</DescriptionListGroup>
29+
<DescriptionListGroup>
30+
<DescriptionListTerm>Memory</DescriptionListTerm>
31+
<DescriptionListDescription>
32+
{formatResourceFromWorkspace(workspace, 'memory')}
33+
</DescriptionListDescription>
34+
</DescriptionListGroup>
35+
</DescriptionList>
36+
);

workspaces/frontend/src/app/pages/Workspaces/WorkspaceConnectAction.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export const WorkspaceConnectAction: React.FunctionComponent<WorkspaceConnectAct
5252
toggle={(toggleRef: React.Ref<MenuToggleElement>) => (
5353
<MenuToggle
5454
ref={toggleRef}
55+
variant="secondary"
5556
onClick={onToggleClick}
5657
isExpanded={open}
5758
isDisabled={workspace.state !== WorkspaceState.WorkspaceStateRunning}
@@ -60,6 +61,7 @@ export const WorkspaceConnectAction: React.FunctionComponent<WorkspaceConnectAct
6061
id="connect-endpoint-button"
6162
key="connect-endpoint-button"
6263
onClick={onClickConnect}
64+
className="connect-button-no-wrap"
6365
>
6466
Connect
6567
</MenuToggleAction>,
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import * as React from 'react';
2+
import {
3+
DescriptionList,
4+
DescriptionListTerm,
5+
DescriptionListDescription,
6+
ListItem,
7+
List,
8+
DescriptionListGroup,
9+
} from '@patternfly/react-core';
10+
import { Workspace } from '~/shared/api/backendApiTypes';
11+
12+
const PACKAGE_LABELS: Record<string, string> = {
13+
jupyterlabVersion: 'JupyterLab',
14+
pythonVersion: 'Python',
15+
// Add more mappings here as needed later
16+
};
17+
18+
interface WorkspacePackageDetailsProps {
19+
workspace: Workspace;
20+
}
21+
22+
export const WorkspacePackageDetails: React.FC<WorkspacePackageDetailsProps> = ({ workspace }) => {
23+
const { labels } = workspace.podTemplate.options.imageConfig.current;
24+
25+
const renderedItems = Object.entries(PACKAGE_LABELS).flatMap(([key, label]) => {
26+
const value = labels.find((l) => l.key === key)?.value;
27+
return value ? <ListItem key={key}>{`${label} v${value}`}</ListItem> : [];
28+
});
29+
30+
return (
31+
<DescriptionList>
32+
<DescriptionListGroup>
33+
<DescriptionListTerm>Packages</DescriptionListTerm>
34+
<DescriptionListDescription>
35+
{renderedItems.length > 0 ? (
36+
<List isPlain>{renderedItems}</List>
37+
) : (
38+
<span>No package information available</span>
39+
)}
40+
</DescriptionListDescription>
41+
</DescriptionListGroup>
42+
</DescriptionList>
43+
);
44+
};
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import * as React from 'react';
2+
import {
3+
DescriptionList,
4+
DescriptionListTerm,
5+
DescriptionListGroup,
6+
DescriptionListDescription,
7+
} from '@patternfly/react-core';
8+
import { Workspace } from '~/shared/api/backendApiTypes';
9+
import { DataVolumesList } from '~/app/pages/Workspaces/DataVolumesList';
10+
11+
interface WorkspaceStorageProps {
12+
workspace: Workspace;
13+
}
14+
15+
export const WorkspaceStorage: React.FC<WorkspaceStorageProps> = ({ workspace }) => (
16+
<DescriptionList>
17+
<DescriptionListGroup>
18+
<DescriptionListTerm>Home volume</DescriptionListTerm>
19+
<DescriptionListDescription>
20+
{workspace.podTemplate.volumes.home?.pvcName ?? 'None'}
21+
</DescriptionListDescription>
22+
</DescriptionListGroup>
23+
<DescriptionListGroup>
24+
<DataVolumesList workspace={workspace} />
25+
</DescriptionListGroup>
26+
</DescriptionList>
27+
);

0 commit comments

Comments
 (0)