1
Fork 0
mirror of https://github.com/Steffo99/sophon.git synced 2024-12-22 06:44:21 +00:00

Improve error handling

This commit is contained in:
Steffo 2021-10-15 18:07:45 +02:00 committed by Stefano Pigozzi
parent f748add494
commit 9af5ba714b
7 changed files with 180 additions and 113 deletions

View file

@ -37,68 +37,70 @@ import {ThemeProvider} from "./contexts/theme"
function App({..._}: RouteComponentProps) {
return React.useMemo(
() => <>
<Chapter>
<SophonDescriptionBox/>
</Chapter>
<InstanceProvider>
<InstanceRouter
unselectedRoute={() => <>
<InstanceFormBox/>
</>}
selectedRoute={() => <>
<Chapter>
<InstanceDescriptionBox/>
</Chapter>
<AuthorizationProvider>
<CacheProvider>
<AuthorizationRouter
unselectedRoute={AuthorizationStepPage}
selectedRoute={() => <>
<GroupRouter
unselectedRoute={GroupStepPage}
selectedRoute={({selection}) => <>
<GroupProvider resource={selection}>
<Chapter>
<ResourceDescriptionBox resource={selection} icon={faUsers}/>
<GroupMembersBox/>
</Chapter>
<ProjectRouter
groupPk={selection.value.slug}
unselectedRoute={({viewSet}) => <>
<GroupCreateBox resource={selection}/>
<ProjectListBox viewSet={viewSet}/>
<ProjectCreateBox viewSet={viewSet}/>
</>}
selectedRoute={({selection}) => <>
<ProjectProvider resource={selection}>
<ResourceDescriptionBox resource={selection} icon={faProjectDiagram}/>
<NotebookRouter
projectPk={selection.value.slug}
unselectedRoute={({viewSet}) => <>
<ProjectCreateBox resource={selection}/>
<NotebookListBox viewSet={viewSet}/>
<NotebookCreateBox viewSet={viewSet}/>
</>}
selectedRoute={({selection}) => <>
<NotebookProvider resource={selection}>
<NotebookDescriptionBox/>
<NotebookCreateBox resource={selection}/>
</NotebookProvider>
</>}
/>
</ProjectProvider>
</>}
/>
</GroupProvider>
</>}
/>
</>}
/>
</CacheProvider>
</AuthorizationProvider>
</>}
/>
</InstanceProvider>
<ErrorCatcherBox>
<Chapter>
<SophonDescriptionBox/>
</Chapter>
<InstanceProvider>
<InstanceRouter
unselectedRoute={() => <>
<InstanceFormBox/>
</>}
selectedRoute={() => <>
<Chapter>
<InstanceDescriptionBox/>
</Chapter>
<AuthorizationProvider>
<CacheProvider>
<AuthorizationRouter
unselectedRoute={AuthorizationStepPage}
selectedRoute={() => <>
<GroupRouter
unselectedRoute={GroupStepPage}
selectedRoute={({selection}) => <>
<GroupProvider resource={selection}>
<Chapter>
<ResourceDescriptionBox resource={selection} icon={faUsers}/>
<GroupMembersBox/>
</Chapter>
<ProjectRouter
groupPk={selection.value.slug}
unselectedRoute={({viewSet}) => <>
<GroupCreateBox resource={selection}/>
<ProjectListBox viewSet={viewSet}/>
<ProjectCreateBox viewSet={viewSet}/>
</>}
selectedRoute={({selection}) => <>
<ProjectProvider resource={selection}>
<ResourceDescriptionBox resource={selection} icon={faProjectDiagram}/>
<NotebookRouter
projectPk={selection.value.slug}
unselectedRoute={({viewSet}) => <>
<ProjectCreateBox resource={selection}/>
<NotebookListBox viewSet={viewSet}/>
<NotebookCreateBox viewSet={viewSet}/>
</>}
selectedRoute={({selection}) => <>
<NotebookProvider resource={selection}>
<NotebookDescriptionBox/>
<NotebookCreateBox resource={selection}/>
</NotebookProvider>
</>}
/>
</ProjectProvider>
</>}
/>
</GroupProvider>
</>}
/>
</>}
/>
</CacheProvider>
</AuthorizationProvider>
</>}
/>
</InstanceProvider>
</ErrorCatcherBox>
</>,
[],
)
@ -112,11 +114,9 @@ export default function AppWrapper() {
<LayoutThreeCol>
<LayoutThreeCol.Center>
<ThemedTitle level={1}/>
<ErrorCatcherBox>
<Reach.Router>
<App default/>
</Reach.Router>
</ErrorCatcherBox>
<SophonFooter/>
</LayoutThreeCol.Center>
</LayoutThreeCol>

View file

@ -0,0 +1,34 @@
import {faLevelUpAlt} from "@fortawesome/free-solid-svg-icons"
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
import * as Reach from "@reach/router"
import {Button} from "@steffo/bluelib-react"
import {ButtonProps} from "@steffo/bluelib-react/dist/components/inputs/Button"
import * as React from "react"
import {useSophonPath} from "../../hooks/useSophonPath"
/**
* A button that takes the user back one sophon level (so two levels).
*
* @constructor
*/
export function GoBackButton({onClick, ...props}: Omit<ButtonProps, "children">): JSX.Element {
const location = useSophonPath()
const onClickWrapped = React.useCallback(
async event => {
event.preventDefault()
if(onClick) {
onClick(event)
}
await Reach.navigate("../..")
},
[onClick],
)
return (
<Button onClick={onClickWrapped} disabled={location.count === 0} {...props}>
<FontAwesomeIcon icon={faLevelUpAlt}/>&nbsp;Go up
</Button>
)
}

View file

@ -0,0 +1,40 @@
import * as Reach from "@reach/router"
import {Button} from "@steffo/bluelib-react"
import {ButtonProps} from "@steffo/bluelib-react/dist/components/inputs/Button"
import * as React from "react"
/**
* The props of {@link NavigateButton}.
*/
export interface NavigateButtonProps extends ButtonProps {
href: string,
}
/**
* A button functioning like a {@link Link}.
*
* @constructor
*/
export function NavigateButton({href, children, onClick, ...props}: NavigateButtonProps): JSX.Element {
const location = Reach.useLocation()
const onClickWrapped = React.useCallback(
event => {
event.preventDefault()
if(onClick) {
onClick(event)
}
if(href) {
// noinspection JSIgnoredPromiseFromCall
Reach.navigate(href)
}
},
[href, onClick],
)
return (
<Button children={children} onClick={onClickWrapped} disabled={location.pathname === href} {...props}/>
)
}

View file

@ -1,7 +1,9 @@
import {Box, Form} from "@steffo/bluelib-react"
import {faAngleDoubleRight, faBug} from "@fortawesome/free-solid-svg-icons"
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
import {Box, Button, Form} from "@steffo/bluelib-react"
import * as React from "react"
import {IgnoreErrorButton} from "./IgnoreErrorButton"
import {ReportBugButton} from "./ReportBugButton"
import {GoBackButton} from "../elements/GoBackButton"
import {NavigateButton} from "../elements/NavigateButton"
interface ErrorCatcherBoxProps {
@ -44,8 +46,13 @@ export class ErrorCatcherBox extends React.Component<ErrorCatcherBoxProps, Error
{this.state.error.toString()}
<Form>
<Form.Row>
<IgnoreErrorButton onClick={this.clearError}/>
<ReportBugButton/>
<NavigateButton href={"https://github.com/Steffo99/sophon/issues/new?assignees=&labels=bug&template=1_bug_report.md&title="}>
<FontAwesomeIcon icon={faBug}/>&nbsp;Report bug
</NavigateButton>
<GoBackButton/>
<Button onClick={this.clearError}>
<FontAwesomeIcon icon={faAngleDoubleRight}/>&nbsp;Try ignoring the error
</Button>
</Form.Row>
</Form>
</Box>

View file

@ -1,18 +0,0 @@
import {faAngleDoubleRight} from "@fortawesome/free-solid-svg-icons"
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
import {Button} from "@steffo/bluelib-react"
import * as React from "react"
export interface IgnoreErrorButtonProps {
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
}
export function IgnoreErrorButton({onClick}: IgnoreErrorButtonProps): JSX.Element {
return (
<Button onClick={onClick}>
<FontAwesomeIcon icon={faAngleDoubleRight}/>&nbsp;Try ignoring the error
</Button>
)
}

View file

@ -1,25 +0,0 @@
import {faBug} from "@fortawesome/free-solid-svg-icons"
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
import {navigate} from "@reach/router"
import {Button} from "@steffo/bluelib-react"
import * as React from "react"
export function ReportBugButton(): JSX.Element {
const onClick =
React.useCallback(
async () => {
await navigate("https://github.com/Steffo99/sophon/issues/new?assignees=&labels=bug&template=1_bug_report.md&title=")
},
[],
)
return React.useMemo(
() => (
<Button>
<FontAwesomeIcon onClick={onClick} icon={faBug}/>&nbsp;Report bug
</Button>
),
[onClick],
)
}

View file

@ -37,6 +37,11 @@ export interface ParsedPath {
* Passed the login page (either by browsing as guest or by logging in).
*/
loggedIn?: boolean,
/**
* The number of pages that separate this to the website root.
*/
count: number,
}
/**
@ -44,7 +49,9 @@ export interface ParsedPath {
* @param path - The path to split.
*/
export function parsePath(path: string): ParsedPath {
let result: ParsedPath = {}
let result: ParsedPath = {
count: 0,
}
result.instance = path.match(/[/]i[/]([^/]+)/)?.[1]
result.userId = path.match(/[/]u[/]([0-9]+)/)?.[1]
@ -54,5 +61,27 @@ export function parsePath(path: string): ParsedPath {
result.notebook = path.match(/[/]n[/]([A-Za-z0-9_-]+)/)?.[1]
result.loggedIn = Boolean(path.match(/[/]l[/]/))
if(result.instance) {
result.count += 1
}
if(result.userId) {
result.count += 1
}
if(result.userName) {
result.count += 1
}
if(result.researchGroup) {
result.count += 1
}
if(result.researchProject) {
result.count += 1
}
if(result.notebook) {
result.count += 1
}
if(result.loggedIn) {
result.count += 1
}
return result
}