Skip to content

Commit

Permalink
Handled deleted resources
Browse files Browse the repository at this point in the history
  • Loading branch information
lokanandaprabhu committed Aug 7, 2024
1 parent cce473c commit 5309cd7
Show file tree
Hide file tree
Showing 6 changed files with 311 additions and 5 deletions.
2 changes: 2 additions & 0 deletions locales/en/plugin__pipelines-console-plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@
"Output": "Output",
"Overview": "Overview",
"Owner": "Owner",
"Page Not Found (404)": "Page Not Found (404)",
"Parameters": "Parameters",
"Partially approved": "Partially approved",
"Password": "Password",
Expand Down Expand Up @@ -304,6 +305,7 @@
"Rerun": "Rerun",
"Reset": "Reset",
"Resource is being fetched from Tekton Results.": "Resource is being fetched from Tekton Results.",
"Resource is deleted.": "Resource is deleted.",
"Route": "Route",
"Routes": "Routes",
"run{{plural}} in other namespaces.": "run{{plural}} in other namespaces.",
Expand Down
25 changes: 25 additions & 0 deletions src/components/common/error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import * as React from 'react';
import { Helmet } from 'react-helmet';
import { useTranslation } from 'react-i18next';
import {
EmptyState,
EmptyStateHeader,
EmptyStateVariant,
} from '@patternfly/react-core';

export const ErrorPage404: React.FC = () => {
const { t } = useTranslation('plugin__pipelines-console-plugin');
return (
<div>
<Helmet>
<title>{t('Page Not Found (404)')}</title>
</Helmet>
<EmptyState variant={EmptyStateVariant.lg}>
<EmptyStateHeader
titleText={t('Page Not Found (404)')}
headingLevel="h4"
/>
</EmptyState>
</div>
);
};
5 changes: 3 additions & 2 deletions src/components/pipelines-details/PipelineDetailsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,15 @@ import { triggerPipeline } from '../pipelines-list/PipelineKebab';
import { StartedByAnnotation } from '../../consts';
import { usePipelineTriggerTemplateNames } from '../utils/triggers';
import { resourcePathFromModel } from '../utils/utils';
import { ErrorPage404 } from '../common/error';

const PipelineDetailsPage = () => {
const { t } = useTranslation('plugin__pipelines-console-plugin');
const params = useParams();
const history = useHistory();
const navigate = useNavigate();
const { name, ns: namespace } = params;
const [pipeline, loaded] = useK8sWatchResource<PipelineKind>({
const [pipeline, loaded, loadError] = useK8sWatchResource<PipelineKind>({
groupVersionKind: getGroupVersionKindForModel(PipelineModel),
namespace,
name,
Expand Down Expand Up @@ -125,7 +126,7 @@ const PipelineDetailsPage = () => {
};

if (!loaded) {
return <LoadingBox />;
return loadError ? <ErrorPage404 /> : <LoadingBox />;
}
return (
<DetailsPage
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import * as React from 'react';
import { useTranslation } from 'react-i18next';
import { EmptyState, EmptyStateVariant } from '@patternfly/react-core';
import { sortable } from '@patternfly/react-table';
import {
TableColumn,
VirtualizedTable,
useActiveColumns,
} from '@openshift-console/dynamic-plugin-sdk';
import {
SummaryProps,
sortByNumbers,
sortByProperty,
sortByTimestamp,
sortTimeStrings,
listPageTableColumnClasses as tableColumnClasses,
} from '../utils';
import PipelineRunsForPipelinesRowK8s from './PipelineRunsForPipelinesRowK8s';
import { Project } from '../../../types';

type PipelineRunsForPipelinesListProps = {
summaryData: SummaryProps[];
summaryDataFiltered?: SummaryProps[];
loaded: boolean;
hideLastRunTime?: boolean;
projects?: Project[];
projectsLoaded?: boolean;
};

const PipelineRunsForPipelinesListK8s: React.FC<
PipelineRunsForPipelinesListProps
> = ({
summaryData,
summaryDataFiltered,
loaded,
hideLastRunTime,
projects,
projectsLoaded,
}) => {
const { t } = useTranslation('plugin__pipelines-console-plugin');
const EmptyMsg = () => (
<EmptyState variant={EmptyStateVariant.lg}>
{t('No PipelineRuns found')}
</EmptyState>
);

const plrColumns = React.useMemo<TableColumn<SummaryProps>[]>(() => {
const columns: TableColumn<SummaryProps>[] = [
{
id: 'pipelineName',
title: t('Pipeline'),
sort: (summary, direction: 'asc' | 'desc') =>
sortByProperty(summary, 'pipelineName', direction),
transforms: [sortable],
props: { className: tableColumnClasses[0] },
},
{
id: 'namespace',
title: t('Project'),
sort: (summary, direction: 'asc' | 'desc') =>
sortByProperty(summary, 'namespace', direction),
transforms: [sortable],
props: { className: tableColumnClasses[1] },
},
{
id: 'total',
title: t('Total Pipelineruns'),
sort: 'total',
transforms: [sortable],
props: { className: tableColumnClasses[2] },
},
{
id: 'totalDuration',
title: t('Total duration'),
sort: (summary, direction: 'asc' | 'desc') =>
sortTimeStrings(summary, 'total_duration', direction),
transforms: [sortable],
props: { className: tableColumnClasses[3] },
},
{
id: 'avgDuration',
title: t('Average duration'),
sort: (summary, direction: 'asc' | 'desc') =>
sortTimeStrings(summary, 'avg_duration', direction),
transforms: [sortable],
props: {
className: tableColumnClasses[4],
info: {
tooltip: t(
'An average of the time taken to run PipelineRuns. The trending shown is based on the time range selected. This metric does not show runs that are running or pending.',
),
className: 'pipeline-overview__for-pipelines-list__tooltip',
},
},
},
{
id: 'successRate',
title: t('Success rate'),
sort: (summary, direction: 'asc' | 'desc') =>
sortByNumbers(summary, 'succeeded', direction),
transforms: [sortable],
props: {
className: tableColumnClasses[5],
info: {
tooltip: t(
'Success rate measure the % of successfully completed pipeline runs in relation to the total number of pipeline runs',
),
className: 'pipeline-overview__for-pipelines-list__tooltip',
},
},
},
];
if (!hideLastRunTime) {
columns.push({
id: 'lastRunTime',
title: t('Last run time'),
sort: (summary, direction: 'asc' | 'desc') =>
sortByTimestamp(summary, 'last_runtime', direction),
transforms: [sortable],
props: { className: tableColumnClasses[6] },
});
}

return columns;
}, [t, hideLastRunTime]);

const [columns] = useActiveColumns({
columns: plrColumns,
showNamespaceOverride: false,
columnManagementID: '',
});

return (
<VirtualizedTable
columns={columns}
Row={PipelineRunsForPipelinesRowK8s}
data={summaryDataFiltered || summaryData}
loaded={loaded}
loadError={false}
unfilteredData={summaryData}
EmptyMsg={EmptyMsg}
rowData={{ hideLastRunTime, projects, projectsLoaded }}
/>
);
};

export default PipelineRunsForPipelinesListK8s;
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import * as React from 'react';
import { Link } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { Tooltip } from '@patternfly/react-core';
import {
SummaryProps,
getReferenceForModel,
listPageTableColumnClasses as tableColumnClasses,
} from '../utils';
import {
ResourceIcon,
ResourceLink,
RowProps,
getGroupVersionKindForModel,
useActiveNamespace,
} from '@openshift-console/dynamic-plugin-sdk';
import { formatTime, formatTimeLastRunTime } from '../dateTime';
import { ALL_NAMESPACES_KEY } from '../../../consts';
import {
PipelineModel,
PipelineModelV1Beta1,
ProjectModel,
} from '../../../models';
import { Project } from '../../../types';

const PipelineRunsForPipelinesRowK8s: React.FC<
RowProps<
SummaryProps,
{
hideLastRunTime?: boolean;
projects: Project[];
projectsLoaded: boolean;
}
>
> = ({ obj, rowData: { hideLastRunTime, projects, projectsLoaded } }) => {
const { t } = useTranslation('plugin__pipelines-console-plugin');
const [activeNamespace] = useActiveNamespace();
const [namespace, name] = obj.group_value.split('/');
const clusterVersion = (window as any).SERVER_FLAGS?.releaseVersion;
const isV1SupportCluster =
clusterVersion?.split('.')[0] === '4' &&
clusterVersion?.split('.')[1] > '13';
const pipelineReference = getReferenceForModel(
isV1SupportCluster ? PipelineModel : PipelineModelV1Beta1,
);
const projectReference = getReferenceForModel(ProjectModel);

const isNamespaceExists = (namespaceName: string) => {
if (!projectsLoaded) {
return false;
}
return projects.some(
(project) =>
project?.metadata && project?.metadata?.name === namespaceName,
);
};

return (
<>
<td className={tableColumnClasses[0]}>
{isNamespaceExists(namespace) ? (
<ResourceLink
groupVersionKind={
isV1SupportCluster
? getGroupVersionKindForModel(PipelineModel)
: getGroupVersionKindForModel(PipelineModelV1Beta1)
}
name={name}
namespace={namespace}
/>
) : (
<Tooltip content={t('Resource is deleted.')}>
<span>
<ResourceIcon kind={pipelineReference} />
{name}
</span>
</Tooltip>
)}
</td>
{activeNamespace === ALL_NAMESPACES_KEY && (
<td className={tableColumnClasses[1]}>
{isNamespaceExists(namespace) ? (
<ResourceLink kind="Namespace" name={namespace} />
) : (
<Tooltip content={t('Resource is deleted.')}>
<span>
<ResourceIcon kind={projectReference} />
{namespace}
</span>
</Tooltip>
)}
</td>
)}
<td className={tableColumnClasses[2]}>
{isNamespaceExists(namespace) ? (
<Link to={`/k8s/ns/${namespace}/${pipelineReference}/${name}/Runs`}>
{obj.total}
</Link>
) : (
<span>{obj.total}</span>
)}
</td>
<td className={tableColumnClasses[3]}>
{formatTime(obj.total_duration)}
</td>
<td className={tableColumnClasses[4]}>{formatTime(obj.avg_duration)}</td>
<td className={tableColumnClasses[5]}>{`${Math.round(
(100 * obj.succeeded) / obj.total,
)}%`}</td>
{!hideLastRunTime && (
<td className={tableColumnClasses[6]}>{`${formatTimeLastRunTime(
obj.last_runtime,
)}`}</td>
)}
</>
);
};

export default PipelineRunsForPipelinesRowK8s;
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import * as React from 'react';
import * as classNames from 'classnames';
import { Card, CardBody, Grid, GridItem } from '@patternfly/react-core';
import { PrometheusResponse } from '@openshift-console/dynamic-plugin-sdk';
import {
PrometheusResponse,
useK8sWatchResource,
} from '@openshift-console/dynamic-plugin-sdk';
import PipelineRunsForRepositoriesList from './PipelineRunsForRepositoriesList';
import PipelineRunsForPipelinesList from './PipelineRunsForPipelinesList';
import PipelineRunsForPipelinesListK8s from './PipelineRunsForPipelinesListK8s';
import SearchInputField from '../SearchInput';
import { isMatchingFirstTickValue, useQueryParams } from '../utils';
import { ALL_NAMESPACES_KEY } from '../../../consts';
Expand All @@ -16,6 +19,7 @@ import {
PipelineQuery,
} from '../../pipelines-metrics/utils';
import { getXaxisValues, secondsToHms } from '../dateTime';
import { Project } from '../../../types';

type PipelineRunsListPageProps = {
bordered?: boolean;
Expand Down Expand Up @@ -122,6 +126,11 @@ const PipelineRunsListPageK8s: React.FC<PipelineRunsListPageProps> = ({
const [searchText, setSearchText] = React.useState('');
const [tickValues, type] = getXaxisValues(timespan);

const [projects, projectsLoaded] = useK8sWatchResource<Project[]>({
isList: true,
kind: 'Project',
optional: true,
});
const [pipelineRunsMetricsCountData] =
namespace == ALL_NAMESPACES_KEY
? usePipelineMetricsForAllNamespacePoll({
Expand Down Expand Up @@ -240,11 +249,13 @@ const PipelineRunsListPageK8s: React.FC<PipelineRunsListPageProps> = ({
<Grid hasGutter>
<GridItem span={12}>
{pageFlag === 1 ? (
<PipelineRunsForPipelinesList
<PipelineRunsForPipelinesListK8s
summaryData={summaryDataK8s}
summaryDataFiltered={summaryDataFiltered}
loaded={true}
hideLastRunTime={true}
projects={projects}
projectsLoaded={projectsLoaded}
/>
) : (
<PipelineRunsForRepositoriesList
Expand Down

0 comments on commit 5309cd7

Please sign in to comment.