Skip to content

Commit

Permalink
Display storage class selecetd in workbenches
Browse files Browse the repository at this point in the history
  • Loading branch information
pnaik1 committed Sep 19, 2024
1 parent b5351a7 commit 2b302b5
Show file tree
Hide file tree
Showing 7 changed files with 243 additions and 27 deletions.
4 changes: 3 additions & 1 deletion frontend/src/__mocks__/mockPVCK8sResource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ type MockResourceConfigType = {
name?: string;
namespace?: string;
storage?: string;
storageClassName?: string;
displayName?: string;
uid?: string;
};
Expand All @@ -13,6 +14,7 @@ export const mockPVCK8sResource = ({
name = 'test-storage',
namespace = 'test-project',
storage = '5Gi',
storageClassName = 'gp3',
displayName = 'Test Storage',
uid = genUID('pvc'),
}: MockResourceConfigType): PersistentVolumeClaimKind => ({
Expand All @@ -38,7 +40,7 @@ export const mockPVCK8sResource = ({
},
},
volumeName: 'pvc-8644e33b-a710-45a3-9d54-7f987494643a',
storageClassName: 'gp3',
storageClassName,
volumeMode: 'Filesystem',
},
status: {
Expand Down
26 changes: 26 additions & 0 deletions frontend/src/__tests__/cypress/cypress/pages/clusterStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,19 @@ class ClusterStorageRow extends TableRow {
this.find().findByRole('button', { name: 'Details' }).click();
}

findDeprecatedLabel() {
return this.find().findByTestId('storage-class-deprecated');
}

shouldHaveDeprecatedTooltip() {
cy.findByTestId('storage-class-deprecated-tooltip').should('be.visible');
return this;
}

findStorageClassColumn() {
return this.find().find('[data-label="Storage class"]');
}

shouldHaveStorageSize(name: string) {
this.find().siblings().find('[data-label=Size]').contains(name).should('exist');
return this;
Expand Down Expand Up @@ -118,6 +131,19 @@ class ClusterStorage {
return this.findClusterStorageTable().find('thead').findByRole('button', { name });
}

shouldHaveDeprecatedAlertMessage() {
return cy
.findByTestId('storage-class-deprecated-alert')
.should(
'contain.text',
'Warning alert:Deprecated storage classA storage class has been deprecated by your administrator, but the cluster storage using it is still active. If you want to migrate your data to cluster storage instance using a different storage class, contact your administrator.',
);
}

closeDeprecatedAlert() {
cy.findByTestId('storage-class-deprecated-alert-close-button').click();
}

getClusterStorageRow(name: string) {
return new ClusterStorageRow(() =>
this.findClusterStorageTable().find(`[data-label=Name]`).contains(name).parents('tr'),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import {
buildMockStorageClass,
mockDashboardConfig,
mockK8sResourceList,
mockNotebookK8sResource,
mockProjectK8sResource,
mockStorageClasses,
mockStorageClassList,
} from '~/__mocks__';

import { mockClusterSettings } from '~/__mocks__/mockClusterSettings';
import { mockPVCK8sResource } from '~/__mocks__/mockPVCK8sResource';
import { mockPodK8sResource } from '~/__mocks__/mockPodK8sResource';
Expand All @@ -27,9 +30,10 @@ import { storageClassesTable } from '~/__tests__/cypress/cypress/pages/storageCl

type HandlersProps = {
isEmpty?: boolean;
storageClassName?: string;
};

const initInterceptors = ({ isEmpty = false }: HandlersProps) => {
const initInterceptors = ({ isEmpty = false, storageClassName }: HandlersProps) => {
cy.interceptOdh('GET /api/cluster-settings', mockClusterSettings({}));
cy.interceptK8sList(PodModel, mockK8sResourceList([mockPodK8sResource({})]));
cy.interceptK8sList(ProjectModel, mockK8sResourceList([mockProjectK8sResource({})]));
Expand All @@ -44,7 +48,7 @@ const initInterceptors = ({ isEmpty = false }: HandlersProps) => {
isEmpty
? []
: [
mockPVCK8sResource({ uid: 'test-id' }),
mockPVCK8sResource({ uid: 'test-id', storageClassName }),
mockPVCK8sResource({ displayName: 'Another Cluster Storage' }),
],
),
Expand All @@ -55,6 +59,43 @@ const initInterceptors = ({ isEmpty = false }: HandlersProps) => {
const [openshiftDefaultStorageClass, otherStorageClass] = mockStorageClasses;

describe('ClusterStorage', () => {
describe('when StorageClasses feature flag is enabled', () => {
beforeEach(() => {
cy.interceptOdh(
'GET /api/config',
mockDashboardConfig({
disableStorageClasses: false,
}),
);

cy.interceptOdh(
'GET /api/k8s/apis/storage.k8s.io/v1/storageclasses',
{},
mockStorageClassList(),
);
});

it('Check whether the Storage class column is present', () => {
initInterceptors({ storageClassName: 'openshift-default-sc' });
clusterStorage.visit('test-project');
const clusterStorageRow = clusterStorage.getClusterStorageRow('Test Storage');
clusterStorageRow.findStorageClassColumn().should('exist');
});

it('Check whether the Storage class is deprecated', () => {
initInterceptors({ storageClassName: 'test-storage-class-1' });
clusterStorage.visit('test-project');

const clusterStorageRow = clusterStorage.getClusterStorageRow('Test Storage');
clusterStorageRow.findDeprecatedLabel().should('exist');

clusterStorageRow.findDeprecatedLabel().trigger('mouseenter');
clusterStorageRow.shouldHaveDeprecatedTooltip();
clusterStorage.shouldHaveDeprecatedAlertMessage();
clusterStorage.closeDeprecatedAlert();
});
});

it('Empty state', () => {
initInterceptors({ isEmpty: true });
clusterStorage.visit('test-project');
Expand Down Expand Up @@ -121,10 +162,17 @@ describe('ClusterStorage', () => {
});
});

it('list accelerator profiles and Table sorting', () => {
it('list cluster storage and Table sorting', () => {
cy.interceptOdh(
'GET /api/config',
mockDashboardConfig({
disableStorageClasses: true,
}),
);
initInterceptors({});
clusterStorage.visit('test-project');
const clusterStorageRow = clusterStorage.getClusterStorageRow('Test Storage');
clusterStorageRow.findStorageClassColumn().should('not.exist');
clusterStorageRow.shouldHaveStorageTypeValue('Persistent storage');
clusterStorageRow.findConnectedWorkbenches().should('have.text', 'No connections');
clusterStorageRow.toggleExpandableContent();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import * as React from 'react';
import { Alert, AlertActionCloseButton } from '@patternfly/react-core';
import { Table } from '~/components/table';
import { PersistentVolumeClaimKind } from '~/k8sTypes';
import DeletePVCModal from '~/pages/projects/pvc/DeletePVCModal';
import { SupportedArea, useIsAreaAvailable } from '~/concepts/areas';
import { getStorageClassConfig } from '~/pages/storageClasses/utils';
import useStorageClasses from '~/concepts/k8s/useStorageClasses';
import StorageTableRow from './StorageTableRow';
import { columns } from './data';
import ManageStorageModal from './ManageStorageModal';
import { StorageTableData } from './types';

type StorageTableProps = {
pvcs: PersistentVolumeClaimKind[];
Expand All @@ -15,20 +20,65 @@ type StorageTableProps = {
const StorageTable: React.FC<StorageTableProps> = ({ pvcs, refresh, onAddPVC }) => {
const [deleteStorage, setDeleteStorage] = React.useState<PersistentVolumeClaimKind | undefined>();
const [editPVC, setEditPVC] = React.useState<PersistentVolumeClaimKind | undefined>();
const isStorageClassesAvailable = useIsAreaAvailable(SupportedArea.STORAGE_CLASSES).status;
const [storageClasses, storageClassesLoaded] = useStorageClasses();
const [alertDismissed, setAlertDismissed] = React.useState<boolean>(false);
const storageTableData: StorageTableData[] = pvcs.map((pvc) => ({
pvc,
storageClass: storageClasses.find((sc) => sc.metadata.name === pvc.spec.storageClassName),
}));
const isDeprecatedAlert = React.useMemo(
() =>
storageClassesLoaded &&
storageTableData.some(
(data) => !data.storageClass || !getStorageClassConfig(data.storageClass)?.isEnabled,
),
[storageClassesLoaded, storageTableData],
);
const shouldShowAlert = isDeprecatedAlert && !alertDismissed && isStorageClassesAvailable;

const getStorageColumns = () => {
let storageColumns = columns;

if (!isStorageClassesAvailable) {
storageColumns = columns.filter((column) => column.field !== 'storage');
}
return storageColumns;
};

return (
<>
{shouldShowAlert && (
<Alert
data-testid="storage-class-deprecated-alert"
variant="warning"
isInline
title="Deprecated storage class"
actionClose={
<AlertActionCloseButton
data-testid="storage-class-deprecated-alert-close-button"
onClose={() => setAlertDismissed(true)}
/>
}
>
A storage class has been deprecated by your administrator, but the cluster storage using
it is still active. If you want to migrate your data to cluster storage instance using a
different storage class, contact your administrator.
</Alert>
)}
<Table
data={pvcs}
columns={columns}
data={storageTableData}
columns={getStorageColumns()}
disableRowRenderSupport
data-testid="storage-table"
variant="compact"
rowRenderer={(pvc, i) => (
rowRenderer={(data, i) => (
<StorageTableRow
key={pvc.metadata.uid}
key={data.pvc.metadata.uid}
rowIndex={i}
obj={pvc}
storageClass={data.storageClass}
storageClassesLoaded={storageClassesLoaded}
pvc={data.pvc}
onEditPVC={setEditPVC}
onDeletePVC={setDeleteStorage}
onAddPVC={onAddPVC}
Expand Down
Loading

0 comments on commit 2b302b5

Please sign in to comment.