• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

EcrituresNumeriques / stylo / 13562375625

27 Feb 2025 08:48AM UTC coverage: 27.922% (-0.004%) from 27.926%
13562375625

push

github

web-flow
Merge pull request #1303 from EcrituresNumeriques/fix/996

372 of 573 branches covered (64.92%)

Branch coverage included in aggregate %.

1 of 3 new or added lines in 2 files covered. (33.33%)

1 existing line in 1 file now uncovered.

3832 of 14483 relevant lines covered (26.46%)

1.9 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/front/src/components/Write/WorkingVersion.jsx
1
import React, { useEffect, useMemo, useState, useCallback } from 'react'
×
2
import { shallowEqual, useSelector } from 'react-redux'
×
3
import { Link } from 'react-router-dom'
×
4
import {
×
5
  AlertCircle,
6
  AlignLeft,
7
  Check,
8
  Edit3,
9
  Eye,
10
  Loader,
11
  Printer,
12
} from 'react-feather'
13
import { useTranslation } from 'react-i18next'
×
NEW
14
import { toBibtex } from '../../helpers/bibtex.js'
×
UNCOV
15
import TimeAgo from '../TimeAgo.jsx'
×
16

17
import styles from './workingVersion.module.scss'
×
18
import buttonStyles from '../button.module.scss'
×
19
import Button from '../Button'
×
20
import Modal from '../Modal'
×
21
import Export from '../Export'
×
22

23
const ONE_MINUTE = 60000
×
24

25
export function ArticleVersion({ version }) {
×
26
  const { t } = useTranslation()
×
27

28
  return (
×
29
    <span>
×
30
      {!version && <span>{t('workingVersion.spanWorkingCopy.text')}</span>}
×
31
      {version && version.message && (
×
32
        <span>
×
33
          <span className={styles.versionLabel}>{version.message}</span>
×
34
          <span className={styles.versionNumber}>
×
35
            v{version.major}.{version.minor}
×
36
          </span>
×
37
        </span>
×
38
      )}
39
      {version && !version.message && (
×
40
        <span>
×
41
          <span className={styles.versionNumber}>
×
42
            v{version.major}.{version.minor}
×
43
          </span>
×
44
        </span>
×
45
      )}
46
    </span>
×
47
  )
48
}
×
49

50
export function ArticleSaveState({ state, updatedAt, stateMessage }) {
×
51
  const [lastRefreshedAt, setLastRefresh] = useState(Date.now())
×
52
  const { t } = useTranslation()
×
53

54
  const stateUiProps = {
×
55
    saved: {
×
56
      text: t('workingVersion.stateUiProps.savedText'),
×
57
      icon: <Check />,
×
58
      style: styles.savedIndicator,
×
59
    },
×
60
    saving: {
×
61
      text: t('workingVersion.stateUiProps.savingText'),
×
62
      icon: <Loader />,
×
63
      style: styles.savingIndicator,
×
64
    },
×
65
    saveFailure: {
×
66
      text: t('workingVersion.stateUiProps.saveErrorText'),
×
67
      icon: <AlertCircle />,
×
68
      style: styles.failureIndicator,
×
69
    },
×
70
  }
×
71
  const stateUi = stateUiProps[state]
×
72

73
  const isoString = useMemo(
×
74
    () => new Date(updatedAt).toISOString(),
×
75
    [updatedAt, lastRefreshedAt]
×
76
  )
×
77

78
  useEffect(() => {
×
79
    const timer = setTimeout(
×
80
      () => setLastRefresh(Date.now() * 1000),
×
81
      ONE_MINUTE
×
82
    )
×
83
    return () => clearTimeout(timer)
×
84
  }, [])
×
85

86
  return (
×
87
    <>
×
88
      <span className={stateUi.style}>
×
89
        {state !== 'saved' && stateUi.icon}
×
90
        {state !== 'saveFailure' && stateUi.text}
×
91
        {state === 'saveFailure' && (
×
92
          <span>
×
93
            <strong>{stateUi.text}</strong>
×
94
            {stateMessage}
×
95
          </span>
×
96
        )}
97
      </span>
×
98

99
      {state === 'saved' && <TimeAgo date={isoString} />}
×
100
    </>
×
101
  )
102
}
×
103

104
export default function WorkingVersion({
×
105
  articleInfos,
×
106
  live,
×
107
  selectedVersion,
×
108
  mode,
×
109
}) {
×
110
  const [exporting, setExporting] = useState(false)
×
111
  const workingArticle = useSelector(
×
112
    (state) => state.workingArticle,
×
113
    shallowEqual
×
114
  )
×
115
  const cancelExport = useCallback(() => setExporting(false), [])
×
116
  const openExport = useCallback(() => setExporting(true), [])
×
117
  const { t } = useTranslation()
×
118

119
  const previewUrl = selectedVersion
×
120
    ? `/article/${articleInfos._id}/version/${selectedVersion}/preview`
×
121
    : `/article/${articleInfos._id}/preview`
×
122
  const articleOwnerAndContributors = [
×
123
    articleInfos.owner.displayName,
×
124
    ...articleInfos.contributors.map(
×
125
      (contributor) => contributor.user.displayName
×
126
    ),
×
127
  ]
×
128

129
  return (
×
130
    <>
×
131
      <section className={styles.section}>
×
132
        <header className={styles.header}>
×
133
          <h1 className={styles.title}>
×
134
            <AlignLeft />
×
135
            {articleInfos.title}
×
136
          </h1>
×
137
        </header>
×
138
        {exporting && (
×
139
          <Modal title="Export" cancel={cancelExport}>
×
140
            <Export
×
141
              articleVersionId={selectedVersion}
×
142
              articleId={articleInfos._id}
×
NEW
143
              bib={toBibtex(workingArticle.bibliography.entries.slice(0, 3))}
×
144
              name={articleInfos.title}
×
145
            />
×
146
          </Modal>
×
147
        )}
148
        <ul className={styles.actions}>
×
149
          {articleInfos.preview.stylesheet && (
×
150
            <>
×
151
              <li>
×
152
                <Link
×
153
                  to={`/article/${articleInfos._id}`}
×
154
                  className={
×
155
                    mode === 'write'
×
156
                      ? buttonStyles.primaryDisabled
×
157
                      : buttonStyles.secondary
×
158
                  }
159
                  title="Edit article"
×
160
                >
161
                  <Edit3 /> Edit
×
162
                </Link>
×
163
              </li>
×
164
              <li>
×
165
                <Link
×
166
                  to={`/article/${articleInfos._id}/preview`}
×
167
                  className={
×
168
                    mode === 'preview'
×
169
                      ? buttonStyles.primaryDisabled
×
170
                      : buttonStyles.secondary
×
171
                  }
172
                  title="Preview article"
×
173
                >
174
                  <Eye />
×
175
                  {articleInfos.preview.stylesheet ? (
×
176
                    'Paged.js'
×
177
                  ) : (
178
                    <abbr title="HyperText Markup Language">HTML</abbr>
×
179
                  )}
×
180
                  &nbsp;Preview
181
                </Link>
×
182
              </li>
×
183
            </>
×
184
          )}
185
          <li>
×
186
            <Button
×
187
              icon
×
188
              title={t('write.title.buttonExport')}
×
189
              onClick={openExport}
×
190
            >
191
              <Printer />
×
192
            </Button>
×
193
          </li>
×
194
          <li>
×
195
            <Link
×
196
              to={previewUrl}
×
197
              title={t('write.title.buttonPreview')}
×
198
              target="_blank"
×
199
              rel="noopener noreferrer"
×
200
              className={buttonStyles.icon}
×
201
            >
202
              <Eye />
×
203
            </Link>
×
204
          </li>
×
205
        </ul>
×
206
      </section>
×
207
      <section>
×
208
        <div className={styles.meta}>
×
209
          <ul className={styles.byLine}>
×
210
            <li className={styles.owners}>
×
211
              {t('workingVersion.by.text')}{' '}
×
212
              {articleOwnerAndContributors.join(', ')}
×
213
            </li>
×
214
            <li className={styles.version}>
×
215
              <ArticleVersion version={live.version} />
×
216
            </li>
×
217
            {!live.version && (
×
218
              <li className={styles.lastSaved}>
×
219
                <ArticleSaveState
×
220
                  state={workingArticle.state}
×
221
                  updatedAt={workingArticle.updatedAt}
×
222
                  stateMessage={workingArticle.stateMessage}
×
223
                />
×
224
              </li>
×
225
            )}
226
          </ul>
×
227
        </div>
×
228
      </section>
×
229
    </>
×
230
  )
231
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc