Skip to content

Commit 5ef2f93

Browse files
authored
feat: workspace list and wizard ui improvements (#973)
Signed-off-by: paulovmr <832830+paulovmr@users.noreply.github.com>
1 parent 635a4c9 commit 5ef2f93

File tree

11 files changed

+89
-124
lines changed

11 files changed

+89
-124
lines changed

workspaces/frontend/src/__tests__/cypress/cypress/pages/workspaces/createWorkspace.ts

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -110,18 +110,7 @@ class CreateWorkspace extends WorkspaceForm {
110110
return this.findClearAllFiltersButton().click();
111111
}
112112

113-
findHomeVolumeToggle(): Cypress.Chainable<JQuery<HTMLElement>> {
114-
return cy.contains('button', 'Home Volume') as unknown as Cypress.Chainable<
115-
JQuery<HTMLElement>
116-
>;
117-
}
118-
119-
expandHomeVolumeSection(): Cypress.Chainable<JQuery<HTMLElement>> {
120-
return this.findHomeVolumeToggle().click();
121-
}
122-
123113
attachHomeVolume(pvcName: string): void {
124-
this.expandHomeVolumeSection();
125114
cy.findByTestId('attach-existing-volume-button').click();
126115
volumesAttachModal.selectPVC(pvcName);
127116
volumesAttachModal.clickAttach();

workspaces/frontend/src/__tests__/cypress/cypress/pages/workspaces/volumesManagement.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
class VolumesManagementPage {
66
// Expandable Section
77
findVolumesSection(): Cypress.Chainable<JQuery<HTMLElement>> {
8-
return cy.contains('button', 'Volumes') as unknown as Cypress.Chainable<JQuery<HTMLElement>>;
8+
return cy.contains('button', 'Data Volumes') as unknown as Cypress.Chainable<
9+
JQuery<HTMLElement>
10+
>;
911
}
1012

1113
expandVolumesSection(): Cypress.Chainable<JQuery<HTMLElement>> {
@@ -14,7 +16,7 @@ class VolumesManagementPage {
1416

1517
// Empty State
1618
findEmptyState(): Cypress.Chainable<JQuery<HTMLElement>> {
17-
return cy.findByTestId('volumes-empty-state');
19+
return cy.findAllByTestId('volumes-empty-state').filter(':visible').last();
1820
}
1921

2022
assertEmptyStateVisible(): Cypress.Chainable<JQuery<HTMLElement>> {
@@ -23,7 +25,7 @@ class VolumesManagementPage {
2325

2426
// Table
2527
findVolumesTable(): Cypress.Chainable<JQuery<HTMLElement>> {
26-
return cy.findByTestId('volumes-table');
28+
return cy.findAllByTestId('volumes-table').filter(':visible').last();
2729
}
2830

2931
findVolumeRow(pvcName: string): Cypress.Chainable<JQuery<HTMLElement>> {
@@ -62,15 +64,15 @@ class VolumesManagementPage {
6264

6365
// Buttons
6466
findAttachExistingPVCButton(): Cypress.Chainable<JQuery<HTMLElement>> {
65-
return cy.findByTestId('attach-existing-volume-button');
67+
return cy.findAllByTestId('attach-existing-volume-button').filter(':visible').last();
6668
}
6769

6870
clickAttachExistingPVC(): Cypress.Chainable<JQuery<HTMLElement>> {
6971
return this.findAttachExistingPVCButton().click();
7072
}
7173

7274
findCreateVolumeButton(): Cypress.Chainable<JQuery<HTMLElement>> {
73-
return cy.findByTestId('attach-new-volume-button');
75+
return cy.findAllByTestId('attach-new-volume-button').filter(':visible').last();
7476
}
7577

7678
clickCreateVolume(): Cypress.Chainable<JQuery<HTMLElement>> {

workspaces/frontend/src/__tests__/cypress/cypress/pages/workspaces/workspaceForm.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,11 +144,19 @@ class WorkspaceForm {
144144
}
145145

146146
assertVolumesCount(count: number): Cypress.Chainable<JQuery<HTMLElement>> {
147-
return cy.findByTestId('volumes-count').should('have.text', `${count} added`);
147+
return cy
148+
.findAllByTestId('volumes-count')
149+
.filter(':visible')
150+
.first()
151+
.should('have.text', `${count} added`);
148152
}
149153

150154
assertSecretsCount(count: number): Cypress.Chainable<JQuery<HTMLElement>> {
151-
return cy.findByTestId('secrets-count').should('have.text', `${count} added`);
155+
return cy
156+
.findAllByTestId('secrets-count')
157+
.filter(':visible')
158+
.first()
159+
.should('have.text', `${count} added`);
152160
}
153161

154162
findSecretsExpandableToggle(): Cypress.Chainable<JQuery<HTMLElement>> {

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

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1217,20 +1217,12 @@ describe('Create workspace', () => {
12171217
it('should display required helper when no home volume is mounted', () => {
12181218
completeAllStepsToProperties(mockWorkspaceKind.name, mockImage.id, mockPodConfig.id);
12191219

1220-
cy.findByTestId('home-volume-status').should('have.text', 'None mounted');
12211220
cy.findByTestId('workspace-home-volume-required-helper').should('be.visible');
12221221
cy.findByTestId('workspace-home-volume-required-helper').should(
12231222
'contain.text',
12241223
'Mounting a home volume is required.',
12251224
);
12261225
});
1227-
1228-
it('should hide the required helper when the Home Volume section is expanded', () => {
1229-
completeAllStepsToProperties(mockWorkspaceKind.name, mockImage.id, mockPodConfig.id);
1230-
1231-
createWorkspace.expandHomeVolumeSection();
1232-
cy.findByTestId('workspace-home-volume-required-helper').should('not.exist');
1233-
});
12341226
});
12351227

12361228
describe('Secret removal flows', () => {
@@ -1278,7 +1270,9 @@ describe('Create workspace', () => {
12781270
// Wait for listSecrets API to complete (component fetches on mount)
12791271
cy.wait('@listSecrets');
12801272

1281-
// Wait for the create button to be visible
1273+
// Scroll to and wait for the create button to be visible
1274+
cy.findByTestId('attach-new-secret-button').should('exist');
1275+
cy.findByTestId('attach-new-secret-button').scrollIntoView();
12821276
cy.findByTestId('attach-new-secret-button').should('be.visible');
12831277

12841278
// Create a new secret
@@ -1336,7 +1330,9 @@ describe('Create workspace', () => {
13361330
// Wait for listSecrets API to complete (component fetches on mount)
13371331
cy.wait('@listSecrets');
13381332

1339-
// Wait for the create button to be visible
1333+
// Scroll to and wait for the create button to be visible
1334+
cy.findByTestId('attach-new-secret-button').should('exist');
1335+
cy.findByTestId('attach-new-secret-button').scrollIntoView();
13401336
cy.findByTestId('attach-new-secret-button').should('be.visible');
13411337

13421338
// Create first secret

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -233,11 +233,11 @@ describe('Filter Images by Labels', () => {
233233
createWorkspace.findImageCard('pytorch-39').should('not.exist');
234234
});
235235

236-
it('should format label keys correctly', () => {
237-
createWorkspace.findLabelCategory('pythonVersion').should('contain', 'Python');
238-
createWorkspace.findLabelCategory('cpu').should('contain', 'CPU');
239-
createWorkspace.findLabelCategory('gpu').should('contain', 'GPU');
240-
createWorkspace.findLabelCategory('framework').should('contain', 'Framework');
236+
it('should display label keys without capitalization', () => {
237+
createWorkspace.findLabelCategory('pythonVersion').should('contain', 'pythonVersion');
238+
createWorkspace.findLabelCategory('cpu').should('contain', 'cpu');
239+
createWorkspace.findLabelCategory('gpu').should('contain', 'gpu');
240+
createWorkspace.findLabelCategory('framework').should('contain', 'framework');
241241
});
242242
});
243243

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -205,10 +205,10 @@ describe('Filter Pod Configs by Labels', () => {
205205
createWorkspace.assertNoResultsFound();
206206
});
207207

208-
it('should format label keys correctly', () => {
209-
createWorkspace.findLabelCategory('cpu').should('contain', 'CPU');
210-
createWorkspace.findLabelCategory('memory').should('contain', 'Memory');
211-
createWorkspace.findLabelCategory('gpu').should('contain', 'GPU');
208+
it('should display label keys without capitalization', () => {
209+
createWorkspace.findLabelCategory('cpu').should('contain', 'cpu');
210+
createWorkspace.findLabelCategory('memory').should('contain', 'memory');
211+
createWorkspace.findLabelCategory('gpu').should('contain', 'gpu');
212212
});
213213
});
214214

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,8 @@ describe('Volumes Management - Attach and Create', () => {
165165
editWorkspace.clickNext(); // Skip image step
166166
editWorkspace.clickNext(); // Skip pod config step, now on properties
167167

168-
// Expand the Volumes section
169-
cy.contains('button', 'Volumes').click();
168+
// Expand the Data Volumes section
169+
cy.contains('button', 'Data Volumes').click();
170170
cy.wait('@listPVCs');
171171
});
172172

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,6 @@ describe('Workspaces', () => {
279279
workspaces.assertExpandedRowExists(mockWorkspace.name);
280280
workspaces.assertExpandedRowContainsText(mockWorkspace.name, 'Home volume');
281281
workspaces.assertExpandedRowContainsText(mockWorkspace.name, 'Packages');
282-
workspaces.assertExpandedRowContainsText(mockWorkspace.name, 'Pod config');
283282
workspaces.assertExpandedRowContainsText(mockWorkspace.name, 'CPU');
284283
workspaces.assertExpandedRowContainsText(mockWorkspace.name, 'Memory');
285284

workspaces/frontend/src/app/pages/Workspaces/Form/properties/WorkspaceFormPropertiesSelection.tsx

Lines changed: 53 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ interface WorkspaceFormPropertiesSelectionProps {
2424
const WorkspaceFormPropertiesSelection: React.FunctionComponent<
2525
WorkspaceFormPropertiesSelectionProps
2626
> = ({ mode, selectedProperties, onSelect, homeVolumeMountPath }) => {
27-
const [isHomeVolumeExpanded, setIsHomeVolumeExpanded] = useState(false);
2827
const [isDataVolumesExpanded, setIsDataVolumesExpanded] = useState(false);
2928
const [isSecretsExpanded, setIsSecretsExpanded] = useState(false);
3029

@@ -50,6 +49,24 @@ const WorkspaceFormPropertiesSelection: React.FunctionComponent<
5049
[selectedProperties, onSelect],
5150
);
5251

52+
const dataVolumesInfo = (
53+
<div className="pf-v6-u-pl-xl pf-v6-u-pt-sm pf-v6-u-pb-sm">
54+
<div>Workspace volumes enable your project data to persist.</div>
55+
<div className="pf-u-font-size-sm">
56+
<strong data-testid="volumes-count">{selectedProperties.volumes.length} added</strong>
57+
</div>
58+
</div>
59+
);
60+
61+
const secretsInfo = (
62+
<div className="pf-v6-u-pl-xl pf-v6-u-pt-sm pf-v6-u-pb-sm">
63+
<div>Secrets enable your project to securely access and manage credentials.</div>
64+
<div className="pf-u-font-size-sm">
65+
<strong data-testid="secrets-count">{selectedProperties.secrets.length} added</strong>
66+
</div>
67+
</div>
68+
);
69+
5370
return (
5471
<Content className="workspace-form__full-height">
5572
<div className="pf-u-p-lg pf-u-max-width-xl">
@@ -81,53 +98,42 @@ const WorkspaceFormPropertiesSelection: React.FunctionComponent<
8198
</HelperTextItem>
8299
</HelperText>
83100
)}
84-
<ExpandableSection
85-
toggleText="Home Volume"
86-
onToggle={() => setIsHomeVolumeExpanded((prev) => !prev)}
87-
isExpanded={isHomeVolumeExpanded}
88-
isIndented
89-
>
90-
{isHomeVolumeExpanded && (
91-
<FormGroup fieldId="home-volume-table" className="workspace-form__form-group--spaced">
92-
<WorkspaceFormPropertiesVolumes
93-
volumes={homeVolumeArray}
94-
setVolumes={handleSetHomeVolume}
95-
fixedMountPath={homeVolumeMountPath}
96-
excludedPvcNames={dataPvcNames}
97-
/>
98-
</FormGroup>
99-
)}
100-
</ExpandableSection>
101-
{!isHomeVolumeExpanded && (
102-
<div className="pf-v6-u-pl-xl pf-v6-u-pt-sm">
101+
<ExpandableSection toggleText="Home Volume" isExpanded isIndented>
102+
<div className="pf-v6-u-pl-xl pf-v6-u-pt-sm pf-v6-u-pb-sm">
103103
<div>The home volume persists your workspace home directory.</div>
104-
<div className="pf-u-font-size-sm pf-v6-u-pb-md">
105-
<strong data-testid="home-volume-status">
106-
{selectedProperties.homeVolume ? '1 mounted' : 'None mounted'}
107-
</strong>
108-
{!selectedProperties.homeVolume && (
109-
<HelperText>
110-
<HelperTextItem
111-
variant="error"
112-
data-testid="workspace-home-volume-required-helper"
113-
className="pf-v6-u-ml-0"
114-
>
115-
<InfoCircleIcon className="pf-v6-u-mr-xs" />
116-
<strong>Mounting a home volume is required.</strong>
117-
</HelperTextItem>
118-
</HelperText>
119-
)}
120-
</div>
121104
</div>
122-
)}
105+
<FormGroup fieldId="home-volume-table" className="workspace-form__form-group--spaced">
106+
<WorkspaceFormPropertiesVolumes
107+
volumes={homeVolumeArray}
108+
setVolumes={handleSetHomeVolume}
109+
fixedMountPath={homeVolumeMountPath}
110+
excludedPvcNames={dataPvcNames}
111+
/>
112+
</FormGroup>
113+
{!selectedProperties.homeVolume && (
114+
<HelperText>
115+
<HelperTextItem
116+
variant="error"
117+
data-testid="workspace-home-volume-required-helper"
118+
className="pf-v6-u-ml-0"
119+
>
120+
<InfoCircleIcon className="pf-v6-u-mr-xs" />
121+
<strong>Mounting a home volume is required.</strong>
122+
</HelperTextItem>
123+
</HelperText>
124+
)}
125+
</ExpandableSection>
123126
<ExpandableSection
124127
toggleText="Data Volumes"
125128
onToggle={() => setIsDataVolumesExpanded((prev) => !prev)}
126129
isExpanded={isDataVolumesExpanded}
127-
isIndented
128130
>
131+
{dataVolumesInfo}
129132
{isDataVolumesExpanded && (
130-
<FormGroup fieldId="volumes-table" className="workspace-form__form-group--spaced">
133+
<FormGroup
134+
fieldId="volumes-table"
135+
className="workspace-form__form-group--spaced pf-v6-u-pl-lg"
136+
>
131137
<WorkspaceFormPropertiesVolumes
132138
volumes={selectedProperties.volumes}
133139
setVolumes={(volumes) => onSelect({ ...selectedProperties, volumes })}
@@ -136,42 +142,27 @@ const WorkspaceFormPropertiesSelection: React.FunctionComponent<
136142
</FormGroup>
137143
)}
138144
</ExpandableSection>
139-
{!isDataVolumesExpanded && (
140-
<div className="pf-v6-u-pl-xl pf-v6-u-pt-sm">
141-
<div>Workspace volumes enable your project data to persist.</div>
142-
<div className="pf-u-font-size-sm pf-v6-u-pb-md">
143-
<strong data-testid="volumes-count">
144-
{selectedProperties.volumes.length} added
145-
</strong>
146-
</div>
147-
</div>
148-
)}
145+
{!isDataVolumesExpanded && dataVolumesInfo}
149146
<ExpandableSection
150147
toggleText="Secrets"
151148
data-testid="secrets-expandable-section"
152149
onToggle={() => setIsSecretsExpanded((prev) => !prev)}
153150
isExpanded={isSecretsExpanded}
154-
isIndented
155151
>
152+
{secretsInfo}
156153
{isSecretsExpanded && (
157-
<FormGroup fieldId="secrets-table" className="workspace-form__form-group--spaced">
154+
<FormGroup
155+
fieldId="secrets-table"
156+
className="workspace-form__form-group--spaced pf-v6-u-pl-lg"
157+
>
158158
<WorkspaceFormPropertiesSecrets
159159
secrets={selectedProperties.secrets}
160160
setSecrets={(secrets) => onSelect({ ...selectedProperties, secrets })}
161161
/>
162162
</FormGroup>
163163
)}
164164
</ExpandableSection>
165-
{!isSecretsExpanded && (
166-
<div className="pf-v6-u-pl-xl pf-v6-u-mt-sm">
167-
<div>Secrets enable your project to securely access and manage credentials.</div>
168-
<div className="pf-u-font-size-sm">
169-
<strong data-testid="secrets-count">
170-
{selectedProperties.secrets.length} added
171-
</strong>
172-
</div>
173-
</div>
174-
)}
165+
{!isSecretsExpanded && secretsInfo}
175166
</Form>
176167
</div>
177168
</Content>

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

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,6 @@ interface WorkspaceConfigDetailsProps {
1414

1515
export const WorkspaceConfigDetails: React.FC<WorkspaceConfigDetailsProps> = ({ workspace }) => (
1616
<DescriptionList>
17-
<DescriptionListGroup>
18-
<DescriptionListTerm>Pod config</DescriptionListTerm>
19-
<DescriptionListDescription>
20-
{workspace.podTemplate.options.podConfig.current.displayName}
21-
</DescriptionListDescription>
22-
</DescriptionListGroup>
2317
<DescriptionListGroup>
2418
<DescriptionListTerm>CPU</DescriptionListTerm>
2519
<DescriptionListDescription>

0 commit comments

Comments
 (0)