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

EcrituresNumeriques / stylo / 14590466161

22 Apr 2025 08:38AM UTC coverage: 23.098%. First build
14590466161

Pull #1435

github

web-flow
Merge 393f0de6c into 12659232d
Pull Request #1435: chore: charge l'éditeur Monaco avec un loader (webworker)

319 of 519 branches covered (61.46%)

Branch coverage included in aggregate %.

0 of 30 new or added lines in 5 files covered. (0.0%)

2611 of 12166 relevant lines covered (21.46%)

2.49 hits per line

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

0.0
/front/src/components/collaborative/CollaborativeTextEditor.jsx
1
import Editor from '@monaco-editor/react'
×
2
import clsx from 'clsx'
×
3
import throttle from 'lodash.throttle'
×
4
import React, { useCallback, useEffect, useMemo, useRef } from 'react'
×
5
import { shallowEqual, useDispatch, useSelector } from 'react-redux'
×
6
import { MonacoBinding } from 'y-monaco'
×
7
import { useArticleVersion } from '../../hooks/article.js'
×
8
import { useCollaboration } from '../../hooks/collaboration.js'
×
9
import Alert from '../molecules/Alert.jsx'
×
10

11
import Loading from '../molecules/Loading.jsx'
×
12
import defaultEditorOptions from '../Write/providers/monaco/options.js'
×
13
import CollaborativeEditorStatus from './CollaborativeEditorStatus.jsx'
×
14
import CollaborativeEditorWebSocketStatus from './CollaborativeEditorWebSocketStatus.jsx'
×
15

16
import styles from './CollaborativeTextEditor.module.scss'
×
NEW
17
import MonacoEditor from '../molecules/MonacoEditor.jsx'
×
18

19
/**
20
 * @param {object} props
21
 * @param {string} props.articleId
22
 * @param {string|undefined} props.versionId
23
 * @returns {Element}
24
 */
25
export default function CollaborativeTextEditor({ articleId, versionId }) {
×
26
  const { yText, awareness, websocketStatus, dynamicStyles } = useCollaboration(
×
27
    { articleId, versionId }
×
28
  )
×
29
  const { version, error, isLoading } = useArticleVersion({ versionId })
×
30
  const dispatch = useDispatch()
×
31
  const editorRef = useRef(null)
×
32
  const editorCursorPosition = useSelector(
×
33
    (state) => state.editorCursorPosition,
×
34
    shallowEqual
×
35
  )
×
36

37
  const hasVersion = useMemo(() => !!versionId, [versionId])
×
38

39
  const options = useMemo(
×
40
    () => ({
×
41
      ...defaultEditorOptions,
×
42
      contextmenu: hasVersion ? false : websocketStatus === 'connected',
×
43
      readOnly: hasVersion ? true : websocketStatus !== 'connected',
×
44
    }),
×
45
    [websocketStatus, hasVersion]
×
46
  )
×
47

48
  const handleUpdateArticleStructureAndStats = throttle(
×
49
    ({ text }) => {
×
50
      dispatch({ type: 'UPDATE_ARTICLE_STATS', md: text })
×
51
      dispatch({ type: 'UPDATE_ARTICLE_STRUCTURE', md: text })
×
52
    },
×
53
    250,
×
54
    { leading: false, trailing: true }
×
55
  )
×
56

57
  const handleCollaborativeEditorDidMount = useCallback(
×
58
    (editor) => {
×
59
      editorRef.current = editor
×
60
      if (yText && awareness) {
×
61
        new MonacoBinding(
×
62
          yText,
×
63
          editor.getModel(),
×
64
          new Set([editor]),
×
65
          awareness
×
66
        )
×
67
      }
×
68
    },
×
69
    [yText, awareness]
×
70
  )
×
71

72
  const handleEditorDidMount = useCallback((editor) => {
×
73
    editorRef.current = editor
×
74
  }, [])
×
75

76
  let timeoutId
×
77
  useEffect(() => {
×
78
    if (yText) {
×
79
      yText.observe(function () {
×
80
        dispatch({
×
81
          type: 'UPDATE_ARTICLE_WORKING_COPY_STATUS',
×
82
          status: 'syncing',
×
83
        })
×
84
        if (timeoutId) {
×
85
          clearTimeout(timeoutId)
×
86
        }
×
87
        timeoutId = setTimeout(() => {
×
88
          dispatch({
×
89
            type: 'UPDATE_ARTICLE_WORKING_COPY_STATUS',
×
90
            status: 'synced',
×
91
          })
×
92
        }, 4000)
×
93

94
        handleUpdateArticleStructureAndStats({ text: yText.toString() })
×
95
      })
×
96
    }
×
97
  }, [yText])
×
98

99
  useEffect(() => {
×
100
    if (version) {
×
101
      dispatch({ type: 'UPDATE_ARTICLE_STATS', md: version.md })
×
102
      dispatch({ type: 'UPDATE_ARTICLE_STRUCTURE', md: version.md })
×
103
    }
×
104
  }, [version])
×
105

106
  useEffect(() => {
×
107
    const line = editorCursorPosition.lineNumber
×
108
    const editor = editorRef.current
×
109
    editor?.focus()
×
110
    const endOfLineColumn = editor?.getModel()?.getLineMaxColumn(line + 1)
×
111
    editor?.setPosition({ lineNumber: line + 1, column: endOfLineColumn })
×
112
    editor?.revealLineNearTop(line + 1, 1) // smooth
×
113
  }, [editorRef, editorCursorPosition])
×
114

115
  if (!yText && !version) {
×
116
    return <Loading />
×
117
  }
×
118

119
  if (isLoading) {
×
120
    return <Loading />
×
121
  }
×
122

123
  if (error) {
×
124
    return <Alert message={error.message} />
×
125
  }
×
126

127
  return (
×
128
    <>
×
129
      <style>{dynamicStyles}</style>
×
130
      <CollaborativeEditorStatus versionId={versionId} />
×
131
      <div className={styles.inlineStatus}>
×
132
        <CollaborativeEditorWebSocketStatus status={websocketStatus} />
×
133
      </div>
×
134
      {version && (
×
NEW
135
        <MonacoEditor
×
136
          width={'100%'}
×
137
          height={'auto'}
×
138
          value={version.md}
×
139
          options={options}
×
140
          className={styles.editor}
×
141
          defaultLanguage="markdown"
×
142
          onMount={handleEditorDidMount}
×
143
        />
×
144
      )}
145
      <div
×
146
        className={clsx(styles.collaborativeEditor, versionId && styles.hidden)}
×
147
      >
NEW
148
        <MonacoEditor
×
149
          width={'100%'}
×
150
          height={'auto'}
×
151
          options={options}
×
152
          className={styles.editor}
×
153
          defaultLanguage="markdown"
×
154
          onMount={handleCollaborativeEditorDidMount}
×
155
        />
×
156
      </div>
×
157
    </>
×
158
  )
159
}
×
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