import React, { useState, useEffect, useRef, useMemo, useCallback, } from 'react'; import { UserPicture } from '@growi/ui'; import CodeMirror from 'codemirror/lib/codemirror'; import { format } from 'date-fns'; import { useTranslation } from 'next-i18next'; import { Modal, ModalHeader, ModalBody, ModalFooter, } from 'reactstrap'; import { IUser } from '~/interfaces/user'; import { useCurrentUser } from '~/stores/context'; import { useEditorMode } from '~/stores/ui'; import PageContainer from '../../client/services/PageContainer'; import { IRevisionOnConflict } from '../../interfaces/revision'; import ExpandOrContractButton from '../ExpandOrContractButton'; import { UncontrolledCodeMirror } from '../UncontrolledCodeMirror'; require('codemirror/lib/codemirror.css'); require('codemirror/addon/merge/merge'); require('codemirror/addon/merge/merge.css'); const DMP = require('diff_match_patch'); Object.keys(DMP).forEach((key) => { window[key] = DMP[key] }); type ConflictDiffModalProps = { isOpen?: boolean; onClose?: (() => void); pageContainer: PageContainer; markdownOnEdit: string; }; type IRevisionOnConflictWithStringDate = Omit & { createdAt: string } const ConflictDiffModalCore = (props: ConflictDiffModalProps & { currentUser: IUser }): JSX.Element => { const { currentUser, pageContainer, onClose } = props; const { data: editorMode } = useEditorMode(); const { t } = useTranslation(''); const [resolvedRevision, setResolvedRevision] = useState(''); const [isRevisionselected, setIsRevisionSelected] = useState(false); const [isModalExpanded, setIsModalExpanded] = useState(false); const [codeMirrorRef, setCodeMirrorRef] = useState(null); const uncontrolledRef = useRef(null); const currentTime: Date = new Date(); const request: IRevisionOnConflictWithStringDate = { revisionId: '', revisionBody: props.markdownOnEdit, createdAt: format(currentTime, 'yyyy/MM/dd HH:mm:ss'), user: currentUser, }; const origin: IRevisionOnConflictWithStringDate = { revisionId: pageContainer.state.revisionId || '', revisionBody: pageContainer.state.markdown || '', createdAt: pageContainer.state.updatedAt || '', user: pageContainer.state.revisionAuthor, }; const latest: IRevisionOnConflictWithStringDate = { revisionId: pageContainer.state.remoteRevisionId || '', revisionBody: pageContainer.state.remoteRevisionBody || '', createdAt: format(new Date(pageContainer.state.remoteRevisionUpdateAt || currentTime.toString()), 'yyyy/MM/dd HH:mm:ss'), user: pageContainer.state.lastUpdateUser, }; useEffect(() => { if (codeMirrorRef != null) { CodeMirror.MergeView(codeMirrorRef, { value: origin.revisionBody, origLeft: request.revisionBody, origRight: latest.revisionBody, lineNumbers: true, collapseIdentical: true, showDifferences: true, highlightDifferences: true, connect: 'connect', readOnly: true, revertButtons: false, }); } }, [codeMirrorRef, origin.revisionBody, request.revisionBody, latest.revisionBody]); const close = useCallback(() => { if (onClose != null) { onClose(); } }, [onClose]); const onResolveConflict = useCallback(async() => { // disable button after clicked setIsRevisionSelected(false); const codeMirrorVal = uncontrolledRef.current?.editor.doc.getValue(); try { await pageContainer.resolveConflict(codeMirrorVal, editorMode); close(); pageContainer.showSuccessToastr(); } catch (error) { pageContainer.showErrorToastr(error); } }, [editorMode, close, pageContainer]); const resizeAndCloseButtons = useMemo(() => (
setIsModalExpanded(true)} contractWindow={() => setIsModalExpanded(false)} />
), [isModalExpanded, close]); const isOpen = props.isOpen ?? false; return ( {t('modal_resolve_conflict.resolve_conflict')} { isOpen && (

{t('modal_resolve_conflict.resolve_conflict_message')}

{t('modal_resolve_conflict.requested_revision')}

updated by {request.user.username}

{request.createdAt}

{t('modal_resolve_conflict.origin_revision')}

updated by {origin.user.username}

{origin.createdAt}

{t('modal_resolve_conflict.latest_revision')}

updated by {latest.user.username}

{latest.createdAt}

{ setCodeMirrorRef(el) }}>

{t('modal_resolve_conflict.selected_editable_revision')}

)}
); }; export const ConflictDiffModal = (props: ConflictDiffModalProps): JSX.Element => { const { isOpen } = props; const { data: currentUser } = useCurrentUser(); if (!isOpen || currentUser == null) { return <>; } return ; };