Skip to content

Commit

Permalink
Prise de contrôle et création de versions automatiques
Browse files Browse the repository at this point in the history
  • Loading branch information
ggrossetie committed Sep 29, 2023
1 parent 2b4bcf5 commit ead842a
Show file tree
Hide file tree
Showing 28 changed files with 396 additions and 183 deletions.
2 changes: 2 additions & 0 deletions front/src/components/Article.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ query getArticleVersions($articleId: ID!) {
message
revision
version
type
createdAt
}
}
}
Expand Down
32 changes: 25 additions & 7 deletions front/src/components/ArticleVersionLinks.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
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 useGraphQL from '../hooks/graphql.js'
import styles from './articles.module.scss'

import { getArticleVersions } from './Article.graphql'
import TimeAgo from './TimeAgo.jsx'

export default function ArticleVersionLinks ({ articleId, article }) {
const { t } = useTranslation()
Expand All @@ -19,7 +21,22 @@ export default function ArticleVersionLinks ({ articleId, article }) {
revalidateOnFocus: false,
revalidateOnReconnect: false
})
const versions = useMemo(() => data?.article?.versions || [], [data])
const getVersions = () => (data?.article?.versions || []).map(v => {
let title = ''
if (v.type === 'editingSessionEnded') {
title = t('version.editingSessionEnded.text')
} else if (v.type === 'collaborativeSessionEnded') {
title = t('version.collaborativeSessionEnded.text')
} else {
title = `v${v.version}.${v.revision} ${v.message}`
}
return {
...v,
type: v.type || 'userAction',
title,
}
})
const versions = useMemo(getVersions, [data])

if (isLoading) {
return <Loading/>
Expand All @@ -32,15 +49,16 @@ export default function ArticleVersionLinks ({ articleId, article }) {
<h4>{t('article.versions.title')}</h4>
<ul className={styles.versions}>
{versions.map((v) => (
<li key={`version-${v._id}`}>
<Link to={`/article/${article._id}/version/${v._id}`}>{`${
v.message ? v.message : 'no label'
} (v${v.version}.${v.revision})`}</Link>
<li key={`version-${v._id}`} className={clsx(v.type === 'userAction' ? styles.userVersion : styles.automaticVersion)}>
<Link to={`/article/${article._id}/version/${v._id}`}>
<span>{v.title}</span>{' '}
<TimeAgo date={v.createdAt}/>
</Link>
</li>
))}
))}
</ul>
</>
}
</>
)
)
}
2 changes: 2 additions & 0 deletions front/src/components/Articles.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ query getUserArticles($user: ID!) {
creator {
_id
}
creatorUsername
createdAt
}
}
Expand Down Expand Up @@ -128,6 +129,7 @@ query getWorkspaceArticles ($workspaceId: ID!) {
creator {
_id
}
creatorUsername
createdAt
}

Expand Down
2 changes: 1 addition & 1 deletion front/src/components/Articles.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ export default function Articles () {
useEffect(() => {
let events
if (!isLoading) {
events = new EventSource(`${backendEndpoint}/events`)
events = new EventSource(`${backendEndpoint}/events?userId=${activeUserId}`)
events.onmessage = (event) => {
handleStateUpdated(event)
}
Expand Down
108 changes: 49 additions & 59 deletions front/src/components/Write/Versions.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useCallback, useState } from 'react'
import PropTypes from 'prop-types'
import { useTranslation } from 'react-i18next'
import { Link } from 'react-router-dom'
import { shallowEqual, useDispatch, useSelector } from 'react-redux'
import { ArrowLeft, Check, ChevronDown, ChevronRight, Edit3 } from 'react-feather'
Expand All @@ -19,20 +20,22 @@ import Field from '../Field'
import CreateVersion from './CreateVersion'
import clsx from 'clsx'

function Version ({ articleId, articleName: name, compareTo, onExport, readOnly, selectedVersion, v }) {
function Version ({ articleId, compareTo, readOnly, selectedVersion, v }) {
const { t } = useTranslation()
const className = clsx({
[styles.selected]: v._id === selectedVersion,
[styles.compareTo]: v._id === compareTo
})

const articleVersionId = v._id
const versionPart = selectedVersion ? `version/${selectedVersion}/` : ''
const compareLink = `/article/${articleId}/${versionPart}compare/${v._id}`
const compareLink = `/article/${articleId}/${versionPart}compare/${v._id}`

const runQuery = useGraphQL()
const [renaming, setRenaming] = useState(false)
const [title, setTitle] = useState(v.message)
const setExportParams = useCallback(() => onExport({ articleId, articleVersionId, bib: v.bibPreview, name }), [])
const versionType = v.type || 'userAction'
const manualVersion = versionType === 'userAction'
const startRenaming = useCallback((event) => event.preventDefault() || setRenaming(true), [])
const cancelRenaming = useCallback(() => setTitle(v.message) || setRenaming(false), [])

Expand All @@ -44,48 +47,56 @@ function Version ({ articleId, articleName: name, compareTo, onExport, readOnly,
setRenaming(false)
}, [title])

return <li className={className}>
{!renaming && <header>
<Link to={`/article/${articleId}/version/${v._id}`}>
<span className={styles.versionLabel}>{title || 'no label'}</span>
<span className={styles.versionNumber}>v{v.version}.{v.revision}</span>
</Link>

{!readOnly && <Button title="Edit" icon={true} className={styles.editTitleButton} onClick={startRenaming}>
<Edit3 size="20" />
</Button>}
</header>}

return <li
className={clsx(className, styles.version, manualVersion ? styles.manualVersion : styles.automaticVersion)}>
{renaming && (
<form className={styles.renamingForm} onSubmit={handleRename}>
<Field autoFocus={true} type="text" value={title} onChange={(event) => setTitle(event.target.value)} />
<Field autoFocus={true} type="text" value={title} onChange={(event) => setTitle(event.target.value)}
placeholder={'Label of the version'}/>
<div className={styles.actions}>
<Button title="Save" primary={true}>
<Check /> Save
<Check/> Save
</Button>
<Button title="Cancel" type="button" onClick={cancelRenaming}>
Cancel
</Button>
</div>
</form>
)}

{!renaming && <p>
{v.owner && (
<span className={styles.author}>
<Link to={`/article/${articleId}/version/${v._id}`} className={clsx(styles.versionLink, selectedVersion && styles.versionLinkCompare)}>
{!renaming && versionType === 'editingSessionEnded' && <header>
{t('version.editingSessionEnded.text')}
</header>}

{!renaming && versionType === 'collaborativeSessionEnded' && <header>
{t('version.collaborativeSessionEnded.text')}
</header>}

{!renaming && versionType === 'userAction' && <header>
<span className={styles.versionLabel}>
v{v.version}.{v.revision}{' '}{title || ''}
</span>
{!readOnly && <Button title="Edit" icon={true} className={styles.editTitleButton} onClick={startRenaming}>
<Edit3 size="20"/>
</Button>}
</header>}

{!renaming && <p>
{v.owner && (
<span className={styles.author}>
by <strong>{v.owner.displayName || v.owner.username}</strong>
</span>
)}
<span className={styles.momentsAgo}>
<TimeAgo date={v.updatedAt} />
)}
<span className={styles.momentsAgo}>
<TimeAgo date={v.updatedAt}/>
</span>
</p>}

{!renaming && <ul className={styles.actions}>
</p>}
</Link>
{!renaming && selectedVersion && <ul className={styles.actions}>
{![compareTo, selectedVersion].includes(v._id) && (
<li>
<Link
className={clsx(buttonStyles.button, buttonStyles.secondary)}
className={clsx(buttonStyles.button, buttonStyles.secondary, styles.action)}
to={compareLink}
>
Compare
Expand All @@ -95,40 +106,23 @@ function Version ({ articleId, articleName: name, compareTo, onExport, readOnly,
{v._id === compareTo && (
<li>
<Link
className={clsx(buttonStyles.button, buttonStyles.secondary)}
className={clsx(buttonStyles.button, buttonStyles.secondary, styles.action)}
to={`/article/${articleId}/${versionPart}`}
>
Stop
</Link>
</li>
)}
<li>
<Link
to={`/article/${articleId}/version/${v._id}/preview`}
target="_blank"
rel="noopener noreferrer"
className={clsx(buttonStyles.button, buttonStyles.secondary)}
>
Preview
</Link>
</li>
<li>
<Button onClick={setExportParams}>
Export
</Button>
</li>
</ul>}
</li>
}

Version.propTypes = {
articleId: PropTypes.string.isRequired,
articleName: PropTypes.string.isRequired,
v: PropTypes.object.isRequired,
selectedVersion: PropTypes.string,
compareTo: PropTypes.string,
readOnly: PropTypes.bool,
onExport: PropTypes.func.isRequired
}

export default function Versions ({ article, selectedVersion, compareTo, readOnly }) {
Expand All @@ -145,7 +139,6 @@ export default function Versions ({ article, selectedVersion, compareTo, readOnl
dispatch({ type: 'ARTICLE_PREFERENCES_TOGGLE', key: 'expandVersions', value: false })
setExpandCreateForm(true)
}, [])
const handleVersionExport = useCallback(({ articleId, articleVersionId, bib, name }) => setExportParams({ articleId, articleVersionId, bib, name }), [])
const cancelExport = useCallback(() => setExportParams({}), [])

return (
Expand All @@ -154,9 +147,10 @@ export default function Versions ({ article, selectedVersion, compareTo, readOnl
{expand ? <ChevronDown/> : <ChevronRight/>}
Versions

<Button className={styles.headingAction} small={true} disabled={readOnly} onClick={createNewVersion}>
{!readOnly && <Button className={styles.headingAction} small={true} disabled={readOnly} onClick={createNewVersion}>
New Version
</Button>
</Button>}
{readOnly && <Link className={clsx(buttonStyles.button, buttonStyles.secondary, styles.editMode, styles.headingAction)} to={`/article/${article._id}`}> <ArrowLeft/> Edit Mode</Link>}
</h1>
{exportParams.articleId && (
<Modal title="Export" cancel={cancelExport}>
Expand All @@ -165,25 +159,21 @@ export default function Versions ({ article, selectedVersion, compareTo, readOnl
)}
{expand && (
<>
{expandCreateForm && <CreateVersion articleId={article._id} readOnly={readOnly} onClose={closeNewVersion} />}
{expandCreateForm && <CreateVersion articleId={article._id} readOnly={readOnly} onClose={closeNewVersion}/>}

{articleVersions.length === 0 && (<p>
<strong>All changes are automatically saved.</strong><br/>
Create a new version to keep track of particular changes.
</p>)}

{readOnly && <Link className={clsx(buttonStyles.button, buttonStyles.secondary, styles.editMode)} to={`/article/${article._id}`}> <ArrowLeft/> Edit Mode</Link>}

<ul className={styles.versionsList}>
{articleVersions.map((v) => (
<Version key={`showVersion-${v._id}`}
articleId={article._id}
articleName={article.title}
selectedVersion={selectedVersion}
compareTo={compareTo}
onExport={handleVersionExport}
readOnly={readOnly}
v={v} />
articleId={article._id}
selectedVersion={selectedVersion}
compareTo={compareTo}
readOnly={readOnly}
v={v}/>
))}
</ul>
</>
Expand Down
6 changes: 5 additions & 1 deletion front/src/components/Write/WorkingVersion.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ export default function WorkingVersion ({ articleInfos, live, selectedVersion, m
const cancelExport = useCallback(() => setExporting(false), [])
const openExport = useCallback(() => setExporting(true), [])


const previewUrl = selectedVersion
? `/article/${articleInfos._id}/version/${selectedVersion}/preview`
: `/article/${articleInfos._id}/preview`
const articleOwnerAndContributors = [
articleInfos.owner.displayName,
...articleInfos.contributors.map(contributor => contributor.user.displayName)
Expand Down Expand Up @@ -114,7 +118,7 @@ export default function WorkingVersion ({ articleInfos, live, selectedVersion, m
</Button>
</li>
<li>
<Link to={`/article/${articleInfos._id}/preview`} title="Preview (open a new window)" target="_blank" rel="noopener noreferrer"
<Link to={previewUrl} title="Preview (open a new window)" target="_blank" rel="noopener noreferrer"
className={buttonStyles.icon}>
<Eye/>
</Link>
Expand Down
1 change: 1 addition & 0 deletions front/src/components/Write/Write.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ query getEditableArticle ($article: ID!, $hasVersion: Boolean!, $version: ID!) {
displayName
username
}
type
}

workingVersion @skip(if: $hasVersion) {
Expand Down
Loading

0 comments on commit ead842a

Please sign in to comment.