Skip to content

Commit

Permalink
Update error pages for PipelineRun, TaskRun, and Run resources
Browse files Browse the repository at this point in the history
Use the `NotFound` page when there's an error loading a run resource
instead of the current `InlineNotification`. Update the suggested
links to point at related list pages filtered by the currently
selected namespace.
  • Loading branch information
AlanGreene authored and tekton-robot committed Sep 19, 2022
1 parent aa24daf commit 836e6ad
Show file tree
Hide file tree
Showing 16 changed files with 122 additions and 90 deletions.
52 changes: 40 additions & 12 deletions src/containers/NotFound/NotFound.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,18 @@ import { injectIntl } from 'react-intl';
import { Link } from 'react-router-dom';
import { Column, Grid, Row } from 'carbon-components-react';
import { Link as CustomLink } from '@tektoncd/dashboard-components';
import { urls } from '@tektoncd/dashboard-utils';
import { ALL_NAMESPACES, urls } from '@tektoncd/dashboard-utils';

import { useSelectedNamespace } from '../../api';
import robocat from '../../images/robocat_404.svg';

const smallConfig = { offset: 1, span: 2 };
const mediumConfig = { offset: 2, span: 4 };
const largeConfig = { offset: 5, span: 6 };

function NotFound({ intl }) {
function NotFound({ intl, suggestions = [] }) {
const { selectedNamespace: namespace } = useSelectedNamespace();

return (
<Grid className="tkn--not-found">
<Row narrow>
Expand Down Expand Up @@ -61,6 +64,13 @@ function NotFound({ intl }) {
</p>

<ul>
{suggestions.map(({ text, to }) => (
<li key={text}>
<Link component={CustomLink} to={to}>
{text}
</Link>
</li>
))}
<li>
<Link component={CustomLink} to="/">
{intl.formatMessage({
Expand All @@ -69,16 +79,34 @@ function NotFound({ intl }) {
})}
</Link>
</li>
<li>
<Link component={CustomLink} to={urls.pipelineRuns.all()}>
PipelineRuns
</Link>
</li>
<li>
<Link component={CustomLink} to={urls.taskRuns.all()}>
TaskRuns
</Link>
</li>
{suggestions.length === 0 ? (
<>
<li>
<Link
component={CustomLink}
to={
namespace !== ALL_NAMESPACES
? urls.pipelineRuns.byNamespace({ namespace })
: urls.pipelineRuns.all()
}
>
PipelineRuns
</Link>
</li>
<li>
<Link
component={CustomLink}
to={
namespace !== ALL_NAMESPACES
? urls.taskRuns.byNamespace({ namespace })
: urls.taskRuns.all()
}
>
TaskRuns
</Link>
</li>
</>
) : null}
</ul>
</Column>
</Row>
Expand Down
20 changes: 18 additions & 2 deletions src/containers/NotFound/NotFound.stories.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright 2021 The Tekton Authors
Copyright 2021-2022 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Expand All @@ -13,18 +13,34 @@ limitations under the License.

import React from 'react';

import { NamespaceContext } from '../../api';
import NotFound from './NotFound';

const namespaceContext = {
selectedNamespace: 'default'
};

export default {
component: NotFound,
decorators: [
Story => (
<div style={{ height: '100vh' }}>
<Story />
<NamespaceContext.Provider value={namespaceContext}>
<Story />
</NamespaceContext.Provider>
</div>
)
],
title: 'Containers/NotFound'
};

export const Base = () => <NotFound />;

export const CustomSuggestions = () => (
<NotFound
suggestions={[
{ text: 'CustomResources', to: '/customresources' },
{ text: 'Another link', to: '/somewhereelse' }
]}
/>
);
30 changes: 22 additions & 8 deletions src/containers/PipelineRun/PipelineRun.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@ import {
useTaskRuns,
useTasks
} from '../../api';

import {
getLogsRetriever,
getLogsToolbar,
getViewChangeHandler
} from '../../utils';
import { NotFound } from '..';

const { PIPELINE_TASK, RETRY, STEP, VIEW } = queryParamConstants;

Expand Down Expand Up @@ -474,6 +474,26 @@ export /* istanbul ignore next */ function PipelineRunContainer({ intl }) {
{ enabled: !!podName && view === 'pod' }
);

const isLoading =
isLoadingPipelineRun ||
isLoadingTaskRuns ||
isLoadingTasks ||
isLoadingClusterTasks ||
isLoadingPipeline;

if (!isLoading && (pipelineRunError || !pipelineRun)) {
return (
<NotFound
suggestions={[
{
text: 'PipelineRuns',
to: urls.pipelineRuns.byNamespace({ namespace })
}
]}
/>
);
}

let podDetails;
if (!currentSelectedStepId) {
podDetails = (events || pod) && { events, resource: pod };
Expand Down Expand Up @@ -517,13 +537,7 @@ export /* istanbul ignore next */ function PipelineRunContainer({ intl }) {
onFallback: setIsUsingExternalLogs
})}
handleTaskSelected={handleTaskSelected}
loading={
isLoadingPipelineRun ||
isLoadingTaskRuns ||
isLoadingTasks ||
isLoadingClusterTasks ||
isLoadingPipeline
}
loading={isLoading}
getLogsToolbar={toolbarParams =>
getLogsToolbar({
...toolbarParams,
Expand Down
21 changes: 16 additions & 5 deletions src/containers/PipelineRun/PipelineRun.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright 2019-2021 The Tekton Authors
Copyright 2019-2022 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Expand All @@ -14,6 +14,7 @@ limitations under the License.
import React from 'react';
import { waitFor } from '@testing-library/react';
import { createIntl } from 'react-intl';
import { paths, urls } from '@tektoncd/dashboard-utils';

import { renderWithRouter } from '../../utils/test';
import * as PipelineRunsAPI from '../../api/pipelineRuns';
Expand Down Expand Up @@ -51,19 +52,29 @@ it('PipelineRunContainer renders data', async () => {
});

it('PipelineRunContainer renders not found state', async () => {
const namespace = 'fake_namespace';
const pipelineRunName = 'fake_pipelineRunName';
jest
.spyOn(PipelineRunsAPI, 'usePipelineRun')
.mockImplementation(() => ({ data: null, error: null }));

const { getByText } = renderWithRouter(<PipelineRunContainer intl={intl} />);
await waitFor(() => getByText(`PipelineRun not found`));
const { getByText } = renderWithRouter(<PipelineRunContainer intl={intl} />, {
path: paths.pipelineRuns.byName(),
route: urls.pipelineRuns.byName({ pipelineRunName, namespace })
});
await waitFor(() => getByText(/Page not found/));
});

it('PipelineRunContainer renders error state', async () => {
const namespace = 'fake_namespace';
const pipelineRunName = 'fake_pipelineRunName';
jest
.spyOn(PipelineRunsAPI, 'usePipelineRun')
.mockImplementation(() => ({ data: null, error: 'some error' }));

const { getByText } = renderWithRouter(<PipelineRunContainer intl={intl} />);
await waitFor(() => getByText('Error loading PipelineRun'));
const { getByText } = renderWithRouter(<PipelineRunContainer intl={intl} />, {
path: paths.pipelineRuns.byName(),
route: urls.pipelineRuns.byName({ pipelineRunName, namespace })
});
await waitFor(() => getByText(/Page not found/));
});
14 changes: 14 additions & 0 deletions src/containers/Run/Run.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { InlineNotification } from 'carbon-components-react';

import { deleteRun, rerunRun, useIsReadOnly, useRun } from '../../api';
import { getViewChangeHandler } from '../../utils';
import { NotFound } from '..';

function getRunDuration(run) {
if (!run) {
Expand Down Expand Up @@ -242,6 +243,19 @@ function Run({ intl }) {
];
}

if (!isFetching && (error || !run)) {
return (
<NotFound
suggestions={[
{
text: 'Runs',
to: urls.runs.byNamespace({ namespace })
}
]}
/>
);
}

return (
<>
{showNotification && (
Expand Down
55 changes: 12 additions & 43 deletions src/containers/TaskRun/TaskRun.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ import {
getLogsToolbar,
getViewChangeHandler
} from '../../utils';

import {
cancelTaskRun,
deleteTaskRun,
Expand All @@ -54,31 +53,10 @@ import {
useTaskByKind,
useTaskRun
} from '../../api';
import { NotFound } from '..';

const { STEP, TASK_RUN_DETAILS, VIEW } = queryParamConstants;

function notification({ intl, kind, message }) {
const titles = {
info: intl.formatMessage({
id: 'dashboard.taskRun.unavailable',
defaultMessage: 'TaskRun not available'
}),
error: intl.formatMessage({
id: 'dashboard.taskRun.errorLoading',
defaultMessage: 'Error loading TaskRun'
})
};
return (
<InlineNotification
kind={kind}
hideCloseButton
lowContrast
title={titles[kind]}
subtitle={message}
/>
);
}

export function TaskRunContainer({ intl }) {
const history = useHistory();
const location = useLocation();
Expand Down Expand Up @@ -358,26 +336,17 @@ export function TaskRunContainer({ intl }) {
return <SkeletonText heading width="60%" />;
}

if (error) {
return notification({
intl,
kind: 'error',
message: intl.formatMessage({
id: 'dashboard.taskRun.errorLoading',
defaultMessage: 'Error loading TaskRun'
})
});
}

if (!taskRun) {
return notification({
intl,
kind: 'info',
message: intl.formatMessage({
id: 'dashboard.taskRun.unavailable',
defaultMessage: 'TaskRun not available'
})
});
if (error || !taskRun) {
return (
<NotFound
suggestions={[
{
text: 'TaskRuns',
to: urls.taskRuns.byNamespace({ namespace })
}
]}
/>
);
}

const definition = getStepDefinition({
Expand Down
2 changes: 0 additions & 2 deletions src/nls/messages_de.json
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,6 @@
"dashboard.tableHeader.task": "",
"dashboard.tableHeader.type": "",
"dashboard.tableHeader.value": "",
"dashboard.taskRun.errorLoading": "",
"dashboard.taskRun.logs": "Protokolle",
"dashboard.taskRun.params": "",
"dashboard.taskRun.resources": "",
Expand All @@ -260,7 +259,6 @@
"dashboard.taskRun.status.succeeded": "Abgeschlossen",
"dashboard.taskRun.status.succeeded.warning": "",
"dashboard.taskRun.status.waiting": "Wartestatus",
"dashboard.taskRun.unavailable": "",
"dashboard.taskRunParams.name": "",
"dashboard.taskRunParams.value": "",
"dashboard.taskRuns.errorLoading": "",
Expand Down
2 changes: 0 additions & 2 deletions src/nls/messages_en.json
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,6 @@
"dashboard.tableHeader.task": "Task",
"dashboard.tableHeader.type": "Type",
"dashboard.tableHeader.value": "Value",
"dashboard.taskRun.errorLoading": "Error loading TaskRun",
"dashboard.taskRun.logs": "Logs",
"dashboard.taskRun.params": "Parameters",
"dashboard.taskRun.resources": "Resources",
Expand All @@ -260,7 +259,6 @@
"dashboard.taskRun.status.succeeded": "Completed",
"dashboard.taskRun.status.succeeded.warning": "Completed with exit code {exitCode}",
"dashboard.taskRun.status.waiting": "Waiting",
"dashboard.taskRun.unavailable": "TaskRun not available",
"dashboard.taskRunParams.name": "Name",
"dashboard.taskRunParams.value": "Value",
"dashboard.taskRuns.errorLoading": "Error loading TaskRuns",
Expand Down
2 changes: 0 additions & 2 deletions src/nls/messages_es.json
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,6 @@
"dashboard.tableHeader.task": "",
"dashboard.tableHeader.type": "",
"dashboard.tableHeader.value": "",
"dashboard.taskRun.errorLoading": "",
"dashboard.taskRun.logs": "Anotaciones",
"dashboard.taskRun.params": "",
"dashboard.taskRun.resources": "",
Expand All @@ -260,7 +259,6 @@
"dashboard.taskRun.status.succeeded": "Completado",
"dashboard.taskRun.status.succeeded.warning": "",
"dashboard.taskRun.status.waiting": "En espera",
"dashboard.taskRun.unavailable": "",
"dashboard.taskRunParams.name": "",
"dashboard.taskRunParams.value": "",
"dashboard.taskRuns.errorLoading": "",
Expand Down
2 changes: 0 additions & 2 deletions src/nls/messages_fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,6 @@
"dashboard.tableHeader.task": "",
"dashboard.tableHeader.type": "",
"dashboard.tableHeader.value": "",
"dashboard.taskRun.errorLoading": "",
"dashboard.taskRun.logs": "Journaux",
"dashboard.taskRun.params": "",
"dashboard.taskRun.resources": "",
Expand All @@ -260,7 +259,6 @@
"dashboard.taskRun.status.succeeded": "Terminé",
"dashboard.taskRun.status.succeeded.warning": "",
"dashboard.taskRun.status.waiting": "En attente",
"dashboard.taskRun.unavailable": "",
"dashboard.taskRunParams.name": "",
"dashboard.taskRunParams.value": "",
"dashboard.taskRuns.errorLoading": "",
Expand Down
Loading

0 comments on commit 836e6ad

Please sign in to comment.