Skip to content

Commit 99dc253

Browse files
authored
Error improvements (#137)
1 parent 13a1d46 commit 99dc253

File tree

11 files changed

+126
-39
lines changed

11 files changed

+126
-39
lines changed

src/npm-fastui-bootstrap/src/index.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,5 +137,11 @@ export const classNameGenerator: ClassNameGenerator = ({
137137
}
138138
case 'Code':
139139
return 'rounded'
140+
case 'Error':
141+
if (props.statusCode === 502) {
142+
return 'm-3 text-muted'
143+
} else {
144+
return 'alert alert-danger m-3'
145+
}
140146
}
141147
}

src/npm-fastui-prebuilt/src/main.scss

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ $link-color: #0d6efd; // bootstrap primary
33

44
@import 'bootstrap/scss/bootstrap';
55

6-
html, body, #root {
6+
html,
7+
body,
8+
#root {
79
height: 100%;
810
}
911

@@ -33,7 +35,12 @@ body {
3335
backdrop-filter: blur(8px);
3436
}
3537

36-
h1, h2, h3, h4, h5, h6 {
38+
h1,
39+
h2,
40+
h3,
41+
h4,
42+
h5,
43+
h6 {
3744
scroll-margin-top: 60px;
3845
}
3946

src/npm-fastui-prebuilt/vite.config.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,25 @@
11
import path from 'path'
22

33
import react from '@vitejs/plugin-react-swc'
4-
import { defineConfig } from 'vite'
4+
import { defineConfig, HttpProxy } from 'vite'
55

66
export default () => {
77
const serverConfig = {
88
host: true,
99
port: 3000,
1010
proxy: {
11-
'/api': 'http://localhost:8000',
11+
'/api': {
12+
target: 'http://localhost:8000',
13+
configure: (proxy: HttpProxy.Server) => {
14+
proxy.on('error', (err, _, res) => {
15+
const { code } = err as any
16+
if (code === 'ECONNREFUSED') {
17+
res.writeHead(502, { 'content-type': 'text/plain' })
18+
res.end('vite-proxy: Proxy connection refused')
19+
}
20+
})
21+
},
22+
},
1223
},
1324
}
1425

src/npm-fastui/src/components/Custom.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1-
import { FC, useContext } from 'react'
1+
import { FC } from 'react'
22

33
import type { Custom } from '../models'
44

5-
import { ErrorContext } from '../hooks/error'
5+
import { DisplayError } from '../hooks/error'
66

77
import { JsonComp } from './Json'
88

99
export const CustomComp: FC<Custom> = (props) => {
1010
const { data, subType, library } = props
11-
const { DisplayError } = useContext(ErrorContext)
1211

1312
const description = [`The custom component "${subType}"`]
1413
if (library) {
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { FC } from 'react'
2+
3+
import type { Error } from '../models'
4+
5+
import { useClassName } from '../hooks/className'
6+
7+
export const ErrorComp: FC<Error> = (props) => {
8+
const { title, description, statusCode, children } = props
9+
return (
10+
<>
11+
<div className={useClassName(props)} role="alert">
12+
{statusCode === 502 ? (
13+
<>Backend server down.</>
14+
) : (
15+
<>
16+
<h4>{title}</h4>
17+
{description}
18+
</>
19+
)}
20+
</div>
21+
{children}
22+
</>
23+
)
24+
}

src/npm-fastui/src/components/index.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { useContext, FC } from 'react'
1+
import { FC } from 'react'
22

33
import type { FastProps, Display, Text, ServerLoad, PageTitle, FireEvent } from '../models'
44

5-
import { ErrorContext } from '../hooks/error'
5+
import { DisplayError } from '../hooks/error'
66
import { useCustomRender } from '../hooks/config'
77
import { unreachable } from '../tools'
88

@@ -37,6 +37,7 @@ import { ImageComp } from './image'
3737
import { IframeComp } from './Iframe'
3838
import { VideoComp } from './video'
3939
import { FireEventComp } from './FireEvent'
40+
import { ErrorComp } from './error'
4041
import { CustomComp } from './Custom'
4142

4243
// TODO some better way to export components
@@ -70,6 +71,7 @@ export {
7071
IframeComp,
7172
VideoComp,
7273
FireEventComp,
74+
ErrorComp,
7375
CustomComp,
7476
LinkRender,
7577
}
@@ -85,8 +87,6 @@ export const AnyCompList: FC<{ propsList: FastProps[] }> = ({ propsList }) => (
8587
)
8688

8789
export const AnyComp: FC<FastProps> = (props) => {
88-
const { DisplayError } = useContext(ErrorContext)
89-
9090
const CustomRenderComp = useCustomRender(props)
9191
if (CustomRenderComp) {
9292
return <CustomRenderComp />
@@ -155,6 +155,8 @@ export const AnyComp: FC<FastProps> = (props) => {
155155
return <VideoComp {...props} />
156156
case 'FireEvent':
157157
return <FireEventComp {...props} />
158+
case 'Error':
159+
return <ErrorComp {...props} />
158160
case 'Custom':
159161
return <CustomComp {...props} />
160162
default:

src/npm-fastui/src/hooks/error.tsx

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,49 @@
11
import { createContext, FC, ReactNode, useCallback, useContext, useState } from 'react'
22

3+
import type { Error as ErrorProps } from '../models'
4+
5+
import { ErrorComp } from '../components'
6+
7+
import { useCustomRender } from './config'
8+
39
interface ErrorDetails {
410
title: string
511
description: string
12+
statusCode?: number
613
}
714

815
interface ErrorDisplayProps extends ErrorDetails {
916
children?: ReactNode
1017
}
1118

12-
export type ErrorDisplayType = FC<ErrorDisplayProps>
13-
1419
interface ErrorContextType {
1520
error: ErrorDetails | null
1621
setError: (error: ErrorDetails | null) => void
17-
DisplayError: ErrorDisplayType
1822
}
1923

20-
const DefaultErrorDisplay: ErrorDisplayType = ({ title, description, children }) => (
21-
<>
22-
<div className="alert alert-danger m-3" role="alert">
23-
<h4>{title}</h4>
24-
{description}
25-
</div>
26-
{children}
27-
</>
28-
)
24+
export const DisplayError: FC<ErrorDisplayProps> = ({ title, description, statusCode, children }) => {
25+
const props: ErrorProps = {
26+
title,
27+
description,
28+
statusCode,
29+
children,
30+
type: 'Error',
31+
}
32+
const CustomRenderComp = useCustomRender(props)
33+
if (CustomRenderComp) {
34+
return <CustomRenderComp />
35+
} else {
36+
return <ErrorComp {...props} />
37+
}
38+
}
2939

3040
export const ErrorContext = createContext<ErrorContextType>({
3141
error: null,
3242
setError: () => null,
33-
DisplayError: DefaultErrorDisplay,
3443
})
3544

3645
const MaybeError: FC<{ children: ReactNode }> = ({ children }) => {
37-
const { error, DisplayError } = useContext(ErrorContext)
46+
const { error } = useContext(ErrorContext)
3847
if (error) {
3948
return <DisplayError {...error}>{children}</DisplayError>
4049
} else {
@@ -43,11 +52,10 @@ const MaybeError: FC<{ children: ReactNode }> = ({ children }) => {
4352
}
4453

4554
interface Props {
46-
DisplayError?: ErrorDisplayType
4755
children: ReactNode
4856
}
4957

50-
export const ErrorContextProvider: FC<Props> = ({ DisplayError, children }) => {
58+
export const ErrorContextProvider: FC<Props> = ({ children }) => {
5159
const [error, setErrorState] = useState<ErrorDetails | null>(null)
5260

5361
const setError = useCallback(
@@ -59,10 +67,9 @@ export const ErrorContextProvider: FC<Props> = ({ DisplayError, children }) => {
5967
},
6068
[setErrorState],
6169
)
62-
const contextValue: ErrorContextType = { error, setError, DisplayError: DisplayError ?? DefaultErrorDisplay }
6370

6471
return (
65-
<ErrorContext.Provider value={contextValue}>
72+
<ErrorContext.Provider value={{ error, setError }}>
6673
<MaybeError>{children}</MaybeError>
6774
</ErrorContext.Provider>
6875
)

src/npm-fastui/src/index.tsx

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { FC, ReactNode } from 'react'
22

3-
import type { ErrorDisplayType } from './hooks/error'
43
import type { FastProps } from './models'
54

65
import { LocationProvider } from './hooks/locationContext'
@@ -26,25 +25,24 @@ export interface FastUIProps {
2625
Spinner?: FC
2726
NotFound?: FC<{ url: string }>
2827
Transition?: FC<{ children: ReactNode; transitioning: boolean }>
29-
DisplayError?: ErrorDisplayType
3028
classNameGenerator?: ClassNameGenerator
3129
customRender?: CustomRender
3230
// defaults to `process.env.NODE_ENV === 'development'
3331
devMode?: boolean
3432
}
3533

3634
export function FastUI(props: FastUIProps) {
37-
const { classNameGenerator, DisplayError, devMode, ...rest } = props
35+
const { classNameGenerator, devMode, ...rest } = props
3836
return (
39-
<ErrorContextProvider DisplayError={DisplayError}>
40-
<LocationProvider>
41-
<ClassNameContext.Provider value={classNameGenerator ?? null}>
37+
<ClassNameContext.Provider value={classNameGenerator ?? null}>
38+
<ErrorContextProvider>
39+
<LocationProvider>
4240
<ConfigContext.Provider value={rest}>
4341
<DevReload enabled={devMode} />
4442
<FastUIController />
4543
</ConfigContext.Provider>
46-
</ClassNameContext.Provider>
47-
</LocationProvider>
48-
</ErrorContextProvider>
44+
</LocationProvider>
45+
</ErrorContextProvider>
46+
</ClassNameContext.Provider>
4947
)
5048
}

src/npm-fastui/src/models.d.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export type FastProps =
2525
| Iframe
2626
| Video
2727
| FireEvent
28+
| Error
2829
| Custom
2930
| Table
3031
| Pagination
@@ -243,6 +244,14 @@ export interface FireEvent {
243244
message?: string
244245
type: 'FireEvent'
245246
}
247+
export interface Error {
248+
title: string
249+
description: string
250+
statusCode?: number
251+
className?: ClassName
252+
type: 'Error'
253+
children?: ReactNode
254+
}
246255
export interface Custom {
247256
data: JsonData
248257
subType: string

src/npm-fastui/src/tools.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,12 @@ export function useRequest(): (args: RequestArgs) => Promise<[number, any]> {
1212
try {
1313
return await request(args)
1414
} catch (e) {
15-
setError({ title: 'Request Error', description: (e as any)?.message })
15+
const title = 'Request Error'
16+
if (e instanceof RequestError) {
17+
setError({ title, description: e.message, statusCode: e.status })
18+
} else {
19+
setError({ title, description: (e as any)?.message })
20+
}
1621
throw e
1722
}
1823
},

0 commit comments

Comments
 (0)