Mirror of https://github.com/roostorg/osprey
github.com/roostorg/osprey
1import * as React from 'react';
2import { ReloadOutlined } from '@ant-design/icons';
3import { Spin, Alert, Button } from 'antd';
4import { sample } from 'lodash';
5
6import { PromiseResult, PromiseResultStatus } from '../hooks/usePromiseResult';
7
8interface RenderResolvedPromiseOptions {
9 // A custom function that will render a specific "resolving" state, rather than the default loading UI.
10 renderResolving?: () => React.ReactElement | null;
11 // A custom function that will render a specific "rejected" state, rather than the default rejection UI.
12 renderRejected?: (error: Error, retry: () => void) => React.ReactElement;
13
14 showStackTrace?: boolean;
15}
16
17const loadingLines = [
18 'Upsorbing the Contents',
19 'Additive Parsing the Load',
20 'Commence Monosaturated Goodening',
21 'Kick Off the Multi-Core Widening',
22 'Bastening the Game Turkey',
23 'Abstracting the Rummage Disc',
24 'Undecerealenizing the Process',
25 'Postrefragmenting the Widget Layer',
26 'Satisfying the Constraints',
27 'Abnoramalzing Some of the Matrices',
28 'Optimizing the People',
29 'Proclaigerizing the Network',
30];
31
32function Resolving() {
33 const loadingLine = React.useMemo(() => sample(loadingLines), []);
34 return (
35 <Spin tip={loadingLine} size="large">
36 <div style={{ height: '100px' }} />
37 </Spin>
38 );
39}
40
41function Rejected({ error, retry, showStackTrace }: { error: Error; retry: () => void; showStackTrace: boolean }) {
42 // Sanitize the stack trace a bit better, by stripping the first line (which will usually be Error: ${error.message})
43 const stackTrace =
44 showStackTrace && error.stack ? (
45 <pre>
46 {error.stack
47 .split('\n')
48 .slice(1)
49 .map((l) => l.trim())
50 .join('\n')}
51 </pre>
52 ) : null;
53
54 const description = (
55 <>
56 {stackTrace}
57 <Button icon={<ReloadOutlined />} size="middle" onClick={retry}>
58 Retry
59 </Button>
60 </>
61 );
62
63 return <Alert message={<code>{error.message}</code>} description={description} type="error" showIcon />;
64}
65
66export function renderFromPromiseResult<T>(
67 promiseResult: PromiseResult<T>,
68 renderResolved: (resolved: T) => React.ReactElement,
69 options: RenderResolvedPromiseOptions = {}
70): React.ReactElement | null {
71 switch (promiseResult.status) {
72 case PromiseResultStatus.Resolving:
73 return options.renderResolving?.() ?? <Resolving />;
74 case PromiseResultStatus.Resolved:
75 return renderResolved(promiseResult.value);
76 case PromiseResultStatus.Rejected:
77 const { error, retry } = promiseResult;
78 return (
79 options.renderRejected?.(error, retry) ?? (
80 <Rejected error={error} retry={retry} showStackTrace={options.showStackTrace ?? true} />
81 )
82 );
83 }
84}