Skip to content

Commit

Permalink
feat: add renderError property (#175)
Browse files Browse the repository at this point in the history
* fix(main): reset "No data" error on change data

* feat(main): Add renderErrorView prop for custom render and handle errors
  • Loading branch information
EgorKluch authored Jun 20, 2023
1 parent 9668776 commit 84c03a9
Show file tree
Hide file tree
Showing 10 changed files with 333 additions and 25 deletions.
2 changes: 1 addition & 1 deletion src/components/ChartKit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ const ChartKitComponentWithErrorBoundary = React.forwardRef<
ChartKitProps<ChartKitType>
>(function ChartKitComponentWithErrorBoundary(props, ref) {
return (
<ErrorBoundary onError={props.onError}>
<ErrorBoundary onError={props.onError} data={props.data} renderError={props.renderError}>
<ChartKitComponent instanceRef={ref} {...props} />
</ErrorBoundary>
);
Expand Down
34 changes: 31 additions & 3 deletions src/components/ErrorBoundary/ErrorBoundary.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import React from 'react';
import type {ChartKitError} from '../../libs';
import type {ChartKitOnError} from '../../types';
import {ErrorView} from '../ErrorView/ErrorView';
import type {ChartKitOnError, ChartKitType, ChartKitWidget, RenderError} from '../../types';
import {getErrorMessage} from '../../utils/getErrorMessage';
import {CHARTKIT_ERROR_CODE} from '../../libs';

type Props = {
onError?: ChartKitOnError;
data: ChartKitWidget[ChartKitType]['data'];
renderError?: RenderError;
};

type State = {
Expand All @@ -28,13 +31,38 @@ export class ErrorBoundary extends React.Component<Props, State> {
}
}

componentDidUpdate(prevProps: Readonly<Props>) {
if (prevProps.data !== this.props.data) {
const {error} = this.state;
if (error && 'code' in error && error.code === CHARTKIT_ERROR_CODE.NO_DATA) {
this.resetError();
}
}
}

render() {
const {error} = this.state;

if (error) {
return <ErrorView error={error} />;
const message = getErrorMessage(error);

if (this.props.renderError) {
return this.props.renderError({
error,
message,
resetError: this.resetError,
});
}

return <div>{message}</div>;
}

return this.props.children;
}

resetError = () => {
if (this.state.error) {
this.setState({error: undefined});
}
};
}
14 changes: 0 additions & 14 deletions src/components/ErrorView/ErrorView.tsx

This file was deleted.

27 changes: 21 additions & 6 deletions src/plugins/highcharts/__stories__/components/ChartStory.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import {Button} from '@gravity-ui/uikit';
import {ChartKitRef} from '../../../../types';
import {ChartKitRef, RenderError} from '../../../../types';
import {settings} from '../../../../libs';
import {HighchartsPlugin} from '../../index';
import holidays from '../../mocks/holidays';
Expand All @@ -11,19 +11,29 @@ const DEFAULT_STORY_HEIGHT = '300px';
const DEFAULT_STORY_WIDTH = '100%';

export type ChartStoryProps = {
data: HighchartsWidgetData;

withoutPlugin?: boolean;
visible?: boolean;
height?: string;
width?: string;

data: HighchartsWidgetData;
renderError?: RenderError;
};
export const ChartStory: React.FC<ChartStoryProps> = (props: ChartStoryProps) => {
const {height, width, data} = props;

const [visible, setVisible] = React.useState(false);
const initRef = React.useRef(false);
const [visible, setVisible] = React.useState(Boolean(props.visible));
const chartKitRef = React.useRef<ChartKitRef>();

if (!initRef.current) {
if (!props.withoutPlugin) {
settings.set({plugins: [HighchartsPlugin], extra: {holidays}});
}
initRef.current = true;
}

if (!visible) {
settings.set({plugins: [HighchartsPlugin], extra: {holidays}});
return <Button onClick={() => setVisible(true)}>Show chart</Button>;
}

Expand All @@ -34,7 +44,12 @@ export const ChartStory: React.FC<ChartStoryProps> = (props: ChartStoryProps) =>
width: width || DEFAULT_STORY_WIDTH,
}}
>
<ChartKit ref={chartKitRef} type="highcharts" data={data} />
<ChartKit
ref={chartKitRef}
type="highcharts"
data={data}
renderError={props.renderError}
/>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import React from 'react';
import {Meta, Story} from '@storybook/react';
import {ChartKit} from '../../../../components/ChartKit';
import {ChartStory} from '../components/ChartStory';
import {Button} from '@gravity-ui/uikit';
import {CHARTKIT_ERROR_CODE, settings} from '../../../../libs';
import {HighchartsPlugin} from '../../index';
import holidays from '../../mocks/holidays';
import {noData, filledData} from '../../mocks/custom-error-render';
import {RenderError} from '../../../../types';

export default {
title: 'Plugins/Highcharts/CustomErrorRender',
component: ChartKit,
} as Meta;

const Template: Story = () => {
const [data, setData] = React.useState(noData);

const renderErrorView: RenderError = React.useCallback(({error, message, resetError}) => {
function renderFixButton() {
if (!('code' in error)) {
return null;
}

switch (error.code) {
case CHARTKIT_ERROR_CODE.UNKNOWN_PLUGIN:
return (
<Button
onClick={() => {
settings.set({plugins: [HighchartsPlugin], extra: {holidays}});
resetError();
}}
>
Add highcharts plugin
</Button>
);
case CHARTKIT_ERROR_CODE.NO_DATA:
return (
<Button
onClick={() => {
setData(filledData);
}}
>
Add data
</Button>
);
default:
return null;
}
}

return (
<div>
<h2>{message}</h2>
{renderFixButton()}
</div>
);
}, []);

return (
<div>
<ChartStory
withoutPlugin={true}
data={data}
visible={true}
renderError={renderErrorView}
/>
</div>
);
};

export const CustomErrorRender = Template.bind({});
30 changes: 30 additions & 0 deletions src/plugins/highcharts/__stories__/no-data/no-data.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';
import {Meta, Story} from '@storybook/react';
import {ChartKit} from '../../../../components/ChartKit';
import {noData, filledData} from '../../mocks/no-data';
import {ChartStory} from '../components/ChartStory';
import {Button} from '@gravity-ui/uikit';

export default {
title: 'Plugins/Highcharts/NoData',
component: ChartKit,
} as Meta;

const Template: Story = () => {
const [data, setData] = React.useState(noData);

const handleUpdateData = React.useCallback(() => {
setData(filledData);
}, []);

return (
<div>
<div style={{marginBottom: 12}}>
<Button onClick={handleUpdateData}>Add data</Button>
</div>
<ChartStory data={data} visible={true} />
</div>
);
};

export const NoData = Template.bind({});
80 changes: 80 additions & 0 deletions src/plugins/highcharts/mocks/custom-error-render.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import type {HighchartsWidgetData} from '../types';
import _ from 'lodash';

const baseData: Omit<HighchartsWidgetData, 'data'> = {
config: {
hideHolidays: false,
normalizeDiv: false,
normalizeSub: false,
},
libraryConfig: {
chart: {
type: 'arearange',
},
title: {
text: 'Temperature variation by day',
},
xAxis: {
type: 'datetime',
},
tooltip: {
valueSuffix: '°C',
},
},
};

export const noData: HighchartsWidgetData = {
...baseData,
data: {
graphs: [
{
name: 'Temperatures',
data: [],
},
],
},
};

export const filledData: HighchartsWidgetData = {
...baseData,
data: {
graphs: [
{
name: 'Temperatures',
data: [
[1246406400000, 10.4, 17],
[1246492800000, 10.3, 28.6],
[1246579200000, 14.8, 18.4],
[1246665600000, 11.5, 25.8],
[1246752000000, 11.1, 24.4],
[1246838400000, 17.7, 19.6],
[1246924800000, 15.1, 18.1],
[1247011200000, 15.1, 27.2],
[1247097600000, 17, 17.5],
[1247184000000, 12.6, 18.5],
[1247270400000, 12.2, 26],
[1247356800000, 15.9, 22.9],
[1247443200000, 17.1, 18.1],
[1247529600000, 13.3, 24.2],
[1247616000000, 17, 28.1],
[1247702400000, 16.2, 22.6],
[1247788800000, 10.6, 19],
[1247875200000, 11.3, 19.7],
[1247961600000, 14.1, 24.6],
[1248048000000, 14.2, 22.5],
[1248134400000, 14.1, 28.5],
[1248220800000, 14, 27],
[1248307200000, 10.2, 20.6],
[1248393600000, 13.1, 29.9],
[1248480000000, 13.7, 21.1],
[1248566400000, 15, 28.6],
[1248652800000, 12, 17.5],
[1248739200000, 17.8, 24.4],
[1248825600000, 11.7, 25.9],
[1248912000000, 13.6, 25.6],
[1248998400000, 17.3, 22.2],
],
},
],
},
};
Loading

0 comments on commit 84c03a9

Please sign in to comment.