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

Gestion des erreurs applicatives #1250

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions front/.eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,6 @@ module.exports = {
globals: {
APP_VERSION: true,
APP_ENVIRONMENT: true,
SENTRY_DSN: true,
__ANNOTATIONS_CANONICAL_BASE_URL__: true,
__BACKEND_ENDPOINT__: true,
__GRAPHQL_ENDPOINT__: true,
__PANDOC_EXPORT_ENDPOINT__: true,
__HUMANID_REGISTER_ENDPOINT__: true,
},
rules: {
'jsdoc/require-description': ['off'],
Expand Down
9,054 changes: 4,147 additions & 4,907 deletions front/package-lock.json

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions front/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@
"react-feather": "^2.0.9",
"react-helmet": "^6.1.0",
"react-i18next": "^12.2.2",
"react-redux": "^7.2.4",
"react-router-dom": "^5.2.0",
"redux": "^4.1.0",
"react-redux": "^9.2.0",
"react-router": "^7.1.5",
"redux": "^5.0.1",
"sass": "^1.56.2",
"slugify": "1.6.6",
"swr": "^2.0.0",
Expand Down Expand Up @@ -103,7 +103,7 @@
"eslint": "^8.2.0",
"eslint-config-prettier": "^10.0.1",
"eslint-plugin-jsdoc": "^50.6.2",
"eslint-plugin-jsonc": "^2.5.0",
"eslint-plugin-jsonc": "^2.19.1",
"eslint-plugin-react": "^7.27.0",
"eslint-plugin-vitest": "^0.5.4",
"jsdom": "^26.0.0",
Expand Down
22 changes: 0 additions & 22 deletions front/src/components/404.jsx

This file was deleted.

2 changes: 1 addition & 1 deletion front/src/components/Article.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useState, useCallback, useEffect, useMemo } from 'react'
import PropTypes from 'prop-types'
import { useTranslation } from 'react-i18next'
import { Link } from 'react-router-dom'
import { Link } from 'react-router'
import clsx from 'clsx'
import {
Modal as GeistModal,
Expand Down
2 changes: 1 addition & 1 deletion front/src/components/ArticleVersionLinks.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Loading } from '@geist-ui/core'
import clsx from 'clsx'
import React, { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { Link } from 'react-router-dom'
import { Link } from 'react-router'
import useGraphQL from '../hooks/graphql.js'
import styles from './articleVersionLinks.module.scss'

Expand Down
2 changes: 1 addition & 1 deletion front/src/components/AuthCallback.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useCallback, useEffect, useState } from 'react'
import { Link, useLocation, useParams } from 'react-router-dom'
import { Link, useLocation, useParams } from 'react-router'
import { useTranslation } from 'react-i18next'

import styles from './Write/write.module.scss'
Expand Down
1 change: 0 additions & 1 deletion front/src/components/AuthCallback.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { describe, expect, test, vi } from 'vitest'
import React from 'react'
import Component from './AuthCallback.jsx'
import { renderWithProviders } from '../../tests/setup.js'
import { Link, useLocation, useParams } from 'react-router-dom'

describe('AuthCallback', () => {
test('display with no hash info and no opener', () => {
Expand Down
152 changes: 152 additions & 0 deletions front/src/components/Book.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import React, { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Link } from 'react-router'
import {
Check,
ChevronDown,
ChevronRight,
Edit3,
MessageSquare,
Printer,
} from 'react-feather'

import Modal from './Modal'
import Export from './Export'
import Chapter from './Chapter'

import etv from '../helpers/eventTargetValue'
import { useGraphQL } from '../helpers/graphQL'
import { updateTag as query } from './Books.graphql'

import styles from './articles.module.scss'
import buttonStyles from './button.module.scss'
import fieldStyles from './field.module.scss'

import Button from './Button'
import Field from './Field'
import { useCurrentUser } from '../contexts/CurrentUser'
import clsx from 'clsx'
import TimeAgo from './TimeAgo.jsx'

export default function Book({ name: tagName, _id, updatedAt, articles }) {
const activeUser = useCurrentUser()

const [expanded, setExpanded] = useState(false)
const [exporting, setExporting] = useState(false)
const [tempName, setTempName] = useState(tagName)
const [name, setName] = useState(tagName)
const [isRenaming, setIsRenaming] = useState(false)
const { t } = useTranslation()

const runQuery = useGraphQL()

const renameBook = useCallback(
async (event) => {
event.preventDefault()
const variables = {
user: activeUser._id,
tag: _id,
name: tempName,
}
const newTag = await runQuery({ query, variables })
setName(newTag.updateTag.name)
setIsRenaming(false)
},
[tempName]
)

return (
<article className={styles.article}>
{exporting && (
<Modal title="Export" cancel={() => setExporting(false)}>
<Export
bookId={_id}
name={name}
bib={articles.at(0)?.versions.at(0).bibPreview}
/>
</Modal>
)}

{!isRenaming && (
<h1 className={styles.title} onClick={() => setExpanded(!expanded)}>
{expanded ? <ChevronDown /> : <ChevronRight />}
{name} <TimeAgo date={updatedAt} />
<Button
className={clsx(buttonStyles.icon, styles.editTitleButton)}
onClick={(evt) => evt.stopPropagation() || setIsRenaming(true)}
>
<Edit3 />
</Button>
</h1>
)}
{isRenaming && (
<form
className={clsx(styles.renamingForm, fieldStyles.inlineFields)}
onSubmit={renameBook}
>
<Field
autoFocus={true}
type="text"
value={tempName}
onChange={(e) => setTempName(etv(e))}
placeholder="Article Title"
/>
<Button title="Save" primary={true} onClick={renameBook}>
<Check /> Save
</Button>
<Button
title="Cancel"
type="button"
onClick={() => {
setIsRenaming(false)
setTempName(name)
}}
>
Cancel
</Button>
</form>
)}

<aside className={styles.actionButtons}>
<Link
className={[
buttonStyles.icon,
buttonStyles.button,
articles.length === 0 ? buttonStyles.isDisabled : '',
]
.filter((d) => d)
.join(' ')}
title={t('corpus.preview.buttonTitle')}
target="_blank"
to={`/books/${_id}/preview`}
>
<MessageSquare />
</Link>
<Button
className={buttonStyles.icon}
title={t('corpus.export.button')}
onClick={() => setExporting(true)}
>
<Printer />
</Button>
</aside>

<section className={styles.metadata}>
{expanded && (
<>
<h4>Chapters</h4>
<ul className={styles.versions}>
{articles.map((article) => {
return (
<li key={`chapter-${_id}-${article._id}`}>
<Chapter article={article} />
</li>
)
})}
</ul>
</>
)}
</section>
</article>
)
}
98 changes: 98 additions & 0 deletions front/src/components/Chapter.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import React, { useState } from 'react'
import { Link } from 'react-router'
import { Check, Edit3 } from 'react-feather'

import { useGraphQL } from '../helpers/graphQL'
import { renameArticle as query } from './Article.graphql'
import Button from './Button'
import buttonStyles from './button.module.scss'
import styles from './chapter.module.scss'
import fieldStyles from './field.module.scss'
import Field from './Field'
import { useCurrentUser } from '../contexts/CurrentUser'
import clsx from 'clsx'

export default function Chapter({ article }) {
const articleId = article._id
const latestVersion = article.versions && article.versions[0]
const latestArticleVersion = latestVersion && {
message: latestVersion.message,
major: latestVersion.version,
minor: latestVersion.revision,
}

const [renaming, setRenaming] = useState(false)
const [title, setTitle] = useState(article.title)
const [tempTitle, setTempTitle] = useState(article.title)
const activeUser = useCurrentUser()
const runQuery = useGraphQL()

const rename = async (e) => {
e.preventDefault()
const variables = {
user: activeUser._id,
article: articleId,
title: tempTitle,
}
await runQuery({ query, variables })
setTitle(tempTitle)
setRenaming(false)
}
const latestArticleVersionLabel = latestArticleVersion
? latestArticleVersion.message || 'No label'
: ''
const latestVersionVersionNumber = latestArticleVersion
? `v${latestArticleVersion.major}.${latestArticleVersion.minor}`
: 'latest'
const currentArticleVersionTitle = ` (${[
latestArticleVersionLabel,
latestVersionVersionNumber,
]
.filter((item) => item)
.join(' ')})`
return (
<>
{!renaming && (
<p>
<Link to={`/article/${articleId}`}>
{title}
{currentArticleVersionTitle}
</Link>
<Button
className={[buttonStyles.icon, styles.renameButton].join(' ')}
onClick={() => setRenaming(true)}
>
<Edit3 />
</Button>
</p>
)}
{renaming && renaming && (
<form
className={clsx(styles.renamingForm, fieldStyles.inlineFields)}
onSubmit={(e) => rename(e)}
>
<Field
autoFocus={true}
type="text"
value={tempTitle}
onChange={(e) => setTempTitle(e.target.value)}
placeholder="Book Title"
/>
<Button title="Save" primary={true} onClick={(e) => rename(e)}>
<Check /> Save
</Button>
<Button
title="Cancel"
type="button"
onClick={() => {
setRenaming(false)
setTempTitle(article.title)
}}
>
Cancel
</Button>
</form>
)}
</>
)
}
42 changes: 32 additions & 10 deletions front/src/components/Error.jsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,44 @@
import React from 'react'
import App from '../layouts/App'
import React, { useEffect } from 'react'
import { useRouteError, isRouteErrorResponse } from 'react-router'
import { captureException } from '@sentry/react'

import styles from '../components/Write/write.module.scss'
import { useTranslation } from 'react-i18next'

export default function Error() {
const urlSearchParams = new URLSearchParams(window.location.search)
const message = urlSearchParams.get('message') || ''
return (
<App layout="fullPage">
const error = useRouteError()
const { t } = useTranslation()
useEffect(() => {
captureException(error)
}, [error])

if (isRouteErrorResponse(error) || Object.hasOwn(error, 'message')) {
return (
<section className={styles.container}>
<article className={styles.error}>
<h2>Error</h2>
<h2>{t('error.title')}</h2>

<p>
Something wrong happened: <code>{message}</code>
{t('error.message')}
<q>
{error.statusText
? `${error.status} ${error.statusText}`
: error.message}
</q>
</p>

{error.stack ||
(error.data && (
<details>
<pre>
<code>{error.stack ?? error.data}</code>
</pre>
</details>
))}
</article>
</section>
</App>
)
)
} else {
return <h1>{t('error.unknown')}</h1>
}
}
Loading
Loading