Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Workflow page error message #670

Original file line number Diff line number Diff line change
@@ -1,18 +1,4 @@
'use client';
import ErrorPanel from '@/components/error-panel/error-panel';
import WorkflowPageTabsError from '@/views/workflow-page/workflow-page-tabs-error/workflow-page-tabs-error';

export default function WorkflowTabsError({
error,
reset,
}: Readonly<{
error: Error;
reset: () => void;
}>) {
return (
<ErrorPanel
error={error}
message="Failed to load workflow content"
reset={reset}
/>
);
}
export default WorkflowPageTabsError;
20 changes: 11 additions & 9 deletions src/utils/logger/pino/pino.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,19 @@ const LOGGER_CONFIG: LoggerOptions<CustomLevels> = {
// customLevels: {
// silly: 5,
// },
browser: {
transmit: {
level: 'warn',
send: (level, logEvent) => {
navigator.sendBeacon(
'/api/log',
JSON.stringify(getLogBody(level, logEvent))
);
...(!isDevelopment && {
browser: {
transmit: {
level: 'warn',
send: (level, logEvent) => {
navigator.sendBeacon(
'/api/log',
JSON.stringify(getLogBody(level, logEvent))
);
},
},
},
},
}),
};

export default LOGGER_CONFIG;
13 changes: 13 additions & 0 deletions src/views/workflow-page/config/workflow-page-tabs-error.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import getWorkflowPageErrorConfig from '../helpers/get-workflow-page-error-config';
import { type WorkflowPageTabsErrorConfig } from '../workflow-page-tabs-error/workflow-page-tabs-error.types';

const workflowPageTabsErrorConfig: WorkflowPageTabsErrorConfig = {
summary: (err) =>
getWorkflowPageErrorConfig(err, 'Failed to load workflow summary'),
history: (err) =>
getWorkflowPageErrorConfig(err, 'Failed to load workflow history'),
queries: (err) =>
getWorkflowPageErrorConfig(err, 'Failed to load workflow queries'),
} as const;

export default workflowPageTabsErrorConfig;
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { RequestError } from '@/utils/request/request-error';

import getWorkflowPageErrorConfig from '../get-workflow-page-error-config';

describe('getWorkflowPageErrorConfig', () => {
it('returns default error config for regular error', () => {
expect(
getWorkflowPageErrorConfig(new Error('Test error'), 'default error')
).toEqual({
message: 'default error',
actions: [{ kind: 'retry', label: 'Retry' }],
});
});

it('returns "Workflow not found" error config when request errors with 404', () => {
expect(
getWorkflowPageErrorConfig(new RequestError('test error', 404))
).toEqual({
message: 'Workflow not found',
omitLogging: true,
actions: [{ kind: 'retry', label: 'Retry' }],
});
});
});
20 changes: 20 additions & 0 deletions src/views/workflow-page/helpers/get-workflow-page-error-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { RequestError } from '@/utils/request/request-error';
import { type DomainPageTabErrorConfig } from '@/views/domain-page/domain-page-tabs-error/domain-page-tabs-error.types';

export default function getWorkflowPageErrorConfig(
err: Error,
defaultErrorMessage: string = 'Failed to load workflow'
): DomainPageTabErrorConfig {
if (err instanceof RequestError && err.status === 404) {
return {
message: 'Workflow not found',
actions: [{ kind: 'retry', label: 'Retry' }],
omitLogging: true,
};
}

return {
message: defaultErrorMessage,
actions: [{ kind: 'retry', label: 'Retry' }],
};
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
'use client';
import React, { Suspense } from 'react';
import React from 'react';

import { Breadcrumbs } from 'baseui/breadcrumbs';
import { StyledLink } from 'baseui/link';
import Image from 'next/image';
import Link from 'next/link';

import cadenceLogoBlack from '@/assets/cadence-logo-black.svg';
import ErrorBoundary from '@/components/error-boundary/error-boundary';
import PageSection from '@/components/page-section/page-section';
import useStyletronClasses from '@/hooks/use-styletron-classes';

Expand Down Expand Up @@ -48,9 +49,9 @@ export default function WorkflowPageHeader({
</StyledLink>
<div className={cls.breadcrumbItemContainer}>
{runId}
<Suspense>
<ErrorBoundary fallbackRender={() => null} omitLogging={true}>
<WorkflowPageStatusTag />
</Suspense>
</ErrorBoundary>
</div>
</Breadcrumbs>
</PageSection>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import type workflowPageTabsConfig from '../config/workflow-page-tabs.config';
import type { WorkflowPageTabsParams } from '../workflow-page-tabs/workflow-page-tabs.types';

export type WorkflowPageTabName =
(typeof workflowPageTabsConfig)[number]['key'];

export type WorkflowPageTabsContentsMap = {
[k in (typeof workflowPageTabsConfig)[number]['key']]:
| React.ComponentType<WorkflowPageTabContentProps>
Expand All @@ -12,7 +15,7 @@ export type WorkflowPageTabContentParams = {
cluster: string;
workflowId: string;
runId: string;
workflowTab: (typeof workflowPageTabsConfig)[number]['key'];
workflowTab: WorkflowPageTabName;
};

export type WorkflowPageTabContentProps = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import React from 'react';

import * as navigationModule from 'next/navigation';

import { render, screen } from '@/test-utils/rtl';

import WorkflowPageTabsError from '../workflow-page-tabs-error';
import type { WorkflowPageTabsErrorConfig } from '../workflow-page-tabs-error.types';

jest.mock('@/components/error-panel/error-panel', () =>
jest.fn(({ message }: { message: string }) => <div>{message}</div>)
);

jest.mock('next/navigation', () => ({
...jest.requireActual('next/navigation'),
useParams: jest.fn(() => ({
domain: 'test-domain',
cluster: 'test-cluster',
workflowTab: 'summary',
})),
}));

jest.mock(
'../../config/workflow-page-tabs-error.config',
() =>
({
summary: () => ({
message: 'summary error',
}),
history: () => ({
message: 'history error',
}),
queries: () => ({
message: 'queries error',
}),
}) as const satisfies WorkflowPageTabsErrorConfig
);

describe('WorkflowPageTabsError', () => {
beforeEach(() => {
jest.clearAllMocks();
});

it('renders tab error correctly when workflow tab exists in config', () => {
setup();
expect(screen.getByText('summary error')).toBeInTheDocument();
});

it('renders tab error with generic text when workflow tab does not exist in config', () => {
jest.spyOn(navigationModule, 'useParams').mockReturnValue({
domain: 'test-domain',
cluster: 'test-cluster',
workflowTab: 'invalid',
});
setup();
expect(
screen.getByText('Failed to load workflow content')
).toBeInTheDocument();
});
});

function setup() {
render(
<WorkflowPageTabsError
error={new Error('something bad happened')}
reset={() => {}}
/>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { useParams } from 'next/navigation';

import ErrorPanel from '@/components/error-panel/error-panel';

import workflowPageTabsErrorConfig from '../config/workflow-page-tabs-error.config';
import { type WorkflowPageTabName } from '../workflow-page-tab-content/workflow-page-tab-content.types';

import { type Props } from './workflow-page-tabs-error.types';

export default function WorkflowPageTabsError({ error, reset }: Props) {
const { workflowTab } = useParams();
const getConfig =
workflowPageTabsErrorConfig[workflowTab as WorkflowPageTabName];

if (typeof getConfig !== 'function') {
return (
<div>
<ErrorPanel
error={error}
message={'Failed to load workflow content'}
reset={reset}
/>
</div>
);
}

const errorConfig = getConfig(error);
return (
<ErrorPanel
error={error}
message={errorConfig.message}
actions={errorConfig.actions}
omitLogging={errorConfig.omitLogging}
reset={reset}
/>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { type Props as ErrorPanelProps } from '@/components/error-panel/error-panel.types';

import { type WorkflowPageTabName } from '../workflow-page-tab-content/workflow-page-tab-content.types';

export type WorkflowPageTabErrorConfig = Omit<
ErrorPanelProps,
'error' | 'reset'
>;

export type WorkflowPageTabsErrorConfig = Record<
WorkflowPageTabName,
(err: Error) => WorkflowPageTabErrorConfig
>;

export type Props = {
error: Error;
reset: () => void;
};
3 changes: 1 addition & 2 deletions src/views/workflow-page/workflow-page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React from 'react';

import PageSection from '@/components/page-section/page-section';
import decodeUrlParams from '@/utils/decode-url-params';

import WorkflowPageHeader from './workflow-page-header/workflow-page-header';
Expand All @@ -19,7 +18,7 @@ export default async function WorkflowPage({ params, children }: Props) {
cluster={decodedParams.cluster}
/>
<WorkflowPageTabs />
<PageSection>{children}</PageSection>
{children}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're removing PageSection here, we need to add it to every workflow tab. Did you make the change in History?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, also i will be making changes later along with the virtual list to handle use cases like query page expand the whole page

</>
);
}
37 changes: 20 additions & 17 deletions src/views/workflow-summary-tab/workflow-summary-tab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React from 'react';

import { useSuspenseQuery } from '@tanstack/react-query';

import PageSection from '@/components/page-section/page-section';
import useStyletronClasses from '@/hooks/use-styletron-classes';
import { type GetWorkflowHistoryResponse } from '@/route-handlers/get-workflow-history/get-workflow-history.types';
import formatWorkflowHistory from '@/utils/data-formatters/format-workflow-history';
Expand Down Expand Up @@ -50,23 +51,25 @@ export default function WorkflowSummaryTab({
: undefined;

return (
<div className={cls.pageContainer}>
<div className={cls.mainContent}>
<WorkflowSummaryTabDetails
firstHistoryEvent={formattedStartEvent}
lastHistoryEvent={formattedLastEvent}
params={params}
/>
{/* <div>Taskslist</div> */}
<PageSection>
<div className={cls.pageContainer}>
<div className={cls.mainContent}>
<WorkflowSummaryTabDetails
firstHistoryEvent={formattedStartEvent}
lastHistoryEvent={formattedLastEvent}
params={params}
/>
{/* <div>Taskslist</div> */}
</div>
<div className={cls.jsonArea}>
<WorkflowSummaryTabJsonView
inputJson={
formattedStartEvent?.[formattedStartEvent.attributes]?.input
}
resultJson={resultJson}
/>
</div>
</div>
<div className={cls.jsonArea}>
<WorkflowSummaryTabJsonView
inputJson={
formattedStartEvent?.[formattedStartEvent.attributes]?.input
}
resultJson={resultJson}
/>
</div>
</div>
</PageSection>
);
}
Loading