Skip to content

Commit

Permalink
Add error state when pipeline version is deleted
Browse files Browse the repository at this point in the history
  • Loading branch information
ppadti committed Jul 3, 2024
1 parent 520c92a commit d7d80cf
Show file tree
Hide file tree
Showing 10 changed files with 142 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,10 @@ class PipelineRunDetails extends RunDetails {
findOutputArtifacts() {
return cy.findByTestId('Output-artifacts');
}

findErrorState(id: string) {
return cy.findByTestId(id);
}
}

export const pipelineDetails = new PipelineDetails();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ import {
buildMockJobKF,
} from '~/__mocks__';
import {
activeRunsTable,
archivedRunsTable,
archiveExperimentModal,
bulkArchiveExperimentModal,
bulkRestoreExperimentModal,
pipelineRunDetails,
pipelineRunJobTable,
pipelineRunsGlobal,
restoreExperimentModal,
Expand All @@ -27,7 +29,7 @@ import {
ProjectModel,
RouteModel,
} from '~/__tests__/cypress/cypress/utils/models';
import { RecurringRunStatus, StorageStateKF } from '~/concepts/pipelines/kfTypes';
import { RecurringRunStatus, RuntimeStateKF, StorageStateKF } from '~/concepts/pipelines/kfTypes';

const projectName = 'test-project-name';
const initialMockPipeline = buildMockPipelineV2({ display_name: 'Test pipeline' });
Expand All @@ -51,6 +53,14 @@ const mockExperiments = [
}),
];

const mockActiveRuns = buildMockRunKF({
display_name: 'Test active run 4',
run_id: 'run-4',
experiment_id: 'test-experiment-1',
created_at: '2024-02-10T00:00:00Z',
state: RuntimeStateKF.SUCCEEDED,
});

describe('Experiments', () => {
describe('Active experiments', () => {
beforeEach(() => {
Expand Down Expand Up @@ -251,6 +261,41 @@ describe('Experiments', () => {
cy.findByLabelText('Experiment').contains(mockExperiment.display_name);
});

it('should display error state when the pipeline version deleted', () => {
cy.interceptOdh(
'GET /api/service/pipelines/:namespace/:serviceName/apis/v2beta1/runs/:runId',
{
path: {
namespace: projectName,
serviceName: 'dspa',
runId: mockActiveRuns.run_id,
},
},
mockActiveRuns,
);
activeRunsTable.getRowByName('Test active run 4').findColumnName('Test active run 4').click();
pipelineRunDetails
.findErrorState('run-graph-error-state')
.should('have.text', 'Pipeline run graph unavailable');

pipelineRunDetails.findDetailsTab().click();
pipelineRunDetails.findDetailItem('Name').findValue().contains(mockActiveRuns.display_name);
pipelineRunDetails
.findDetailItem('Pipeline version')
.findValue()
.contains('No pipeline version');
pipelineRunDetails.findDetailItem('Project').findValue().contains(projectName);
pipelineRunDetails.findDetailItem('Run ID').findValue().contains(mockActiveRuns.run_id);
pipelineRunDetails
.findDetailItem('Workflow name')
.findValue()
.contains(mockActiveRuns.display_name);
pipelineRunDetails.findPipelineSpecTab().click();
pipelineRunDetails
.findErrorState('pipeline-spec-error-state')
.should('have.text', 'Pipeline spec unavailable');
});

it('navigates back to experiments from "Create run" page breadcrumb', () => {
pipelineRunsGlobal.findCreateRunButton().click();
cy.findByLabelText('Breadcrumb').findByText(`Experiments - ${projectName}`).click();
Expand Down Expand Up @@ -370,7 +415,7 @@ const initIntercepts = () => {
{
path: { namespace: projectName, serviceName: 'dspa' },
},
{ runs: [] },
{ runs: [mockActiveRuns] },
);

cy.interceptOdh(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const DashboardCodeEditor: React.FC<Partial<DashboardCodeEditorProps>> = ({
height = 'calc(100% - 38px)',
...props
}) => (
<div data-testid={props.testId} style={{ height }}>
<div data-testid={props.testId} style={{ height, padding: '14px' }}>
<CodeEditor height="100%" className="odh-dashboard__code-editor" {...props} />
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,29 @@ import {
} from '@patternfly/react-core';
import { ExclamationCircleIcon } from '@patternfly/react-icons/dist/esm/icons/exclamation-circle-icon';
import DashboardCodeEditor from '~/concepts/dashboard/codeEditor/DashboardCodeEditor';
import PipelineVersionError from './PipelineVersionError';

type PipelineDetailsYAMLProps = {
filename?: string;
content?: Record<string, unknown> | null;
versionError?: Error;
};

const PipelineDetailsYAML: React.FC<PipelineDetailsYAMLProps> = ({ filename, content }) => {
const PipelineDetailsYAML: React.FC<PipelineDetailsYAMLProps> = ({
versionError,
filename,
content,
}) => {
if (versionError) {
return (
<PipelineVersionError
title="Pipeline spec unavailable"
description="The pipeline version that this pipeline spec belongs to has been deleted."
testId="pipeline-spec-error-state"
/>
);
}

if (!content) {
return (
<EmptyState>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import {
EmptyState,
EmptyStateBody,
EmptyStateHeader,
EmptyStateIcon,
EmptyStateVariant,
PageSection,
} from '@patternfly/react-core';
import { ExclamationTriangleIcon } from '@patternfly/react-icons';
import React from 'react';

type PipelineVersionErrorProps = {
title?: string;
description?: string;
testId?: string;
};

const PipelineVersionError: React.FC<PipelineVersionErrorProps> = ({
title,
description,
testId,
}) => (
<PageSection className="pf-v5-u-h-100">
<EmptyState variant={EmptyStateVariant.lg} isFullHeight>
<EmptyStateHeader
data-testid={testId}
titleText={title}
icon={
<EmptyStateIcon
color="var(--pf-v5-global--warning-color--100)"
icon={ExclamationTriangleIcon}
/>
}
headingLevel="h2"
/>
<EmptyStateBody>{description}</EmptyStateBody>
</EmptyState>
</PageSection>
);

export default PipelineVersionError;
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ const PipelineDetails: PipelineCoreDetailsPageComponent = ({ breadcrumbPath }) =
hidden={PipelineDetailsTab.YAML !== activeTabKey}
className="pf-v5-u-h-100"
>
<TabContentBody hasPadding className="pf-v5-u-h-100">
<TabContentBody className="pf-v5-u-h-100">
<PipelineDetailsYAML
filename={`Pipeline ${
getCorePipelineSpec(pipelineVersion?.pipeline_spec)?.pipelineInfo.name ??
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ const PipelineRunDetails: PipelineCoreDetailsPageComponent = ({ breadcrumbPath,
[selectedId, nodes],
);

const loaded = runLoaded && (versionLoaded || !!run?.pipeline_spec);
const error = versionError || runError;
const loaded = runLoaded && (versionLoaded || !!run?.pipeline_spec || !!versionError);
const error = runError;

if (error) {
return (
Expand Down Expand Up @@ -160,10 +160,12 @@ const PipelineRunDetails: PipelineCoreDetailsPageComponent = ({ breadcrumbPath,
>
<PipelineRunDetailsTabs
run={run}
versionError={versionError}
pipelineSpec={version?.pipeline_spec}
graphContent={
<PipelineTopology
nodes={nodes}
versionError={versionError}
selectedIds={selectedId ? [selectedId] : []}
onSelectionChange={(ids) => {
const firstId = ids[0];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@ interface PipelineRunDetailsTabsProps {
run: PipelineRunKFv2 | PipelineRunJobKFv2 | null;
pipelineSpec: PipelineSpecVariable | undefined;
graphContent: React.ReactNode;
versionError?: Error;
}

export const PipelineRunDetailsTabs: React.FC<PipelineRunDetailsTabsProps> = ({
run,
pipelineSpec,
graphContent,
versionError,
}) => {
const [activeKey, setActiveKey] = React.useState<string | number>(DetailsTabKey.Graph);
const isJob = run && isPipelineRunJob(run);
Expand Down Expand Up @@ -57,7 +59,7 @@ export const PipelineRunDetailsTabs: React.FC<PipelineRunDetailsTabsProps> = ({
</TabContentBody>
</Tab>

{!isJob && pipelineSpec && (
{!isJob && (
<Tab
eventKey={DetailsTabKey.Spec}
tabContentId={DetailsTabKey.Spec}
Expand All @@ -73,6 +75,7 @@ export const PipelineRunDetailsTabs: React.FC<PipelineRunDetailsTabsProps> = ({
id={DetailsTabKey.Graph}
eventKey={DetailsTabKey.Graph}
className="pf-v5-u-h-100"
data-testid="pipeline-graph-tab"
>
<TabContentBody className="pf-v5-u-h-100">{graphContent}</TabContentBody>
</TabContent>
Expand All @@ -83,9 +86,14 @@ export const PipelineRunDetailsTabs: React.FC<PipelineRunDetailsTabsProps> = ({
eventKey={DetailsTabKey.Spec}
hidden={activeKey !== DetailsTabKey.Spec}
style={{ flex: 1 }}
data-testid="pipeline-spec-tab"
>
<TabContentBody className="pf-v5-u-h-100" hasPadding>
<PipelineDetailsYAML filename={run?.display_name} content={pipelineSpec} />
<TabContentBody className="pf-v5-u-h-100">
<PipelineDetailsYAML
filename={run?.display_name}
content={pipelineSpec}
versionError={versionError}
/>
</TabContentBody>
</TabContent>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ const PipelineRunTabDetails: React.FC<PipelineRunTabDetailsProps> = ({ run, work
),
},
]
: versionError
? [{ key: 'Pipeline version', value: 'No pipeline version' }]
: []),
...(pipeline
? [
Expand Down
15 changes: 14 additions & 1 deletion frontend/src/concepts/topology/PipelineTopology.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,23 @@ import {
VisualizationProvider,
} from '@patternfly/react-topology';
import { Bullseye, Spinner } from '@patternfly/react-core';
import PipelineVersionError from '~/concepts/pipelines/content/pipelinesDetails/PipelineVersionError';
import PipelineTopologyEmpty from './PipelineTopologyEmpty';
import useTopologyController from './useTopologyController';
import PipelineVisualizationSurface from './PipelineVisualizationSurface';
import PipelineTopologyEmpty from './PipelineTopologyEmpty';

type PipelineTopologyProps = {
selectedIds?: string[];
onSelectionChange?: (selectionIds: string[]) => void;
nodes: PipelineNodeModel[];
versionError?: Error;
};

const PipelineTopology: React.FC<PipelineTopologyProps> = ({
nodes,
selectedIds,
onSelectionChange,
versionError,
}) => {
const controller = useTopologyController('g1');

Expand All @@ -37,6 +40,16 @@ const PipelineTopology: React.FC<PipelineTopologyProps> = ({
return undefined;
}, [controller, onSelectionChange]);

if (versionError) {
return (
<PipelineVersionError
title="Pipeline run graph unavailable"
description="The pipeline version that this run graph belongs to has been deleted."
testId="run-graph-error-state"
/>
);
}

if (!nodes.length) {
return <PipelineTopologyEmpty />;
}
Expand Down

0 comments on commit d7d80cf

Please sign in to comment.