From 9706f989ecfc560de7d4c30184f5cc340eddc18c Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Mon, 15 Jan 2024 12:58:55 +0530 Subject: [PATCH 01/50] added states for handling merge UI --- renderer/src/components/Projects/ProjectRow.js | 17 +++++++++++++++++ .../hooks/projects/useProjectsSort.js | 3 +++ 2 files changed, 20 insertions(+) diff --git a/renderer/src/components/Projects/ProjectRow.js b/renderer/src/components/Projects/ProjectRow.js index 310f91eb9..9d746ce84 100644 --- a/renderer/src/components/Projects/ProjectRow.js +++ b/renderer/src/components/Projects/ProjectRow.js @@ -34,6 +34,7 @@ const ProjectRow = ({ setNotifications, setCallEditProject, setActiveNotificationCount, + setOpenTextTranslationMerge, }, } = useContext(AutographaContext); @@ -204,6 +205,22 @@ const ProjectRow = ({ )} + {project.type === 'Text Translation' && ( + + + {({ active }) => ( + + )} + + )} {({ active }) => ( + + + {/* contents section */} + content + + + + + modalClose()} + confirmMessage={model.confirmMessage} + buttonName={model.buttonName} + closeModal={() => handleOnAbortMerge()} + /> + + ); +} + +export default TranslationMergeUI; From d5b928e200a22cdf9a90372629314b4eb00b0577 Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Mon, 15 Jan 2024 14:44:05 +0530 Subject: [PATCH 03/50] import file function added --- .../src/components/Projects/ProjectRow.js | 2 +- .../TranslationMergNavBar.jsx | 36 +++++++++ .../TranslationMergeUI.jsx | 76 +++++++++++++++++-- .../hooks/projects/useProjectsSort.js | 5 +- 4 files changed, 110 insertions(+), 9 deletions(-) create mode 100644 renderer/src/components/TextTranslationMerge/TranslationMergNavBar.jsx diff --git a/renderer/src/components/Projects/ProjectRow.js b/renderer/src/components/Projects/ProjectRow.js index 9d746ce84..196f4ea70 100644 --- a/renderer/src/components/Projects/ProjectRow.js +++ b/renderer/src/components/Projects/ProjectRow.js @@ -214,7 +214,7 @@ const ProjectRow = ({ aria-label="edit-project" className={`${active ? 'bg-primary text-white' : 'text-gray-900' } group rounded-md items-center w-full px-2 py-2 text-sm ${project.isArchived ? 'hidden' : 'flex'}`} - onClick={() => setOpenTextTranslationMerge(true)} + onClick={() => setOpenTextTranslationMerge({ open: true, meta: project })} > {t('label-merge')} diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergNavBar.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergNavBar.jsx new file mode 100644 index 000000000..06bb513d0 --- /dev/null +++ b/renderer/src/components/TextTranslationMerge/TranslationMergNavBar.jsx @@ -0,0 +1,36 @@ +// import { Cog8ToothIcon } from '@heroicons/react/24/outline'; +import { useTranslation } from 'react-i18next'; + +function TranslationMergNavBar({ + conflictData, setSelectedFileName, selectedFileName, resolvedFileNames, +}) { + const { t } = useTranslation(); + return ( +
+
+ + {` ${t('label-book')} - ${conflictData?.data?.files?.filepaths.length || ''}`} + + {/* */} +
+
    + {conflictData?.data?.files?.filepaths?.sort()?.map((file) => ( +
  • setSelectedFileName(file)} + aria-disabled={resolvedFileNames.includes(file)} + className={`px-5 py-2 ${resolvedFileNames.includes(file) + ? 'line-through decoration-2 pointer-events-none' + : `${selectedFileName === file ? 'bg-primary/70' : 'hover:bg-primary cursor-pointer'}`} `} + > + {file} +
  • + ))} +
+
+ ); +} + +export default TranslationMergNavBar; diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index 44ab31d7d..9e3aeb1a0 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -6,8 +6,13 @@ import { AutographaContext } from '@/components/context/AutographaContext'; import { useTranslation } from 'react-i18next'; import { XMarkIcon } from '@heroicons/react/24/outline'; import ConfirmationModal from '@/layouts/editor/ConfirmationModal'; +import TranslationMergNavBar from './TranslationMergNavBar'; +import * as logger from '../../logger'; +import useGetCurrentProjectMeta from '../Sync/hooks/useGetCurrentProjectMeta'; function TranslationMergeUI() { + const [importedUsfmFolderPath, setImportedUsfmFolderPath] = useState([]); + const { states: { openTextTranslationMerge, @@ -26,6 +31,13 @@ function TranslationMergeUI() { buttonName: '', }); + const { + state: { currentProjectMeta }, + actions: { getProjectMeta }, + } = useGetCurrentProjectMeta(); + + // console.log({ openTextTranslationMerge, currentProjectMeta, importedUsfmFolderPath }); + const modalClose = () => { setModel({ openModel: false, @@ -50,16 +62,43 @@ function TranslationMergeUI() { }; const handleOnAbortMerge = () => { - console.log('Agreed on abort'); modalClose(); - setOpenTextTranslationMerge(false); + setOpenTextTranslationMerge({ open: false, meta: null }); + }; + + useEffect(() => { + if (openTextTranslationMerge?.meta && !currentProjectMeta) { + const { id, name } = openTextTranslationMerge.meta; + (async () => { + await getProjectMeta(`${name}_${id[0]}`); + })(); + } + }, []); + + const openFileDialogSettingData = async () => { + logger.debug('translationMergeUI.js', 'Inside openFileDialogSettingData'); + const options = { + properties: ['openFile'], + filters: [{ name: 'usfm files', extensions: ['usfm', 'sfm', 'USFM', 'SFM'] }], + }; + const { dialog } = window.require('@electron/remote'); + const chosenFolder = await dialog.showOpenDialog(options); + if ((chosenFolder.filePaths).length > 0) { + logger.debug('translationMergeUI.js', 'Selected the files'); + setImportedUsfmFolderPath(chosenFolder.filePaths); + } else { + logger.debug('translationMergeUI.js', 'Didn\'t select any file'); + } + }; + + const handleImportUsfm = () => { + openFileDialogSettingData(); }; return ( <> - removeSection(true)} >
-
+

{t('label-resolve-conflict')}

{/* close btn section */} @@ -93,7 +132,30 @@ function TranslationMergeUI() {
{/* contents section */} - content +
+
+ +
+
+
+ Project Scope : + {Object.keys(currentProjectMeta?.type?.flavorType?.currentScope).map((scope) => ( + {scope} + ))} + +
+ +
+
Footer
+
+
+
diff --git a/renderer/src/components/hooks/projects/useProjectsSort.js b/renderer/src/components/hooks/projects/useProjectsSort.js index 5320778b4..992dd8fbe 100644 --- a/renderer/src/components/hooks/projects/useProjectsSort.js +++ b/renderer/src/components/hooks/projects/useProjectsSort.js @@ -24,7 +24,10 @@ function useProjectsSort() { const [callEditProject, setCallEditProject] = React.useState(false); const [loading, setLoading] = React.useState(false); const [activeNotificationCount, setActiveNotificationCount] = React.useState(0); - const [openTextTranslationMerge, setOpenTextTranslationMerge] = React.useState(false); + const [openTextTranslationMerge, setOpenTextTranslationMerge] = React.useState({ + open: false, + meta: null, + }); const starrtedData = []; const unstarrtedData = []; From d3985a58fb62b6a697203c38e9b0537959d1d399 Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Mon, 15 Jan 2024 15:35:56 +0530 Subject: [PATCH 04/50] added fucntions to read and parse impoted file and check the same file in the current project --- .../TranslationMergeUI.jsx | 92 +++++++++++++++---- 1 file changed, 75 insertions(+), 17 deletions(-) diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index 9e3aeb1a0..d3c1a3e89 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -9,9 +9,18 @@ import ConfirmationModal from '@/layouts/editor/ConfirmationModal'; import TranslationMergNavBar from './TranslationMergNavBar'; import * as logger from '../../logger'; import useGetCurrentProjectMeta from '../Sync/hooks/useGetCurrentProjectMeta'; +import LoadingScreen from '../Loading/LoadingScreen'; + +const grammar = require('usfm-grammar'); function TranslationMergeUI() { const [importedUsfmFolderPath, setImportedUsfmFolderPath] = useState([]); + const [files, setFiles] = useState({ + imported: null, + current: null, + }); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(''); const { states: { @@ -36,7 +45,9 @@ function TranslationMergeUI() { actions: { getProjectMeta }, } = useGetCurrentProjectMeta(); - // console.log({ openTextTranslationMerge, currentProjectMeta, importedUsfmFolderPath }); + console.log({ + openTextTranslationMerge, currentProjectMeta, importedUsfmFolderPath, files, + }); const modalClose = () => { setModel({ @@ -62,8 +73,11 @@ function TranslationMergeUI() { }; const handleOnAbortMerge = () => { - modalClose(); + setError(''); + setFiles({ imported: null, current: null }); + setImportedUsfmFolderPath([]); setOpenTextTranslationMerge({ open: false, meta: null }); + modalClose(); }; useEffect(() => { @@ -95,6 +109,42 @@ function TranslationMergeUI() { openFileDialogSettingData(); }; + async function readAndParseUsfm(filePath) { + const fs = window.require('fs'); + const usfm = fs.readFileSync(filePath, 'utf8'); + const myUsfmParser = new grammar.USFMParser(usfm, grammar.LEVEL.RELAXED); + const isJsonValid = myUsfmParser.validate(); + return { valid: isJsonValid, data: myUsfmParser.toJSON() }; + } + + const parseFiles = async () => { + // parse imported + console.log('started parsing'); + const importedJson = await readAndParseUsfm(importedUsfmFolderPath[0]); + if (!importedJson.valid) { + setError('Imported Usfm is invalid'); + } else if (!Object.keys(currentProjectMeta?.type?.flavorType?.currentScope).includes(importedJson?.data?.book?.bookCode) + && !Object.keys(currentProjectMeta?.type?.flavorType?.currentScope).includes(importedJson?.data?.book?.bookCode?.toLowerCase())) { + setError('Imported USFM is not in the scope of Current Project'); + } else { + setError(''); + setFiles((prev) => ({ ...prev, imported: importedJson.data })); + // Parse current project same book + const importedBookCode = `${importedJson.data.book.bookCode.toLowerCase()}.usfm`; + const currentBookPath = Object.keys(currentProjectMeta?.ingredients).find((code) => code.toLowerCase().endsWith(importedBookCode)); + console.log('FOUND ====> ', { currentBookPath }); + } + setLoading(false); + }; + + useEffect(() => { + // get usfm and parse + if (importedUsfmFolderPath.length === 1 && currentProjectMeta) { + setLoading(true); + parseFiles(); + } + }, [importedUsfmFolderPath, currentProjectMeta]); + return ( <>
-
- Project Scope : - {Object.keys(currentProjectMeta?.type?.flavorType?.currentScope).map((scope) => ( - {scope} - ))} - -
- + + {loading ? () : ( + <> +
+ Project Scope : + {currentProjectMeta && Object.keys(currentProjectMeta?.type?.flavorType?.currentScope).map((scope) => ( + {scope} + ))} + +
+ + + )} + +
+
+

{error}

-
Footer
From 3d4e8f1ebeb615b2603dc410c699e4912064e1f4 Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Mon, 15 Jan 2024 15:50:32 +0530 Subject: [PATCH 05/50] added util function to read usfm from a project --- renderer/src/core/projects/userSettings.js | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/renderer/src/core/projects/userSettings.js b/renderer/src/core/projects/userSettings.js index 4ea179167..a8359a764 100644 --- a/renderer/src/core/projects/userSettings.js +++ b/renderer/src/core/projects/userSettings.js @@ -109,3 +109,26 @@ export const saveUserSettings = async (userSettingsJson) => { throw new Error(err?.message || err); } }; + +// this will read usfm file based on path name / bookname (eg : ingredients/MAT.usfm) +export const readUsfmFile = async (filename, projectName) => { + try { + logger.debug('userSettings.js', 'In readUsfm file'); + const currentUser = await localForage.getItem('userProfile'); + const newpath = localStorage.getItem('userPath'); + const fs = window.require('fs'); + const path = require('path'); + const file = path.join(newpath, packageInfo.name, 'users', currentUser.username, 'projects', projectName, filename); + if (fs.existsSync(file)) { + const usfm = await fs.readFileSync(file); + if (usfm) { + logger.debug('userSettings.js', 'read usfm file successfully'); + return usfm; + } + + throw new Error('failed to read usfm file'); + } + } catch (err) { + throw new Error(err?.message || err); + } +}; From afab4e80450cf309ea50e7d62eacbd759ceb2c9b Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Mon, 15 Jan 2024 16:13:25 +0530 Subject: [PATCH 06/50] getting parsed usfm json for imported and exisiting --- .../src/components/Projects/ProjectList.js | 5 +- .../TranslationMergeUI.jsx | 50 ++++++++++++------- renderer/src/core/projects/userSettings.js | 2 +- 3 files changed, 35 insertions(+), 22 deletions(-) diff --git a/renderer/src/components/Projects/ProjectList.js b/renderer/src/components/Projects/ProjectList.js index 6880ca526..a9bacd918 100644 --- a/renderer/src/components/Projects/ProjectList.js +++ b/renderer/src/components/Projects/ProjectList.js @@ -30,6 +30,7 @@ export default function ProjectList() { projects, // unstarredProjects, callEditProject, + openTextTranslationMerge, }, action: { handleClickStarred, @@ -54,7 +55,7 @@ export default function ProjectList() { }; const closeEditProject = async () => { - logger.debug('ProjectList.js', 'Closing edit project page and updating the values'); + logger.debug('ProjectList.js', 'Closing edit project page and updating the valuesd'); setCallEditProject(false); await FetchProjects(); }; @@ -103,7 +104,7 @@ export default function ProjectList() { ) : closeEditProject()} />} - + {openTextTranslationMerge.open && } ); } diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index d3c1a3e89..cd4e836b4 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -6,6 +6,7 @@ import { AutographaContext } from '@/components/context/AutographaContext'; import { useTranslation } from 'react-i18next'; import { XMarkIcon } from '@heroicons/react/24/outline'; import ConfirmationModal from '@/layouts/editor/ConfirmationModal'; +import { readUsfmFile } from '@/core/projects/userSettings'; import TranslationMergNavBar from './TranslationMergNavBar'; import * as logger from '../../logger'; import useGetCurrentProjectMeta from '../Sync/hooks/useGetCurrentProjectMeta'; @@ -15,7 +16,7 @@ const grammar = require('usfm-grammar'); function TranslationMergeUI() { const [importedUsfmFolderPath, setImportedUsfmFolderPath] = useState([]); - const [files, setFiles] = useState({ + const [usfmJsons, setUsfmJsons] = useState({ imported: null, current: null, }); @@ -46,7 +47,7 @@ function TranslationMergeUI() { } = useGetCurrentProjectMeta(); console.log({ - openTextTranslationMerge, currentProjectMeta, importedUsfmFolderPath, files, + openTextTranslationMerge, currentProjectMeta, importedUsfmFolderPath, usfmJsons, }); const modalClose = () => { @@ -74,14 +75,15 @@ function TranslationMergeUI() { const handleOnAbortMerge = () => { setError(''); - setFiles({ imported: null, current: null }); + setUsfmJsons({ imported: null, current: null }); setImportedUsfmFolderPath([]); setOpenTextTranslationMerge({ open: false, meta: null }); modalClose(); }; useEffect(() => { - if (openTextTranslationMerge?.meta && !currentProjectMeta) { + console.log('in call meta : '); + if (openTextTranslationMerge?.meta) { const { id, name } = openTextTranslationMerge.meta; (async () => { await getProjectMeta(`${name}_${id[0]}`); @@ -109,9 +111,7 @@ function TranslationMergeUI() { openFileDialogSettingData(); }; - async function readAndParseUsfm(filePath) { - const fs = window.require('fs'); - const usfm = fs.readFileSync(filePath, 'utf8'); + async function parseUsfm(usfm) { const myUsfmParser = new grammar.USFMParser(usfm, grammar.LEVEL.RELAXED); const isJsonValid = myUsfmParser.validate(); return { valid: isJsonValid, data: myUsfmParser.toJSON() }; @@ -120,19 +120,31 @@ function TranslationMergeUI() { const parseFiles = async () => { // parse imported console.log('started parsing'); - const importedJson = await readAndParseUsfm(importedUsfmFolderPath[0]); - if (!importedJson.valid) { - setError('Imported Usfm is invalid'); - } else if (!Object.keys(currentProjectMeta?.type?.flavorType?.currentScope).includes(importedJson?.data?.book?.bookCode) - && !Object.keys(currentProjectMeta?.type?.flavorType?.currentScope).includes(importedJson?.data?.book?.bookCode?.toLowerCase())) { - setError('Imported USFM is not in the scope of Current Project'); + const fs = window.require('fs'); + const readUsfm = fs.readFileSync(importedUsfmFolderPath[0], 'utf8'); + if (readUsfm) { + const importedJson = await parseUsfm(readUsfm); + if (!importedJson.valid) { + setError('Imported Usfm is invalid'); + } else if (!Object.keys(currentProjectMeta?.type?.flavorType?.currentScope).includes(importedJson?.data?.book?.bookCode) + && !Object.keys(currentProjectMeta?.type?.flavorType?.currentScope).includes(importedJson?.data?.book?.bookCode?.toLowerCase())) { + setError('Imported USFM is not in the scope of Current Project'); + } else { + setError(''); + setUsfmJsons((prev) => ({ ...prev, imported: importedJson.data })); + // Parse current project same book + const importedBookCode = `${importedJson.data.book.bookCode.toLowerCase()}.usfm`; + const currentBookPath = Object.keys(currentProjectMeta?.ingredients).find((code) => code.toLowerCase().endsWith(importedBookCode)); + const { id, name } = openTextTranslationMerge.meta; + const currentBookUsfm = await readUsfmFile(currentBookPath, `${name}_${id[0]}`); + console.log('FOUND ====> ', { currentBookPath, currentBookUsfm }); + if (currentBookUsfm) { + const currentJson = await parseUsfm(currentBookUsfm); + currentJson && currentJson?.valid && setUsfmJsons((prev) => ({ ...prev, current: currentJson.data })); + } + } } else { - setError(''); - setFiles((prev) => ({ ...prev, imported: importedJson.data })); - // Parse current project same book - const importedBookCode = `${importedJson.data.book.bookCode.toLowerCase()}.usfm`; - const currentBookPath = Object.keys(currentProjectMeta?.ingredients).find((code) => code.toLowerCase().endsWith(importedBookCode)); - console.log('FOUND ====> ', { currentBookPath }); + setError('unable to read imported USFM'); } setLoading(false); }; diff --git a/renderer/src/core/projects/userSettings.js b/renderer/src/core/projects/userSettings.js index a8359a764..b0e8b4fb4 100644 --- a/renderer/src/core/projects/userSettings.js +++ b/renderer/src/core/projects/userSettings.js @@ -120,7 +120,7 @@ export const readUsfmFile = async (filename, projectName) => { const path = require('path'); const file = path.join(newpath, packageInfo.name, 'users', currentUser.username, 'projects', projectName, filename); if (fs.existsSync(file)) { - const usfm = await fs.readFileSync(file); + const usfm = await fs.readFileSync(file, 'utf-8'); if (usfm) { logger.debug('userSettings.js', 'read usfm file successfully'); return usfm; From f6a51db63d7d5750ee3703083bc3aad4a6cad3d7 Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Mon, 15 Jan 2024 17:00:00 +0530 Subject: [PATCH 07/50] parsed usfm --- .../TextTranslationMerge/TranslationMergeUI.jsx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index cd4e836b4..bc1d214ec 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -117,6 +117,12 @@ function TranslationMergeUI() { return { valid: isJsonValid, data: myUsfmParser.toJSON() }; } + async function parseJsonToUsfm(json) { + const myUsfmParser = new grammar.JSONParser(json); + const usfm = myUsfmParser.toUSFM(); + return usfm; + } + const parseFiles = async () => { // parse imported console.log('started parsing'); @@ -149,6 +155,12 @@ function TranslationMergeUI() { setLoading(false); }; + const testToUsfm = async () => { + const json = { book: usfmJsons.current.book, chapters: [usfmJsons.current.chapters[0]] }; + const data = await parseJsonToUsfm(json); + console.log({ data }); + }; + useEffect(() => { // get usfm and parse if (importedUsfmFolderPath.length === 1 && currentProjectMeta) { @@ -219,6 +231,8 @@ function TranslationMergeUI() { )} + +

{error}

From 9da3d4c15cc8dc20c3df7b2e342e1e89dde1e014 Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Wed, 17 Jan 2024 09:31:08 +0530 Subject: [PATCH 08/50] added chapters number and book in nav ui --- .../TranslationMergNavBar.jsx | 42 ++++++++++--------- .../TranslationMergeUI.jsx | 11 ++++- 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergNavBar.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergNavBar.jsx index 06bb513d0..45a6b9b30 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergNavBar.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergNavBar.jsx @@ -2,33 +2,37 @@ import { useTranslation } from 'react-i18next'; function TranslationMergNavBar({ - conflictData, setSelectedFileName, selectedFileName, resolvedFileNames, + currentUsfmJson, setSelectedChapter, selectedChapter, resolvedFileNames, }) { const { t } = useTranslation(); + console.log({ currentUsfmJson }); return ( -
+
- {` ${t('label-book')} - ${conflictData?.data?.files?.filepaths.length || ''}`} + {` ${t('label-book')} - ${currentUsfmJson?.book?.bookCode || ''}`} {/* */}
-
    - {conflictData?.data?.files?.filepaths?.sort()?.map((file) => ( -
  • setSelectedFileName(file)} - aria-disabled={resolvedFileNames.includes(file)} - className={`px-5 py-2 ${resolvedFileNames.includes(file) - ? 'line-through decoration-2 pointer-events-none' - : `${selectedFileName === file ? 'bg-primary/70' : 'hover:bg-primary cursor-pointer'}`} `} - > - {file} -
  • - ))} -
+ +
+
    + {currentUsfmJson?.chapters?.map((chapter) => ( +
  • setSelectedChapter(chapter.chapterNumber)} + aria-disabled={resolvedFileNames.includes(chapter.chapterNumber)} + className={`px-5 py-2 ${resolvedFileNames.includes(chapter.chapterNumber) + ? 'line-through decoration-2 pointer-events-none' + : `${selectedChapter === chapter.chapterNumber ? 'bg-primary/70' : 'hover:bg-primary cursor-pointer'}`} `} + > + {chapter.chapterNumber} +
  • + ))} +
+
); } diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index bc1d214ec..17620c241 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -20,6 +20,9 @@ function TranslationMergeUI() { imported: null, current: null, }); + const [selectedChapter, setSelectedChapter] = useState(1); + const [resolvedFileNames, setResolvedFileNames] = useState([]); + const [loading, setLoading] = useState(false); const [error, setError] = useState(''); @@ -208,7 +211,13 @@ function TranslationMergeUI() { {/* contents section */}
- + +
From e0edd592f727676393824934b2f5736ea211fe25 Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Wed, 17 Jan 2024 09:42:13 +0530 Subject: [PATCH 09/50] added usfm conflict ui and import components --- .../TextTranslationMerge/ImportUsfmUI.jsx | 24 ++++++++++ .../TranslationMergeUI.jsx | 45 +++++++------------ .../UsfmConflictEditor.jsx | 9 ++++ 3 files changed, 49 insertions(+), 29 deletions(-) create mode 100644 renderer/src/components/TextTranslationMerge/ImportUsfmUI.jsx create mode 100644 renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx diff --git a/renderer/src/components/TextTranslationMerge/ImportUsfmUI.jsx b/renderer/src/components/TextTranslationMerge/ImportUsfmUI.jsx new file mode 100644 index 000000000..4067864cd --- /dev/null +++ b/renderer/src/components/TextTranslationMerge/ImportUsfmUI.jsx @@ -0,0 +1,24 @@ +import React from 'react'; + +function ImportUsfmUI({ currentProjectMeta, handleImportUsfm, buttonName }) { + return ( + <> +
+ Project Scope : + {currentProjectMeta && Object.keys(currentProjectMeta?.type?.flavorType?.currentScope).map((scope) => ( + {scope} + ))} + +
+ + + ); +} + +export default ImportUsfmUI; diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index 17620c241..daf5b9c88 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -1,3 +1,4 @@ +/* eslint-disable no-nested-ternary */ import React, { useRef, Fragment, useState, useEffect, useContext, } from 'react'; @@ -11,6 +12,8 @@ import TranslationMergNavBar from './TranslationMergNavBar'; import * as logger from '../../logger'; import useGetCurrentProjectMeta from '../Sync/hooks/useGetCurrentProjectMeta'; import LoadingScreen from '../Loading/LoadingScreen'; +import ImportUsfmUI from './ImportUsfmUI'; +import UsfmConflictEditor from './UsfmConflictEditor'; const grammar = require('usfm-grammar'); @@ -49,9 +52,7 @@ function TranslationMergeUI() { actions: { getProjectMeta }, } = useGetCurrentProjectMeta(); - console.log({ - openTextTranslationMerge, currentProjectMeta, importedUsfmFolderPath, usfmJsons, - }); + console.log({ openTextTranslationMerge, currentProjectMeta }); const modalClose = () => { setModel({ @@ -85,7 +86,6 @@ function TranslationMergeUI() { }; useEffect(() => { - console.log('in call meta : '); if (openTextTranslationMerge?.meta) { const { id, name } = openTextTranslationMerge.meta; (async () => { @@ -128,7 +128,6 @@ function TranslationMergeUI() { const parseFiles = async () => { // parse imported - console.log('started parsing'); const fs = window.require('fs'); const readUsfm = fs.readFileSync(importedUsfmFolderPath[0], 'utf8'); if (readUsfm) { @@ -146,7 +145,7 @@ function TranslationMergeUI() { const currentBookPath = Object.keys(currentProjectMeta?.ingredients).find((code) => code.toLowerCase().endsWith(importedBookCode)); const { id, name } = openTextTranslationMerge.meta; const currentBookUsfm = await readUsfmFile(currentBookPath, `${name}_${id[0]}`); - console.log('FOUND ====> ', { currentBookPath, currentBookUsfm }); + // console.log('FOUND ====> ', { currentBookPath, currentBookUsfm }); if (currentBookUsfm) { const currentJson = await parseUsfm(currentBookUsfm); currentJson && currentJson?.valid && setUsfmJsons((prev) => ({ ...prev, current: currentJson.data })); @@ -158,12 +157,6 @@ function TranslationMergeUI() { setLoading(false); }; - const testToUsfm = async () => { - const json = { book: usfmJsons.current.book, chapters: [usfmJsons.current.chapters[0]] }; - const data = await parseJsonToUsfm(json); - console.log({ data }); - }; - useEffect(() => { // get usfm and parse if (importedUsfmFolderPath.length === 1 && currentProjectMeta) { @@ -222,25 +215,19 @@ function TranslationMergeUI() {
{loading ? () : ( - <> -
- Project Scope : - {currentProjectMeta && Object.keys(currentProjectMeta?.type?.flavorType?.currentScope).map((scope) => ( - {scope} - ))} -
- - - )} + (usfmJsons.current && usfmJsons.imported) ? ( + + ) + : ( + + ) - + )}
diff --git a/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx b/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx new file mode 100644 index 000000000..d553a5ef7 --- /dev/null +++ b/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx @@ -0,0 +1,9 @@ +import React from 'react'; + +function UsfmConflictEditor({ usfmJsons }) { + return ( +
UsfmConflictEditor
+ ); +} + +export default UsfmConflictEditor; From f629c45ee566c863d9f4a9abf5a732d9906bd9d1 Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Wed, 17 Jan 2024 11:23:25 +0530 Subject: [PATCH 10/50] sample render of usfm diff for test --- package.json | 1 + .../TranslationMergeUI.jsx | 20 ++++++++++++++----- .../UsfmConflictEditor.jsx | 20 ++++++++++++++++++- yarn.lock | 5 +++++ 4 files changed, 40 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 78dfc3661..fc21a2746 100644 --- a/package.json +++ b/package.json @@ -138,6 +138,7 @@ "bible-reference-rcl": "1.1.0", "clsx": "1.1.1", "crypto-js": "^4.1.1", + "diff-match-patch": "^1.0.5", "dotenv": "^16.3.1", "electron-is-dev": "^2.0.0", "electron-log": "4.4.7", diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index daf5b9c88..54ffcf9fb 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -1,6 +1,6 @@ /* eslint-disable no-nested-ternary */ import React, { - useRef, Fragment, useState, useEffect, useContext, + useRef, Fragment, useState, useEffect, useContext, useMemo, } from 'react'; import { Dialog, Transition } from '@headlessui/react'; import { AutographaContext } from '@/components/context/AutographaContext'; @@ -8,6 +8,7 @@ import { useTranslation } from 'react-i18next'; import { XMarkIcon } from '@heroicons/react/24/outline'; import ConfirmationModal from '@/layouts/editor/ConfirmationModal'; import { readUsfmFile } from '@/core/projects/userSettings'; +import DiffMatchPatch from 'diff-match-patch'; import TranslationMergNavBar from './TranslationMergNavBar'; import * as logger from '../../logger'; import useGetCurrentProjectMeta from '../Sync/hooks/useGetCurrentProjectMeta'; @@ -17,11 +18,14 @@ import UsfmConflictEditor from './UsfmConflictEditor'; const grammar = require('usfm-grammar'); +const dmp = new DiffMatchPatch(); + function TranslationMergeUI() { const [importedUsfmFolderPath, setImportedUsfmFolderPath] = useState([]); const [usfmJsons, setUsfmJsons] = useState({ imported: null, current: null, + diffOut: null, }); const [selectedChapter, setSelectedChapter] = useState(1); const [resolvedFileNames, setResolvedFileNames] = useState([]); @@ -129,9 +133,9 @@ function TranslationMergeUI() { const parseFiles = async () => { // parse imported const fs = window.require('fs'); - const readUsfm = fs.readFileSync(importedUsfmFolderPath[0], 'utf8'); - if (readUsfm) { - const importedJson = await parseUsfm(readUsfm); + const IncomingUsfm = fs.readFileSync(importedUsfmFolderPath[0], 'utf8'); + if (IncomingUsfm) { + const importedJson = await parseUsfm(IncomingUsfm); if (!importedJson.valid) { setError('Imported Usfm is invalid'); } else if (!Object.keys(currentProjectMeta?.type?.flavorType?.currentScope).includes(importedJson?.data?.book?.bookCode) @@ -149,6 +153,10 @@ function TranslationMergeUI() { if (currentBookUsfm) { const currentJson = await parseUsfm(currentBookUsfm); currentJson && currentJson?.valid && setUsfmJsons((prev) => ({ ...prev, current: currentJson.data })); + + // compare usfms to check conflcit or not + const diffOut = await dmp.diff_main(IncomingUsfm, currentBookUsfm); + setUsfmJsons((prev) => ({ ...prev, diffOut })); } } } else { @@ -217,7 +225,9 @@ function TranslationMergeUI() { {loading ? () : ( (usfmJsons.current && usfmJsons.imported) ? ( - +
+ +
) : ( UsfmConflictEditor
+
+
Sample USFM render
+
+ {usfmJsons.diffOut?.map((item, index) => ( + + {item[1]} + + ))} +
+
); } diff --git a/yarn.lock b/yarn.lock index d1a764ae0..e5e52ded7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7956,6 +7956,11 @@ didyoumean@^1.2.2: resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037" integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw== +diff-match-patch@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/diff-match-patch/-/diff-match-patch-1.0.5.tgz#abb584d5f10cd1196dfc55aa03701592ae3f7b37" + integrity sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw== + diff-sequences@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1" From 321200b106c1eb1225bc87a4681b556c062b2066 Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Thu, 18 Jan 2024 09:35:40 +0530 Subject: [PATCH 11/50] added a prsing script to check and find the comparison results --- .../TranslationMergNavBar.jsx | 2 +- .../TranslationMergeUI.jsx | 21 ++- .../UsfmConflictEditor.jsx | 128 +++++++++++++++--- .../TextTranslationMerge/processUsfmObjs.js | 48 +++++++ 4 files changed, 176 insertions(+), 23 deletions(-) create mode 100644 renderer/src/components/TextTranslationMerge/processUsfmObjs.js diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergNavBar.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergNavBar.jsx index 45a6b9b30..6912d1019 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergNavBar.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergNavBar.jsx @@ -5,7 +5,7 @@ function TranslationMergNavBar({ currentUsfmJson, setSelectedChapter, selectedChapter, resolvedFileNames, }) { const { t } = useTranslation(); - console.log({ currentUsfmJson }); + // console.log({ currentUsfmJson }); return (
diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index 54ffcf9fb..f47180c3f 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -15,6 +15,7 @@ import useGetCurrentProjectMeta from '../Sync/hooks/useGetCurrentProjectMeta'; import LoadingScreen from '../Loading/LoadingScreen'; import ImportUsfmUI from './ImportUsfmUI'; import UsfmConflictEditor from './UsfmConflictEditor'; +import { processAndIdentiyVerseChangeinUSFMJsons } from './processUsfmObjs'; const grammar = require('usfm-grammar'); @@ -25,7 +26,7 @@ function TranslationMergeUI() { const [usfmJsons, setUsfmJsons] = useState({ imported: null, current: null, - diffOut: null, + merge: null, }); const [selectedChapter, setSelectedChapter] = useState(1); const [resolvedFileNames, setResolvedFileNames] = useState([]); @@ -136,6 +137,7 @@ function TranslationMergeUI() { const IncomingUsfm = fs.readFileSync(importedUsfmFolderPath[0], 'utf8'); if (IncomingUsfm) { const importedJson = await parseUsfm(IncomingUsfm); + // const normalisedIncomingUSFM = await parseJsonToUsfm(importedJson.data); if (!importedJson.valid) { setError('Imported Usfm is invalid'); } else if (!Object.keys(currentProjectMeta?.type?.flavorType?.currentScope).includes(importedJson?.data?.book?.bookCode) @@ -152,11 +154,20 @@ function TranslationMergeUI() { // console.log('FOUND ====> ', { currentBookPath, currentBookUsfm }); if (currentBookUsfm) { const currentJson = await parseUsfm(currentBookUsfm); - currentJson && currentJson?.valid && setUsfmJsons((prev) => ({ ...prev, current: currentJson.data })); + // const currentNormalisedUsfm = await parseJsonToUsfm(currentJson.data); + + // generate the merge object with current , incoming , merge verses + processAndIdentiyVerseChangeinUSFMJsons(importedJson.data, currentJson.data).then((out) => { + console.log('processed files : ', { out }); + }).catch((err) => { + console.log('process usfm : ', err); + }); + + currentJson && currentJson?.valid && setUsfmJsons((prev) => ({ ...prev, current: currentJson.data, mergeJson: JSON.parse(JSON.stringify(currentJson.data)) })); // compare usfms to check conflcit or not - const diffOut = await dmp.diff_main(IncomingUsfm, currentBookUsfm); - setUsfmJsons((prev) => ({ ...prev, diffOut })); + // const diffOut = await dmp.diff_main(normalisedIncomingUSFM, currentNormalisedUsfm); + // setUsfmJsons((prev) => ({ ...prev, diffOut })); } } } else { @@ -226,7 +237,7 @@ function TranslationMergeUI() { (usfmJsons.current && usfmJsons.imported) ? (
- +
) : ( diff --git a/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx b/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx index ca5f241da..69c9b8ea0 100644 --- a/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx +++ b/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx @@ -1,24 +1,118 @@ /* eslint-disable no-nested-ternary */ -import React from 'react'; +import React, { useState } from 'react'; +import { useTranslation } from 'react-i18next'; + +function UsfmConflictEditor({ usfmJsons, currentProjectMeta }) { + console.log({ usfmJsons, currentProjectMeta }); + + const [resolveAllActive, setResolveALlActive] = useState(); + const [resetAlll, setResetAll] = useState(); + const { t } = useTranslation(); + + const resolveAllTogether = (data, type) => { + console.log('resolve all together'); + }; + + const handleResetSingle = (data, index) => { + console.log('hanlde reset single conflcit'); + }; + + const resetAllResolved = () => { + console.log('reset all conflict '); + }; -function UsfmConflictEditor({ usfmJsons }) { - console.log({ usfmJsons }); return ( -
-
Sample USFM render
-
- {usfmJsons.diffOut?.map((item, index) => ( - + {/* Header and Buttons */} +
+
+
+ {t('label-comparison')} +
+
+ + + + + + + + +
+
+ {/*
+ +
*/} +
+ + {/* Content */} +
+ {/* {selectedFileContent.map((content, index) => ( +
- {item[1]} - - ))} + +
+ ggg + +
+ +
+ ))} */}
); diff --git a/renderer/src/components/TextTranslationMerge/processUsfmObjs.js b/renderer/src/components/TextTranslationMerge/processUsfmObjs.js new file mode 100644 index 000000000..f7cdc7964 --- /dev/null +++ b/renderer/src/components/TextTranslationMerge/processUsfmObjs.js @@ -0,0 +1,48 @@ +async function processAndIdentiyVerseChangeinUSFMJsons(currentJson, IncomingJson) { + // process USFM JSONs and generate comparaison object + + return new Promise((resolve, reject) => { + const compareVerses = async (incomingVerse, currentVerse, chapter) => new Promise((resolve, reject) => { + try { + resolve(incomingVerse.verseText === currentVerse.verseText); + } catch (err) { + console.log({ incomingVerse, currentVerse, chapter }); + reject(err); + } + }); + + const processChapter = async (incomingChapter, currentChapter) => { + const versesComparisonPromises = incomingChapter.contents.map(async (incomingVerse, i) => { + const currentVerse = currentChapter.contents[i]; + const versesAreEqual = await compareVerses(incomingVerse, currentVerse, currentChapter.chapterNumber); + return { [incomingVerse.verseNumber]: { versesAreEqual } }; + }); + const data = await Promise.all(versesComparisonPromises); + const reducedObj = data.reduce((final, item) => { + const key = Object.keys(item)[0]; + final[key] = item[key]; + return final; + }, {}); + return reducedObj; + }; + + const comparisonResult = async () => { + const chapterComparisonPromises = IncomingJson.chapters.map(async (incomingChapter, index) => { + const currentChapter = currentJson.chapters[index]; + const data = await processChapter(incomingChapter, currentChapter); + return { [currentChapter.chapterNumber]: data }; + }); + const data = await Promise.all(chapterComparisonPromises); + const reducedObj = data.reduce((final, item) => { + const key = Object.keys(item)[0]; + final[key] = item[key]; + return final; + }, {}); + return reducedObj; + }; + + comparisonResult().then((out) => resolve(out)).catch((err) => reject(err)); + }); +} + +export { processAndIdentiyVerseChangeinUSFMJsons }; From dcb294c63fcf17b0f44aff77313dd2bf31fd8252 Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Thu, 18 Jan 2024 16:24:49 +0530 Subject: [PATCH 12/50] added custom ui to render chapter wise one file --- .../TranslationMergeUI.jsx | 9 ++- .../UsfmConflictEditor.jsx | 64 +++++++++++++++++-- .../TextTranslationMerge/processUsfmObjs.js | 57 ++++++++--------- 3 files changed, 90 insertions(+), 40 deletions(-) diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index f47180c3f..64d992acc 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -157,7 +157,8 @@ function TranslationMergeUI() { // const currentNormalisedUsfm = await parseJsonToUsfm(currentJson.data); // generate the merge object with current , incoming , merge verses - processAndIdentiyVerseChangeinUSFMJsons(importedJson.data, currentJson.data).then((out) => { + const mergeJson = JSON.parse(JSON.stringify(currentJson.data)); + processAndIdentiyVerseChangeinUSFMJsons(importedJson.data, mergeJson).then((out) => { console.log('processed files : ', { out }); }).catch((err) => { console.log('process usfm : ', err); @@ -237,7 +238,11 @@ function TranslationMergeUI() { (usfmJsons.current && usfmJsons.imported) ? (
- +
) : ( diff --git a/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx b/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx index 69c9b8ea0..febf0545b 100644 --- a/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx +++ b/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx @@ -1,14 +1,32 @@ /* eslint-disable no-nested-ternary */ -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; -function UsfmConflictEditor({ usfmJsons, currentProjectMeta }) { - console.log({ usfmJsons, currentProjectMeta }); - +const DisplayTagObj = ({ tagObj }) => ( + + typeof tagObj === 'string' ? (

{tagObj}

) + : ( + Object.entries(tagObj).map(([tag, value, index]) => ( +

+ {tag} + {' '} + {value} +

+ )) + ) +); + +function UsfmConflictEditor({ usfmJsons, currentProjectMeta, selectedChapter }) { const [resolveAllActive, setResolveALlActive] = useState(); const [resetAlll, setResetAll] = useState(); const { t } = useTranslation(); + const [currentChapter, setCurrentChapter] = useState(null); + + console.log({ + usfmJsons, currentProjectMeta, selectedChapter, currentChapter, + }); + const resolveAllTogether = (data, type) => { console.log('resolve all together'); }; @@ -21,6 +39,15 @@ function UsfmConflictEditor({ usfmJsons, currentProjectMeta }) { console.log('reset all conflict '); }; + useEffect(() => { + if (usfmJsons && selectedChapter) { + const currentCh = usfmJsons.mergeJson.chapters.slice(selectedChapter - 1, selectedChapter); + if (currentCh?.length === 1) { + setCurrentChapter(currentCh[0]); + } + } + }, [selectedChapter, usfmJsons]); + return (
{/* Header and Buttons */} @@ -81,8 +108,8 @@ function UsfmConflictEditor({ usfmJsons, currentProjectMeta }) {
{/* Content */} -
- {/* {selectedFileContent.map((content, index) => ( + {/*
+ {selectedFileContent.map((content, index) => (
- ))} */} + ))} +
*/} + + {/* --------------------------------------------- testing -------------------------------------------- */} + +
+ {selectedChapter && currentChapter && currentChapter.contents.map((item, index) => ( + item?.verseNumber + ? ( +
+ {item.verseNumber} +
+ {item.contents.map((tag, index) => )} +
+
+ ) + + : ( +
+ +
+ ) + ))}
+
); } diff --git a/renderer/src/components/TextTranslationMerge/processUsfmObjs.js b/renderer/src/components/TextTranslationMerge/processUsfmObjs.js index f7cdc7964..46a3bc68d 100644 --- a/renderer/src/components/TextTranslationMerge/processUsfmObjs.js +++ b/renderer/src/components/TextTranslationMerge/processUsfmObjs.js @@ -1,44 +1,39 @@ async function processAndIdentiyVerseChangeinUSFMJsons(currentJson, IncomingJson) { // process USFM JSONs and generate comparaison object + const mergeTempJson = JSON.parse(JSON.stringify(currentJson)); + return new Promise((resolve, reject) => { - const compareVerses = async (incomingVerse, currentVerse, chapter) => new Promise((resolve, reject) => { - try { - resolve(incomingVerse.verseText === currentVerse.verseText); - } catch (err) { - console.log({ incomingVerse, currentVerse, chapter }); - reject(err); - } - }); + // const compareVerses = async (incomingVerse, currentVerse, chapter) => new Promise((resolve, reject) => { + // try { + // resolve(incomingVerse.verseText === currentVerse.verseText); + // } catch (err) { + // console.log({ incomingVerse, currentVerse, chapter }); + // reject(err); + // } + // }); - const processChapter = async (incomingChapter, currentChapter) => { - const versesComparisonPromises = incomingChapter.contents.map(async (incomingVerse, i) => { - const currentVerse = currentChapter.contents[i]; - const versesAreEqual = await compareVerses(incomingVerse, currentVerse, currentChapter.chapterNumber); - return { [incomingVerse.verseNumber]: { versesAreEqual } }; - }); - const data = await Promise.all(versesComparisonPromises); - const reducedObj = data.reduce((final, item) => { - const key = Object.keys(item)[0]; - final[key] = item[key]; - return final; - }, {}); - return reducedObj; - }; + // const processChapter = async (incomingChapter, currentChapter) => { + // const versesComparisonPromises = incomingChapter.contents.map(async (incomingVerse, i) => { + // const currentVerse = currentChapter.contents[i]; + // const versesAreEqual = await compareVerses(incomingVerse, currentVerse, currentChapter.chapterNumber); + // return { [incomingVerse.verseNumber]: { versesAreEqual } }; + // }); + // const data = await Promise.all(versesComparisonPromises); + // const reducedObj = data.reduce((final, item) => { + // const key = Object.keys(item)[0]; + // final[key] = item[key]; + // return final; + // }, {}); + // return reducedObj; + // }; const comparisonResult = async () => { const chapterComparisonPromises = IncomingJson.chapters.map(async (incomingChapter, index) => { const currentChapter = currentJson.chapters[index]; - const data = await processChapter(incomingChapter, currentChapter); - return { [currentChapter.chapterNumber]: data }; + await processChapter(incomingChapter, currentChapter); }); - const data = await Promise.all(chapterComparisonPromises); - const reducedObj = data.reduce((final, item) => { - const key = Object.keys(item)[0]; - final[key] = item[key]; - return final; - }, {}); - return reducedObj; + await Promise.all(chapterComparisonPromises); }; comparisonResult().then((out) => resolve(out)).catch((err) => reject(err)); From 9c9e2559ed59da68ef25fa062067c115565355f5 Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Thu, 18 Jan 2024 16:46:04 +0530 Subject: [PATCH 13/50] simple primary render view chapter wise - single json --- .../TextTranslationMerge/TranslationMergNavBar.jsx | 6 +++--- .../components/TextTranslationMerge/UsfmConflictEditor.jsx | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergNavBar.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergNavBar.jsx index 6912d1019..5a7bf6554 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergNavBar.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergNavBar.jsx @@ -7,7 +7,7 @@ function TranslationMergNavBar({ const { t } = useTranslation(); // console.log({ currentUsfmJson }); return ( -
+
{` ${t('label-book')} - ${currentUsfmJson?.book?.bookCode || ''}`} @@ -15,8 +15,8 @@ function TranslationMergNavBar({ {/* */}
-
-
    +
    +
      {currentUsfmJson?.chapters?.map((chapter) => (
    • (

      {tag} {' '} - {value} + {Array.isArray(value) ? value.map((v, index) => ) : value}

      )) ) From 65dcd00b22c43ed8233b3107b900053c0a66e856 Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Fri, 19 Jan 2024 13:16:30 +0530 Subject: [PATCH 14/50] test ui --- .../UsfmConflictEditor.jsx | 41 ++----------------- 1 file changed, 3 insertions(+), 38 deletions(-) diff --git a/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx b/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx index 5387945a6..ef580d3dd 100644 --- a/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx +++ b/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx @@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; -const DisplayTagObj = ({ tagObj }) => ( +const DisplayTagObj = ({ key, tagObj }) => ( typeof tagObj === 'string' ? (

      {tagObj}

      ) : ( @@ -107,48 +107,13 @@ function UsfmConflictEditor({ usfmJsons, currentProjectMeta, selectedChapter })
    */}
- {/* Content */} - {/*
- {selectedFileContent.map((content, index) => ( -
- -
- ggg - -
- -
- ))} -
*/} - {/* --------------------------------------------- testing -------------------------------------------- */}
{selectedChapter && currentChapter && currentChapter.contents.map((item, index) => ( item?.verseNumber ? ( -
+
{item.verseNumber}
{item.contents.map((tag, index) => )} @@ -157,7 +122,7 @@ function UsfmConflictEditor({ usfmJsons, currentProjectMeta, selectedChapter }) ) : ( -
+
) From d49d6f0ed351455abc2271466f1a9eb983dd7b37 Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Tue, 6 Feb 2024 11:48:56 +0530 Subject: [PATCH 15/50] added logic to indentify the conflicts and display with basic styling --- .../TranslationMergeUI.jsx | 8 +-- .../UsfmConflictEditor.jsx | 63 ++++++++++--------- .../TextTranslationMerge/processUsfmObjs.js | 44 +++++-------- .../projects/Import/ConflictResolverUI.jsx | 16 ++--- 4 files changed, 60 insertions(+), 71 deletions(-) diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index 64d992acc..35ef842cb 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -157,14 +157,12 @@ function TranslationMergeUI() { // const currentNormalisedUsfm = await parseJsonToUsfm(currentJson.data); // generate the merge object with current , incoming , merge verses - const mergeJson = JSON.parse(JSON.stringify(currentJson.data)); - processAndIdentiyVerseChangeinUSFMJsons(importedJson.data, mergeJson).then((out) => { - console.log('processed files : ', { out }); - }).catch((err) => { + // const mergeJson = JSON.parse(JSON.stringify(currentJson.data)); + const mergeJson = await processAndIdentiyVerseChangeinUSFMJsons(importedJson.data, currentJson.data).catch((err) => { console.log('process usfm : ', err); }); - currentJson && currentJson?.valid && setUsfmJsons((prev) => ({ ...prev, current: currentJson.data, mergeJson: JSON.parse(JSON.stringify(currentJson.data)) })); + currentJson && currentJson?.valid && setUsfmJsons((prev) => ({ ...prev, current: currentJson.data, mergeJson })); // compare usfms to check conflcit or not // const diffOut = await dmp.diff_main(normalisedIncomingUSFM, currentNormalisedUsfm); diff --git a/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx b/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx index ef580d3dd..0c0a76d4c 100644 --- a/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx +++ b/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx @@ -2,20 +2,6 @@ import React, { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; -const DisplayTagObj = ({ key, tagObj }) => ( - - typeof tagObj === 'string' ? (

{tagObj}

) - : ( - Object.entries(tagObj).map(([tag, value, index]) => ( -

- {tag} - {' '} - {Array.isArray(value) ? value.map((v, index) => ) : value} -

- )) - ) -); - function UsfmConflictEditor({ usfmJsons, currentProjectMeta, selectedChapter }) { const [resolveAllActive, setResolveALlActive] = useState(); const [resetAlll, setResetAll] = useState(); @@ -42,6 +28,7 @@ function UsfmConflictEditor({ usfmJsons, currentProjectMeta, selectedChapter }) useEffect(() => { if (usfmJsons && selectedChapter) { const currentCh = usfmJsons.mergeJson.chapters.slice(selectedChapter - 1, selectedChapter); + // identify conflicts in the chapter if (currentCh?.length === 1) { setCurrentChapter(currentCh[0]); } @@ -110,23 +97,41 @@ function UsfmConflictEditor({ usfmJsons, currentProjectMeta, selectedChapter }) {/* --------------------------------------------- testing -------------------------------------------- */}
- {selectedChapter && currentChapter && currentChapter.contents.map((item, index) => ( - item?.verseNumber - ? ( -
- {item.verseNumber} -
- {item.contents.map((tag, index) => )} -
-
- ) - - : ( -
- + {selectedChapter && usfmJsons.mergeJson + && usfmJsons?.mergeJson?.chapters?.slice(selectedChapter - 1, selectedChapter)[0].contents.map((item, index) => ( + item.verseNumber + && ( +
+ {item.verseNumber} + {/* conflict is / was there */} + {item?.resolved ? ( + + // conflict resolved section (Data from resolved.resolvedContent) + item.resolved.status ? ( +
+ conflict Resolved +
+ ) + : ( + // conflict Exist Show Both data +
+
+ {item.verseText} +
+
+ {item.incoming.verseText} +
+
+ ) + ) + : ( +
+ {item.verseText} +
+ )}
) - ))} + ))}
diff --git a/renderer/src/components/TextTranslationMerge/processUsfmObjs.js b/renderer/src/components/TextTranslationMerge/processUsfmObjs.js index 46a3bc68d..0c2d512a9 100644 --- a/renderer/src/components/TextTranslationMerge/processUsfmObjs.js +++ b/renderer/src/components/TextTranslationMerge/processUsfmObjs.js @@ -4,39 +4,25 @@ async function processAndIdentiyVerseChangeinUSFMJsons(currentJson, IncomingJson const mergeTempJson = JSON.parse(JSON.stringify(currentJson)); return new Promise((resolve, reject) => { - // const compareVerses = async (incomingVerse, currentVerse, chapter) => new Promise((resolve, reject) => { - // try { - // resolve(incomingVerse.verseText === currentVerse.verseText); - // } catch (err) { - // console.log({ incomingVerse, currentVerse, chapter }); - // reject(err); - // } - // }); - - // const processChapter = async (incomingChapter, currentChapter) => { - // const versesComparisonPromises = incomingChapter.contents.map(async (incomingVerse, i) => { - // const currentVerse = currentChapter.contents[i]; - // const versesAreEqual = await compareVerses(incomingVerse, currentVerse, currentChapter.chapterNumber); - // return { [incomingVerse.verseNumber]: { versesAreEqual } }; - // }); - // const data = await Promise.all(versesComparisonPromises); - // const reducedObj = data.reduce((final, item) => { - // const key = Object.keys(item)[0]; - // final[key] = item[key]; - // return final; - // }, {}); - // return reducedObj; - // }; - const comparisonResult = async () => { - const chapterComparisonPromises = IncomingJson.chapters.map(async (incomingChapter, index) => { - const currentChapter = currentJson.chapters[index]; - await processChapter(incomingChapter, currentChapter); + mergeTempJson.chapters.forEach((chapter, index) => { + const IncomingChap = IncomingJson.chapters[index]; + chapter.contents.forEach((content) => { + if (content.verseNumber) { + const IncomingVerse = IncomingChap.contents.find((ch) => ch.verseNumber === content.verseNumber); + // console.log(IncomingVerse); + if (content.verseText !== IncomingVerse.verseText) { + // add incoming data + content.incoming = IncomingVerse; + content.resolved = { status: false, resolvedContent: null }; + } + } + }); }); - await Promise.all(chapterComparisonPromises); + // console.log({ mergeTempJson }); }; - comparisonResult().then((out) => resolve(out)).catch((err) => reject(err)); + comparisonResult().then(() => resolve(mergeTempJson)).catch((err) => reject(err)); }); } diff --git a/renderer/src/layouts/projects/Import/ConflictResolverUI.jsx b/renderer/src/layouts/projects/Import/ConflictResolverUI.jsx index 988678625..fa557270e 100644 --- a/renderer/src/layouts/projects/Import/ConflictResolverUI.jsx +++ b/renderer/src/layouts/projects/Import/ConflictResolverUI.jsx @@ -188,14 +188,14 @@ function ConflictResolverUI({ conflictData, setConflictPopup }) { onClick={() => removeSection()} > {finishingMerge - ? ( -
- ) - : <>{t('label-done')}} + ? ( +
+ ) + : <>{t('label-done')}}
)} From 0e9ec327b04aa47829ec96f3db8ec64fb136a16e Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Tue, 6 Feb 2024 12:22:40 +0530 Subject: [PATCH 16/50] added reset single and select current or incoming section --- .../UsfmConflictEditor.jsx | 58 ++++++++++++++----- 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx b/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx index 0c0a76d4c..236b59f87 100644 --- a/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx +++ b/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx @@ -1,39 +1,49 @@ /* eslint-disable no-nested-ternary */ import React, { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; +import { + ArrowSmallDownIcon, ArrowSmallUpIcon, ArrowsUpDownIcon, ArrowPathRoundedSquareIcon, +} from '@heroicons/react/20/solid'; function UsfmConflictEditor({ usfmJsons, currentProjectMeta, selectedChapter }) { const [resolveAllActive, setResolveALlActive] = useState(); const [resetAlll, setResetAll] = useState(); const { t } = useTranslation(); - const [currentChapter, setCurrentChapter] = useState(null); - console.log({ - usfmJsons, currentProjectMeta, selectedChapter, currentChapter, + usfmJsons, currentProjectMeta, selectedChapter, }); const resolveAllTogether = (data, type) => { console.log('resolve all together'); }; - const handleResetSingle = (data, index) => { + const handleResetSingle = (verseNum) => { console.log('hanlde reset single conflcit'); + const currentVerseObj = usfmJsons.mergeJson.chapters.slice(selectedChapter - 1, selectedChapter)[0] + .contents.find((item) => item?.verseNumber === verseNum); + currentVerseObj.resolved.status = false; + currentVerseObj.resolved.resolvedContent = null; }; const resetAllResolved = () => { console.log('reset all conflict '); }; - useEffect(() => { - if (usfmJsons && selectedChapter) { - const currentCh = usfmJsons.mergeJson.chapters.slice(selectedChapter - 1, selectedChapter); - // identify conflicts in the chapter - if (currentCh?.length === 1) { - setCurrentChapter(currentCh[0]); - } + const handleResolveSingle = (type, verseNum) => { + const currentVerseObj = usfmJsons.mergeJson.chapters.slice(selectedChapter - 1, selectedChapter)[0] + .contents.find((item) => item?.verseNumber === verseNum); + let currentData = {}; + if (type === 'current') { + currentData = { verseText: currentVerseObj.verseText, contents: currentVerseObj.contents, verseNumber: verseNum }; + } else { + currentData = currentVerseObj.incoming; } - }, [selectedChapter, usfmJsons]); + + // assign to resolved section + currentVerseObj.resolved.status = true; + currentVerseObj.resolved.resolvedContent = currentData; + }; return (
@@ -109,16 +119,34 @@ function UsfmConflictEditor({ usfmJsons, currentProjectMeta, selectedChapter }) // conflict resolved section (Data from resolved.resolvedContent) item.resolved.status ? (
- conflict Resolved +
+
{item.resolved.resolvedContent.verseText}
+ handleResetSingle(item.verseNumber)} + /> +
) : ( // conflict Exist Show Both data
-
+
handleResolveSingle('current', item.verseNumber)} + > {item.verseText}
-
+
handleResolveSingle('incoming', item.verseNumber)} + > {item.incoming.verseText}
From 82bf7d9e0388e09a1596d60fea73bd80d62b9841 Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Fri, 9 Feb 2024 10:24:01 +0530 Subject: [PATCH 17/50] added conflict ui --- .../TranslationMergeUI.jsx | 2 +- .../UsfmConflictEditor.jsx | 108 +++++++++++++----- 2 files changed, 79 insertions(+), 31 deletions(-) diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index 35ef842cb..de55255bc 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -26,7 +26,6 @@ function TranslationMergeUI() { const [usfmJsons, setUsfmJsons] = useState({ imported: null, current: null, - merge: null, }); const [selectedChapter, setSelectedChapter] = useState(1); const [resolvedFileNames, setResolvedFileNames] = useState([]); @@ -240,6 +239,7 @@ function TranslationMergeUI() { usfmJsons={usfmJsons} currentProjectMeta={currentProjectMeta} selectedChapter={selectedChapter} + setUsfmJsons={setUsfmJsons} />
) diff --git a/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx b/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx index 236b59f87..ad346fec4 100644 --- a/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx +++ b/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx @@ -5,7 +5,9 @@ import { ArrowSmallDownIcon, ArrowSmallUpIcon, ArrowsUpDownIcon, ArrowPathRoundedSquareIcon, } from '@heroicons/react/20/solid'; -function UsfmConflictEditor({ usfmJsons, currentProjectMeta, selectedChapter }) { +function UsfmConflictEditor({ + usfmJsons, currentProjectMeta, selectedChapter, setUsfmJsons, +}) { const [resolveAllActive, setResolveALlActive] = useState(); const [resetAlll, setResetAll] = useState(); const { t } = useTranslation(); @@ -14,8 +16,8 @@ function UsfmConflictEditor({ usfmJsons, currentProjectMeta, selectedChapter }) usfmJsons, currentProjectMeta, selectedChapter, }); - const resolveAllTogether = (data, type) => { - console.log('resolve all together'); + const resolveAllTogether = (type) => { + console.log('resolve all together', type); }; const handleResetSingle = (verseNum) => { @@ -24,6 +26,7 @@ function UsfmConflictEditor({ usfmJsons, currentProjectMeta, selectedChapter }) .contents.find((item) => item?.verseNumber === verseNum); currentVerseObj.resolved.status = false; currentVerseObj.resolved.resolvedContent = null; + setUsfmJsons((prev) => ({ ...prev, mergeJson: usfmJsons.mergeJson })); }; const resetAllResolved = () => { @@ -43,6 +46,7 @@ function UsfmConflictEditor({ usfmJsons, currentProjectMeta, selectedChapter }) // assign to resolved section currentVerseObj.resolved.status = true; currentVerseObj.resolved.resolvedContent = currentData; + setUsfmJsons((prev) => ({ ...prev, mergeJson: usfmJsons.mergeJson })); }; return ( @@ -56,35 +60,35 @@ function UsfmConflictEditor({ usfmJsons, currentProjectMeta, selectedChapter })
- + */}
@@ -111,8 +114,12 @@ function UsfmConflictEditor({ usfmJsons, currentProjectMeta, selectedChapter }) && usfmJsons?.mergeJson?.chapters?.slice(selectedChapter - 1, selectedChapter)[0].contents.map((item, index) => ( item.verseNumber && ( -
- {item.verseNumber} +
+ {item.verseNumber} {/* conflict is / was there */} {item?.resolved ? ( @@ -130,24 +137,65 @@ function UsfmConflictEditor({ usfmJsons, currentProjectMeta, selectedChapter }) ) : ( // conflict Exist Show Both data -
-
handleResolveSingle('current', item.verseNumber)} - > - {item.verseText} +
+
+
handleResolveSingle('current', item.verseNumber)} + > + {item.verseText} +
+
handleResolveSingle('incoming', item.verseNumber)} + > + {item.incoming.verseText} +
-
handleResolveSingle('incoming', item.verseNumber)} - > - {item.incoming.verseText} + +
+ {/* current */} +
handleResolveSingle('current', item.verseNumber)} + // onMouseEnter={() => setHoveredId('current')} + // onMouseLeave={() => setHoveredId('')} + title={t('tooltip-merge-orginal-btn')} + className="bg-black w-6 h-6 rounded-full flex justify-center items-center" + > + +
+ {/* Both */} + {/*
{ }} + onMouseEnter={() => setHoveredId('both')} + onMouseLeave={() => setHoveredId('')} + title={t('tooltip-merge-both-btn')} + className="bg-blue-500 w-6 h-6 rounded-full flex justify-center items-center" + > + +
*/} + {/* Incoming */} +
handleResolveSingle('incoming', item.verseNumber)} + // onMouseEnter={() => setHoveredId('incoming')} + // onMouseLeave={() => setHoveredId('')} + title={t('tooltip-merge-new-btn')} + className="bg-success w-6 h-6 rounded-full flex justify-center items-center" + > + +
) From 6229b25dc76d5ba11f8ccc0ef4abcdde3c97e4ef Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Fri, 9 Feb 2024 13:09:00 +0530 Subject: [PATCH 18/50] only listing conflicted fiels --- .../TranslationMergNavBar.jsx | 32 +++++++++++-------- .../TranslationMergeUI.jsx | 11 +++++-- .../TextTranslationMerge/processUsfmObjs.js | 7 ++-- 3 files changed, 30 insertions(+), 20 deletions(-) diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergNavBar.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergNavBar.jsx index 5a7bf6554..75ff89444 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergNavBar.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergNavBar.jsx @@ -2,34 +2,38 @@ import { useTranslation } from 'react-i18next'; function TranslationMergNavBar({ - currentUsfmJson, setSelectedChapter, selectedChapter, resolvedFileNames, + currentUsfmJson, setSelectedChapter, selectedChapter, conflictedChapters, resolvedChapters, }) { const { t } = useTranslation(); - // console.log({ currentUsfmJson }); return (
{` ${t('label-book')} - ${currentUsfmJson?.book?.bookCode || ''}`} + + {`${conflictedChapters?.length} `} + {/* */}
    {currentUsfmJson?.chapters?.map((chapter) => ( -
  • setSelectedChapter(chapter.chapterNumber)} - aria-disabled={resolvedFileNames.includes(chapter.chapterNumber)} - className={`px-5 py-2 ${resolvedFileNames.includes(chapter.chapterNumber) - ? 'line-through decoration-2 pointer-events-none' - : `${selectedChapter === chapter.chapterNumber ? 'bg-primary/70' : 'hover:bg-primary cursor-pointer'}`} `} - > - {chapter.chapterNumber} -
  • + conflictedChapters.includes(chapter.chapterNumber) && ( +
  • setSelectedChapter(chapter.chapterNumber)} + aria-disabled={resolvedChapters.includes(chapter.chapterNumber)} + className={`px-5 py-2 ${resolvedChapters.includes(chapter.chapterNumber) + ? 'line-through decoration-2 pointer-events-none' + : `${selectedChapter === chapter.chapterNumber ? 'bg-primary/70' : 'hover:bg-primary cursor-pointer'}`} `} + > + {chapter.chapterNumber} +
  • + ) ))}
diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index de55255bc..ec8f9e63c 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -28,7 +28,8 @@ function TranslationMergeUI() { current: null, }); const [selectedChapter, setSelectedChapter] = useState(1); - const [resolvedFileNames, setResolvedFileNames] = useState([]); + const [conflictedChapters, setConflictedChapters] = useState([]); + const [resolvedChapters, setResolvedChapters] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(''); @@ -157,9 +158,12 @@ function TranslationMergeUI() { // generate the merge object with current , incoming , merge verses // const mergeJson = JSON.parse(JSON.stringify(currentJson.data)); - const mergeJson = await processAndIdentiyVerseChangeinUSFMJsons(importedJson.data, currentJson.data).catch((err) => { + const processOutArr = await processAndIdentiyVerseChangeinUSFMJsons(importedJson.data, currentJson.data).catch((err) => { console.log('process usfm : ', err); }); + const mergeJson = processOutArr[0]; + console.log('processOutArr[1] : ', processOutArr[1]); + setConflictedChapters(processOutArr[1]); currentJson && currentJson?.valid && setUsfmJsons((prev) => ({ ...prev, current: currentJson.data, mergeJson })); @@ -223,7 +227,8 @@ function TranslationMergeUI() {
diff --git a/renderer/src/components/TextTranslationMerge/processUsfmObjs.js b/renderer/src/components/TextTranslationMerge/processUsfmObjs.js index 0c2d512a9..62616f3e7 100644 --- a/renderer/src/components/TextTranslationMerge/processUsfmObjs.js +++ b/renderer/src/components/TextTranslationMerge/processUsfmObjs.js @@ -2,6 +2,7 @@ async function processAndIdentiyVerseChangeinUSFMJsons(currentJson, IncomingJson // process USFM JSONs and generate comparaison object const mergeTempJson = JSON.parse(JSON.stringify(currentJson)); + const conflictedChapters = []; return new Promise((resolve, reject) => { const comparisonResult = async () => { @@ -15,14 +16,14 @@ async function processAndIdentiyVerseChangeinUSFMJsons(currentJson, IncomingJson // add incoming data content.incoming = IncomingVerse; content.resolved = { status: false, resolvedContent: null }; + !conflictedChapters.includes(chapter.chapterNumber) && conflictedChapters.push(chapter.chapterNumber); } } }); }); - // console.log({ mergeTempJson }); + // console.log({ mergeTempJson, conflictedChapters }); }; - - comparisonResult().then(() => resolve(mergeTempJson)).catch((err) => reject(err)); + comparisonResult().then(() => resolve([mergeTempJson, conflictedChapters])).catch((err) => reject(err)); }); } From 80d8ac9b9aacbaf3ad9a63c7a438b243e446c2e1 Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Mon, 12 Feb 2024 09:54:31 +0530 Subject: [PATCH 19/50] detect chapter conflict resolution --- .../TranslationMergNavBar.jsx | 1 + .../TranslationMergeUI.jsx | 7 ++ .../UsfmConflictEditor.jsx | 70 ++++++++++++++++--- 3 files changed, 67 insertions(+), 11 deletions(-) diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergNavBar.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergNavBar.jsx index 75ff89444..03812cb61 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergNavBar.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergNavBar.jsx @@ -4,6 +4,7 @@ import { useTranslation } from 'react-i18next'; function TranslationMergNavBar({ currentUsfmJson, setSelectedChapter, selectedChapter, conflictedChapters, resolvedChapters, }) { + console.log({ resolvedChapters, conflictedChapters }); const { t } = useTranslation(); return (
diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index ec8f9e63c..522a4d5f0 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -30,6 +30,7 @@ function TranslationMergeUI() { const [selectedChapter, setSelectedChapter] = useState(1); const [conflictedChapters, setConflictedChapters] = useState([]); const [resolvedChapters, setResolvedChapters] = useState([]); + const [chapterResolveDone, setChapterResolveDone] = useState(false); const [loading, setLoading] = useState(false); const [error, setError] = useState(''); @@ -186,6 +187,10 @@ function TranslationMergeUI() { } }, [importedUsfmFolderPath, currentProjectMeta]); + useEffect(() => { + setChapterResolveDone(false); + }, [selectedChapter]); + return ( <>
) diff --git a/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx b/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx index ad346fec4..4471b17ca 100644 --- a/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx +++ b/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx @@ -6,18 +6,35 @@ import { } from '@heroicons/react/20/solid'; function UsfmConflictEditor({ - usfmJsons, currentProjectMeta, selectedChapter, setUsfmJsons, + usfmJsons, currentProjectMeta, selectedChapter, setUsfmJsons, setResolvedChapters, }) { - const [resolveAllActive, setResolveALlActive] = useState(); - const [resetAlll, setResetAll] = useState(); + const [resolveAllActive, setResolveALlActive] = useState(true); + const [resetAlll, setResetAll] = useState(false); const { t } = useTranslation(); - console.log({ - usfmJsons, currentProjectMeta, selectedChapter, - }); + // console.log({ + // usfmJsons, currentProjectMeta, selectedChapter, + // }); const resolveAllTogether = (type) => { - console.log('resolve all together', type); + usfmJsons.mergeJson.chapters.slice(selectedChapter - 1, selectedChapter)[0] + .contents.forEach((verseObj) => { + if (verseObj?.resolved?.status === false) { + let currentData = {}; + if (type === 'current') { + currentData = { verseText: verseObj.verseText, contents: verseObj.contents, verseNumber: verseObj.verseNumber }; + } else { + currentData = verseObj.incoming; + } + + // assign to resolved section + verseObj.resolved.status = true; + verseObj.resolved.resolvedContent = currentData; + } + }); + setUsfmJsons((prev) => ({ ...prev, mergeJson: usfmJsons.mergeJson })); + setResolveALlActive(false); + setResetAll(true); }; const handleResetSingle = (verseNum) => { @@ -27,10 +44,21 @@ function UsfmConflictEditor({ currentVerseObj.resolved.status = false; currentVerseObj.resolved.resolvedContent = null; setUsfmJsons((prev) => ({ ...prev, mergeJson: usfmJsons.mergeJson })); + setResolveALlActive(true); + setResetAll(false); }; const resetAllResolved = () => { - console.log('reset all conflict '); + usfmJsons.mergeJson.chapters.slice(selectedChapter - 1, selectedChapter)[0] + .contents.forEach((verseObj) => { + if (verseObj?.resolved?.status === true) { + verseObj.resolved.status = false; + verseObj.resolved.resolvedContent = null; + } + }); + setUsfmJsons((prev) => ({ ...prev, mergeJson: usfmJsons.mergeJson })); + setResolveALlActive(true); + setResetAll(false); }; const handleResolveSingle = (type, verseNum) => { @@ -49,6 +77,26 @@ function UsfmConflictEditor({ setUsfmJsons((prev) => ({ ...prev, mergeJson: usfmJsons.mergeJson })); }; + useEffect(() => { + // check all resolved in the current ch + let resolvedStatus = false; + + for (let index = 0; index < usfmJsons.mergeJson.chapters.slice(selectedChapter - 1, selectedChapter)[0].contents.length; index++) { + const verseObj = usfmJsons.mergeJson.chapters.slice(selectedChapter - 1, selectedChapter)[0].contents[index]; + if (verseObj?.resolved && verseObj?.resolved?.status === false) { + resolvedStatus = false; + break; + } else { + resolvedStatus = true; + } + } + + if (resolvedStatus) { + console.log('in resolved status ---------------->'); + // setResolvedChapters((prev) => [...prev, selectedChapter]); + } + }, [usfmJsons, selectedChapter]); + return (
{/* Header and Buttons */} @@ -63,7 +111,7 @@ function UsfmConflictEditor({ onClick={() => resolveAllTogether('current')} disabled={resolveAllActive === false} title={t('tooltip-merge-all-orginal-btn')} - className={`${true ? 'px-2.5 py-0.5 bg-black text-white font-semibold tracking-wider text-xs uppercase rounded-xl' : 'hidden'}`} + className={`${resolveAllActive ? 'px-2.5 py-0.5 bg-black text-white font-semibold tracking-wider text-xs uppercase rounded-xl' : 'hidden'}`} > {t('label-original')} @@ -73,7 +121,7 @@ function UsfmConflictEditor({ onClick={() => resolveAllTogether('incoming')} disabled={resolveAllActive === false} title={t('tooltip-merge-all-new-btn')} - className={`${true ? 'px-2.5 py-0.5 bg-success text-white font-semibold tracking-wider text-xs uppercase rounded-xl' : 'hidden'}`} + className={`${resolveAllActive ? 'px-2.5 py-0.5 bg-success text-white font-semibold tracking-wider text-xs uppercase rounded-xl' : 'hidden'}`} > {t('label-new')} @@ -201,7 +249,7 @@ function UsfmConflictEditor({ ) ) : ( -
+
{item.verseText}
)} From f380e4984f7cf333e8cd8a9df1383b89dafb6059 Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Mon, 12 Feb 2024 14:04:52 +0530 Subject: [PATCH 20/50] added resolve ,reset functionality to retain previous stages based on the chapter resolution --- .../TranslationMergeUI.jsx | 22 ++++++++++++++----- .../UsfmConflictEditor.jsx | 17 ++++++++------ 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index 522a4d5f0..a21a7cced 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -187,9 +187,9 @@ function TranslationMergeUI() { } }, [importedUsfmFolderPath, currentProjectMeta]); - useEffect(() => { - setChapterResolveDone(false); - }, [selectedChapter]); + const resolveAndMarkDoneChapter = () => { + setResolvedChapters((prev) => [...prev, selectedChapter]); + }; return ( <> @@ -250,8 +250,8 @@ function TranslationMergeUI() { currentProjectMeta={currentProjectMeta} selectedChapter={selectedChapter} setUsfmJsons={setUsfmJsons} - setResolvedChapters={setResolvedChapters} setChapterResolveDone={setChapterResolveDone} + resolvedChapters={resolvedChapters} />
) @@ -266,8 +266,20 @@ function TranslationMergeUI() { )}
-
+

{error}

+ {usfmJsons.current && usfmJsons.imported && ( + + )}
diff --git a/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx b/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx index 4471b17ca..3be59cb70 100644 --- a/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx +++ b/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx @@ -6,7 +6,7 @@ import { } from '@heroicons/react/20/solid'; function UsfmConflictEditor({ - usfmJsons, currentProjectMeta, selectedChapter, setUsfmJsons, setResolvedChapters, + usfmJsons, currentProjectMeta, selectedChapter, setUsfmJsons, setChapterResolveDone, resolvedChapters, }) { const [resolveAllActive, setResolveALlActive] = useState(true); const [resetAlll, setResetAll] = useState(false); @@ -38,7 +38,6 @@ function UsfmConflictEditor({ }; const handleResetSingle = (verseNum) => { - console.log('hanlde reset single conflcit'); const currentVerseObj = usfmJsons.mergeJson.chapters.slice(selectedChapter - 1, selectedChapter)[0] .contents.find((item) => item?.verseNumber === verseNum); currentVerseObj.resolved.status = false; @@ -46,6 +45,7 @@ function UsfmConflictEditor({ setUsfmJsons((prev) => ({ ...prev, mergeJson: usfmJsons.mergeJson })); setResolveALlActive(true); setResetAll(false); + setChapterResolveDone(false); }; const resetAllResolved = () => { @@ -59,6 +59,7 @@ function UsfmConflictEditor({ setUsfmJsons((prev) => ({ ...prev, mergeJson: usfmJsons.mergeJson })); setResolveALlActive(true); setResetAll(false); + setChapterResolveDone(false); }; const handleResolveSingle = (type, verseNum) => { @@ -80,20 +81,22 @@ function UsfmConflictEditor({ useEffect(() => { // check all resolved in the current ch let resolvedStatus = false; - for (let index = 0; index < usfmJsons.mergeJson.chapters.slice(selectedChapter - 1, selectedChapter)[0].contents.length; index++) { const verseObj = usfmJsons.mergeJson.chapters.slice(selectedChapter - 1, selectedChapter)[0].contents[index]; if (verseObj?.resolved && verseObj?.resolved?.status === false) { resolvedStatus = false; + setChapterResolveDone(false); + setResetAll(false); + setResolveALlActive(true); break; } else { resolvedStatus = true; } } - if (resolvedStatus) { - console.log('in resolved status ---------------->'); - // setResolvedChapters((prev) => [...prev, selectedChapter]); + setChapterResolveDone(true); + setResetAll(true); + setResolveALlActive(false); } }, [usfmJsons, selectedChapter]); @@ -169,7 +172,7 @@ function UsfmConflictEditor({ > {item.verseNumber} {/* conflict is / was there */} - {item?.resolved ? ( + {(item?.resolved && !resolvedChapters.includes(selectedChapter)) ? ( // conflict resolved section (Data from resolved.resolvedContent) item.resolved.status ? ( From 2c897029a340b38a9b374996d28b33f62e753dc9 Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Tue, 13 Feb 2024 19:09:28 +0530 Subject: [PATCH 21/50] added functionality to save and load conflict files, conflict fixed --- .../TextTranslationMerge/ImportUsfmUI.jsx | 21 ++- .../TranslationMergeUI.jsx | 124 ++++++++++++++++-- renderer/src/translations/en.js | 2 + 3 files changed, 133 insertions(+), 14 deletions(-) diff --git a/renderer/src/components/TextTranslationMerge/ImportUsfmUI.jsx b/renderer/src/components/TextTranslationMerge/ImportUsfmUI.jsx index 4067864cd..b9c06d938 100644 --- a/renderer/src/components/TextTranslationMerge/ImportUsfmUI.jsx +++ b/renderer/src/components/TextTranslationMerge/ImportUsfmUI.jsx @@ -1,6 +1,8 @@ import React from 'react'; -function ImportUsfmUI({ currentProjectMeta, handleImportUsfm, buttonName }) { +function ImportUsfmUI({ + currentProjectMeta, handleImportUsfm, buttonName, savedConflictsBooks, resumeConflictResolution, +}) { return ( <>
@@ -17,6 +19,23 @@ function ImportUsfmUI({ currentProjectMeta, handleImportUsfm, buttonName }) { > {buttonName} + {/* saved conflicts - resume */} +
+
Resume Conflict Resolution
+
+ + {savedConflictsBooks.map((book) => ( + + ))} +
+
); } diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index a21a7cced..277e330db 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -9,6 +9,7 @@ import { XMarkIcon } from '@heroicons/react/24/outline'; import ConfirmationModal from '@/layouts/editor/ConfirmationModal'; import { readUsfmFile } from '@/core/projects/userSettings'; import DiffMatchPatch from 'diff-match-patch'; +import localforage from 'localforage'; import TranslationMergNavBar from './TranslationMergNavBar'; import * as logger from '../../logger'; import useGetCurrentProjectMeta from '../Sync/hooks/useGetCurrentProjectMeta'; @@ -16,6 +17,7 @@ import LoadingScreen from '../Loading/LoadingScreen'; import ImportUsfmUI from './ImportUsfmUI'; import UsfmConflictEditor from './UsfmConflictEditor'; import { processAndIdentiyVerseChangeinUSFMJsons } from './processUsfmObjs'; +import packageInfo from '../../../../package.json'; const grammar = require('usfm-grammar'); @@ -28,10 +30,14 @@ function TranslationMergeUI() { current: null, }); const [selectedChapter, setSelectedChapter] = useState(1); + const [selectedBookId, setSelectedBookId] = useState(null); const [conflictedChapters, setConflictedChapters] = useState([]); const [resolvedChapters, setResolvedChapters] = useState([]); const [chapterResolveDone, setChapterResolveDone] = useState(false); + const [savedConflictsBooks, setSavedConflictsBooks] = useState([]); + const [existImportedBook, setExistImportedBook] = useState({ status: false, bookId: null }); + const [loading, setLoading] = useState(false); const [error, setError] = useState(''); @@ -58,7 +64,7 @@ function TranslationMergeUI() { actions: { getProjectMeta }, } = useGetCurrentProjectMeta(); - console.log({ openTextTranslationMerge, currentProjectMeta }); + console.log({ openTextTranslationMerge, currentProjectMeta, selectedBookId }); const modalClose = () => { setModel({ @@ -69,6 +75,25 @@ function TranslationMergeUI() { }); }; + const handleStartOver = () => { + console.log('start over called ----'); + setExistImportedBook({ status: false, bookId: null }); + modalClose(); + }; + + const handleOnAbortMerge = (buttonName) => { + console.log({ buttonName }, model); + if (model.buttonName === t('label-abort')) { + setError(''); + setUsfmJsons({ imported: null, current: null }); + setImportedUsfmFolderPath([]); + setOpenTextTranslationMerge({ open: false, meta: null }); + modalClose(); + } else { + handleStartOver(); + } + }; + const removeSection = async (abort = false) => { if (abort === false) { // pass @@ -83,12 +108,30 @@ function TranslationMergeUI() { } }; - const handleOnAbortMerge = () => { - setError(''); - setUsfmJsons({ imported: null, current: null }); - setImportedUsfmFolderPath([]); - setOpenTextTranslationMerge({ open: false, meta: null }); - modalClose(); + const readMergeDirOrSingleFile = async (readDir = true, fileName = null) => { + const fs = window.require('fs'); + const { id, name } = openTextTranslationMerge.meta; + const _projectName = `${name}_${id[0]}`; + const newpath = localStorage.getItem('userPath'); + const path = require('path'); + + const user = await localforage.getItem('userProfile'); + if (user?.username) { + const USFMMergeDirPath = path.join(newpath, packageInfo.name, 'users', user?.username, '.merge-usfm'); + if (!fs.existsSync(path.join(USFMMergeDirPath, _projectName))) { + return null; + } + if (readDir) { + const files = fs.readdirSync(path.join(USFMMergeDirPath, _projectName)); + console.log({ files }); + return files; + } + // read file - json + let jsonFile = fs.readFileSync(path.join(USFMMergeDirPath, _projectName, fileName)); + jsonFile = JSON.parse(jsonFile); + return jsonFile; + } + console.error('no user : ', { user }); }; useEffect(() => { @@ -96,6 +139,9 @@ function TranslationMergeUI() { const { id, name } = openTextTranslationMerge.meta; (async () => { await getProjectMeta(`${name}_${id[0]}`); + // check for existing merge and display ui based on that + const mergeDirContents = await readMergeDirOrSingleFile(); + setSavedConflictsBooks(mergeDirContents); })(); } }, []); @@ -120,6 +166,29 @@ function TranslationMergeUI() { openFileDialogSettingData(); }; + const resumeConflictResolution = async (bookId) => { + // bookid (same as backendfilename) - > mat.json + console.log('book id : ', bookId); + const { usfmJsons } = await readMergeDirOrSingleFile(false, bookId); + setUsfmJsons(usfmJsons); + setExistImportedBook({ status: false, bookId: null }); + + const _conflictedBooks = []; + setSelectedBookId(usfmJsons.mergeJson.book.bookCode.toLowerCase()); + usfmJsons.mergeJson.chapters.forEach((chapter, index) => { + chapter.contents.forEach((content) => { + if (content.verseNumber) { + if (content?.resolved && !content?.resolved?.status) { + !_conflictedBooks.includes(chapter.chapterNumber) && _conflictedBooks.push(chapter.chapterNumber); + } + } + }); + }); + + setConflictedChapters(_conflictedBooks); + console.log({ usfmJsons }); + }; + async function parseUsfm(usfm) { const myUsfmParser = new grammar.USFMParser(usfm, grammar.LEVEL.RELAXED); const isJsonValid = myUsfmParser.validate(); @@ -145,10 +214,12 @@ function TranslationMergeUI() { && !Object.keys(currentProjectMeta?.type?.flavorType?.currentScope).includes(importedJson?.data?.book?.bookCode?.toLowerCase())) { setError('Imported USFM is not in the scope of Current Project'); } else { - setError(''); - setUsfmJsons((prev) => ({ ...prev, imported: importedJson.data })); // Parse current project same book const importedBookCode = `${importedJson.data.book.bookCode.toLowerCase()}.usfm`; + + setError(''); + setUsfmJsons((prev) => ({ ...prev, imported: importedJson.data })); + setSelectedBookId(importedJson.data.book.bookCode.toLowerCase()); const currentBookPath = Object.keys(currentProjectMeta?.ingredients).find((code) => code.toLowerCase().endsWith(importedBookCode)); const { id, name } = openTextTranslationMerge.meta; const currentBookUsfm = await readUsfmFile(currentBookPath, `${name}_${id[0]}`); @@ -166,6 +237,17 @@ function TranslationMergeUI() { console.log('processOutArr[1] : ', processOutArr[1]); setConflictedChapters(processOutArr[1]); + if (savedConflictsBooks.includes(`${importedJson.data.book.bookCode.toLowerCase()}.json`)) { + setExistImportedBook({ status: true, bookId: importedJson.data.book.bookCode.toLowerCase() }); + console.log('existing book'); + setModel({ + openModel: true, + title: t('modal-title-abort-conflict-resolution'), + confirmMessage: t('msg-conflict-resolution-duplicate-book', { bookId: importedJson.data.book.bookCode.toUpperCase() }), + buttonName: t('label-startover'), + }); + } + currentJson && currentJson?.valid && setUsfmJsons((prev) => ({ ...prev, current: currentJson.data, mergeJson })); // compare usfms to check conflcit or not @@ -189,6 +271,20 @@ function TranslationMergeUI() { const resolveAndMarkDoneChapter = () => { setResolvedChapters((prev) => [...prev, selectedChapter]); + // store the jsons to the backend (/.merge/projectName/BookID.json) + const fs = window.require('fs'); + const { id, name } = openTextTranslationMerge.meta; + const _projectName = `${name}_${id[0]}`; + const newpath = localStorage.getItem('userPath'); + const path = require('path'); + localforage.getItem('userProfile').then((user) => { + const USFMMergeDirPath = path.join(newpath, packageInfo.name, 'users', user?.username, '.merge-usfm'); + if (!fs.existsSync(path.join(USFMMergeDirPath, _projectName))) { + fs.mkdirSync(path.join(USFMMergeDirPath, _projectName), { recursive: true }); + } + console.log('write this book :', `${selectedBookId}.json`); + fs.writeFileSync(path.join(USFMMergeDirPath, _projectName, `${selectedBookId}.json`), JSON.stringify({ usfmJsons })); + }); }; return ( @@ -231,8 +327,8 @@ function TranslationMergeUI() {
) : ( - (usfmJsons.current && usfmJsons.imported) ? ( + (usfmJsons.current && usfmJsons.imported && !existImportedBook.status) ? (
) @@ -294,7 +392,7 @@ function TranslationMergeUI() { setOpenModal={() => modalClose()} confirmMessage={model.confirmMessage} buttonName={model.buttonName} - closeModal={() => handleOnAbortMerge()} + closeModal={() => handleOnAbortMerge(model.buttonName)} /> ); diff --git a/renderer/src/translations/en.js b/renderer/src/translations/en.js index 5be9f51a8..fe6e091eb 100644 --- a/renderer/src/translations/en.js +++ b/renderer/src/translations/en.js @@ -281,4 +281,6 @@ export const En = { 'tooltip-supported-resources': 'supported resources are TN, TW, TQ, TA', 'label-upload-help-resources': 'Upload Help Resources', 'label-filter': 'Filter', + 'msg-conflict-resolution-duplicate-book': 'Conflict resolution for {{bookId}} is in progress. Do you want to start over. You will loose all your progress and can not be reverted.', + 'label-startover': 'start over', }; From 287ab33a9f6837f1fe07ee1f51d57bb23e3f8aa0 Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Wed, 14 Feb 2024 17:37:52 +0530 Subject: [PATCH 22/50] UI for Import and resume usfm conflict --- .../TextTranslationMerge/ImportUsfmUI.jsx | 63 +++++++++++-------- 1 file changed, 38 insertions(+), 25 deletions(-) diff --git a/renderer/src/components/TextTranslationMerge/ImportUsfmUI.jsx b/renderer/src/components/TextTranslationMerge/ImportUsfmUI.jsx index b9c06d938..d1b3047e6 100644 --- a/renderer/src/components/TextTranslationMerge/ImportUsfmUI.jsx +++ b/renderer/src/components/TextTranslationMerge/ImportUsfmUI.jsx @@ -4,39 +4,52 @@ function ImportUsfmUI({ currentProjectMeta, handleImportUsfm, buttonName, savedConflictsBooks, resumeConflictResolution, }) { return ( - <> -
- Project Scope : - {currentProjectMeta && Object.keys(currentProjectMeta?.type?.flavorType?.currentScope).map((scope) => ( - {scope} - ))} +
+
-
- - {/* saved conflicts - resume */} -
-
Resume Conflict Resolution
-
- - {savedConflictsBooks.map((book) => ( +
+ +
+

Current Project Scope

+
+ + {currentProjectMeta && Object.keys(currentProjectMeta?.type?.flavorType?.currentScope).map((scope) => ( + {scope} + ))} +
- ))} +
+ +
+ +
+ + {/* saved conflicts - resume */} +
+ +

Resume Conflict Resolution

+
+ + {savedConflictsBooks.map((book) => ( + + ))} +
- +
); } From 3b531fc6b095e142d64f8e5777e6e571d7f16158 Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Thu, 15 Feb 2024 11:44:47 +0530 Subject: [PATCH 23/50] added functionality for finiahs conflict resolution --- .../TextTranslationMerge/ImportUsfmUI.jsx | 35 +++---- .../TranslationMergeUI.jsx | 95 +++++++++++++++++-- 2 files changed, 105 insertions(+), 25 deletions(-) diff --git a/renderer/src/components/TextTranslationMerge/ImportUsfmUI.jsx b/renderer/src/components/TextTranslationMerge/ImportUsfmUI.jsx index d1b3047e6..6319bfaa2 100644 --- a/renderer/src/components/TextTranslationMerge/ImportUsfmUI.jsx +++ b/renderer/src/components/TextTranslationMerge/ImportUsfmUI.jsx @@ -31,23 +31,26 @@ function ImportUsfmUI({
{/* saved conflicts - resume */} -
- -

Resume Conflict Resolution

-
- - {savedConflictsBooks.map((book) => ( - - ))} + {savedConflictsBooks?.length > 0 && ( + +
+ +

Resume Conflict Resolution

+
+ + {savedConflictsBooks.map((book) => ( + + ))} +
-
+ )}
); diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index 277e330db..0b832648c 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -40,6 +40,7 @@ function TranslationMergeUI() { const [loading, setLoading] = useState(false); const [error, setError] = useState(''); + const [finishedConflict, setFinishedConflict] = useState(false); const { states: { @@ -64,7 +65,9 @@ function TranslationMergeUI() { actions: { getProjectMeta }, } = useGetCurrentProjectMeta(); - console.log({ openTextTranslationMerge, currentProjectMeta, selectedBookId }); + console.log({ + openTextTranslationMerge, currentProjectMeta, selectedBookId, usfmJsons, + }); const modalClose = () => { setModel({ @@ -186,6 +189,7 @@ function TranslationMergeUI() { }); setConflictedChapters(_conflictedBooks); + setFinishedConflict(false); console.log({ usfmJsons }); }; @@ -266,9 +270,16 @@ function TranslationMergeUI() { if (importedUsfmFolderPath.length === 1 && currentProjectMeta) { setLoading(true); parseFiles(); + setFinishedConflict(false); } }, [importedUsfmFolderPath, currentProjectMeta]); + useEffect(() => { + if (conflictedChapters.length === resolvedChapters.length) { + setFinishedConflict(true); + } + }, [conflictedChapters.length, resolvedChapters.length]); + const resolveAndMarkDoneChapter = () => { setResolvedChapters((prev) => [...prev, selectedChapter]); // store the jsons to the backend (/.merge/projectName/BookID.json) @@ -287,6 +298,60 @@ function TranslationMergeUI() { }); }; + const handleFinishedResolution = async () => { + try { + const path = require('path'); + const fs = window.require('fs'); + + const { id, name } = openTextTranslationMerge.meta; + const _projectName = `${name}_${id[0]}`; + const newpath = localStorage.getItem('userPath'); + + const user = await localforage.getItem('userProfile'); + if (user?.username) { + const USFMMergeDirPath = path.join(newpath, packageInfo.name, 'users', user?.username, '.merge-usfm'); + const currentJsonFile = `${existImportedBook.bookId}.json`; + const OrgProjectFilePath = path.join(newpath, packageInfo.name, 'users', user?.username, 'projects', _projectName, 'ingredients', existImportedBook.bookId.toUpperCase()); + + // convert usfmJson.mergeJson to norml parsedJson and convert to usfm + + const resolvedTempJson = JSON.parse(JSON.stringify(usfmJsons.mergeJson)); + + for (let index = 0; index < resolvedTempJson.chapters.length; index++) { + const chObjContents = usfmJsons.mergeJson.chapters[index].contents; + for (let j = 0; j < chObjContents.length; j++) { + let verseObj = chObjContents[j]; + if (verseObj?.resolved) { + const tempResolvedContent = verseObj.resolved.resolvedContent; + verseObj = { ...tempResolvedContent }; + } + } + } + + const usfm = await parseJsonToUsfm(resolvedTempJson); + fs.writeFileSync(OrgProjectFilePath, usfm, 'utf-8'); + + // delete saved json in merge dir - check if it is the last one then delete folder too + if (!fs.existsSync(path.join(USFMMergeDirPath, _projectName))) { + const files = fs.readdirSync(path.join(USFMMergeDirPath, _projectName)); + if (files?.length > 1) { + // delete single file + await fs.unlinkSync(path.join(USFMMergeDirPath, currentJsonFile)); + } else { + // delete dir + await fs.rmdirSync(USFMMergeDirPath, { recursive: true }, (err) => { + if (err) { + throw new Error(`Error delete .usfm-merge dir : ${err}`); + } + }); + } + } + } + } catch (err) { + console.log('error : finishd move file ---> ', err); + } + }; + return ( <>

{error}

{usfmJsons.current && usfmJsons.imported && ( - + ) : ( + + + > + Resolve + + ) )}
From 8ad16dd6c7f80af325217ef116f6c05107c24619 Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Thu, 22 Feb 2024 15:06:40 +0530 Subject: [PATCH 24/50] refactor codebase to handle file based merge to project based merge, handle multi book-chapter conflict resolution --- .../src/components/Projects/ProjectList.js | 2 - .../src/components/Projects/ProjectRow.js | 16 - .../TranslationMergNavBar.jsx | 60 ++- .../TranslationMergeUI copy.jsx | 468 ++++++++++++++++++ .../TranslationMergeUI.jsx | 377 ++++---------- .../UsfmConflictEditor.jsx | 26 +- .../mergeTextTranslationProject.js | 63 +++ .../hooks/projects/useProjectsSort.js | 6 - renderer/src/core/burrito/importBurrito.js | 4 +- .../src/core/burrito/updateTranslationSB.js | 2 +- .../layouts/projects/Import/mergeProject.js | 1 + .../layouts/projects/ImportProjectPopUp.js | 14 +- renderer/src/layouts/projects/Layout.js | 12 +- 13 files changed, 719 insertions(+), 332 deletions(-) create mode 100644 renderer/src/components/TextTranslationMerge/TranslationMergeUI copy.jsx create mode 100644 renderer/src/components/TextTranslationMerge/mergeTextTranslationProject.js diff --git a/renderer/src/components/Projects/ProjectList.js b/renderer/src/components/Projects/ProjectList.js index a9bacd918..8dad7e4be 100644 --- a/renderer/src/components/Projects/ProjectList.js +++ b/renderer/src/components/Projects/ProjectList.js @@ -30,7 +30,6 @@ export default function ProjectList() { projects, // unstarredProjects, callEditProject, - openTextTranslationMerge, }, action: { handleClickStarred, @@ -104,7 +103,6 @@ export default function ProjectList() { ) : closeEditProject()} />} - {openTextTranslationMerge.open && } ); } diff --git a/renderer/src/components/Projects/ProjectRow.js b/renderer/src/components/Projects/ProjectRow.js index 196f4ea70..867033621 100644 --- a/renderer/src/components/Projects/ProjectRow.js +++ b/renderer/src/components/Projects/ProjectRow.js @@ -34,7 +34,6 @@ const ProjectRow = ({ setNotifications, setCallEditProject, setActiveNotificationCount, - setOpenTextTranslationMerge, }, } = useContext(AutographaContext); @@ -205,22 +204,7 @@ const ProjectRow = ({ )} - {project.type === 'Text Translation' && ( - - {({ active }) => ( - - )} - - )} {({ active }) => ( + {/* chapter selection */} + {selectedBook === book && ( + +
+ {conflictedChapters?.map((chNo) => ( + + ))} +
+ )} + - ) - ))} + ); + })}
diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI copy.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI copy.jsx new file mode 100644 index 000000000..fcd664a81 --- /dev/null +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI copy.jsx @@ -0,0 +1,468 @@ +/* eslint-disable no-nested-ternary */ +import React, { + useRef, Fragment, useState, useEffect, useContext, useMemo, +} from 'react'; +import { Dialog, Transition } from '@headlessui/react'; +import { AutographaContext } from '@/components/context/AutographaContext'; +import { useTranslation } from 'react-i18next'; +import { XMarkIcon } from '@heroicons/react/24/outline'; +import ConfirmationModal from '@/layouts/editor/ConfirmationModal'; +import { readUsfmFile } from '@/core/projects/userSettings'; +import DiffMatchPatch from 'diff-match-patch'; +import localforage from 'localforage'; +import TranslationMergNavBar from './TranslationMergNavBar'; +import * as logger from '../../logger'; +import useGetCurrentProjectMeta from '../Sync/hooks/useGetCurrentProjectMeta'; +import LoadingScreen from '../Loading/LoadingScreen'; +import ImportUsfmUI from './ImportUsfmUI'; +import UsfmConflictEditor from './UsfmConflictEditor'; +import { processAndIdentiyVerseChangeinUSFMJsons } from './processUsfmObjs'; +import packageInfo from '../../../../package.json'; + +const grammar = require('usfm-grammar'); + +function TranslationMergeUI({ conflictData, setConflictPopup }) { + console.log({ conflictData }); + const [importedUsfmFolderPath, setImportedUsfmFolderPath] = useState([]); + const [usfmJsons, setUsfmJsons] = useState({ + imported: null, + current: null, + }); + const [selectedChapter, setSelectedChapter] = useState(1); + const [selectedBookId, setSelectedBookId] = useState(null); + const [conflictedChapters, setConflictedChapters] = useState([]); + const [resolvedChapters, setResolvedChapters] = useState([]); + const [chapterResolveDone, setChapterResolveDone] = useState(false); + + const [savedConflictsBooks, setSavedConflictsBooks] = useState([]); + const [existImportedBook, setExistImportedBook] = useState({ status: false, bookId: null }); + + const [loading, setLoading] = useState(false); + const [error, setError] = useState(''); + const [finishedConflict, setFinishedConflict] = useState(false); + + const { t } = useTranslation(); + const cancelButtonRef = useRef(null); + const [model, setModel] = React.useState({ + openModel: false, + title: '', + confirmMessage: '', + buttonName: '', + }); + + const { + state: { currentProjectMeta }, + actions: { getProjectMeta }, + } = useGetCurrentProjectMeta(); + + console.log({ + currentProjectMeta, selectedBookId, usfmJsons, + }); + + const modalClose = () => { + setModel({ + openModel: false, + title: '', + confirmMessage: '', + buttonName: '', + }); + }; + + const handleStartOver = () => { + console.log('start over called ----'); + setExistImportedBook({ status: false, bookId: null }); + modalClose(); + }; + + const handleOnAbortMerge = (buttonName) => { + console.log({ buttonName }, model); + if (model.buttonName === t('label-abort')) { + setError(''); + setUsfmJsons({}); + setImportedUsfmFolderPath([]); + setOpenTextTranslationMerge({ open: false, meta: null }); + modalClose(); + } else { + handleStartOver(); + } + }; + + const removeSection = async (abort = false) => { + if (abort === false) { + // pass + } else { + // popup with warning + setModel({ + openModel: true, + title: t('modal-title-abort-conflict-resolution'), + confirmMessage: t('msg-abort-conflict-resolution'), + buttonName: t('label-abort'), + }); + } + }; + + const readMergeDirOrSingleFile = async (readDir = true, fileName = null) => { + const fs = window.require('fs'); + const { id, name } = openTextTranslationMerge.meta; + const _projectName = `${name}_${id[0]}`; + const newpath = localStorage.getItem('userPath'); + const path = require('path'); + + const user = await localforage.getItem('userProfile'); + if (user?.username) { + const USFMMergeDirPath = path.join(newpath, packageInfo.name, 'users', user?.username, '.merge-usfm'); + if (!fs.existsSync(path.join(USFMMergeDirPath, _projectName))) { + return null; + } + if (readDir) { + const files = fs.readdirSync(path.join(USFMMergeDirPath, _projectName)); + console.log({ files }); + return files; + } + // read file - json + let jsonFile = fs.readFileSync(path.join(USFMMergeDirPath, _projectName, fileName)); + jsonFile = JSON.parse(jsonFile); + return jsonFile; + } + console.error('no user : ', { user }); + }; + + useEffect(() => { + if (openTextTranslationMerge?.meta) { + const { id, name } = openTextTranslationMerge.meta; + (async () => { + await getProjectMeta(`${name}_${id[0]}`); + // check for existing merge and display ui based on that + const mergeDirContents = await readMergeDirOrSingleFile(); + setSavedConflictsBooks(mergeDirContents); + })(); + } + }, []); + + const openFileDialogSettingData = async () => { + logger.debug('translationMergeUI.js', 'Inside openFileDialogSettingData'); + const options = { + properties: ['openFile'], + filters: [{ name: 'usfm files', extensions: ['usfm', 'sfm', 'USFM', 'SFM'] }], + }; + const { dialog } = window.require('@electron/remote'); + const chosenFolder = await dialog.showOpenDialog(options); + if ((chosenFolder.filePaths).length > 0) { + logger.debug('translationMergeUI.js', 'Selected the files'); + setImportedUsfmFolderPath(chosenFolder.filePaths); + } else { + logger.debug('translationMergeUI.js', 'Didn\'t select any file'); + } + }; + + const handleImportUsfm = () => { + openFileDialogSettingData(); + }; + + const resumeConflictResolution = async (bookId) => { + // bookid (same as backendfilename) - > mat.json + console.log('book id : ', bookId); + const { usfmJsons } = await readMergeDirOrSingleFile(false, bookId); + setUsfmJsons(usfmJsons); + setExistImportedBook({ status: false, bookId: null }); + + const _conflictedBooks = []; + setSelectedBookId(usfmJsons.mergeJson.book.bookCode.toLowerCase()); + usfmJsons.mergeJson.chapters.forEach((chapter, index) => { + chapter.contents.forEach((content) => { + if (content.verseNumber) { + if (content?.resolved && !content?.resolved?.status) { + !_conflictedBooks.includes(chapter.chapterNumber) && _conflictedBooks.push(chapter.chapterNumber); + } + } + }); + }); + + setConflictedChapters(_conflictedBooks); + setFinishedConflict(false); + console.log({ usfmJsons }); + }; + + async function parseUsfm(usfm) { + const myUsfmParser = new grammar.USFMParser(usfm, grammar.LEVEL.RELAXED); + const isJsonValid = myUsfmParser.validate(); + return { valid: isJsonValid, data: myUsfmParser.toJSON() }; + } + + async function parseJsonToUsfm(json) { + const myUsfmParser = new grammar.JSONParser(json); + const usfm = myUsfmParser.toUSFM(); + return usfm; + } + + const parseFiles = async () => { + // parse imported + const fs = window.require('fs'); + const IncomingUsfm = fs.readFileSync(importedUsfmFolderPath[0], 'utf8'); + if (IncomingUsfm) { + const importedJson = await parseUsfm(IncomingUsfm); + // const normalisedIncomingUSFM = await parseJsonToUsfm(importedJson.data); + if (!importedJson.valid) { + setError('Imported Usfm is invalid'); + } else if (!Object.keys(currentProjectMeta?.type?.flavorType?.currentScope).includes(importedJson?.data?.book?.bookCode) + && !Object.keys(currentProjectMeta?.type?.flavorType?.currentScope).includes(importedJson?.data?.book?.bookCode?.toLowerCase())) { + setError('Imported USFM is not in the scope of Current Project'); + } else { + // Parse current project same book + const importedBookCode = `${importedJson.data.book.bookCode.toLowerCase()}.usfm`; + + setError(''); + setUsfmJsons((prev) => ({ ...prev, imported: importedJson.data })); + setSelectedBookId(importedJson.data.book.bookCode.toLowerCase()); + const currentBookPath = Object.keys(currentProjectMeta?.ingredients).find((code) => code.toLowerCase().endsWith(importedBookCode)); + const { id, name } = openTextTranslationMerge.meta; + const currentBookUsfm = await readUsfmFile(currentBookPath, `${name}_${id[0]}`); + // console.log('FOUND ====> ', { currentBookPath, currentBookUsfm }); + if (currentBookUsfm) { + const currentJson = await parseUsfm(currentBookUsfm); + // const currentNormalisedUsfm = await parseJsonToUsfm(currentJson.data); + + // generate the merge object with current , incoming , merge verses + // const mergeJson = JSON.parse(JSON.stringify(currentJson.data)); + const processOutArr = await processAndIdentiyVerseChangeinUSFMJsons(importedJson.data, currentJson.data).catch((err) => { + console.log('process usfm : ', err); + }); + const mergeJson = processOutArr[0]; + console.log('processOutArr[1] : ', processOutArr[1]); + setConflictedChapters(processOutArr[1]); + + if (savedConflictsBooks.includes(`${importedJson.data.book.bookCode.toLowerCase()}.json`)) { + setExistImportedBook({ status: true, bookId: importedJson.data.book.bookCode.toLowerCase() }); + console.log('existing book'); + setModel({ + openModel: true, + title: t('modal-title-abort-conflict-resolution'), + confirmMessage: t('msg-conflict-resolution-duplicate-book', { bookId: importedJson.data.book.bookCode.toUpperCase() }), + buttonName: t('label-startover'), + }); + } + + currentJson && currentJson?.valid && setUsfmJsons((prev) => ({ ...prev, current: currentJson.data, mergeJson })); + + // compare usfms to check conflcit or not + // const diffOut = await dmp.diff_main(normalisedIncomingUSFM, currentNormalisedUsfm); + // setUsfmJsons((prev) => ({ ...prev, diffOut })); + } + } + } else { + setError('unable to read imported USFM'); + } + setLoading(false); + }; + + useEffect(() => { + // get usfm and parse + if (importedUsfmFolderPath.length === 1 && currentProjectMeta) { + setLoading(true); + parseFiles(); + setFinishedConflict(false); + } + }, [importedUsfmFolderPath, currentProjectMeta]); + + useEffect(() => { + if (conflictedChapters.length === resolvedChapters.length) { + setFinishedConflict(true); + } + }, [conflictedChapters.length, resolvedChapters.length]); + + const resolveAndMarkDoneChapter = () => { + setResolvedChapters((prev) => [...prev, selectedChapter]); + // store the jsons to the backend (/.merge/projectName/BookID.json) + const fs = window.require('fs'); + const { id, name } = openTextTranslationMerge.meta; + const _projectName = `${name}_${id[0]}`; + const newpath = localStorage.getItem('userPath'); + const path = require('path'); + localforage.getItem('userProfile').then((user) => { + const USFMMergeDirPath = path.join(newpath, packageInfo.name, 'users', user?.username, '.merge-usfm'); + if (!fs.existsSync(path.join(USFMMergeDirPath, _projectName))) { + fs.mkdirSync(path.join(USFMMergeDirPath, _projectName), { recursive: true }); + } + console.log('write this book :', `${selectedBookId}.json`); + fs.writeFileSync(path.join(USFMMergeDirPath, _projectName, `${selectedBookId}.json`), JSON.stringify({ usfmJsons })); + }); + }; + + const handleFinishedResolution = async () => { + try { + const path = require('path'); + const fs = window.require('fs'); + + const { id, name } = openTextTranslationMerge.meta; + const _projectName = `${name}_${id[0]}`; + const newpath = localStorage.getItem('userPath'); + + const user = await localforage.getItem('userProfile'); + if (user?.username) { + const USFMMergeDirPath = path.join(newpath, packageInfo.name, 'users', user?.username, '.merge-usfm'); + const currentJsonFile = `${existImportedBook.bookId}.json`; + const OrgProjectFilePath = path.join(newpath, packageInfo.name, 'users', user?.username, 'projects', _projectName, 'ingredients', existImportedBook.bookId.toUpperCase()); + + // convert usfmJson.mergeJson to norml parsedJson and convert to usfm + + const resolvedTempJson = JSON.parse(JSON.stringify(usfmJsons.mergeJson)); + + for (let index = 0; index < resolvedTempJson.chapters.length; index++) { + const chObjContents = usfmJsons.mergeJson.chapters[index].contents; + for (let j = 0; j < chObjContents.length; j++) { + let verseObj = chObjContents[j]; + if (verseObj?.resolved) { + const tempResolvedContent = verseObj.resolved.resolvedContent; + verseObj = { ...tempResolvedContent }; + } + } + } + + const usfm = await parseJsonToUsfm(resolvedTempJson); + fs.writeFileSync(OrgProjectFilePath, usfm, 'utf-8'); + + // delete saved json in merge dir - check if it is the last one then delete folder too + if (!fs.existsSync(path.join(USFMMergeDirPath, _projectName))) { + const files = fs.readdirSync(path.join(USFMMergeDirPath, _projectName)); + if (files?.length > 1) { + // delete single file + await fs.unlinkSync(path.join(USFMMergeDirPath, currentJsonFile)); + } else { + // delete dir + await fs.rmdirSync(USFMMergeDirPath, { recursive: true }, (err) => { + if (err) { + throw new Error(`Error delete .usfm-merge dir : ${err}`); + } + }); + } + } + } + } catch (err) { + console.log('error : finishd move file ---> ', err); + } + }; + + return ( + <> + + removeSection(true)} + > + + +
+
+

{t('label-resolve-conflict')}

+
+ {/* close btn section */} + +
+ + {/* contents section */} +
+
+ + +
+
+ + {loading ? () : ( + + (usfmJsons.current && usfmJsons.imported && !existImportedBook.status) ? ( +
+ +
+ ) + : ( + + ) + + )} + +
+
+

{error}

+ {usfmJsons.current && usfmJsons.imported && ( + finishedConflict ? ( + + + ) : ( + + + ) + )} +
+
+
+
+
+
+
+ + modalClose()} + confirmMessage={model.confirmMessage} + buttonName={model.buttonName} + closeModal={() => handleOnAbortMerge(model.buttonName)} + /> + + ); +} + +export default TranslationMergeUI; diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index 0b832648c..5ae8a6325 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -20,36 +20,10 @@ import { processAndIdentiyVerseChangeinUSFMJsons } from './processUsfmObjs'; import packageInfo from '../../../../package.json'; const grammar = require('usfm-grammar'); +const path = require('path'); -const dmp = new DiffMatchPatch(); - -function TranslationMergeUI() { - const [importedUsfmFolderPath, setImportedUsfmFolderPath] = useState([]); - const [usfmJsons, setUsfmJsons] = useState({ - imported: null, - current: null, - }); - const [selectedChapter, setSelectedChapter] = useState(1); - const [selectedBookId, setSelectedBookId] = useState(null); - const [conflictedChapters, setConflictedChapters] = useState([]); - const [resolvedChapters, setResolvedChapters] = useState([]); - const [chapterResolveDone, setChapterResolveDone] = useState(false); - - const [savedConflictsBooks, setSavedConflictsBooks] = useState([]); - const [existImportedBook, setExistImportedBook] = useState({ status: false, bookId: null }); - - const [loading, setLoading] = useState(false); - const [error, setError] = useState(''); - const [finishedConflict, setFinishedConflict] = useState(false); - - const { - states: { - openTextTranslationMerge, - }, - action: { - setOpenTextTranslationMerge, - }, - } = useContext(AutographaContext); +function TranslationMergeUI({ conflictData, closeMergeWindow }) { + console.log({ conflictData }); const { t } = useTranslation(); const cancelButtonRef = useRef(null); @@ -60,14 +34,27 @@ function TranslationMergeUI() { buttonName: '', }); - const { - state: { currentProjectMeta }, - actions: { getProjectMeta }, - } = useGetCurrentProjectMeta(); + const [selectedBook, setSelectedBook] = useState(conflictData?.data?.files[0]); + const [selectedChapter, setSelectedChapter] = useState(); + const [resolvedBooks, setResolvedBooks] = useState([]); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(''); + const [usfmJsons, setUsfmJsons] = useState({}); + const [conflictedChapters, setConflictedChapters] = useState({}); - console.log({ - openTextTranslationMerge, currentProjectMeta, selectedBookId, usfmJsons, - }); + const removeSection = async (abort = false) => { + if (abort === false) { + // TODO : allow to close and continue later + } else { + // popup with warning + setModel({ + openModel: true, + title: t('modal-title-abort-conflict-resolution'), + confirmMessage: t('msg-abort-conflict-resolution'), + buttonName: t('label-abort'), + }); + } + }; const modalClose = () => { setModel({ @@ -80,7 +67,6 @@ function TranslationMergeUI() { const handleStartOver = () => { console.log('start over called ----'); - setExistImportedBook({ status: false, bookId: null }); modalClose(); }; @@ -88,111 +74,13 @@ function TranslationMergeUI() { console.log({ buttonName }, model); if (model.buttonName === t('label-abort')) { setError(''); - setUsfmJsons({ imported: null, current: null }); - setImportedUsfmFolderPath([]); - setOpenTextTranslationMerge({ open: false, meta: null }); modalClose(); + closeMergeWindow(); } else { handleStartOver(); } }; - const removeSection = async (abort = false) => { - if (abort === false) { - // pass - } else { - // popup with warning - setModel({ - openModel: true, - title: t('modal-title-abort-conflict-resolution'), - confirmMessage: t('msg-abort-conflict-resolution'), - buttonName: t('label-abort'), - }); - } - }; - - const readMergeDirOrSingleFile = async (readDir = true, fileName = null) => { - const fs = window.require('fs'); - const { id, name } = openTextTranslationMerge.meta; - const _projectName = `${name}_${id[0]}`; - const newpath = localStorage.getItem('userPath'); - const path = require('path'); - - const user = await localforage.getItem('userProfile'); - if (user?.username) { - const USFMMergeDirPath = path.join(newpath, packageInfo.name, 'users', user?.username, '.merge-usfm'); - if (!fs.existsSync(path.join(USFMMergeDirPath, _projectName))) { - return null; - } - if (readDir) { - const files = fs.readdirSync(path.join(USFMMergeDirPath, _projectName)); - console.log({ files }); - return files; - } - // read file - json - let jsonFile = fs.readFileSync(path.join(USFMMergeDirPath, _projectName, fileName)); - jsonFile = JSON.parse(jsonFile); - return jsonFile; - } - console.error('no user : ', { user }); - }; - - useEffect(() => { - if (openTextTranslationMerge?.meta) { - const { id, name } = openTextTranslationMerge.meta; - (async () => { - await getProjectMeta(`${name}_${id[0]}`); - // check for existing merge and display ui based on that - const mergeDirContents = await readMergeDirOrSingleFile(); - setSavedConflictsBooks(mergeDirContents); - })(); - } - }, []); - - const openFileDialogSettingData = async () => { - logger.debug('translationMergeUI.js', 'Inside openFileDialogSettingData'); - const options = { - properties: ['openFile'], - filters: [{ name: 'usfm files', extensions: ['usfm', 'sfm', 'USFM', 'SFM'] }], - }; - const { dialog } = window.require('@electron/remote'); - const chosenFolder = await dialog.showOpenDialog(options); - if ((chosenFolder.filePaths).length > 0) { - logger.debug('translationMergeUI.js', 'Selected the files'); - setImportedUsfmFolderPath(chosenFolder.filePaths); - } else { - logger.debug('translationMergeUI.js', 'Didn\'t select any file'); - } - }; - - const handleImportUsfm = () => { - openFileDialogSettingData(); - }; - - const resumeConflictResolution = async (bookId) => { - // bookid (same as backendfilename) - > mat.json - console.log('book id : ', bookId); - const { usfmJsons } = await readMergeDirOrSingleFile(false, bookId); - setUsfmJsons(usfmJsons); - setExistImportedBook({ status: false, bookId: null }); - - const _conflictedBooks = []; - setSelectedBookId(usfmJsons.mergeJson.book.bookCode.toLowerCase()); - usfmJsons.mergeJson.chapters.forEach((chapter, index) => { - chapter.contents.forEach((content) => { - if (content.verseNumber) { - if (content?.resolved && !content?.resolved?.status) { - !_conflictedBooks.includes(chapter.chapterNumber) && _conflictedBooks.push(chapter.chapterNumber); - } - } - }); - }); - - setConflictedChapters(_conflictedBooks); - setFinishedConflict(false); - console.log({ usfmJsons }); - }; - async function parseUsfm(usfm) { const myUsfmParser = new grammar.USFMParser(usfm, grammar.LEVEL.RELAXED); const isJsonValid = myUsfmParser.validate(); @@ -205,58 +93,52 @@ function TranslationMergeUI() { return usfm; } - const parseFiles = async () => { + console.log({ usfmJsons }); + + const checkForConflictInSelectedBook = async (selectedBook) => { // parse imported const fs = window.require('fs'); - const IncomingUsfm = fs.readFileSync(importedUsfmFolderPath[0], 'utf8'); + const IncomingUsfm = fs.readFileSync(path.join(conflictData.data.incomingPath, selectedBook), 'utf8'); if (IncomingUsfm) { const importedJson = await parseUsfm(IncomingUsfm); - // const normalisedIncomingUSFM = await parseJsonToUsfm(importedJson.data); if (!importedJson.valid) { setError('Imported Usfm is invalid'); - } else if (!Object.keys(currentProjectMeta?.type?.flavorType?.currentScope).includes(importedJson?.data?.book?.bookCode) - && !Object.keys(currentProjectMeta?.type?.flavorType?.currentScope).includes(importedJson?.data?.book?.bookCode?.toLowerCase())) { - setError('Imported USFM is not in the scope of Current Project'); } else { // Parse current project same book const importedBookCode = `${importedJson.data.book.bookCode.toLowerCase()}.usfm`; setError(''); - setUsfmJsons((prev) => ({ ...prev, imported: importedJson.data })); - setSelectedBookId(importedJson.data.book.bookCode.toLowerCase()); - const currentBookPath = Object.keys(currentProjectMeta?.ingredients).find((code) => code.toLowerCase().endsWith(importedBookCode)); - const { id, name } = openTextTranslationMerge.meta; - const currentBookUsfm = await readUsfmFile(currentBookPath, `${name}_${id[0]}`); + + setUsfmJsons((prev) => ({ ...prev, [selectedBook]: { ...prev[selectedBook], imported: importedJson.data } })); + + // setSelectedBookId(importedJson.data.book.bookCode.toLowerCase()); + // const currentBookPath = Object.keys(conflictData.data.currentMeta.ingredients).find((code) => code.toLowerCase().endsWith(importedBookCode)); + const { projectFullName } = conflictData.data; + const currentBookUsfm = await readUsfmFile(selectedBook, projectFullName); // console.log('FOUND ====> ', { currentBookPath, currentBookUsfm }); if (currentBookUsfm) { const currentJson = await parseUsfm(currentBookUsfm); - // const currentNormalisedUsfm = await parseJsonToUsfm(currentJson.data); - // generate the merge object with current , incoming , merge verses - // const mergeJson = JSON.parse(JSON.stringify(currentJson.data)); const processOutArr = await processAndIdentiyVerseChangeinUSFMJsons(importedJson.data, currentJson.data).catch((err) => { console.log('process usfm : ', err); }); const mergeJson = processOutArr[0]; console.log('processOutArr[1] : ', processOutArr[1]); - setConflictedChapters(processOutArr[1]); - - if (savedConflictsBooks.includes(`${importedJson.data.book.bookCode.toLowerCase()}.json`)) { - setExistImportedBook({ status: true, bookId: importedJson.data.book.bookCode.toLowerCase() }); - console.log('existing book'); - setModel({ - openModel: true, - title: t('modal-title-abort-conflict-resolution'), - confirmMessage: t('msg-conflict-resolution-duplicate-book', { bookId: importedJson.data.book.bookCode.toUpperCase() }), - buttonName: t('label-startover'), - }); - } - - currentJson && currentJson?.valid && setUsfmJsons((prev) => ({ ...prev, current: currentJson.data, mergeJson })); - - // compare usfms to check conflcit or not - // const diffOut = await dmp.diff_main(normalisedIncomingUSFM, currentNormalisedUsfm); - // setUsfmJsons((prev) => ({ ...prev, diffOut })); + currentJson && currentJson?.valid && setUsfmJsons((prev) => ({ ...prev, [selectedBook]: { ...prev[selectedBook], current: currentJson.data, mergeJson } })); + setConflictedChapters((prev) => ({ ...prev, [selectedBook]: processOutArr[1] })); + setLoading(false); + + // old UI logic of import and parse already saved book + // if (savedConflictsBooks.includes(`${importedJson.data.book.bookCode.toLowerCase()}.json`)) { + // setExistImportedBook({ status: true, bookId: importedJson.data.book.bookCode.toLowerCase() }); + // console.log('existing book'); + // setModel({ + // openModel: true, + // title: t('modal-title-abort-conflict-resolution'), + // confirmMessage: t('msg-conflict-resolution-duplicate-book', { bookId: importedJson.data.book.bookCode.toUpperCase() }), + // buttonName: t('label-startover'), + // }); + // } } } } else { @@ -265,97 +147,28 @@ function TranslationMergeUI() { setLoading(false); }; - useEffect(() => { - // get usfm and parse - if (importedUsfmFolderPath.length === 1 && currentProjectMeta) { - setLoading(true); - parseFiles(); - setFinishedConflict(false); - } - }, [importedUsfmFolderPath, currentProjectMeta]); + console.log({ conflictedChapters, selectedBook }); + // handle conflict check for a book on book nav useEffect(() => { - if (conflictedChapters.length === resolvedChapters.length) { - setFinishedConflict(true); - } - }, [conflictedChapters.length, resolvedChapters.length]); - - const resolveAndMarkDoneChapter = () => { - setResolvedChapters((prev) => [...prev, selectedChapter]); - // store the jsons to the backend (/.merge/projectName/BookID.json) - const fs = window.require('fs'); - const { id, name } = openTextTranslationMerge.meta; - const _projectName = `${name}_${id[0]}`; - const newpath = localStorage.getItem('userPath'); - const path = require('path'); - localforage.getItem('userProfile').then((user) => { - const USFMMergeDirPath = path.join(newpath, packageInfo.name, 'users', user?.username, '.merge-usfm'); - if (!fs.existsSync(path.join(USFMMergeDirPath, _projectName))) { - fs.mkdirSync(path.join(USFMMergeDirPath, _projectName), { recursive: true }); - } - console.log('write this book :', `${selectedBookId}.json`); - fs.writeFileSync(path.join(USFMMergeDirPath, _projectName, `${selectedBookId}.json`), JSON.stringify({ usfmJsons })); - }); - }; - - const handleFinishedResolution = async () => { - try { - const path = require('path'); - const fs = window.require('fs'); - - const { id, name } = openTextTranslationMerge.meta; - const _projectName = `${name}_${id[0]}`; - const newpath = localStorage.getItem('userPath'); - - const user = await localforage.getItem('userProfile'); - if (user?.username) { - const USFMMergeDirPath = path.join(newpath, packageInfo.name, 'users', user?.username, '.merge-usfm'); - const currentJsonFile = `${existImportedBook.bookId}.json`; - const OrgProjectFilePath = path.join(newpath, packageInfo.name, 'users', user?.username, 'projects', _projectName, 'ingredients', existImportedBook.bookId.toUpperCase()); - - // convert usfmJson.mergeJson to norml parsedJson and convert to usfm - - const resolvedTempJson = JSON.parse(JSON.stringify(usfmJsons.mergeJson)); - - for (let index = 0; index < resolvedTempJson.chapters.length; index++) { - const chObjContents = usfmJsons.mergeJson.chapters[index].contents; - for (let j = 0; j < chObjContents.length; j++) { - let verseObj = chObjContents[j]; - if (verseObj?.resolved) { - const tempResolvedContent = verseObj.resolved.resolvedContent; - verseObj = { ...tempResolvedContent }; - } - } - } - - const usfm = await parseJsonToUsfm(resolvedTempJson); - fs.writeFileSync(OrgProjectFilePath, usfm, 'utf-8'); - - // delete saved json in merge dir - check if it is the last one then delete folder too - if (!fs.existsSync(path.join(USFMMergeDirPath, _projectName))) { - const files = fs.readdirSync(path.join(USFMMergeDirPath, _projectName)); - if (files?.length > 1) { - // delete single file - await fs.unlinkSync(path.join(USFMMergeDirPath, currentJsonFile)); - } else { - // delete dir - await fs.rmdirSync(USFMMergeDirPath, { recursive: true }, (err) => { - if (err) { - throw new Error(`Error delete .usfm-merge dir : ${err}`); - } - }); - } + if (!loading) { + (async () => { + setLoading(true); + if (conflictedChapters[selectedBook]) { + setLoading(false); + } else { + await checkForConflictInSelectedBook(selectedBook); } - } - } catch (err) { - console.log('error : finishd move file ---> ', err); + })(); + } else { + // TODO : add a message loading is showing some other process is going on } - }; + }, [selectedBook]); return ( <> removeSection(true)} > @@ -391,10 +204,14 @@ function TranslationMergeUI() { {/* contents section */}
+ @@ -404,34 +221,50 @@ function TranslationMergeUI() { {loading ? () : ( - (usfmJsons.current && usfmJsons.imported && !existImportedBook.status) ? ( + usfmJsons[selectedBook]?.current && usfmJsons[selectedBook]?.imported && (
{ }} + resolvedChapters={[]} />
) - : ( - - ) + + // (usfmJsons.current && usfmJsons.imported && !existImportedBook.status) ? ( + //
+ // + //
+ // ) + // : ( + // + // ) )}

{error}

- {usfmJsons.current && usfmJsons.imported && ( +

Buttons Sections

+ {/* BUTTONS SECTIONS --------------------------------------------------------------------------- TODO add buttos */} + {/* {usfmJsons.current && usfmJsons.imported && ( finishedConflict ? ( ) - )} + )} */}
diff --git a/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx b/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx index 3be59cb70..1d407128a 100644 --- a/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx +++ b/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx @@ -6,7 +6,7 @@ import { } from '@heroicons/react/20/solid'; function UsfmConflictEditor({ - usfmJsons, currentProjectMeta, selectedChapter, setUsfmJsons, setChapterResolveDone, resolvedChapters, + usfmJsons, currentProjectMeta, selectedChapter, setUsfmJsons, setChapterResolveDone, resolvedChapters, selectedBook, }) { const [resolveAllActive, setResolveALlActive] = useState(true); const [resetAlll, setResetAll] = useState(false); @@ -17,7 +17,7 @@ function UsfmConflictEditor({ // }); const resolveAllTogether = (type) => { - usfmJsons.mergeJson.chapters.slice(selectedChapter - 1, selectedChapter)[0] + usfmJsons[selectedBook].mergeJson.chapters.slice(selectedChapter - 1, selectedChapter)[0] .contents.forEach((verseObj) => { if (verseObj?.resolved?.status === false) { let currentData = {}; @@ -32,38 +32,38 @@ function UsfmConflictEditor({ verseObj.resolved.resolvedContent = currentData; } }); - setUsfmJsons((prev) => ({ ...prev, mergeJson: usfmJsons.mergeJson })); + setUsfmJsons((prev) => ({ ...prev, [selectedBook]: { ...prev[selectedBook], mergeJson: usfmJsons[selectedBook].mergeJson } })); setResolveALlActive(false); setResetAll(true); }; const handleResetSingle = (verseNum) => { - const currentVerseObj = usfmJsons.mergeJson.chapters.slice(selectedChapter - 1, selectedChapter)[0] + const currentVerseObj = usfmJsons[selectedBook].mergeJson.chapters.slice(selectedChapter - 1, selectedChapter)[0] .contents.find((item) => item?.verseNumber === verseNum); currentVerseObj.resolved.status = false; currentVerseObj.resolved.resolvedContent = null; - setUsfmJsons((prev) => ({ ...prev, mergeJson: usfmJsons.mergeJson })); + setUsfmJsons((prev) => ({ ...prev, [selectedBook]: { ...prev[selectedBook], mergeJson: usfmJsons[selectedBook].mergeJson } })); setResolveALlActive(true); setResetAll(false); setChapterResolveDone(false); }; const resetAllResolved = () => { - usfmJsons.mergeJson.chapters.slice(selectedChapter - 1, selectedChapter)[0] + usfmJsons[selectedBook].mergeJson.chapters.slice(selectedChapter - 1, selectedChapter)[0] .contents.forEach((verseObj) => { if (verseObj?.resolved?.status === true) { verseObj.resolved.status = false; verseObj.resolved.resolvedContent = null; } }); - setUsfmJsons((prev) => ({ ...prev, mergeJson: usfmJsons.mergeJson })); + setUsfmJsons((prev) => ({ ...prev, [selectedBook]: { ...prev[selectedBook], mergeJson: usfmJsons[selectedBook].mergeJson } })); setResolveALlActive(true); setResetAll(false); setChapterResolveDone(false); }; const handleResolveSingle = (type, verseNum) => { - const currentVerseObj = usfmJsons.mergeJson.chapters.slice(selectedChapter - 1, selectedChapter)[0] + const currentVerseObj = usfmJsons[selectedBook].mergeJson.chapters.slice(selectedChapter - 1, selectedChapter)[0] .contents.find((item) => item?.verseNumber === verseNum); let currentData = {}; if (type === 'current') { @@ -75,14 +75,14 @@ function UsfmConflictEditor({ // assign to resolved section currentVerseObj.resolved.status = true; currentVerseObj.resolved.resolvedContent = currentData; - setUsfmJsons((prev) => ({ ...prev, mergeJson: usfmJsons.mergeJson })); + setUsfmJsons((prev) => ({ ...prev, [selectedBook]: { ...prev[selectedBook], mergeJson: usfmJsons[selectedBook].mergeJson } })); }; useEffect(() => { // check all resolved in the current ch let resolvedStatus = false; - for (let index = 0; index < usfmJsons.mergeJson.chapters.slice(selectedChapter - 1, selectedChapter)[0].contents.length; index++) { - const verseObj = usfmJsons.mergeJson.chapters.slice(selectedChapter - 1, selectedChapter)[0].contents[index]; + for (let index = 0; index < usfmJsons[selectedBook].mergeJson.chapters.slice(selectedChapter - 1, selectedChapter)[0].contents.length; index++) { + const verseObj = usfmJsons[selectedBook].mergeJson.chapters.slice(selectedChapter - 1, selectedChapter)[0].contents[index]; if (verseObj?.resolved && verseObj?.resolved?.status === false) { resolvedStatus = false; setChapterResolveDone(false); @@ -161,8 +161,8 @@ function UsfmConflictEditor({ {/* --------------------------------------------- testing -------------------------------------------- */}
- {selectedChapter && usfmJsons.mergeJson - && usfmJsons?.mergeJson?.chapters?.slice(selectedChapter - 1, selectedChapter)[0].contents.map((item, index) => ( + {selectedChapter && usfmJsons[selectedBook].mergeJson + && usfmJsons[selectedBook]?.mergeJson?.chapters?.slice(selectedChapter - 1, selectedChapter)[0].contents.map((item, index) => ( item.verseNumber && (
{ + try { + // update the metadata of current md5 --- updateTranslationSB (src/core/burrito/) + await updateTranslationSB(currentUser, { name: incomingMeta.projectName, id: incomingMeta.id }, false).then((updatedCurrentMeta) => { + console.log({ updatedCurrentMeta }); + // compare md5s of incoming and current ingredients + const incomingIngredients = incomingMeta.ingredientsObj; + const currentIngredients = updatedCurrentMeta.ingredients; + const conflictedIngFilePaths = []; + + Object.entries(incomingIngredients).forEach(([key, val]) => { + if (val.scope) { + // if scope then its is usfm + const bookId = Object.keys(val.scope)[0]; + console.log('bookId : ', bookId); + const currentMd5 = currentIngredients[key]?.checksum?.md5; + const incomingMd5 = val.checksum.md5; + if (currentMd5 && incomingMd5) { + if (currentMd5 !== incomingMd5) { + conflictedIngFilePaths.push(key); + } + } else { + // error no book in incoming + throw new Error('Can not proceed Merge, Project have scope difference.'); + } + } + }); + + console.log('conflict', { conflictedIngFilePaths }); + if (conflictedIngFilePaths.length > 0) { + // TODO : CREATE A BACKUP in GIT - with a proper message of backup before merge and Timestamp (Idea is to manual git reset to commit based on timestamp) + // conflcit section + setConflictPopup({ + open: true, + data: { + projectType: 'textTranslation', + files: conflictedIngFilePaths, + incomingPath, + incomingMeta, + currentMeta: updatedCurrentMeta, + projectId: incomingMeta.id[0], + projectName: incomingMeta.projectName, + projectFullName: `${incomingMeta.projectName}_${incomingMeta.id[0]}`, + currentUser, + }, + }); + } else { + // TODO : ADD A MESSGAGE HERE -nothing to merge + } + + setProcessMerge(false); + }); + + // identify conflicted books + // rest of the codes are in the current implementation ofr book wise chapter conflict + // + } catch (err) { + setProcessMerge(false); + console.error('Failue in MergeText Process : ', err); + } +}; diff --git a/renderer/src/components/hooks/projects/useProjectsSort.js b/renderer/src/components/hooks/projects/useProjectsSort.js index 992dd8fbe..7759de11f 100644 --- a/renderer/src/components/hooks/projects/useProjectsSort.js +++ b/renderer/src/components/hooks/projects/useProjectsSort.js @@ -24,10 +24,6 @@ function useProjectsSort() { const [callEditProject, setCallEditProject] = React.useState(false); const [loading, setLoading] = React.useState(false); const [activeNotificationCount, setActiveNotificationCount] = React.useState(0); - const [openTextTranslationMerge, setOpenTextTranslationMerge] = React.useState({ - open: false, - meta: null, - }); const starrtedData = []; const unstarrtedData = []; @@ -357,7 +353,6 @@ function useProjectsSort() { selectedProject, notifications, activeNotificationCount, - openTextTranslationMerge, }, actions: { handleClickStarred, @@ -379,7 +374,6 @@ function useProjectsSort() { setSelectedProject, setNotifications, setActiveNotificationCount, - setOpenTextTranslationMerge, }, }; return response; diff --git a/renderer/src/core/burrito/importBurrito.js b/renderer/src/core/burrito/importBurrito.js index c85f14110..5bd3c4d3d 100644 --- a/renderer/src/core/burrito/importBurrito.js +++ b/renderer/src/core/burrito/importBurrito.js @@ -90,8 +90,9 @@ export const viewBurrito = async (filePath, currentUser, resource) => { let sb = fs.readFileSync(path.join(filePath, 'metadata.json')); const metadata = JSON.parse(sb); // Fixing the issue of previous version of AG. The dateCreated was left empty and it will fail the validation. + const agId = Object.keys(metadata?.identification?.primary?.scribe); + result.id = agId; if (!metadata?.meta?.dateCreated) { - const agId = Object.keys(metadata?.identification?.primary?.scribe); metadata.meta.dateCreated = metadata?.identification?.primary?.scribe[agId[0]].timestamp; sb = JSON.stringify(metadata); } @@ -103,6 +104,7 @@ export const viewBurrito = async (filePath, currentUser, resource) => { result.version = metadata.meta.version; result.burritoType = `${metadata.type?.flavorType?.name} / ${metadata.type?.flavorType?.flavor?.name}`; result.ingredients = Object.keys(metadata.ingredients).map((key) => key); + result.ingredientsObj = metadata.ingredients; result.primaryKey = metadata.identification.primary; result.publicDomain = metadata.copyright?.publicDomain; result.language = metadata.languages.map((lang) => lang.name.en); diff --git a/renderer/src/core/burrito/updateTranslationSB.js b/renderer/src/core/burrito/updateTranslationSB.js index 7ae82d664..228d42a1b 100644 --- a/renderer/src/core/burrito/updateTranslationSB.js +++ b/renderer/src/core/burrito/updateTranslationSB.js @@ -88,7 +88,7 @@ const updateTranslationSB = async (username, project, updateBurrito) => new Prom try { logger.debug('updateTranslationSB.js', 'Updating the metadata.json (burrito) file.'); fs.writeFileSync(path.join(folder, 'metadata.json'), JSON.stringify(metadata)); - resolve(true); + resolve(metadata); } catch { logger.error('updateTranslationSB.js', 'Failed to update the metadata.json (burrito) file.'); resolve(false); diff --git a/renderer/src/layouts/projects/Import/mergeProject.js b/renderer/src/layouts/projects/Import/mergeProject.js index 45a2e8a78..01b1a4f1b 100644 --- a/renderer/src/layouts/projects/Import/mergeProject.js +++ b/renderer/src/layouts/projects/Import/mergeProject.js @@ -167,6 +167,7 @@ export const mergeProject = async (incomingPath, currentUser, setConflictPopup, setConflictPopup({ open: true, data: { + projectType: 'textStories', files: mergeStatus.data, mergeDirPath, projectPath: targetPath, diff --git a/renderer/src/layouts/projects/ImportProjectPopUp.js b/renderer/src/layouts/projects/ImportProjectPopUp.js index 436bd2fe1..f7858ccf1 100644 --- a/renderer/src/layouts/projects/ImportProjectPopUp.js +++ b/renderer/src/layouts/projects/ImportProjectPopUp.js @@ -18,7 +18,9 @@ import * as logger from '../../logger'; import ConfirmationModal from '../editor/ConfirmationModal'; import burrito from '../../lib/BurritoTemplete.json'; import { mergeProject } from './Import/mergeProject'; + import { LoadingSpinner } from '@/components/LoadingSpinner'; +import { mergeTextTranslationProject } from '@/components/TextTranslationMerge/mergeTextTranslationProject'; export default function ImportProjectPopUp(props) { const { @@ -187,13 +189,21 @@ export default function ImportProjectPopUp(props) { logger.debug('importProjectPopUp.js', 'call for merge'); setProcessMerge(true) modelClose(); - await mergeProject(folderPath, currentUser, setConflictPopup, setModel, setProcessMerge); + if (sbData?.burritoType === 'gloss / textStories'){ + await mergeProject(folderPath, currentUser, setConflictPopup, setModel, setProcessMerge); + }else if (sbData?.burritoType === 'scripture / textTranslation') { + console.log("Started Indentify Merge conflicts ------"); + await mergeTextTranslationProject(folderPath, currentUser, setConflictPopup, setProcessMerge, sbData) + console.log("completed merge idenitfy process ------"); + } setMerge(false) setSbData({}); close() logger.debug('importProjectPopUp.js', 'git merge process done'); } + console.log({sbData}); + const importProject = async () => { logger.debug('ImportProjectPopUp.js', 'Inside importProject'); if (folderPath) { @@ -202,7 +212,7 @@ export default function ImportProjectPopUp(props) { if (sbData.duplicate === true) { logger.warn('ImportProjectPopUp.js', 'Project already available'); // currently MERGE feature only Enabled for OBS projects - if (sbData?.burritoType === 'gloss / textStories'){ + if (sbData?.burritoType === 'gloss / textStories' || sbData?.burritoType === 'scripture / textTranslation'){ setMerge(true) } setModel({ diff --git a/renderer/src/layouts/projects/Layout.js b/renderer/src/layouts/projects/Layout.js index 3ba5e3104..8aae80731 100644 --- a/renderer/src/layouts/projects/Layout.js +++ b/renderer/src/layouts/projects/Layout.js @@ -12,6 +12,7 @@ import SideBar from './SideBar'; import TopMenuBar from './TopMenuBar'; import ImportProjectPopUp from './ImportProjectPopUp'; import ConflictResolverUI from './Import/ConflictResolverUI'; +import TranslationMergeUI from '@/components/TextTranslationMerge/TranslationMergeUI'; export default function ProjectsLayout(props) { const { @@ -34,6 +35,13 @@ export default function ProjectsLayout(props) { data: undefined, }); + function closeMergeWindow() { + setConflictPopup({ + open: false, + data: undefined, + }); + } + const { t } = useTranslation(); function handleOpenImportPopUp() { setOpenImportPopUp(true); @@ -83,7 +91,9 @@ export default function ProjectsLayout(props) { {conflictPopup.open && (
- + {conflictPopup.data?.projectType === 'textTranslation' + ? + : }
)} From 8a83618cb70e2494faf27d63f756084a70307628 Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Fri, 23 Feb 2024 12:45:37 +0530 Subject: [PATCH 25/50] added resolve chapter and book functions added. book resolved ui need to add, and save functionality pending --- .../src/components/Projects/ProjectList.js | 1 - .../TranslationMergeUI.jsx | 61 ++++++++++++++----- .../mergeTextTranslationProject.js | 18 +++++- 3 files changed, 61 insertions(+), 19 deletions(-) diff --git a/renderer/src/components/Projects/ProjectList.js b/renderer/src/components/Projects/ProjectList.js index 8dad7e4be..3e9dd95c6 100644 --- a/renderer/src/components/Projects/ProjectList.js +++ b/renderer/src/components/Projects/ProjectList.js @@ -15,7 +15,6 @@ import NewProject from './NewProject'; import * as logger from '../../logger'; import ProjectRow from './ProjectRow'; import { ProjectContext } from '../context/ProjectContext'; -import TranslationMergeUI from '../TextTranslationMerge/TranslationMergeUI'; export default function ProjectList() { const { t } = useTranslation(); diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index 5ae8a6325..5c4bec671 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -34,13 +34,16 @@ function TranslationMergeUI({ conflictData, closeMergeWindow }) { buttonName: '', }); - const [selectedBook, setSelectedBook] = useState(conflictData?.data?.files[0]); const [selectedChapter, setSelectedChapter] = useState(); const [resolvedBooks, setResolvedBooks] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(''); const [usfmJsons, setUsfmJsons] = useState({}); + const [selectedBook, setSelectedBook] = useState(); const [conflictedChapters, setConflictedChapters] = useState({}); + const [chapterResolveDone, setChapterResolveDone] = useState(false); + const [finishedConflict, setFinishedConflict] = useState(false); + const [resolvedChapters, setResolvedChapters] = useState({}); const removeSection = async (abort = false) => { if (abort === false) { @@ -93,12 +96,12 @@ function TranslationMergeUI({ conflictData, closeMergeWindow }) { return usfm; } - console.log({ usfmJsons }); + console.log({ conflictedChapters, selectedBook, usfmJsons }); const checkForConflictInSelectedBook = async (selectedBook) => { // parse imported const fs = window.require('fs'); - const IncomingUsfm = fs.readFileSync(path.join(conflictData.data.incomingPath, selectedBook), 'utf8'); + const IncomingUsfm = fs.readFileSync(path.join(usfmJsons.conflictMeta.incomingPath, selectedBook), 'utf8'); if (IncomingUsfm) { const importedJson = await parseUsfm(IncomingUsfm); if (!importedJson.valid) { @@ -112,8 +115,8 @@ function TranslationMergeUI({ conflictData, closeMergeWindow }) { setUsfmJsons((prev) => ({ ...prev, [selectedBook]: { ...prev[selectedBook], imported: importedJson.data } })); // setSelectedBookId(importedJson.data.book.bookCode.toLowerCase()); - // const currentBookPath = Object.keys(conflictData.data.currentMeta.ingredients).find((code) => code.toLowerCase().endsWith(importedBookCode)); - const { projectFullName } = conflictData.data; + // const currentBookPath = Object.keys(usfmJsons.conflictMeta.currentMeta.ingredients).find((code) => code.toLowerCase().endsWith(importedBookCode)); + const { projectFullName } = usfmJsons.conflictMeta; const currentBookUsfm = await readUsfmFile(selectedBook, projectFullName); // console.log('FOUND ====> ', { currentBookPath, currentBookUsfm }); if (currentBookUsfm) { @@ -147,11 +150,40 @@ function TranslationMergeUI({ conflictData, closeMergeWindow }) { setLoading(false); }; - console.log({ conflictedChapters, selectedBook }); + const handleFinishedResolution = () => { + + }; + + const resolveAndMarkDoneChapter = () => { + const restOfTheChapters = conflictedChapters[selectedBook]?.filter((chNo) => chNo !== selectedChapter); + setConflictedChapters((prev) => ({ ...prev, [selectedBook]: restOfTheChapters })); + if (restOfTheChapters?.length === 0) { + // completed conflicts for that particualr book + setResolvedBooks((prev) => [...prev, selectedBook]); + } + // store the jsons to the backend (/.merge/projectName/BookID.json) + const fs = window.require('fs'); + const { projectFullName } = usfmJsons.conflictMeta; + const newpath = localStorage.getItem('userPath'); + const path = require('path'); + localforage.getItem('userProfile').then((user) => { + const USFMMergeDirPath = path.join(newpath, packageInfo.name, 'users', user?.username, '.merge-usfm'); + if (!fs.existsSync(path.join(USFMMergeDirPath, projectFullName))) { + fs.mkdirSync(path.join(USFMMergeDirPath, projectFullName), { recursive: true }); + } + fs.writeFileSync(path.join(USFMMergeDirPath, projectFullName, `${usfmJsons}.json`), JSON.stringify({ usfmJsons })); + }); + }; + + // store conflict data to usfm jsons meta + useEffect(() => { + setUsfmJsons((prev) => ({ ...prev, conflictMeta: conflictData.data })); + setSelectedBook(conflictData?.data?.files[0]); + }, [conflictData]); // handle conflict check for a book on book nav useEffect(() => { - if (!loading) { + if (!loading && usfmJsons?.conflictMeta) { (async () => { setLoading(true); if (conflictedChapters[selectedBook]) { @@ -163,7 +195,7 @@ function TranslationMergeUI({ conflictData, closeMergeWindow }) { } else { // TODO : add a message loading is showing some other process is going on } - }, [selectedBook]); + }, [selectedBook, usfmJsons.conflictMeta]); return ( <> @@ -206,7 +238,7 @@ function TranslationMergeUI({ conflictData, closeMergeWindow }) {
{ }} + setChapterResolveDone={setChapterResolveDone} resolvedChapters={[]} />
@@ -262,11 +294,8 @@ function TranslationMergeUI({ conflictData, closeMergeWindow }) {

{error}

-

Buttons Sections

- {/* BUTTONS SECTIONS --------------------------------------------------------------------------- TODO add buttos */} - {/* {usfmJsons.current && usfmJsons.imported && ( + {usfmJsons[selectedBook]?.current && usfmJsons[selectedBook]?.imported && ( finishedConflict ? ( - ) - )} */} + )}
diff --git a/renderer/src/components/TextTranslationMerge/mergeTextTranslationProject.js b/renderer/src/components/TextTranslationMerge/mergeTextTranslationProject.js index 26c193aea..53359646f 100644 --- a/renderer/src/components/TextTranslationMerge/mergeTextTranslationProject.js +++ b/renderer/src/components/TextTranslationMerge/mergeTextTranslationProject.js @@ -1,9 +1,15 @@ import updateTranslationSB from '@/core/burrito/updateTranslationSB'; +import packageInfo from '../../../../package.json'; export const mergeTextTranslationProject = async (incomingPath, currentUser, setConflictPopup, setProcessMerge, incomingMeta) => { try { // update the metadata of current md5 --- updateTranslationSB (src/core/burrito/) - await updateTranslationSB(currentUser, { name: incomingMeta.projectName, id: incomingMeta.id }, false).then((updatedCurrentMeta) => { + const fse = window.require('fs-extra'); + const fs = window.require('fs'); + const path = require('path'); + const newpath = localStorage.getItem('userPath'); + + await updateTranslationSB(currentUser, { name: incomingMeta.projectName, id: incomingMeta.id }, false).then(async (updatedCurrentMeta) => { console.log({ updatedCurrentMeta }); // compare md5s of incoming and current ingredients const incomingIngredients = incomingMeta.ingredientsObj; @@ -30,6 +36,14 @@ export const mergeTextTranslationProject = async (incomingPath, currentUser, set console.log('conflict', { conflictedIngFilePaths }); if (conflictedIngFilePaths.length > 0) { + // move imported project to backup folder + const USFMMergeDirPath = path.join(newpath, packageInfo.name, 'users', currentUser, '.merge-usfm'); + + if (!fs.existsSync(path.join(USFMMergeDirPath, `${incomingMeta.projectName}_${incomingMeta.id[0]}`))) { + fs.mkdirSync(path.join(USFMMergeDirPath, `${incomingMeta.projectName}_${incomingMeta.id[0]}`), { recursive: true }); + } + await fse.copy(incomingPath, path.join(USFMMergeDirPath, `${incomingMeta.projectName}_${incomingMeta.id[0]}`, 'incoming')); + // TODO : CREATE A BACKUP in GIT - with a proper message of backup before merge and Timestamp (Idea is to manual git reset to commit based on timestamp) // conflcit section setConflictPopup({ @@ -37,7 +51,7 @@ export const mergeTextTranslationProject = async (incomingPath, currentUser, set data: { projectType: 'textTranslation', files: conflictedIngFilePaths, - incomingPath, + incomingPath: path.join(USFMMergeDirPath, `${incomingMeta.projectName}_${incomingMeta.id[0]}`, 'incoming'), incomingMeta, currentMeta: updatedCurrentMeta, projectId: incomingMeta.id[0], From 596736ea01453b129d6779fadbad8a40e5d7257f Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Wed, 17 Apr 2024 12:12:01 +0530 Subject: [PATCH 26/50] strike out and remove nav from resolved chapter; fixed backend file name; resolve button fixed on complete; --- .../TextTranslationMerge/TranslationMergNavBar.jsx | 7 ++++--- .../components/TextTranslationMerge/TranslationMergeUI.jsx | 6 +++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergNavBar.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergNavBar.jsx index 478da842d..827a9f121 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergNavBar.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergNavBar.jsx @@ -26,7 +26,7 @@ function TranslationMergNavBar({ key={book} // className="w-full" className={`w-full py-2 mb-4 ${resolvedBooks.includes(book) - ? 'line-through decoration-2 pointer-events-none' + ? 'pointer-events-none' : `${selectedBook === book ? 'bg-primary/70' : 'hover:bg-primary cursor-pointer'}`} `} // eslint-disable-next-line jsx-a11y/no-noninteractive-element-to-interactive-role @@ -38,10 +38,11 @@ function TranslationMergNavBar({ className="w-full text-center" > - {bookId[1]} + {bookId[1]} + {/* chapter selection */} - {selectedBook === book && ( + {selectedBook === book && !resolvedBooks.includes(book) && (
{conflictedChapters?.map((chNo) => ( diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index 5c4bec671..15a2dc417 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -155,11 +155,15 @@ function TranslationMergeUI({ conflictData, closeMergeWindow }) { }; const resolveAndMarkDoneChapter = () => { + setChapterResolveDone(false); const restOfTheChapters = conflictedChapters[selectedBook]?.filter((chNo) => chNo !== selectedChapter); setConflictedChapters((prev) => ({ ...prev, [selectedBook]: restOfTheChapters })); if (restOfTheChapters?.length === 0) { // completed conflicts for that particualr book setResolvedBooks((prev) => [...prev, selectedBook]); + } else { + // current book have pending chapter , // Switch to next chapter or book + setSelectedChapter(restOfTheChapters[0]); } // store the jsons to the backend (/.merge/projectName/BookID.json) const fs = window.require('fs'); @@ -171,7 +175,7 @@ function TranslationMergeUI({ conflictData, closeMergeWindow }) { if (!fs.existsSync(path.join(USFMMergeDirPath, projectFullName))) { fs.mkdirSync(path.join(USFMMergeDirPath, projectFullName), { recursive: true }); } - fs.writeFileSync(path.join(USFMMergeDirPath, projectFullName, `${usfmJsons}.json`), JSON.stringify({ usfmJsons })); + fs.writeFileSync(path.join(USFMMergeDirPath, projectFullName, 'usfmJsons.json'), JSON.stringify({ usfmJsons })); }); }; From b77cf9c2924c40e27ba2f6fc0c53eed7ef858076 Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Wed, 17 Apr 2024 12:40:44 +0530 Subject: [PATCH 27/50] disabled reset option on chapter conflict resolution, auto switch chapter on completion; fixed issue of last chapter conflict resolved and reset issue; --- .../TranslationMergeUI.jsx | 2 ++ .../UsfmConflictEditor.jsx | 21 ++++++++++++------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index 15a2dc417..afd999906 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -267,6 +267,8 @@ function TranslationMergeUI({ conflictData, closeMergeWindow }) { setUsfmJsons={setUsfmJsons} setChapterResolveDone={setChapterResolveDone} resolvedChapters={[]} + resolvedBooks={resolvedBooks} + conflictedChapters={conflictedChapters[selectedBook]} />
) diff --git a/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx b/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx index 1d407128a..eec16213b 100644 --- a/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx +++ b/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx @@ -6,7 +6,7 @@ import { } from '@heroicons/react/20/solid'; function UsfmConflictEditor({ - usfmJsons, currentProjectMeta, selectedChapter, setUsfmJsons, setChapterResolveDone, resolvedChapters, selectedBook, + usfmJsons, currentProjectMeta, selectedChapter, setUsfmJsons, setChapterResolveDone, resolvedChapters, selectedBook, resolvedBooks, conflictedChapters, }) { const [resolveAllActive, setResolveALlActive] = useState(true); const [resetAlll, setResetAll] = useState(false); @@ -16,6 +16,8 @@ function UsfmConflictEditor({ // usfmJsons, currentProjectMeta, selectedChapter, // }); + console.log('conflicted chapters ]]]]]]]]]]]]]] : ', conflictedChapters); + const resolveAllTogether = (type) => { usfmJsons[selectedBook].mergeJson.chapters.slice(selectedChapter - 1, selectedChapter)[0] .contents.forEach((verseObj) => { @@ -144,9 +146,9 @@ function UsfmConflictEditor({ @@ -172,17 +174,20 @@ function UsfmConflictEditor({ > {item.verseNumber} {/* conflict is / was there */} - {(item?.resolved && !resolvedChapters.includes(selectedChapter)) ? ( + {/* {(item?.resolved && !resolvedChapters.includes(selectedChapter)) ? ( */} + {(item?.resolved) ? ( // conflict resolved section (Data from resolved.resolvedContent) item.resolved.status ? (
{item.resolved.resolvedContent.verseText}
- handleResetSingle(item.verseNumber)} - /> + {conflictedChapters?.includes(selectedChapter) && ( + handleResetSingle(item.verseNumber)} + /> + )}
) From 714a6e578edd71b560bc172f6f0b85ec8973d915 Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Thu, 18 Apr 2024 12:38:18 +0530 Subject: [PATCH 28/50] functions to trigger complete conflict done --- .../TextTranslationMerge/TranslationMergeUI.jsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index afd999906..38c2db550 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -8,7 +8,6 @@ import { useTranslation } from 'react-i18next'; import { XMarkIcon } from '@heroicons/react/24/outline'; import ConfirmationModal from '@/layouts/editor/ConfirmationModal'; import { readUsfmFile } from '@/core/projects/userSettings'; -import DiffMatchPatch from 'diff-match-patch'; import localforage from 'localforage'; import TranslationMergNavBar from './TranslationMergNavBar'; import * as logger from '../../logger'; @@ -151,13 +150,15 @@ function TranslationMergeUI({ conflictData, closeMergeWindow }) { }; const handleFinishedResolution = () => { - + console.log('in finish complete resolution ===============> '); }; const resolveAndMarkDoneChapter = () => { setChapterResolveDone(false); + // remove current chapter from conflicted list const restOfTheChapters = conflictedChapters[selectedBook]?.filter((chNo) => chNo !== selectedChapter); setConflictedChapters((prev) => ({ ...prev, [selectedBook]: restOfTheChapters })); + if (restOfTheChapters?.length === 0) { // completed conflicts for that particualr book setResolvedBooks((prev) => [...prev, selectedBook]); @@ -179,10 +180,18 @@ function TranslationMergeUI({ conflictData, closeMergeWindow }) { }); }; + // useEffect to trigger comleted all conflict Resolution + useEffect(() => { + if (resolvedBooks.length >= Object.keys(conflictedChapters).length) { + setFinishedConflict(true); + } + }, [resolvedBooks, conflictedChapters]); + // store conflict data to usfm jsons meta useEffect(() => { setUsfmJsons((prev) => ({ ...prev, conflictMeta: conflictData.data })); setSelectedBook(conflictData?.data?.files[0]); + // TODO : Auto Select first Chapter of the selected Book }, [conflictData]); // handle conflict check for a book on book nav From 4be97dc1e6128e9d316cd5b677a5e801a568f7fc Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Thu, 18 Apr 2024 15:37:45 +0530 Subject: [PATCH 29/50] functionality for merge success;replace source files; delete .merge project --- .../TranslationMergeUI.jsx | 47 +++++++++++++++---- .../UsfmConflictEditor.jsx | 28 +++++++---- .../mergeTextTranslationProject.js | 14 +++--- .../TextTranslationMerge/processUsfmObjs.js | 2 +- renderer/src/layouts/projects/Layout.js | 41 +++++++++++----- 5 files changed, 96 insertions(+), 36 deletions(-) diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index 38c2db550..8c1221e1e 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -1,19 +1,17 @@ /* eslint-disable no-nested-ternary */ import React, { - useRef, Fragment, useState, useEffect, useContext, useMemo, + useRef, Fragment, useState, useEffect, } from 'react'; import { Dialog, Transition } from '@headlessui/react'; -import { AutographaContext } from '@/components/context/AutographaContext'; import { useTranslation } from 'react-i18next'; import { XMarkIcon } from '@heroicons/react/24/outline'; import ConfirmationModal from '@/layouts/editor/ConfirmationModal'; import { readUsfmFile } from '@/core/projects/userSettings'; import localforage from 'localforage'; +import { flushSync } from 'react-dom'; import TranslationMergNavBar from './TranslationMergNavBar'; import * as logger from '../../logger'; -import useGetCurrentProjectMeta from '../Sync/hooks/useGetCurrentProjectMeta'; import LoadingScreen from '../Loading/LoadingScreen'; -import ImportUsfmUI from './ImportUsfmUI'; import UsfmConflictEditor from './UsfmConflictEditor'; import { processAndIdentiyVerseChangeinUSFMJsons } from './processUsfmObjs'; import packageInfo from '../../../../package.json'; @@ -21,9 +19,7 @@ import packageInfo from '../../../../package.json'; const grammar = require('usfm-grammar'); const path = require('path'); -function TranslationMergeUI({ conflictData, closeMergeWindow }) { - console.log({ conflictData }); - +function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) { const { t } = useTranslation(); const cancelButtonRef = useRef(null); const [model, setModel] = React.useState({ @@ -95,7 +91,7 @@ function TranslationMergeUI({ conflictData, closeMergeWindow }) { return usfm; } - console.log({ conflictedChapters, selectedBook, usfmJsons }); + // console.log({ conflictedChapters, selectedBook, usfmJsons }); const checkForConflictInSelectedBook = async (selectedBook) => { // parse imported @@ -149,8 +145,36 @@ function TranslationMergeUI({ conflictData, closeMergeWindow }) { setLoading(false); }; - const handleFinishedResolution = () => { - console.log('in finish complete resolution ===============> '); + const handleFinishedResolution = async () => { + const fs = window.require('fs'); + + flushSync(() => { + setLoading(true); + setFinishedConflict(false); + }); + + const resolvedBooks = { ...usfmJsons }; + delete resolvedBooks.conflictMeta; + console.log('after delete ============> ', resolvedBooks, usfmJsons); + // TODO : Disable all clicks when loading is true + + // loop over the resolved books + // eslint-disable-next-line no-restricted-syntax + for (const bookName of Object.keys(resolvedBooks)) { + const resolvedMergeJson = resolvedBooks[bookName]?.mergeJson; + // eslint-disable-next-line no-await-in-loop + const generatedUSFM = await parseJsonToUsfm(resolvedMergeJson); + const sourceIngredientPath = path.join(usfmJsons.conflictMeta.sourceProjectPath); + // overwrite the source file with new file + fs.writeFileSync(path.join(sourceIngredientPath, 'ingredients', `${resolvedMergeJson.book.bookCode}.usfm`), generatedUSFM); + } + + // remove .merge/project + await fs.rmSync(usfmJsons.conflictMeta.projectMergePath, { recursive: true, force: true }); + + setLoading(false); + triggerSnackBar('success', 'Conflict Resolved Successfully'); + closeMergeWindow(); }; const resolveAndMarkDoneChapter = () => { @@ -184,6 +208,8 @@ function TranslationMergeUI({ conflictData, closeMergeWindow }) { useEffect(() => { if (resolvedBooks.length >= Object.keys(conflictedChapters).length) { setFinishedConflict(true); + } else { + setFinishedConflict(false); } }, [resolvedBooks, conflictedChapters]); @@ -348,6 +374,7 @@ function TranslationMergeUI({ conflictData, closeMergeWindow }) { buttonName={model.buttonName} closeModal={() => handleOnAbortMerge(model.buttonName)} /> + ); } diff --git a/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx b/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx index eec16213b..97120a278 100644 --- a/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx +++ b/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx @@ -12,11 +12,9 @@ function UsfmConflictEditor({ const [resetAlll, setResetAll] = useState(false); const { t } = useTranslation(); - // console.log({ - // usfmJsons, currentProjectMeta, selectedChapter, - // }); - - console.log('conflicted chapters ]]]]]]]]]]]]]] : ', conflictedChapters); + console.log({ + usfmJsons, currentProjectMeta, selectedChapter, + }); const resolveAllTogether = (type) => { usfmJsons[selectedBook].mergeJson.chapters.slice(selectedChapter - 1, selectedChapter)[0] @@ -32,6 +30,9 @@ function UsfmConflictEditor({ // assign to resolved section verseObj.resolved.status = true; verseObj.resolved.resolvedContent = currentData; + // set the current data to the verse => contents and verse => verseText + verseObj.contents = currentData.contents; + verseObj.verseText = currentData.verseText; } }); setUsfmJsons((prev) => ({ ...prev, [selectedBook]: { ...prev[selectedBook], mergeJson: usfmJsons[selectedBook].mergeJson } })); @@ -44,6 +45,9 @@ function UsfmConflictEditor({ .contents.find((item) => item?.verseNumber === verseNum); currentVerseObj.resolved.status = false; currentVerseObj.resolved.resolvedContent = null; + // reset the default contents and verseText with current data + currentVerseObj.contents = currentVerseObj.current.contents; + currentVerseObj.verseText = currentVerseObj.current.verseText; setUsfmJsons((prev) => ({ ...prev, [selectedBook]: { ...prev[selectedBook], mergeJson: usfmJsons[selectedBook].mergeJson } })); setResolveALlActive(true); setResetAll(false); @@ -56,6 +60,9 @@ function UsfmConflictEditor({ if (verseObj?.resolved?.status === true) { verseObj.resolved.status = false; verseObj.resolved.resolvedContent = null; + // reset the default contents and verseText with current data + verseObj.contents = verseObj.current.contents; + verseObj.verseText = verseObj.current.verseText; } }); setUsfmJsons((prev) => ({ ...prev, [selectedBook]: { ...prev[selectedBook], mergeJson: usfmJsons[selectedBook].mergeJson } })); @@ -69,7 +76,9 @@ function UsfmConflictEditor({ .contents.find((item) => item?.verseNumber === verseNum); let currentData = {}; if (type === 'current') { + // INFO: the the resolved data is now storing in contents and verseText , which can be used to USFM generation easily currentData = { verseText: currentVerseObj.verseText, contents: currentVerseObj.contents, verseNumber: verseNum }; + // the content & verse text by default have the current content } else { currentData = currentVerseObj.incoming; } @@ -77,6 +86,9 @@ function UsfmConflictEditor({ // assign to resolved section currentVerseObj.resolved.status = true; currentVerseObj.resolved.resolvedContent = currentData; + // set the current data to the verse => contents and verse => verseText + currentVerseObj.contents = currentData.contents; + currentVerseObj.verseText = currentData.verseText; setUsfmJsons((prev) => ({ ...prev, [selectedBook]: { ...prev[selectedBook], mergeJson: usfmJsons[selectedBook].mergeJson } })); }; @@ -174,14 +186,14 @@ function UsfmConflictEditor({ > {item.verseNumber} {/* conflict is / was there */} - {/* {(item?.resolved && !resolvedChapters.includes(selectedChapter)) ? ( */} {(item?.resolved) ? ( // conflict resolved section (Data from resolved.resolvedContent) item.resolved.status ? (
-
{item.resolved.resolvedContent.verseText}
+ {/*
{item.resolved.resolvedContent.verseText}
*/} +
{item.verseText}
{conflictedChapters?.includes(selectedChapter) && ( handleResolveSingle('current', item.verseNumber)} > - {item.verseText} + {item.current.verseText}
0) { // move imported project to backup folder const USFMMergeDirPath = path.join(newpath, packageInfo.name, 'users', currentUser, '.merge-usfm'); - - if (!fs.existsSync(path.join(USFMMergeDirPath, `${incomingMeta.projectName}_${incomingMeta.id[0]}`))) { - fs.mkdirSync(path.join(USFMMergeDirPath, `${incomingMeta.projectName}_${incomingMeta.id[0]}`), { recursive: true }); + const projectDirName = `${incomingMeta.projectName}_${incomingMeta.id[0]}`; + if (!fs.existsSync(path.join(USFMMergeDirPath, projectDirName))) { + fs.mkdirSync(path.join(USFMMergeDirPath, projectDirName), { recursive: true }); } - await fse.copy(incomingPath, path.join(USFMMergeDirPath, `${incomingMeta.projectName}_${incomingMeta.id[0]}`, 'incoming')); + await fse.copy(incomingPath, path.join(USFMMergeDirPath, projectDirName, 'incoming')); // TODO : CREATE A BACKUP in GIT - with a proper message of backup before merge and Timestamp (Idea is to manual git reset to commit based on timestamp) // conflcit section @@ -51,12 +51,14 @@ export const mergeTextTranslationProject = async (incomingPath, currentUser, set data: { projectType: 'textTranslation', files: conflictedIngFilePaths, - incomingPath: path.join(USFMMergeDirPath, `${incomingMeta.projectName}_${incomingMeta.id[0]}`, 'incoming'), + incomingPath: path.join(USFMMergeDirPath, projectDirName, 'incoming'), incomingMeta, currentMeta: updatedCurrentMeta, projectId: incomingMeta.id[0], projectName: incomingMeta.projectName, - projectFullName: `${incomingMeta.projectName}_${incomingMeta.id[0]}`, + projectFullName: projectDirName, + sourceProjectPath: path.join(newpath, packageInfo.name, 'users', currentUser, 'projects', projectDirName), + projectMergePath: path.join(USFMMergeDirPath, projectDirName), currentUser, }, }); diff --git a/renderer/src/components/TextTranslationMerge/processUsfmObjs.js b/renderer/src/components/TextTranslationMerge/processUsfmObjs.js index 62616f3e7..ccc6071ec 100644 --- a/renderer/src/components/TextTranslationMerge/processUsfmObjs.js +++ b/renderer/src/components/TextTranslationMerge/processUsfmObjs.js @@ -1,6 +1,5 @@ async function processAndIdentiyVerseChangeinUSFMJsons(currentJson, IncomingJson) { // process USFM JSONs and generate comparaison object - const mergeTempJson = JSON.parse(JSON.stringify(currentJson)); const conflictedChapters = []; @@ -14,6 +13,7 @@ async function processAndIdentiyVerseChangeinUSFMJsons(currentJson, IncomingJson // console.log(IncomingVerse); if (content.verseText !== IncomingVerse.verseText) { // add incoming data + content.current = JSON.parse(JSON.stringify(content)); content.incoming = IncomingVerse; content.resolved = { status: false, resolvedContent: null }; !conflictedChapters.includes(chapter.chapterNumber) && conflictedChapters.push(chapter.chapterNumber); diff --git a/renderer/src/layouts/projects/Layout.js b/renderer/src/layouts/projects/Layout.js index 8aae80731..b85d064a6 100644 --- a/renderer/src/layouts/projects/Layout.js +++ b/renderer/src/layouts/projects/Layout.js @@ -1,4 +1,5 @@ import React, { useContext, useState } from 'react'; +import { SnackBar } from '@/components/SnackBar'; import PropTypes from 'prop-types'; import { ArchiveBoxIcon, @@ -35,6 +36,16 @@ export default function ProjectsLayout(props) { data: undefined, }); + const [snackBar, setOpenSnackBar] = useState(false); + const [snackText, setSnackText] = useState(''); + const [notify, setNotify] = useState(); + + const triggerSnackBar = (status, message) => { + setNotify(status); + setSnackText(message); + setOpenSnackBar(true); + }; + function closeMergeWindow() { setConflictPopup({ open: false, @@ -55,15 +66,16 @@ export default function ProjectsLayout(props) { } return ( -
+ <> +
- + -
+
- + - {title && ( + {title && (
{!isTwoCol ? ( @@ -92,7 +104,7 @@ export default function ProjectsLayout(props) { && (
{conflictPopup.data?.projectType === 'textTranslation' - ? + ? : }
)} @@ -144,13 +156,20 @@ export default function ProjectsLayout(props) {
)} -
- {children} -
+
+ {children} +
+
- -
+ + ); } From f5ca445b1538d568c2f749d836c7dae7fe5ef2ec Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Fri, 19 Apr 2024 12:09:57 +0530 Subject: [PATCH 30/50] added auto select chapter for the current parsed book in the ui --- .../TranslationMergeUI.jsx | 14 ++++++++++- .../mergeTextTranslationProject.js | 25 +++++++++++++++---- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index 8c1221e1e..3749feffb 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -15,6 +15,7 @@ import LoadingScreen from '../Loading/LoadingScreen'; import UsfmConflictEditor from './UsfmConflictEditor'; import { processAndIdentiyVerseChangeinUSFMJsons } from './processUsfmObjs'; import packageInfo from '../../../../package.json'; +import { commitChanges } from '../Sync/Isomorphic/utils'; const grammar = require('usfm-grammar'); const path = require('path'); @@ -121,9 +122,13 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) console.log('process usfm : ', err); }); const mergeJson = processOutArr[0]; + const conflcitedChapters = processOutArr[1]; console.log('processOutArr[1] : ', processOutArr[1]); currentJson && currentJson?.valid && setUsfmJsons((prev) => ({ ...prev, [selectedBook]: { ...prev[selectedBook], current: currentJson.data, mergeJson } })); setConflictedChapters((prev) => ({ ...prev, [selectedBook]: processOutArr[1] })); + if (conflcitedChapters && conflcitedChapters?.length > 0) { + setSelectedChapter(conflcitedChapters[0]); + } setLoading(false); // old UI logic of import and parse already saved book @@ -171,6 +176,10 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) // remove .merge/project await fs.rmSync(usfmJsons.conflictMeta.projectMergePath, { recursive: true, force: true }); + // commit all changes after merge finish + const commitAuthor = { name: 'scribeInternal', email: 'scribe@bridgeconn.com' }; + const backupMessage = `Scribe Internal Commit After Text Merge Finish : ${usfmJsons.conflictMeta.projectFullName} : ${new Date()}`; + await commitChanges(fs, usfmJsons.conflictMeta.sourceProjectPath, commitAuthor, backupMessage, true); setLoading(false); triggerSnackBar('success', 'Conflict Resolved Successfully'); @@ -217,7 +226,6 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) useEffect(() => { setUsfmJsons((prev) => ({ ...prev, conflictMeta: conflictData.data })); setSelectedBook(conflictData?.data?.files[0]); - // TODO : Auto Select first Chapter of the selected Book }, [conflictData]); // handle conflict check for a book on book nav @@ -226,6 +234,10 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) (async () => { setLoading(true); if (conflictedChapters[selectedBook]) { + // TODO : Auto Select first Chapter of the selected Book + if (conflictedChapters[selectedBook] && conflictedChapters[selectedBook].length > 0) { + setSelectedChapter(conflictedChapters[selectedBook][0]); + } setLoading(false); } else { await checkForConflictInSelectedBook(selectedBook); diff --git a/renderer/src/components/TextTranslationMerge/mergeTextTranslationProject.js b/renderer/src/components/TextTranslationMerge/mergeTextTranslationProject.js index 77482b2f8..c8fc62b9a 100644 --- a/renderer/src/components/TextTranslationMerge/mergeTextTranslationProject.js +++ b/renderer/src/components/TextTranslationMerge/mergeTextTranslationProject.js @@ -1,5 +1,6 @@ import updateTranslationSB from '@/core/burrito/updateTranslationSB'; import packageInfo from '../../../../package.json'; +import { commitChanges } from '../Sync/Isomorphic/utils'; export const mergeTextTranslationProject = async (incomingPath, currentUser, setConflictPopup, setProcessMerge, incomingMeta) => { try { @@ -36,16 +37,29 @@ export const mergeTextTranslationProject = async (incomingPath, currentUser, set console.log('conflict', { conflictedIngFilePaths }); if (conflictedIngFilePaths.length > 0) { - // move imported project to backup folder + /** + * Check the current Project is new or inprogres + * Check the current ProjectName in => ./merge/ProjectName + * move imported project to backup folder + * create a GIT Backup before start merge : Create a COMMIT with Proper Msg and Timestamp + * TODO: Idea is to manual git reset to commit based on timestamp + */ const USFMMergeDirPath = path.join(newpath, packageInfo.name, 'users', currentUser, '.merge-usfm'); const projectDirName = `${incomingMeta.projectName}_${incomingMeta.id[0]}`; + const sourceProjectPath = path.join(newpath, packageInfo.name, 'users', currentUser, 'projects', projectDirName); + let isNewProjectMerge = true; if (!fs.existsSync(path.join(USFMMergeDirPath, projectDirName))) { fs.mkdirSync(path.join(USFMMergeDirPath, projectDirName), { recursive: true }); + await fse.copy(incomingPath, path.join(USFMMergeDirPath, projectDirName, 'incoming')); + // commit existing changes before merge start + const commitAuthor = { name: 'scribeInternal', email: 'scribe@bridgeconn.com' }; + const backupMessage = `Scribe Internal Commit Before Text Merge Start : ${projectDirName} : ${new Date()}`; + await commitChanges(fs, sourceProjectPath, commitAuthor, backupMessage, true); + } else { + isNewProjectMerge = false; } - await fse.copy(incomingPath, path.join(USFMMergeDirPath, projectDirName, 'incoming')); - // TODO : CREATE A BACKUP in GIT - with a proper message of backup before merge and Timestamp (Idea is to manual git reset to commit based on timestamp) - // conflcit section + // conflcit section - set values and open conflict window setConflictPopup({ open: true, data: { @@ -57,9 +71,10 @@ export const mergeTextTranslationProject = async (incomingPath, currentUser, set projectId: incomingMeta.id[0], projectName: incomingMeta.projectName, projectFullName: projectDirName, - sourceProjectPath: path.join(newpath, packageInfo.name, 'users', currentUser, 'projects', projectDirName), + sourceProjectPath, projectMergePath: path.join(USFMMergeDirPath, projectDirName), currentUser, + isNewProjectMerge, }, }); } else { From ced52498f209565d17896084f1ba6e888a36870c Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Fri, 19 Apr 2024 16:52:15 +0530 Subject: [PATCH 31/50] updated meta and md5 on final replace --- .../TranslationMergeUI.jsx | 82 +++++++++++++++++-- .../mergeTextTranslationProject.js | 12 ++- 2 files changed, 86 insertions(+), 8 deletions(-) diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index 3749feffb..670aa7cd5 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -19,6 +19,7 @@ import { commitChanges } from '../Sync/Isomorphic/utils'; const grammar = require('usfm-grammar'); const path = require('path'); +const md5 = require('md5'); function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) { const { t } = useTranslation(); @@ -160,20 +161,31 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) const resolvedBooks = { ...usfmJsons }; delete resolvedBooks.conflictMeta; - console.log('after delete ============> ', resolvedBooks, usfmJsons); + + const currentSourceMeta = usfmJsons?.conflictMeta?.currentMeta; + // TODO : Disable all clicks when loading is true + const sourceIngredientPath = path.join(usfmJsons.conflictMeta.sourceProjectPath); // loop over the resolved books // eslint-disable-next-line no-restricted-syntax for (const bookName of Object.keys(resolvedBooks)) { const resolvedMergeJson = resolvedBooks[bookName]?.mergeJson; // eslint-disable-next-line no-await-in-loop const generatedUSFM = await parseJsonToUsfm(resolvedMergeJson); - const sourceIngredientPath = path.join(usfmJsons.conflictMeta.sourceProjectPath); + // overwrite the source file with new file fs.writeFileSync(path.join(sourceIngredientPath, 'ingredients', `${resolvedMergeJson.book.bookCode}.usfm`), generatedUSFM); + + // get and update the usfms ingredients + const stat = fs.statSync(path.join(sourceIngredientPath, 'ingredients', `${resolvedMergeJson.book.bookCode}.usfm`)); + currentSourceMeta.ingredients[bookName].checksum.md5 = md5(generatedUSFM); + currentSourceMeta.ingredients[bookName].size = stat.size; } + // write updated metadata here + fs.writeFileSync(path.join(sourceIngredientPath, 'metadata.json'), JSON.stringify(currentSourceMeta)); + // remove .merge/project await fs.rmSync(usfmJsons.conflictMeta.projectMergePath, { recursive: true, force: true }); // commit all changes after merge finish @@ -191,10 +203,11 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) // remove current chapter from conflicted list const restOfTheChapters = conflictedChapters[selectedBook]?.filter((chNo) => chNo !== selectedChapter); setConflictedChapters((prev) => ({ ...prev, [selectedBook]: restOfTheChapters })); - + let isBookResolved = false; if (restOfTheChapters?.length === 0) { // completed conflicts for that particualr book setResolvedBooks((prev) => [...prev, selectedBook]); + isBookResolved = true; } else { // current book have pending chapter , // Switch to next chapter or book setSelectedChapter(restOfTheChapters[0]); @@ -204,15 +217,63 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) const { projectFullName } = usfmJsons.conflictMeta; const newpath = localStorage.getItem('userPath'); const path = require('path'); + // resolved chapters of each book and resolved books in the conflictMeta and store in the BE + const currentUSFMJsonsData = JSON.parse(JSON.stringify(usfmJsons)); + // initial time (if resolved chapters exist for the project) + if (currentUSFMJsonsData.conflictMeta?.resolvedStatus) { + currentUSFMJsonsData.conflictMeta.resolvedStatus[selectedBook] = { conflictedChapters: restOfTheChapters, isBookResolved }; + } else { + currentUSFMJsonsData.conflictMeta.resolvedStatus = { [selectedBook]: { conflictedChapters: restOfTheChapters, isBookResolved } }; + } + setUsfmJsons(currentUSFMJsonsData); localforage.getItem('userProfile').then((user) => { const USFMMergeDirPath = path.join(newpath, packageInfo.name, 'users', user?.username, '.merge-usfm'); if (!fs.existsSync(path.join(USFMMergeDirPath, projectFullName))) { fs.mkdirSync(path.join(USFMMergeDirPath, projectFullName), { recursive: true }); } - fs.writeFileSync(path.join(USFMMergeDirPath, projectFullName, 'usfmJsons.json'), JSON.stringify({ usfmJsons })); + fs.writeFileSync(path.join(USFMMergeDirPath, projectFullName, 'usfmJsons.json'), JSON.stringify(currentUSFMJsonsData)); }); }; + /** + * existing project merge + * read usfm json data from backend + */ + const getInprogressMergeProject = async (data) => { + const fs = window.require('fs'); + if (fs.existsSync(path.join(data.projectMergePath, 'usfmJsons.json'))) { + let usfmJsonsContent = fs.readFileSync(path.join(data.projectMergePath, 'usfmJsons.json'), 'utf8'); + usfmJsonsContent = JSON.parse(usfmJsonsContent); + if (usfmJsonsContent) { + setUsfmJsons(usfmJsonsContent); + // check the books is already resolved or not => then select current book and unresolved chapters + let bookToSelect; + const resolvedBooksArr = []; + const conflictedChsOfBooks = {}; + // eslint-disable-next-line no-restricted-syntax + for (const book in usfmJsonsContent.conflictMeta.resolvedStatus) { + if (book in usfmJsonsContent.conflictMeta.resolvedStatus) { + const currentBook = usfmJsonsContent.conflictMeta.resolvedStatus[book]; + if (!currentBook.isBookResolved && !bookToSelect) { + bookToSelect = book; + } + if (currentBook.isBookResolved) { + resolvedBooksArr.push(book); + } + conflictedChsOfBooks[book] = currentBook.conflictedChapters; + } + } + setSelectedBook(bookToSelect); + setResolvedBooks(resolvedBooksArr); + setConflictedChapters(conflictedChsOfBooks); + } else { + console.error('Inprogress project config is corrupted'); + } + } else { + console.error('Unable to get the inprogress config'); + } + }; + // useEffect to trigger comleted all conflict Resolution useEffect(() => { if (resolvedBooks.length >= Object.keys(conflictedChapters).length) { @@ -224,8 +285,15 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) // store conflict data to usfm jsons meta useEffect(() => { - setUsfmJsons((prev) => ({ ...prev, conflictMeta: conflictData.data })); - setSelectedBook(conflictData?.data?.files[0]); + /** + * check the project merge is new or existing + */ + if (conflictData.data.isNewProjectMerge) { + setUsfmJsons((prev) => ({ ...prev, conflictMeta: conflictData.data })); + setSelectedBook(conflictData?.data?.files[0]); + } else { + getInprogressMergeProject(conflictData.data); + } }, [conflictData]); // handle conflict check for a book on book nav @@ -234,7 +302,7 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) (async () => { setLoading(true); if (conflictedChapters[selectedBook]) { - // TODO : Auto Select first Chapter of the selected Book + // Auto Select first Chapter of the selected Book if (conflictedChapters[selectedBook] && conflictedChapters[selectedBook].length > 0) { setSelectedChapter(conflictedChapters[selectedBook][0]); } diff --git a/renderer/src/components/TextTranslationMerge/mergeTextTranslationProject.js b/renderer/src/components/TextTranslationMerge/mergeTextTranslationProject.js index c8fc62b9a..83f661c4d 100644 --- a/renderer/src/components/TextTranslationMerge/mergeTextTranslationProject.js +++ b/renderer/src/components/TextTranslationMerge/mergeTextTranslationProject.js @@ -47,6 +47,7 @@ export const mergeTextTranslationProject = async (incomingPath, currentUser, set const USFMMergeDirPath = path.join(newpath, packageInfo.name, 'users', currentUser, '.merge-usfm'); const projectDirName = `${incomingMeta.projectName}_${incomingMeta.id[0]}`; const sourceProjectPath = path.join(newpath, packageInfo.name, 'users', currentUser, 'projects', projectDirName); + let existingIncomingMeta; let isNewProjectMerge = true; if (!fs.existsSync(path.join(USFMMergeDirPath, projectDirName))) { fs.mkdirSync(path.join(USFMMergeDirPath, projectDirName), { recursive: true }); @@ -57,6 +58,13 @@ export const mergeTextTranslationProject = async (incomingPath, currentUser, set await commitChanges(fs, sourceProjectPath, commitAuthor, backupMessage, true); } else { isNewProjectMerge = false; + // read existing meta of incoming instead of using the new because the merge is inprogress + if (fs.existsSync(path.join(path.join(USFMMergeDirPath, projectDirName, 'incoming', 'metadata.json')))) { + existingIncomingMeta = fs.readFileSync(path.join(path.join(USFMMergeDirPath, projectDirName, 'incoming', 'metadata.json')), 'utf-8'); + existingIncomingMeta = JSON.parse(existingIncomingMeta); + } else { + throw new Error('Can not proceed Merge, Unable to find the metadata for imported Project'); + } } // conflcit section - set values and open conflict window @@ -66,7 +74,7 @@ export const mergeTextTranslationProject = async (incomingPath, currentUser, set projectType: 'textTranslation', files: conflictedIngFilePaths, incomingPath: path.join(USFMMergeDirPath, projectDirName, 'incoming'), - incomingMeta, + incomingMeta: isNewProjectMerge ? incomingMeta : existingIncomingMeta, currentMeta: updatedCurrentMeta, projectId: incomingMeta.id[0], projectName: incomingMeta.projectName, @@ -79,6 +87,7 @@ export const mergeTextTranslationProject = async (incomingPath, currentUser, set }); } else { // TODO : ADD A MESSGAGE HERE -nothing to merge + return; } setProcessMerge(false); @@ -90,5 +99,6 @@ export const mergeTextTranslationProject = async (incomingPath, currentUser, set } catch (err) { setProcessMerge(false); console.error('Failue in MergeText Process : ', err); + throw new Error(err); } }; From 50f33e921da01ecc5b923379bb09f269006f30f3 Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Mon, 22 Apr 2024 17:09:58 +0530 Subject: [PATCH 32/50] added docs and flow diagram --- .../Offline-Merge-TextTransaltion.svg | 890 ++++++++++++++++++ .../development.md | 18 + 2 files changed, 908 insertions(+) create mode 100644 docs/Development/Offline Merge Text Translation/Offline-Merge-TextTransaltion.svg create mode 100644 docs/Development/Offline Merge Text Translation/development.md diff --git a/docs/Development/Offline Merge Text Translation/Offline-Merge-TextTransaltion.svg b/docs/Development/Offline Merge Text Translation/Offline-Merge-TextTransaltion.svg new file mode 100644 index 000000000..5730939d0 --- /dev/null +++ b/docs/Development/Offline Merge Text Translation/Offline-Merge-TextTransaltion.svg @@ -0,0 +1,890 @@ + + + + + + + + + Text + Offline Merge + + + + Import Same + Project + + + + Replace / Merge + + + + + + + + + + + + + + + + + Parse USFMs and + Find conflicts + + + + + + + + + + + + + + + + + Merge + + + + Commit Current State with TimeStamp + + + + + + + + + + + + + + + + UI + process data and Shows Conflicted Booksand Chapter + + + + + + + + + + + + + + + + Send Data to + UI + + + + store the parsed + JSONwith + orginal , incoming and merged JsonsUpdate on chapter conflict + finish.merge/projectName + + + + + + + + + + + + + ROM + 1 + 2 + 3 + 4 + Chapter Done + + + + + Finish Click + onChapter Conflict Done + + + + + + + + + + + + + + + + + + + + + + + + + Book Count : 3 + + PSA + + + + + + + 1 + + + + 2 + + + + 5 + ACT + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Finish + + + + Complete All + Conflict + + + + + + + + + + + + + + + + Get + Merged Json from BE + + + + + + + + + + + + + + + + Convert JSON To + USFMBook by Book + + + + + + + + + + + + + + + + + + + + + + + + + + + + Replace in the + original Project Source + + + + Remove .merge and + project + + + + check for Inprogress Merge + + + + + + + + + + + + + + + + + NO + + + + + + + Yes + + + + + + + + + + + + + + + + load existing + configand + data + Load Existing + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Not + Found data + + + + Error Load Data + /Config + Corrupted + + + + Update MD5 and + Metadata + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + If conflict + + + + + + + + + + + + + + + + Yes + + + + Commit Finish Conflict Status with TimeStamp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + update mergeJson + content based + onselection / + reset + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/Development/Offline Merge Text Translation/development.md b/docs/Development/Offline Merge Text Translation/development.md new file mode 100644 index 000000000..50c39281c --- /dev/null +++ b/docs/Development/Offline Merge Text Translation/development.md @@ -0,0 +1,18 @@ +## Offline Merge Transaltion + +- Offline Merge Feature for Text Translation +- Merge Option available on Import Existing Project ( Flavour Text Translation ) +- The Merge Can be resumed later from the check point ( Check Point will be the completion of each chapter. The system will only take care of chapter by chapter . You can not stop and continue from middle of a chapter ) +- The merge will be corrupted if back end data is modified / removed manually. Can not be restored +- One commit will be created on merge start with all the changes before the merge ( timestamp and commit message can be used to identify the commit) +- One commit will be created after the merge with all the merged changes ( timestamp and commit message can be used to identify) +- This commit can be used to revert back to earlier stage ( **advanced option** ) +- Can not re work on chapter or book once you finish the conflicts with book / chapter +- updating `metadata.json` with new USFM's metadata on finish merge conflict for entire project +- Merge UI ( options) + - Accept all new changes + - Keep All existing changes + - Revert All changes + - Accept single changes ( current or new ) + - Chapter Completion ( Check point ) + - Merge Conflict Completion ( on completion : replace the original USFM with new merge USFM ) From 39c58c3adc9e6f7ac518e72bdc45e101993ba2fb Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Wed, 24 Apr 2024 11:10:40 +0530 Subject: [PATCH 33/50] refactor fucntions; checkpoint for config store on initial load; fix for load back from inprogress on initial load --- .../TranslationMergeUI.jsx | 61 ++++++++++++------- .../mergeTextTranslationProject.js | 4 +- .../layouts/projects/ImportProjectPopUp.js | 17 +++++- 3 files changed, 57 insertions(+), 25 deletions(-) diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index 670aa7cd5..4518d4fe8 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -98,6 +98,7 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) const checkForConflictInSelectedBook = async (selectedBook) => { // parse imported const fs = window.require('fs'); + console.log('..............................>>>>>>>>>>>>>>>>>>> ', usfmJsons.conflictMeta, selectedBook); const IncomingUsfm = fs.readFileSync(path.join(usfmJsons.conflictMeta.incomingPath, selectedBook), 'utf8'); if (IncomingUsfm) { const importedJson = await parseUsfm(IncomingUsfm); @@ -198,7 +199,21 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) closeMergeWindow(); }; - const resolveAndMarkDoneChapter = () => { + // Function to write back the current usfmJSON data as config in the .merge + const writeBackConflictConfigData = async (projectFullName, configData) => { + const fs = window.require('fs'); + const newpath = localStorage.getItem('userPath'); + const path = require('path'); + localforage.getItem('userProfile').then((user) => { + const USFMMergeDirPath = path.join(newpath, packageInfo.name, 'users', user?.username, '.merge-usfm'); + if (!fs.existsSync(path.join(USFMMergeDirPath, projectFullName))) { + fs.mkdirSync(path.join(USFMMergeDirPath, projectFullName), { recursive: true }); + } + fs.writeFileSync(path.join(USFMMergeDirPath, projectFullName, 'usfmJsons.json'), JSON.stringify(configData)); + }); + }; + + const resolveAndMarkDoneChapter = async () => { setChapterResolveDone(false); // remove current chapter from conflicted list const restOfTheChapters = conflictedChapters[selectedBook]?.filter((chNo) => chNo !== selectedChapter); @@ -213,10 +228,9 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) setSelectedChapter(restOfTheChapters[0]); } // store the jsons to the backend (/.merge/projectName/BookID.json) - const fs = window.require('fs'); + const { projectFullName } = usfmJsons.conflictMeta; - const newpath = localStorage.getItem('userPath'); - const path = require('path'); + // resolved chapters of each book and resolved books in the conflictMeta and store in the BE const currentUSFMJsonsData = JSON.parse(JSON.stringify(usfmJsons)); // initial time (if resolved chapters exist for the project) @@ -226,13 +240,7 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) currentUSFMJsonsData.conflictMeta.resolvedStatus = { [selectedBook]: { conflictedChapters: restOfTheChapters, isBookResolved } }; } setUsfmJsons(currentUSFMJsonsData); - localforage.getItem('userProfile').then((user) => { - const USFMMergeDirPath = path.join(newpath, packageInfo.name, 'users', user?.username, '.merge-usfm'); - if (!fs.existsSync(path.join(USFMMergeDirPath, projectFullName))) { - fs.mkdirSync(path.join(USFMMergeDirPath, projectFullName), { recursive: true }); - } - fs.writeFileSync(path.join(USFMMergeDirPath, projectFullName, 'usfmJsons.json'), JSON.stringify(currentUSFMJsonsData)); - }); + await writeBackConflictConfigData(projectFullName, currentUSFMJsonsData); }; /** @@ -250,19 +258,27 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) let bookToSelect; const resolvedBooksArr = []; const conflictedChsOfBooks = {}; - // eslint-disable-next-line no-restricted-syntax - for (const book in usfmJsonsContent.conflictMeta.resolvedStatus) { - if (book in usfmJsonsContent.conflictMeta.resolvedStatus) { - const currentBook = usfmJsonsContent.conflictMeta.resolvedStatus[book]; - if (!currentBook.isBookResolved && !bookToSelect) { - bookToSelect = book; - } - if (currentBook.isBookResolved) { - resolvedBooksArr.push(book); + + // loading config - config have data of atleast 1 chapter of any book resolved ( checkpoint ) + if (usfmJsonsContent.conflictMeta.resolvedStatus) { + // eslint-disable-next-line no-restricted-syntax + for (const book in usfmJsonsContent.conflictMeta.resolvedStatus) { + if (book in usfmJsonsContent.conflictMeta.resolvedStatus) { + const currentBook = usfmJsonsContent.conflictMeta.resolvedStatus[book]; + if (!currentBook.isBookResolved && !bookToSelect) { + bookToSelect = book; + } + if (currentBook.isBookResolved) { + resolvedBooksArr.push(book); + } + conflictedChsOfBooks[book] = currentBook.conflictedChapters; } - conflictedChsOfBooks[book] = currentBook.conflictedChapters; } + } else { + // checkpoint - stored on initially and not worked on any chapter + bookToSelect = usfmJsonsContent.conflictMeta.files[0]; } + setSelectedBook(bookToSelect); setResolvedBooks(resolvedBooksArr); setConflictedChapters(conflictedChsOfBooks); @@ -274,6 +290,8 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) } }; + console.log({ conflictData, conflictedChapters, resolvedBooks }); + // useEffect to trigger comleted all conflict Resolution useEffect(() => { if (resolvedBooks.length >= Object.keys(conflictedChapters).length) { @@ -309,6 +327,7 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) setLoading(false); } else { await checkForConflictInSelectedBook(selectedBook); + await writeBackConflictConfigData(usfmJsons.conflictMeta.projectFullName, usfmJsons); } })(); } else { diff --git a/renderer/src/components/TextTranslationMerge/mergeTextTranslationProject.js b/renderer/src/components/TextTranslationMerge/mergeTextTranslationProject.js index 83f661c4d..74fd68247 100644 --- a/renderer/src/components/TextTranslationMerge/mergeTextTranslationProject.js +++ b/renderer/src/components/TextTranslationMerge/mergeTextTranslationProject.js @@ -26,6 +26,7 @@ export const mergeTextTranslationProject = async (incomingPath, currentUser, set const incomingMd5 = val.checksum.md5; if (currentMd5 && incomingMd5) { if (currentMd5 !== incomingMd5) { + console.log('MD5s xxxxxxxxxxxxxx : ', { bookId, currentMd5, incomingMd5 }, currentMd5 === incomingIngredients); conflictedIngFilePaths.push(key); } } else { @@ -86,8 +87,7 @@ export const mergeTextTranslationProject = async (incomingPath, currentUser, set }, }); } else { - // TODO : ADD A MESSGAGE HERE -nothing to merge - return; + return 'noConflict'; } setProcessMerge(false); diff --git a/renderer/src/layouts/projects/ImportProjectPopUp.js b/renderer/src/layouts/projects/ImportProjectPopUp.js index f7858ccf1..65f17f0cc 100644 --- a/renderer/src/layouts/projects/ImportProjectPopUp.js +++ b/renderer/src/layouts/projects/ImportProjectPopUp.js @@ -61,6 +61,12 @@ export default function ImportProjectPopUp(props) { completedSteps: 0, }); + const triggerSnackBar = (status, message) => { + setNotify(status); + setSnackText(message); + setOpenSnackBar(true); + }; + async function close(triggeredFrom) { logger.debug('ImportProjectPopUp.js', `Closing the Dialog box : Triggered from : ${triggeredFrom}`); removeExtractedZipDir() @@ -193,8 +199,15 @@ export default function ImportProjectPopUp(props) { await mergeProject(folderPath, currentUser, setConflictPopup, setModel, setProcessMerge); }else if (sbData?.burritoType === 'scripture / textTranslation') { console.log("Started Indentify Merge conflicts ------"); - await mergeTextTranslationProject(folderPath, currentUser, setConflictPopup, setProcessMerge, sbData) - console.log("completed merge idenitfy process ------"); + try { + const response = await mergeTextTranslationProject(folderPath, currentUser, setConflictPopup, setProcessMerge, sbData) + if(response === "noConflict") { + triggerSnackBar('success', "No Conflict Found",) + } + console.log("completed merge idenitfy process ------"); + } catch(err) { + + } } setMerge(false) setSbData({}); From 998fbea845e4c2c10794217f11a5513ad58c8d26 Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Wed, 24 Apr 2024 11:35:35 +0530 Subject: [PATCH 34/50] fixed issue : showing current and incoming incorrect. --- .../TextTranslationMerge/TranslationMergeUI.jsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index 4518d4fe8..335b77f0c 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -98,7 +98,6 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) const checkForConflictInSelectedBook = async (selectedBook) => { // parse imported const fs = window.require('fs'); - console.log('..............................>>>>>>>>>>>>>>>>>>> ', usfmJsons.conflictMeta, selectedBook); const IncomingUsfm = fs.readFileSync(path.join(usfmJsons.conflictMeta.incomingPath, selectedBook), 'utf8'); if (IncomingUsfm) { const importedJson = await parseUsfm(IncomingUsfm); @@ -120,7 +119,7 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) if (currentBookUsfm) { const currentJson = await parseUsfm(currentBookUsfm); // generate the merge object with current , incoming , merge verses - const processOutArr = await processAndIdentiyVerseChangeinUSFMJsons(importedJson.data, currentJson.data).catch((err) => { + const processOutArr = await processAndIdentiyVerseChangeinUSFMJsons(currentJson.data, importedJson.data).catch((err) => { console.log('process usfm : ', err); }); const mergeJson = processOutArr[0]; @@ -290,16 +289,19 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) } }; - console.log({ conflictData, conflictedChapters, resolvedBooks }); + console.log({ + conflictData, conflictedChapters, resolvedBooks, finishedConflict, + }); // useEffect to trigger comleted all conflict Resolution useEffect(() => { - if (resolvedBooks.length >= Object.keys(conflictedChapters).length) { + console.log('finish check =============> ', resolvedBooks.length >= usfmJsons?.conflictMeta?.files?.length.length); + if (resolvedBooks.length >= usfmJsons?.conflictMeta?.files?.length) { setFinishedConflict(true); } else { setFinishedConflict(false); } - }, [resolvedBooks, conflictedChapters]); + }, [resolvedBooks]); // store conflict data to usfm jsons meta useEffect(() => { From 59c163d763012539a570e3d678b0a643f19468bd Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Wed, 24 Apr 2024 15:58:06 +0530 Subject: [PATCH 35/50] updated abort modal and fixed loading issue in no conflcit --- .../src/components/TextTranslationMerge/TranslationMergeUI.jsx | 2 +- .../TextTranslationMerge/mergeTextTranslationProject.js | 2 ++ renderer/src/translations/ar.js | 1 + renderer/src/translations/en.js | 1 + renderer/src/translations/fa.js | 1 + renderer/src/translations/fr.js | 1 + renderer/src/translations/hi.js | 1 + renderer/src/translations/ne.js | 1 + renderer/src/translations/ru.js | 1 + 9 files changed, 10 insertions(+), 1 deletion(-) diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index 335b77f0c..d1b8756db 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -50,7 +50,7 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) setModel({ openModel: true, title: t('modal-title-abort-conflict-resolution'), - confirmMessage: t('msg-abort-conflict-resolution'), + confirmMessage: t('text-msg-abort-conflict-resolution'), buttonName: t('label-abort'), }); } diff --git a/renderer/src/components/TextTranslationMerge/mergeTextTranslationProject.js b/renderer/src/components/TextTranslationMerge/mergeTextTranslationProject.js index 74fd68247..ee18890ee 100644 --- a/renderer/src/components/TextTranslationMerge/mergeTextTranslationProject.js +++ b/renderer/src/components/TextTranslationMerge/mergeTextTranslationProject.js @@ -87,6 +87,8 @@ export const mergeTextTranslationProject = async (incomingPath, currentUser, set }, }); } else { + setProcessMerge(false); + console.log('No Conflict =================>'); return 'noConflict'; } diff --git a/renderer/src/translations/ar.js b/renderer/src/translations/ar.js index 740f81ea2..a8004fe57 100644 --- a/renderer/src/translations/ar.js +++ b/renderer/src/translations/ar.js @@ -262,6 +262,7 @@ export const Ar = { 'label-overwrite': 'إستبدال', 'modal-title-abort-conflict-resolution': 'إلغاء حل النزاعات', 'msg-abort-conflict-resolution': 'هل تريد إلغاء عملية حل النزاع. إذا قمت بالإلغاء، سوف تفقد كل تقدمك وتحتاج إلى البدء من جديد.', + 'text-msg-abort-conflict-resolution': 'هل تريد إجهاض عملية حل النزاع. يرجى التأكد من وصولك إلى نقطة التفتيش للمتابعة لاحقًا. نقطة التفتيش هي الانتهاء من كل فصل. إذا قمت بالإجهاض في منتصف الفصل، فسوف تفقد كل التقدم الذي أحرزته في الفصل وستحتاج إلى البدء من جديد.', 'label-done': 'تم', 'label-resolved': 'محلولة', 'label-resolve-conflict': 'حل النزاع', diff --git a/renderer/src/translations/en.js b/renderer/src/translations/en.js index fe6e091eb..7e9263b8a 100644 --- a/renderer/src/translations/en.js +++ b/renderer/src/translations/en.js @@ -262,6 +262,7 @@ export const En = { 'label-overwrite': 'Overwrite', 'modal-title-abort-conflict-resolution': 'Abort Conflict Resolution', 'msg-abort-conflict-resolution': 'Do you want to abort conflict Resolution process. If you abort , you will loose all your progress and need to start over.', + 'text-msg-abort-conflict-resolution': 'Do you want to abort conflict Resolution process. Please ensure you have reached a checkpoint to continue later. The checkpoint is the completion of each chapter. If you abort in the middle of a chapter , you will loose all your progress of the chapter and need to start over the chapter.', 'label-done': 'Done', 'label-resolved': 'Resolved', 'label-resolve-conflict': 'Resolve Conflict', diff --git a/renderer/src/translations/fa.js b/renderer/src/translations/fa.js index 30bce2101..f9d7edb1c 100644 --- a/renderer/src/translations/fa.js +++ b/renderer/src/translations/fa.js @@ -262,6 +262,7 @@ export const Fa = { 'label-overwrite': 'بازنویسی', 'modal-title-abort-conflict-resolution': 'لغو حل مشکل تعارض', 'msg-abort-conflict-resolution': 'آیا می خواهید فرآیند حل مشکل تعارض را متوقف کنید؟ اگر لغو کنید، تمام تغییرات انجام شده را از دست خواهید داد و باید از نو شروع کنید.', + 'text-msg-abort-conflict-resolution': 'آیا می خواهید فرآیند حل تعارض را متوقف کنید؟ لطفاً مطمئن شوید که به یک ایست بازرسی رسیده‌اید تا بعداً ادامه دهید. نقطه بازرسی تکمیل هر فصل است. اگر در وسط یک فصل سقط شوید، تمام پیشرفت فصل خود را از دست خواهید داد و باید از فصل شروع کنید.', 'label-done': 'انجام شد', 'label-resolved': 'حل شد', 'label-resolve-conflict': 'حل تعارض‌ها', diff --git a/renderer/src/translations/fr.js b/renderer/src/translations/fr.js index 38e602bb0..472b65695 100644 --- a/renderer/src/translations/fr.js +++ b/renderer/src/translations/fr.js @@ -262,6 +262,7 @@ export const Fr = { 'label-overwrite': 'Écraser', 'modal-title-abort-conflict-resolution': 'Abandonner la résolution des conflits', 'msg-abort-conflict-resolution': 'Voulez-vous abandonner le processus de résolution des conflits. Si vous abandonnez, vous perdrez toute votre progression et devrez recommencer.', + 'text-msg-abort-conflict-resolution': 'Voulez-vous abandonner le processus de résolution des conflits. Veuillez vous assurer d\'avoir atteint un point de contrôle pour continuer plus tard. Le point de contrôle est l’achèvement de chaque chapitre. Si vous abandonnez au milieu d\'un chapitre, vous perdrez toute votre progression dans le chapitre et devrez recommencer le chapitre.', 'label-done': 'fait', 'label-resolved': 'résolu', 'label-resolve-conflict': 'résoudre un conflit', diff --git a/renderer/src/translations/hi.js b/renderer/src/translations/hi.js index a942a7503..b774d4cb5 100644 --- a/renderer/src/translations/hi.js +++ b/renderer/src/translations/hi.js @@ -262,6 +262,7 @@ export const Hi = { 'label-overwrite': 'ओवरराइट', 'modal-title-abort-conflict-resolution': 'संघर्ष समाधान निरस्त करें', 'msg-abort-conflict-resolution': 'क्या आप संघर्ष समाधान प्रक्रिया को निरस्त करना चाहते हैं? यदि आप गर्भपात करते हैं, तो आप अपनी सारी प्रगति और दोबारा शुरू करने की आवश्यकता खो देंगे।', + 'text-msg-abort-conflict-resolution': 'क्या आप संघर्ष समाधान प्रक्रिया को निरस्त करना चाहते हैं? कृपया सुनिश्चित करें कि आप बाद में जारी रखने के लिए चेकपॉइंट पर पहुंच गए हैं। चेकप्वाइंट प्रत्येक अध्याय का पूरा होना है। यदि आप किसी अध्याय को बीच में ही समाप्त कर देते हैं, तो आप अध्याय की अपनी सारी प्रगति खो देंगे और अध्याय को फिर से शुरू करने की आवश्यकता होगी।', 'label-done': 'हो गया', 'label-resolved': 'हल किया', 'label-resolve-conflict': 'विवाद हल करो', diff --git a/renderer/src/translations/ne.js b/renderer/src/translations/ne.js index a54aa0b1a..2d93dc700 100644 --- a/renderer/src/translations/ne.js +++ b/renderer/src/translations/ne.js @@ -262,6 +262,7 @@ export const Ne = { 'label-overwrite': 'अधिलेखन गर्नुहोस्', 'modal-title-abort-conflict-resolution': 'द्वन्द्व समाधान रद्द गर्नुहोस्', 'msg-abort-conflict-resolution': 'तपाईं द्वन्द्व समाधान प्रक्रिया रद्द गर्न चाहनुहुन्छ। यदि तपाईंले रद्द गर्नुभयो भने, तपाईंले आफ्नो सबै प्रगति गुमाउनुहुनेछ र फेरि सुरु गर्न आवश्यक छ।', + 'text-msg-abort-conflict-resolution': 'तपाईं द्वन्द्व समाधान प्रक्रिया रद्द गर्न चाहनुहुन्छ। कृपया पछि जारी राख्नको लागि तपाईं चेकपोइन्टमा पुग्नुभएको सुनिश्चित गर्नुहोस्। चेकपोइन्ट भनेको प्रत्येक अध्यायको समाप्ति हो। यदि तपाईंले अध्यायको बिचमा रद्द गर्नुभयो भने, तपाईंले अध्यायको सबै प्रगति गुमाउनुहुनेछ र अध्यायबाट सुरु गर्न आवश्यक छ।', 'label-done': 'सकियो', 'label-resolved': 'समाधान गरियो', 'label-resolve-conflict': 'विवाद समाधान', diff --git a/renderer/src/translations/ru.js b/renderer/src/translations/ru.js index 712fac96f..fd5d4841c 100644 --- a/renderer/src/translations/ru.js +++ b/renderer/src/translations/ru.js @@ -262,6 +262,7 @@ export const Ru = { 'label-overwrite': 'Перезаписать', 'modal-title-abort-conflict-resolution': 'Прервать разрешение конфликта', 'msg-abort-conflict-resolution': 'Хотите прервать процесс разрешения конфликта? Если вы прервете, вы потеряете весь свой прогресс и вам придется начинать все сначала.', + 'text-msg-abort-conflict-resolution': 'Хотите прервать процесс разрешения конфликта? Пожалуйста, убедитесь, что вы достигли контрольно-пропускного пункта, чтобы продолжить позже. Контрольной точкой является завершение каждой главы. Если вы прервете чтение в середине главы, вы потеряете весь прогресс в этой главе и вам придется начинать ее заново.', 'label-done': 'сделанный', 'label-resolved': 'решено', 'label-resolve-conflict': 'разрешить конфликт', From e9c4385da1ce6e498ca49e9ca36772dfba2e5788 Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Thu, 25 Apr 2024 13:27:45 +0530 Subject: [PATCH 36/50] added new hook for grammar to perf usfm conversion. logic added in sidebar. need to move to mergeUI before writing. --- .../TranslationMergeUI.jsx | 6 +- renderer/src/hooks/useGrammartoPerf.js | 77 ++++++++++++++++ renderer/src/layouts/projects/SideBar.js | 87 +++++++++++++++++++ 3 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 renderer/src/hooks/useGrammartoPerf.js diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index d1b8756db..35ba416fd 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -174,8 +174,12 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) // eslint-disable-next-line no-await-in-loop const generatedUSFM = await parseJsonToUsfm(resolvedMergeJson); + // TODO : convert here to PERF + + const perfUSFM = ''; + // overwrite the source file with new file - fs.writeFileSync(path.join(sourceIngredientPath, 'ingredients', `${resolvedMergeJson.book.bookCode}.usfm`), generatedUSFM); + fs.writeFileSync(path.join(sourceIngredientPath, 'ingredients', `${resolvedMergeJson.book.bookCode}.usfm`), perfUSFM); // get and update the usfms ingredients const stat = fs.statSync(path.join(sourceIngredientPath, 'ingredients', `${resolvedMergeJson.book.bookCode}.usfm`)); diff --git a/renderer/src/hooks/useGrammartoPerf.js b/renderer/src/hooks/useGrammartoPerf.js new file mode 100644 index 000000000..681e751dc --- /dev/null +++ b/renderer/src/hooks/useGrammartoPerf.js @@ -0,0 +1,77 @@ +import React, { useEffect, useState } from 'react'; +import { useProskomma, useImport, useCatalog } from 'proskomma-react-hooks'; +import { + useDeepCompareCallback, + useDeepCompareEffect, + useDeepCompareMemo, +} from 'use-deep-compare'; +import EpiteleteHtml from 'epitelete-html'; +import usePerf from '../components/EditorPage/TextEditor/hooks/usePerf'; +import htmlMap from '../components/EditorPage/TextEditor/hooks/htmlmap'; + +export const useGrammartoPerf = (perfArr = [], selectedBook = '') => { + let selectedDocument; + let refName; + + console.log({ perfArr }); + + const { proskomma, stateId, newStateId } = useProskomma({ verbose: false }); + + console.log({ proskomma, stateId, newStateId }); + + const { done } = useImport({ + proskomma, + stateId, + newStateId, + documents: perfArr, + }); + + console.log({ done }); + + const { catalog } = useCatalog({ proskomma, stateId, verbose: false }); + const { id: docSetId, documents } = (done && catalog.docSets[0]) || {}; // why documents no getting ----------------------- + + console.log(' ----------------- ------------ >', { catalog, docSetId, documents }); + + if (done) { + selectedDocument = documents?.find( + (doc) => { + console.log('finidng book code ===> ', doc.bookCode, selectedBook); + return doc.bookCode === selectedBook; + }, + ); + } + + console.log({ selectedDocument }); + + const { bookCode, h: bookName } = selectedDocument || {}; + const ready = (docSetId && bookCode) || false; + + console.log({ bookCode, ready }); + + const epiteleteHtml = useDeepCompareMemo( + () => ready + && new EpiteleteHtml({ + proskomma, + docSetId, + htmlMap, + options: { historySize: 100 }, + }), + [proskomma, ready, docSetId, refName], + ); + + useDeepCompareEffect(() => { + console.log('Triggering useDeepCompareEffect ==========> '); + if (epiteleteHtml) { + console.log('Insde useDeepCompareEffect ......................', bookCode); + const fs = window.require('fs'); + epiteleteHtml.readHtml(bookCode, { cloning: false }, htmlMap).then(async (_htmlPerf) => { + console.log('INSIDE READ HTML =============> ', _htmlPerf); + const usfmPerfString = await epiteleteHtml?.readUsfm(bookCode); + await fs.writeFileSync('testedUSFMTIT.usfm', usfmPerfString); + console.log(' ============> ', usfmPerfString); + // remove htmlMap for default classes + }); + } + }, [epiteleteHtml, bookCode]); +}; diff --git a/renderer/src/layouts/projects/SideBar.js b/renderer/src/layouts/projects/SideBar.js index d5a484e4f..3a1ed33d6 100644 --- a/renderer/src/layouts/projects/SideBar.js +++ b/renderer/src/layouts/projects/SideBar.js @@ -8,9 +8,66 @@ import LogoIcon from '@/icons/logo.svg'; import ProjectsIcon from '@/icons/projects.svg'; import NewProjectIcon from '@/icons/new.svg'; import SyncIcon from '@/icons/sync.svg'; +import { useGrammartoPerf } from '@/hooks2/useGrammartoPerf'; import AboutModal from '../editor/AboutModal'; +const usfmGrammarString = `\\id TIT + \\h TIT + \\mt1 TIT + \\c 1 + \\p + \\v 1 .verse1.. + \\v 2 .verse2.. + \\v 3 .verse3.. + \\v 4 .verse4.. + \\v 5 ... + \\v 6 ... + \\v 7 ... + \\v 8 ... + \\v 9 ... + \\v 10 ... + \\v 11 ... + \\v 12 ... + \\v 13 ... + \\v 14 ... + \\v 15 ... + \\v 16 ... + \\c 2 + \\p + \\v 1 ... + \\v 2 ... + \\v 3 ... + \\v 4 ... + \\v 5 ... + \\v 6 ... + \\v 7 ... + \\v 8 ... + \\v 9 ... + \\v 10 ... + \\v 11 ... + \\v 12 ... + \\v 13 ... + \\v 14 ... + \\v 15 ... + \\c 3 + \\p + \\v 1 ... + \\v 2 ... + \\v 3 ... + \\v 4 ... + \\v 5 ... + \\v 6 ... + \\v 7 ... + \\v 8 ... + \\v 9 ... + \\v 10 ... + \\v 11 ... + \\v 12 ... + \\v 13 ... + \\v 14 ... + \\v 15 ...`; + export default function SideBar() { const [open, setOpen] = useState(false); // const [appMode, setAppMode] = useState(); @@ -28,6 +85,12 @@ export default function SideBar() { setOpen(isOpen); } + const [selected, setselectedBook] = useState(''); + const [perfArr, setPerfArr] = useState([]); + + // Testing HOOk for usfm to perf + useGrammartoPerf(perfArr, selected); + return (
@@ -85,6 +148,30 @@ export default function SideBar() { + {/* Testing link ----------------------------------------------------------================================================= */} +
  • + +
  • {/* From 999bb247d8aeb1baed9f6559bfa7fdcb0c8e8a21 Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Tue, 30 Apr 2024 11:10:12 +0530 Subject: [PATCH 37/50] logic and hooks to convert grammar usfm to perf usfm. added feature for book by book resolve and rewrite --- .../TranslationMergeUI.jsx | 330 +++++++++++++----- renderer/src/hooks/useGrammartoPerf.js | 15 +- renderer/src/layouts/projects/SideBar.js | 87 ----- 3 files changed, 257 insertions(+), 175 deletions(-) diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index 35ba416fd..bc00ce1e8 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -16,6 +16,7 @@ import UsfmConflictEditor from './UsfmConflictEditor'; import { processAndIdentiyVerseChangeinUSFMJsons } from './processUsfmObjs'; import packageInfo from '../../../../package.json'; import { commitChanges } from '../Sync/Isomorphic/utils'; +import { useGrammartoPerf } from '@/hooks2/useGrammartoPerf'; const grammar = require('usfm-grammar'); const path = require('path'); @@ -39,8 +40,14 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) const [selectedBook, setSelectedBook] = useState(); const [conflictedChapters, setConflictedChapters] = useState({}); const [chapterResolveDone, setChapterResolveDone] = useState(false); - const [finishedConflict, setFinishedConflict] = useState(false); - const [resolvedChapters, setResolvedChapters] = useState({}); + const [finishedConflict, setFinishedConflict] = useState([]); + // const [resolvedChapters, setResolvedChapters] = useState({}); + + const [currentPerfInputArr, setCurrentPerfInputArr] = useState([]); + const [currentPerfResolveBookCode, setCurrentPerfResolveBookCode] = useState(''); + const [generatedPerfUSFM, setGeneratedPerfUSFM] = useState(); + + useGrammartoPerf(currentPerfInputArr, currentPerfResolveBookCode, setGeneratedPerfUSFM); const removeSection = async (abort = false) => { if (abort === false) { @@ -98,6 +105,7 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) const checkForConflictInSelectedBook = async (selectedBook) => { // parse imported const fs = window.require('fs'); + console.log('READ ON CONTINUE LOAD ========> ', usfmJsons.conflictMeta.incomingPath, ' selected : ', selectedBook); const IncomingUsfm = fs.readFileSync(path.join(usfmJsons.conflictMeta.incomingPath, selectedBook), 'utf8'); if (IncomingUsfm) { const importedJson = await parseUsfm(IncomingUsfm); @@ -151,13 +159,83 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) setLoading(false); }; - const handleFinishedResolution = async () => { - const fs = window.require('fs'); + console.log('PERF STATES >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ', { currentPerfInputArr, currentPerfResolveBookCode }); + + // Previous function to handle all books together ( JSON => usfm all together at the end ) + // const handleFinishedResolution = async () => { + // const fs = window.require('fs'); + + // flushSync(() => { + // setLoading(true); + // setFinishedConflict(false); + // }); + + // const resolvedBooks = { ...usfmJsons }; + // delete resolvedBooks.conflictMeta; + + // const currentSourceMeta = usfmJsons?.conflictMeta?.currentMeta; + + // // TODO : Disable all clicks when loading is true + + // const sourceIngredientPath = path.join(usfmJsons.conflictMeta.sourceProjectPath); + // // loop over the resolved books + // // eslint-disable-next-line no-restricted-syntax + // for (const bookName of Object.keys(resolvedBooks)) { + // const resolvedMergeJson = resolvedBooks[bookName]?.mergeJson; + // // eslint-disable-next-line no-await-in-loop + // const generatedUSFM = await parseJsonToUsfm(resolvedMergeJson); + + // // TODO : convert here to PERF + + // const perfUSFM = ''; + + // // overwrite the source file with new file + // fs.writeFileSync(path.join(sourceIngredientPath, 'ingredients', `${resolvedMergeJson.book.bookCode}.usfm`), generatedUSFM); + + // // get and update the usfms ingredients + // const stat = fs.statSync(path.join(sourceIngredientPath, 'ingredients', `${resolvedMergeJson.book.bookCode}.usfm`)); + // currentSourceMeta.ingredients[bookName].checksum.md5 = md5(generatedUSFM); + // currentSourceMeta.ingredients[bookName].size = stat.size; + // } + + // // write updated metadata here + // fs.writeFileSync(path.join(sourceIngredientPath, 'metadata.json'), JSON.stringify(currentSourceMeta)); + + // // remove .merge/project + // await fs.rmSync(usfmJsons.conflictMeta.projectMergePath, { recursive: true, force: true }); + // // commit all changes after merge finish + // const commitAuthor = { name: 'scribeInternal', email: 'scribe@bridgeconn.com' }; + // const backupMessage = `Scribe Internal Commit After Text Merge Finish : ${usfmJsons.conflictMeta.projectFullName} : ${new Date()}`; + // await commitChanges(fs, usfmJsons.conflictMeta.sourceProjectPath, commitAuthor, backupMessage, true); - flushSync(() => { + // setLoading(false); + // triggerSnackBar('success', 'Conflict Resolved Successfully'); + // closeMergeWindow(); + // }; + + const handleFinishMergeProcess = async () => { + try { setLoading(true); - setFinishedConflict(false); - }); + console.log('Done everything '); + const fs = window.require('fs'); + // remove temp merge path of project + await fs.rmSync(usfmJsons.conflictMeta.projectMergePath, { recursive: true, force: true }); + setLoading(false); + triggerSnackBar('success', 'Conflict Resolved Successfully'); + closeMergeWindow(); + } catch (err) { + console.error('Error Finish Process : ', err); + setLoading(false); + } + }; + + const handleFinishedBookResolution = async () => { + const fs = window.require('fs'); + + // flushSync(() => { + // setLoading(true); + // // setFinishedConflict((prev) => ([...prev, currentBook])); + // }); const resolvedBooks = { ...usfmJsons }; delete resolvedBooks.conflictMeta; @@ -167,83 +245,113 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) // TODO : Disable all clicks when loading is true const sourceIngredientPath = path.join(usfmJsons.conflictMeta.sourceProjectPath); - // loop over the resolved books - // eslint-disable-next-line no-restricted-syntax - for (const bookName of Object.keys(resolvedBooks)) { - const resolvedMergeJson = resolvedBooks[bookName]?.mergeJson; - // eslint-disable-next-line no-await-in-loop - const generatedUSFM = await parseJsonToUsfm(resolvedMergeJson); - // TODO : convert here to PERF + // work on single book + const resolvedMergeJson = resolvedBooks[selectedBook]?.mergeJson; + const generatedUSFM = await parseJsonToUsfm(resolvedMergeJson); + + if (generatedUSFM && resolvedMergeJson.book.bookCode) { + setCurrentPerfInputArr([{ + selectors: { org: 'unfoldingWord', lang: 'en', abbr: 'ult' }, + bookCode: resolvedMergeJson.book.bookCode.toLowerCase(), + data: generatedUSFM, + }]); + setCurrentPerfResolveBookCode(resolvedMergeJson.book.bookCode.toUpperCase()); + } else { + console.error('Can not generate usfm of current book : ', selectedBook); + } - const perfUSFM = ''; + // // loop over the resolved books + // // eslint-disable-next-line no-restricted-syntax + // for (const bookName of Object.keys(resolvedBooks)) { + // const resolvedMergeJson = resolvedBooks[bookName]?.mergeJson; + // // eslint-disable-next-line no-await-in-loop + // const generatedUSFM = await parseJsonToUsfm(resolvedMergeJson); - // overwrite the source file with new file - fs.writeFileSync(path.join(sourceIngredientPath, 'ingredients', `${resolvedMergeJson.book.bookCode}.usfm`), perfUSFM); + // // TODO : convert here to PERF - // get and update the usfms ingredients - const stat = fs.statSync(path.join(sourceIngredientPath, 'ingredients', `${resolvedMergeJson.book.bookCode}.usfm`)); - currentSourceMeta.ingredients[bookName].checksum.md5 = md5(generatedUSFM); - currentSourceMeta.ingredients[bookName].size = stat.size; - } + // const perfUSFM = ''; - // write updated metadata here - fs.writeFileSync(path.join(sourceIngredientPath, 'metadata.json'), JSON.stringify(currentSourceMeta)); + // // overwrite the source file with new file + // fs.writeFileSync(path.join(sourceIngredientPath, 'ingredients', `${resolvedMergeJson.book.bookCode}.usfm`), generatedUSFM); - // remove .merge/project - await fs.rmSync(usfmJsons.conflictMeta.projectMergePath, { recursive: true, force: true }); - // commit all changes after merge finish - const commitAuthor = { name: 'scribeInternal', email: 'scribe@bridgeconn.com' }; - const backupMessage = `Scribe Internal Commit After Text Merge Finish : ${usfmJsons.conflictMeta.projectFullName} : ${new Date()}`; - await commitChanges(fs, usfmJsons.conflictMeta.sourceProjectPath, commitAuthor, backupMessage, true); + // // get and update the usfms ingredients + // const stat = fs.statSync(path.join(sourceIngredientPath, 'ingredients', `${resolvedMergeJson.book.bookCode}.usfm`)); + // currentSourceMeta.ingredients[bookName].checksum.md5 = md5(generatedUSFM); + // currentSourceMeta.ingredients[bookName].size = stat.size; - setLoading(false); - triggerSnackBar('success', 'Conflict Resolved Successfully'); - closeMergeWindow(); + // write updated metadata here + // fs.writeFileSync(path.join(sourceIngredientPath, 'metadata.json'), JSON.stringify(currentSourceMeta)); + + // // remove .merge/project + // await fs.rmSync(usfmJsons.conflictMeta.projectMergePath, { recursive: true, force: true }); + // // commit all changes after merge finish + // const commitAuthor = { name: 'scribeInternal', email: 'scribe@bridgeconn.com' }; + // const backupMessage = `Scribe Internal Commit After Text Merge Finish : ${usfmJsons.conflictMeta.projectFullName} : ${new Date()}`; + // await commitChanges(fs, usfmJsons.conflictMeta.sourceProjectPath, commitAuthor, backupMessage, true); + + // setLoading(false); + // triggerSnackBar('success', 'Conflict Resolved Successfully'); + // closeMergeWindow(); }; // Function to write back the current usfmJSON data as config in the .merge const writeBackConflictConfigData = async (projectFullName, configData) => { - const fs = window.require('fs'); - const newpath = localStorage.getItem('userPath'); - const path = require('path'); - localforage.getItem('userProfile').then((user) => { - const USFMMergeDirPath = path.join(newpath, packageInfo.name, 'users', user?.username, '.merge-usfm'); - if (!fs.existsSync(path.join(USFMMergeDirPath, projectFullName))) { - fs.mkdirSync(path.join(USFMMergeDirPath, projectFullName), { recursive: true }); - } - fs.writeFileSync(path.join(USFMMergeDirPath, projectFullName, 'usfmJsons.json'), JSON.stringify(configData)); - }); + try { + const fs = window.require('fs'); + const newpath = localStorage.getItem('userPath'); + const path = require('path'); + localforage.getItem('userProfile').then((user) => { + const USFMMergeDirPath = path.join(newpath, packageInfo.name, 'users', user?.username, '.merge-usfm'); + if (!fs.existsSync(path.join(USFMMergeDirPath, projectFullName))) { + fs.mkdirSync(path.join(USFMMergeDirPath, projectFullName), { recursive: true }); + } + fs.writeFileSync(path.join(USFMMergeDirPath, projectFullName, 'usfmJsons.json'), JSON.stringify(configData)); + setLoading(false); + }); + } catch (err) { + console.error('Error Writeback config : ', err); + setLoading(false); + } }; const resolveAndMarkDoneChapter = async () => { - setChapterResolveDone(false); - // remove current chapter from conflicted list - const restOfTheChapters = conflictedChapters[selectedBook]?.filter((chNo) => chNo !== selectedChapter); - setConflictedChapters((prev) => ({ ...prev, [selectedBook]: restOfTheChapters })); - let isBookResolved = false; - if (restOfTheChapters?.length === 0) { - // completed conflicts for that particualr book - setResolvedBooks((prev) => [...prev, selectedBook]); - isBookResolved = true; - } else { - // current book have pending chapter , // Switch to next chapter or book - setSelectedChapter(restOfTheChapters[0]); - } - // store the jsons to the backend (/.merge/projectName/BookID.json) - - const { projectFullName } = usfmJsons.conflictMeta; - - // resolved chapters of each book and resolved books in the conflictMeta and store in the BE - const currentUSFMJsonsData = JSON.parse(JSON.stringify(usfmJsons)); - // initial time (if resolved chapters exist for the project) - if (currentUSFMJsonsData.conflictMeta?.resolvedStatus) { - currentUSFMJsonsData.conflictMeta.resolvedStatus[selectedBook] = { conflictedChapters: restOfTheChapters, isBookResolved }; - } else { - currentUSFMJsonsData.conflictMeta.resolvedStatus = { [selectedBook]: { conflictedChapters: restOfTheChapters, isBookResolved } }; + try { + setChapterResolveDone(false); + // remove current chapter from conflicted list + const restOfTheChapters = conflictedChapters[selectedBook]?.filter((chNo) => chNo !== selectedChapter); + setConflictedChapters((prev) => ({ ...prev, [selectedBook]: restOfTheChapters })); + let isBookResolved = false; + if (restOfTheChapters?.length === 0) { + // completed conflicts for that particualr book + flushSync(() => { + setLoading(true); + }); + await handleFinishedBookResolution(selectedBook); + setResolvedBooks((prev) => [...prev, selectedBook]); + isBookResolved = true; + } else { + // current book have pending chapter , // Switch to next chapter or book + setSelectedChapter(restOfTheChapters[0]); + } + // store the jsons to the backend (/.merge/projectName/BookID.json) + + // const { projectFullName } = usfmJsons.conflictMeta; + + // // resolved chapters of each book and resolved books in the conflictMeta and store in the BE + // const currentUSFMJsonsData = JSON.parse(JSON.stringify(usfmJsons)); + // // initial time (if resolved chapters exist for the project) + // if (currentUSFMJsonsData.conflictMeta?.resolvedStatus) { + // currentUSFMJsonsData.conflictMeta.resolvedStatus[selectedBook] = { conflictedChapters: restOfTheChapters, isBookResolved }; + // } else { + // currentUSFMJsonsData.conflictMeta.resolvedStatus = { [selectedBook]: { conflictedChapters: restOfTheChapters, isBookResolved } }; + // } + // setUsfmJsons(currentUSFMJsonsData); + // await writeBackConflictConfigData(projectFullName, currentUSFMJsonsData); + } catch (err) { + console.error('Failed resolve book : ', err); + setLoading(false); } - setUsfmJsons(currentUSFMJsonsData); - await writeBackConflictConfigData(projectFullName, currentUSFMJsonsData); }; /** @@ -297,6 +405,66 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) conflictData, conflictedChapters, resolvedBooks, finishedConflict, }); + /** + * Function overwrite the org usmf with generated perf usfm + * update config of the merge + * update metadata with new perf data + * reset perf states + */ + const writeBackPerfUSFMandUpdateConfig = async (generatedPerfUSFM) => { + try { + console.log('generated perf in useEffect &&&&&&&&&&&&&&&&&&&&&&&& : ', generatedPerfUSFM); + const fs = window.require('fs'); + setChapterResolveDone(false); + setCurrentPerfInputArr([]); + const { projectFullName } = usfmJsons.conflictMeta; + + // resolved chapters of each book and resolved books in the conflictMeta and store in the BE + const currentUSFMJsonsData = JSON.parse(JSON.stringify(usfmJsons)); + // initial time (if resolved chapters exist for the project) + if (currentUSFMJsonsData.conflictMeta?.resolvedStatus) { + currentUSFMJsonsData.conflictMeta.resolvedStatus[selectedBook] = { conflictedChapters, isBookResolved: true }; + } else { + currentUSFMJsonsData.conflictMeta.resolvedStatus = { [selectedBook]: { conflictedChapters, isBookResolved: true } }; + } + setUsfmJsons(currentUSFMJsonsData); + + // overwrite the source file with new file + // const currentSourceMeta = usfmJsons?.conflictMeta?.currentMeta; + // work on single book + const sourceIngredientPath = path.join(usfmJsons.conflictMeta.sourceProjectPath); + fs.writeFileSync(path.join(sourceIngredientPath, 'ingredients', `${currentPerfResolveBookCode.toUpperCase()}.usfm`), generatedPerfUSFM); + + const stat = fs.statSync(path.join(sourceIngredientPath, 'ingredients', `${currentPerfResolveBookCode.toUpperCase()}.usfm`)); + + // read source meta - update the for the current book - write back + const sourceMeta = fs.readFileSync(path.join(sourceIngredientPath, 'metadata.json')); + const sourceMetaJson = JSON.parse(sourceMeta); + sourceMetaJson.ingredients[selectedBook].checksum.md5 = md5(generatedPerfUSFM); + sourceMetaJson.ingredients[selectedBook].size = stat.size; + fs.writeFileSync(path.join(sourceIngredientPath, 'metadata.json'), JSON.stringify(sourceMetaJson)); + + // commit for the overwritten usfm + const commitAuthor = { name: 'scribeInternal', email: 'scribe@bridgeconn.com' }; + const backupMessage = `Scribe Internal Commit - conflict resolved for book : ${currentPerfResolveBookCode.toUpperCase()} : ${new Date()}`; + await commitChanges(fs, usfmJsons.conflictMeta.sourceProjectPath, commitAuthor, backupMessage, true); + + await writeBackConflictConfigData(projectFullName, currentUSFMJsonsData); + setCurrentPerfResolveBookCode(''); + setLoading(false); + } catch (err) { + console.error('error writeBackPerfUSFMandUpdateConfig : ', err); + setLoading(false); + } + }; + + // perf updation handle + useEffect(() => { + if (generatedPerfUSFM) { + writeBackPerfUSFMandUpdateConfig(generatedPerfUSFM); + } + }, [generatedPerfUSFM]); + // useEffect to trigger comleted all conflict Resolution useEffect(() => { console.log('finish check =============> ', resolvedBooks.length >= usfmJsons?.conflictMeta?.files?.length.length); @@ -322,7 +490,7 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) // handle conflict check for a book on book nav useEffect(() => { - if (!loading && usfmJsons?.conflictMeta) { + if (!loading && usfmJsons?.conflictMeta && selectedBook) { (async () => { setLoading(true); if (conflictedChapters[selectedBook]) { @@ -378,7 +546,7 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar })
  • {/* contents section */} -
    +
    handleFinishedResolution()} + onClick={() => handleFinishMergeProcess()} className="px-4 py-1 rounded-md uppercase bg-success/75 cursor-pointer hover:bg-success text-white" > Finish ) : ( - + > + {conflictedChapters?.[selectedBook]?.length <= 1 ? 'Resolve Book' : 'Done'} + + ) ) )}
    diff --git a/renderer/src/hooks/useGrammartoPerf.js b/renderer/src/hooks/useGrammartoPerf.js index 681e751dc..097acde51 100644 --- a/renderer/src/hooks/useGrammartoPerf.js +++ b/renderer/src/hooks/useGrammartoPerf.js @@ -1,15 +1,12 @@ -import React, { useEffect, useState } from 'react'; import { useProskomma, useImport, useCatalog } from 'proskomma-react-hooks'; import { - useDeepCompareCallback, useDeepCompareEffect, useDeepCompareMemo, } from 'use-deep-compare'; import EpiteleteHtml from 'epitelete-html'; -import usePerf from '../components/EditorPage/TextEditor/hooks/usePerf'; import htmlMap from '../components/EditorPage/TextEditor/hooks/htmlmap'; -export const useGrammartoPerf = (perfArr = [], selectedBook = '') => { +export const useGrammartoPerf = (perfArr = [], selectedBook = '', setGeneratedPerfUSFM = () => {}) => { let selectedDocument; let refName; @@ -29,7 +26,7 @@ export const useGrammartoPerf = (perfArr = [], selectedBook = '') => { console.log({ done }); const { catalog } = useCatalog({ proskomma, stateId, verbose: false }); - const { id: docSetId, documents } = (done && catalog.docSets[0]) || {}; // why documents no getting ----------------------- + const { id: docSetId, documents } = (done && catalog.docSets[0]) || {}; console.log(' ----------------- ------------ >', { catalog, docSetId, documents }); @@ -64,12 +61,14 @@ export const useGrammartoPerf = (perfArr = [], selectedBook = '') => { console.log('Triggering useDeepCompareEffect ==========> '); if (epiteleteHtml) { console.log('Insde useDeepCompareEffect ......................', bookCode); - const fs = window.require('fs'); + // const fs = window.require('fs'); epiteleteHtml.readHtml(bookCode, { cloning: false }, htmlMap).then(async (_htmlPerf) => { console.log('INSIDE READ HTML =============> ', _htmlPerf); const usfmPerfString = await epiteleteHtml?.readUsfm(bookCode); - await fs.writeFileSync('testedUSFMTIT.usfm', usfmPerfString); - console.log(' ============> ', usfmPerfString); + // await fs.writeFileSync(`${bookCode}-TEST.usfm`, usfmPerfString); + console.log(' Conversion done for PER USFM ============> ', usfmPerfString); + setGeneratedPerfUSFM(usfmPerfString); + // remove htmlMap for default classes }); } diff --git a/renderer/src/layouts/projects/SideBar.js b/renderer/src/layouts/projects/SideBar.js index 3a1ed33d6..d5a484e4f 100644 --- a/renderer/src/layouts/projects/SideBar.js +++ b/renderer/src/layouts/projects/SideBar.js @@ -8,66 +8,9 @@ import LogoIcon from '@/icons/logo.svg'; import ProjectsIcon from '@/icons/projects.svg'; import NewProjectIcon from '@/icons/new.svg'; import SyncIcon from '@/icons/sync.svg'; -import { useGrammartoPerf } from '@/hooks2/useGrammartoPerf'; import AboutModal from '../editor/AboutModal'; -const usfmGrammarString = `\\id TIT - \\h TIT - \\mt1 TIT - \\c 1 - \\p - \\v 1 .verse1.. - \\v 2 .verse2.. - \\v 3 .verse3.. - \\v 4 .verse4.. - \\v 5 ... - \\v 6 ... - \\v 7 ... - \\v 8 ... - \\v 9 ... - \\v 10 ... - \\v 11 ... - \\v 12 ... - \\v 13 ... - \\v 14 ... - \\v 15 ... - \\v 16 ... - \\c 2 - \\p - \\v 1 ... - \\v 2 ... - \\v 3 ... - \\v 4 ... - \\v 5 ... - \\v 6 ... - \\v 7 ... - \\v 8 ... - \\v 9 ... - \\v 10 ... - \\v 11 ... - \\v 12 ... - \\v 13 ... - \\v 14 ... - \\v 15 ... - \\c 3 - \\p - \\v 1 ... - \\v 2 ... - \\v 3 ... - \\v 4 ... - \\v 5 ... - \\v 6 ... - \\v 7 ... - \\v 8 ... - \\v 9 ... - \\v 10 ... - \\v 11 ... - \\v 12 ... - \\v 13 ... - \\v 14 ... - \\v 15 ...`; - export default function SideBar() { const [open, setOpen] = useState(false); // const [appMode, setAppMode] = useState(); @@ -85,12 +28,6 @@ export default function SideBar() { setOpen(isOpen); } - const [selected, setselectedBook] = useState(''); - const [perfArr, setPerfArr] = useState([]); - - // Testing HOOk for usfm to perf - useGrammartoPerf(perfArr, selected); - return (
    @@ -148,30 +85,6 @@ export default function SideBar() { - {/* Testing link ----------------------------------------------------------================================================= */} -
  • - -
  • {/* From 06390434bcfbbf4c74b390e68b28222b5547cc49 Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Tue, 30 Apr 2024 11:22:01 +0530 Subject: [PATCH 38/50] no conflict notification and checks --- .../TextTranslationMerge/mergeTextTranslationProject.js | 4 ++-- renderer/src/layouts/projects/ImportProjectPopUp.js | 5 +---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/renderer/src/components/TextTranslationMerge/mergeTextTranslationProject.js b/renderer/src/components/TextTranslationMerge/mergeTextTranslationProject.js index ee18890ee..59ad7741e 100644 --- a/renderer/src/components/TextTranslationMerge/mergeTextTranslationProject.js +++ b/renderer/src/components/TextTranslationMerge/mergeTextTranslationProject.js @@ -2,7 +2,7 @@ import updateTranslationSB from '@/core/burrito/updateTranslationSB'; import packageInfo from '../../../../package.json'; import { commitChanges } from '../Sync/Isomorphic/utils'; -export const mergeTextTranslationProject = async (incomingPath, currentUser, setConflictPopup, setProcessMerge, incomingMeta) => { +export const mergeTextTranslationProject = async (incomingPath, currentUser, setConflictPopup, setProcessMerge, incomingMeta, triggerSnackBar) => { try { // update the metadata of current md5 --- updateTranslationSB (src/core/burrito/) const fse = window.require('fs-extra'); @@ -88,8 +88,8 @@ export const mergeTextTranslationProject = async (incomingPath, currentUser, set }); } else { setProcessMerge(false); + triggerSnackBar('success', 'No Conflict Found'); console.log('No Conflict =================>'); - return 'noConflict'; } setProcessMerge(false); diff --git a/renderer/src/layouts/projects/ImportProjectPopUp.js b/renderer/src/layouts/projects/ImportProjectPopUp.js index 65f17f0cc..28b4b558c 100644 --- a/renderer/src/layouts/projects/ImportProjectPopUp.js +++ b/renderer/src/layouts/projects/ImportProjectPopUp.js @@ -200,10 +200,7 @@ export default function ImportProjectPopUp(props) { }else if (sbData?.burritoType === 'scripture / textTranslation') { console.log("Started Indentify Merge conflicts ------"); try { - const response = await mergeTextTranslationProject(folderPath, currentUser, setConflictPopup, setProcessMerge, sbData) - if(response === "noConflict") { - triggerSnackBar('success', "No Conflict Found",) - } + await mergeTextTranslationProject(folderPath, currentUser, setConflictPopup, setProcessMerge, sbData, triggerSnackBar) console.log("completed merge idenitfy process ------"); } catch(err) { From 860a4566d3cbedd5b2ffda1793549e724fea1d7a Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Tue, 30 Apr 2024 16:46:49 +0530 Subject: [PATCH 39/50] added confirm on continue merge for startover;perf logics --- .../TranslationMergeUI.jsx | 3 +- .../mergeTextTranslationProject.js | 13 ++- .../layouts/projects/ImportProjectPopUp.js | 91 ++++++++++++++++--- 3 files changed, 88 insertions(+), 19 deletions(-) diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index bc00ce1e8..9b8b12708 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -490,7 +490,8 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) // handle conflict check for a book on book nav useEffect(() => { - if (!loading && usfmJsons?.conflictMeta && selectedBook) { + if (!loading && usfmJsons?.conflictMeta) { + // if (!loading && usfmJsons?.conflictMeta && selectedBook) { (async () => { setLoading(true); if (conflictedChapters[selectedBook]) { diff --git a/renderer/src/components/TextTranslationMerge/mergeTextTranslationProject.js b/renderer/src/components/TextTranslationMerge/mergeTextTranslationProject.js index 59ad7741e..4778b8e60 100644 --- a/renderer/src/components/TextTranslationMerge/mergeTextTranslationProject.js +++ b/renderer/src/components/TextTranslationMerge/mergeTextTranslationProject.js @@ -2,9 +2,12 @@ import updateTranslationSB from '@/core/burrito/updateTranslationSB'; import packageInfo from '../../../../package.json'; import { commitChanges } from '../Sync/Isomorphic/utils'; -export const mergeTextTranslationProject = async (incomingPath, currentUser, setConflictPopup, setProcessMerge, incomingMeta, triggerSnackBar) => { +export const mergeTextTranslationProject = async (incomingPath, currentUser, setConflictPopup, setProcessMerge, incomingMeta, triggerSnackBar, startOver = false) => { try { // update the metadata of current md5 --- updateTranslationSB (src/core/burrito/) + console.log({ + incomingPath, currentUser, incomingMeta, startOver, +}); const fse = window.require('fs-extra'); const fs = window.require('fs'); const path = require('path'); @@ -50,16 +53,20 @@ export const mergeTextTranslationProject = async (incomingPath, currentUser, set const sourceProjectPath = path.join(newpath, packageInfo.name, 'users', currentUser, 'projects', projectDirName); let existingIncomingMeta; let isNewProjectMerge = true; + console.log({ isNewProjectMerge }); if (!fs.existsSync(path.join(USFMMergeDirPath, projectDirName))) { + console.log('not exist directory ==========='); fs.mkdirSync(path.join(USFMMergeDirPath, projectDirName), { recursive: true }); await fse.copy(incomingPath, path.join(USFMMergeDirPath, projectDirName, 'incoming')); + console.log('After copy 0000000000000000000'); // commit existing changes before merge start const commitAuthor = { name: 'scribeInternal', email: 'scribe@bridgeconn.com' }; - const backupMessage = `Scribe Internal Commit Before Text Merge Start : ${projectDirName} : ${new Date()}`; + const backupMessage = `Scribe Internal Commit Before Text Merge Start : ${projectDirName} : ${new Date()} , startOver : ${startOver}`; await commitChanges(fs, sourceProjectPath, commitAuthor, backupMessage, true); } else { isNewProjectMerge = false; - // read existing meta of incoming instead of using the new because the merge is inprogress + // read existing meta of incoming instead of using the new because the merge is + console.log('exist directory ===========xxxxxxxxxx'); if (fs.existsSync(path.join(path.join(USFMMergeDirPath, projectDirName, 'incoming', 'metadata.json')))) { existingIncomingMeta = fs.readFileSync(path.join(path.join(USFMMergeDirPath, projectDirName, 'incoming', 'metadata.json')), 'utf-8'); existingIncomingMeta = JSON.parse(existingIncomingMeta); diff --git a/renderer/src/layouts/projects/ImportProjectPopUp.js b/renderer/src/layouts/projects/ImportProjectPopUp.js index 28b4b558c..e677505cc 100644 --- a/renderer/src/layouts/projects/ImportProjectPopUp.js +++ b/renderer/src/layouts/projects/ImportProjectPopUp.js @@ -18,7 +18,7 @@ import * as logger from '../../logger'; import ConfirmationModal from '../editor/ConfirmationModal'; import burrito from '../../lib/BurritoTemplete.json'; import { mergeProject } from './Import/mergeProject'; - +import packageInfo from '../../../../package.json'; import { LoadingSpinner } from '@/components/LoadingSpinner'; import { mergeTextTranslationProject } from '@/components/TextTranslationMerge/mergeTextTranslationProject'; @@ -47,6 +47,12 @@ export default function ImportProjectPopUp(props) { title: '', confirmMessage: '', buttonName: '', + buttonName2: { + active: false, + loading: false, + name: null, + action: () => {}, + } }); const { action: { FetchProjects } } = useContext(AutographaContext); const { @@ -71,14 +77,13 @@ export default function ImportProjectPopUp(props) { logger.debug('ImportProjectPopUp.js', `Closing the Dialog box : Triggered from : ${triggeredFrom}`); removeExtractedZipDir() setValid(false); - setSbData() - setFolderPath() closePopUp(false); setShow(false); setImportProgress((prev)=>({...prev, importStarted:false, completedSteps: 0, totalSteps: 4})) } const openFileDialogSettingData = async () => { + setFolderPath() logger.debug('ImportProjectPopUp.js', 'Inside openFileDialogSettingData'); // const options = { properties: ['openFile','openDirectory'] }; const options = importingIsZip ? { properties: ['openFile'], filters: [{name:'zip file', extensions:["zip"]}] } : { properties: ['openDirectory'] }; @@ -137,7 +142,14 @@ export default function ImportProjectPopUp(props) { title: '', confirmMessage: '', buttonName: '', + buttonName2: { + active: false, + loading: false, + name: null, + action: () => {}, + } }); + setProcessMerge(false) setImportProgress((prev)=>({...prev, importStarted:false, completedSteps: 0, totalSteps: 4})) }; @@ -180,12 +192,37 @@ export default function ImportProjectPopUp(props) { callImport(false); } }; + + const startTextTranslationMergeProcess = async (startOver=false) => { + try { + if(startOver) { + const path = require('path'); + const fs = window.require('fs'); + const newpath = localStorage.getItem('userPath'); + const USFMMergeDirPath = path.join(newpath, packageInfo.name, 'users', currentUser, '.merge-usfm'); + const projectDirName = `${sbData.projectName}_${sbData.id[0]}`; + await fs.rmSync(path.join(USFMMergeDirPath,projectDirName), { recursive: true, force: true }); + } + // start conflict checks continue / start over + await mergeTextTranslationProject(folderPath, currentUser, setConflictPopup, setProcessMerge, sbData, triggerSnackBar, startOver) + console.log("completed merge idenitfy process ------"); + setSbData({}); + setFolderPath() + } catch(err) { + setSbData({}); + console.error("error in merge process : ", err); + } + } const callFunction = () => { if (model.buttonName === 'Replace') { setMerge(false); checkBurritoVersion(); - } else { + } + else if(model.buttonName === t('label-startover')) { + startTextTranslationMergeProcess(true) + } + else { callImport(true); } }; @@ -200,19 +237,42 @@ export default function ImportProjectPopUp(props) { }else if (sbData?.burritoType === 'scripture / textTranslation') { console.log("Started Indentify Merge conflicts ------"); try { - await mergeTextTranslationProject(folderPath, currentUser, setConflictPopup, setProcessMerge, sbData, triggerSnackBar) - console.log("completed merge idenitfy process ------"); + // confirm the user need to comtinue or start over the conflict process before move + const path = require('path'); + const fs = window.require('fs'); + const newpath = localStorage.getItem('userPath'); + const USFMMergeDirPath = path.join(newpath, packageInfo.name, 'users', currentUser, '.merge-usfm'); + const projectDirName = `${sbData.projectName}_${sbData.id[0]}`; + if(fs.existsSync(path.join(USFMMergeDirPath, projectDirName))) { + console.log("in IF ###############"); + setModel({ + openModel: true, + title: "Confirm", + confirmMessage: "You already have a conflict resolution in progress. Do you want to continue or start over.", + buttonName: t('label-startover'), + buttonName2 : { + active: true, + loading: false, + name:t('label-continue'), + action: () => startTextTranslationMergeProcess(false), + } + }); + } else { + console.log("in ELSE ###############"); + await startTextTranslationMergeProcess(false) + } } catch(err) { - + setMerge(false) + setProcessMerge(false) + console.log("error merge fucntion : ", err); } } setMerge(false) - setSbData({}); close() logger.debug('importProjectPopUp.js', 'git merge process done'); } - console.log({sbData}); + console.log({sbData, model}); const importProject = async () => { logger.debug('ImportProjectPopUp.js', 'Inside importProject'); @@ -230,6 +290,12 @@ export default function ImportProjectPopUp(props) { title: t('modal-title-replace-resource'), confirmMessage: t('dynamic-msg-confirm-replace-resource'), buttonName: t('btn-replace'), + buttonName2 : { + active: merge, + loading: processMerge, + name:t('label-merge'), + action: () => MergeFunction(), + } }); } else { logger.debug('ImportProjectPopUp.js', 'Its a new project'); @@ -428,12 +494,7 @@ export default function ImportProjectPopUp(props) { confirmMessage={model.confirmMessage} buttonName={model.buttonName} closeModal={() => callFunction()} - buttonName2={{ - active: merge, - loading: processMerge, - name:t('label-merge'), - action: () => MergeFunction(), - }} + buttonName2={model?.buttonName2} /> ); From 94b2227b22bb3aedc923a834b2a0b5560100c8de Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Thu, 2 May 2024 10:25:16 +0530 Subject: [PATCH 40/50] chapter level checkpoint and reload from the checkpoint of chapte --- .../TranslationMergeUI.jsx | 38 ++++++------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index 9b8b12708..d717db3b6 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -336,18 +336,18 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) } // store the jsons to the backend (/.merge/projectName/BookID.json) - // const { projectFullName } = usfmJsons.conflictMeta; - - // // resolved chapters of each book and resolved books in the conflictMeta and store in the BE - // const currentUSFMJsonsData = JSON.parse(JSON.stringify(usfmJsons)); - // // initial time (if resolved chapters exist for the project) - // if (currentUSFMJsonsData.conflictMeta?.resolvedStatus) { - // currentUSFMJsonsData.conflictMeta.resolvedStatus[selectedBook] = { conflictedChapters: restOfTheChapters, isBookResolved }; - // } else { - // currentUSFMJsonsData.conflictMeta.resolvedStatus = { [selectedBook]: { conflictedChapters: restOfTheChapters, isBookResolved } }; - // } - // setUsfmJsons(currentUSFMJsonsData); - // await writeBackConflictConfigData(projectFullName, currentUSFMJsonsData); + const { projectFullName } = usfmJsons.conflictMeta; + + // resolved chapters of each book and resolved books in the conflictMeta and store in the BE + const currentUSFMJsonsData = JSON.parse(JSON.stringify(usfmJsons)); + // initial time (if resolved chapters exist for the project) + if (currentUSFMJsonsData.conflictMeta?.resolvedStatus) { + currentUSFMJsonsData.conflictMeta.resolvedStatus[selectedBook] = { conflictedChapters: restOfTheChapters, isBookResolved }; + } else { + currentUSFMJsonsData.conflictMeta.resolvedStatus = { [selectedBook]: { conflictedChapters: restOfTheChapters, isBookResolved } }; + } + setUsfmJsons(currentUSFMJsonsData); + await writeBackConflictConfigData(projectFullName, currentUSFMJsonsData); } catch (err) { console.error('Failed resolve book : ', err); setLoading(false); @@ -417,20 +417,7 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) const fs = window.require('fs'); setChapterResolveDone(false); setCurrentPerfInputArr([]); - const { projectFullName } = usfmJsons.conflictMeta; - - // resolved chapters of each book and resolved books in the conflictMeta and store in the BE - const currentUSFMJsonsData = JSON.parse(JSON.stringify(usfmJsons)); - // initial time (if resolved chapters exist for the project) - if (currentUSFMJsonsData.conflictMeta?.resolvedStatus) { - currentUSFMJsonsData.conflictMeta.resolvedStatus[selectedBook] = { conflictedChapters, isBookResolved: true }; - } else { - currentUSFMJsonsData.conflictMeta.resolvedStatus = { [selectedBook]: { conflictedChapters, isBookResolved: true } }; - } - setUsfmJsons(currentUSFMJsonsData); - // overwrite the source file with new file - // const currentSourceMeta = usfmJsons?.conflictMeta?.currentMeta; // work on single book const sourceIngredientPath = path.join(usfmJsons.conflictMeta.sourceProjectPath); fs.writeFileSync(path.join(sourceIngredientPath, 'ingredients', `${currentPerfResolveBookCode.toUpperCase()}.usfm`), generatedPerfUSFM); @@ -449,7 +436,6 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) const backupMessage = `Scribe Internal Commit - conflict resolved for book : ${currentPerfResolveBookCode.toUpperCase()} : ${new Date()}`; await commitChanges(fs, usfmJsons.conflictMeta.sourceProjectPath, commitAuthor, backupMessage, true); - await writeBackConflictConfigData(projectFullName, currentUSFMJsonsData); setCurrentPerfResolveBookCode(''); setLoading(false); } catch (err) { From 241c82ef985596adc820a4d0fa8186d3fb13d53d Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Thu, 2 May 2024 10:57:38 +0530 Subject: [PATCH 41/50] merge button not showing initially --- renderer/src/layouts/projects/ImportProjectPopUp.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/renderer/src/layouts/projects/ImportProjectPopUp.js b/renderer/src/layouts/projects/ImportProjectPopUp.js index e677505cc..bea400db0 100644 --- a/renderer/src/layouts/projects/ImportProjectPopUp.js +++ b/renderer/src/layouts/projects/ImportProjectPopUp.js @@ -279,11 +279,13 @@ export default function ImportProjectPopUp(props) { if (folderPath) { setImportProgress((prev)=>({...prev, importStarted:true, completedSteps: prev.completedSteps + 1 })) setValid(false); + let IsMergeOption = false if (sbData.duplicate === true) { logger.warn('ImportProjectPopUp.js', 'Project already available'); // currently MERGE feature only Enabled for OBS projects if (sbData?.burritoType === 'gloss / textStories' || sbData?.burritoType === 'scripture / textTranslation'){ setMerge(true) + IsMergeOption = true } setModel({ openModel: true, @@ -291,7 +293,7 @@ export default function ImportProjectPopUp(props) { confirmMessage: t('dynamic-msg-confirm-replace-resource'), buttonName: t('btn-replace'), buttonName2 : { - active: merge, + active: IsMergeOption, loading: processMerge, name:t('label-merge'), action: () => MergeFunction(), From 2e15f6b15449acb80ef62f4f4b5846977e4f12ec Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Thu, 2 May 2024 11:53:00 +0530 Subject: [PATCH 42/50] loadback inprogress based on config status --- .../TextTranslationMerge/TranslationMergeUI.jsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index d717db3b6..ae788580a 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -359,10 +359,12 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) * read usfm json data from backend */ const getInprogressMergeProject = async (data) => { + console.log('Loading Existing Project ================= ..................', { data }); const fs = window.require('fs'); if (fs.existsSync(path.join(data.projectMergePath, 'usfmJsons.json'))) { let usfmJsonsContent = fs.readFileSync(path.join(data.projectMergePath, 'usfmJsons.json'), 'utf8'); usfmJsonsContent = JSON.parse(usfmJsonsContent); + console.log({ usfmJsonsContent }); if (usfmJsonsContent) { setUsfmJsons(usfmJsonsContent); // check the books is already resolved or not => then select current book and unresolved chapters @@ -385,6 +387,13 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) conflictedChsOfBooks[book] = currentBook.conflictedChapters; } } + + // bookToSelect == undefined => All books in the resolved Status are completly resolved + if (!bookToSelect) { + const pendingBook = usfmJsonsContent.conflictMeta.files.find((bukName) => !(bukName in usfmJsonsContent.conflictMeta.resolvedStatus)); + // if pendingBook == undefined means all files conflict are resolved + bookToSelect = pendingBook || usfmJsonsContent.conflictMeta.files[0]; + } } else { // checkpoint - stored on initially and not worked on any chapter bookToSelect = usfmJsonsContent.conflictMeta.files[0]; @@ -451,7 +460,7 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) } }, [generatedPerfUSFM]); - // useEffect to trigger comleted all conflict Resolution + // useEffect to trigger completed all conflict Resolution useEffect(() => { console.log('finish check =============> ', resolvedBooks.length >= usfmJsons?.conflictMeta?.files?.length.length); if (resolvedBooks.length >= usfmJsons?.conflictMeta?.files?.length) { From 50a4a276896e65ae0098bf7a089489879354388f Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Thu, 2 May 2024 14:33:38 +0530 Subject: [PATCH 43/50] added conflict detection based on the current and incoming content values --- .../TextTranslationMerge/TranslationMergeUI.jsx | 3 --- .../components/TextTranslationMerge/processUsfmObjs.js | 9 +++++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index ae788580a..587c0f995 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -105,7 +105,6 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) const checkForConflictInSelectedBook = async (selectedBook) => { // parse imported const fs = window.require('fs'); - console.log('READ ON CONTINUE LOAD ========> ', usfmJsons.conflictMeta.incomingPath, ' selected : ', selectedBook); const IncomingUsfm = fs.readFileSync(path.join(usfmJsons.conflictMeta.incomingPath, selectedBook), 'utf8'); if (IncomingUsfm) { const importedJson = await parseUsfm(IncomingUsfm); @@ -159,8 +158,6 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) setLoading(false); }; - console.log('PERF STATES >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ', { currentPerfInputArr, currentPerfResolveBookCode }); - // Previous function to handle all books together ( JSON => usfm all together at the end ) // const handleFinishedResolution = async () => { // const fs = window.require('fs'); diff --git a/renderer/src/components/TextTranslationMerge/processUsfmObjs.js b/renderer/src/components/TextTranslationMerge/processUsfmObjs.js index ccc6071ec..5a67bfad3 100644 --- a/renderer/src/components/TextTranslationMerge/processUsfmObjs.js +++ b/renderer/src/components/TextTranslationMerge/processUsfmObjs.js @@ -10,8 +10,13 @@ async function processAndIdentiyVerseChangeinUSFMJsons(currentJson, IncomingJson chapter.contents.forEach((content) => { if (content.verseNumber) { const IncomingVerse = IncomingChap.contents.find((ch) => ch.verseNumber === content.verseNumber); - // console.log(IncomingVerse); - if (content.verseText !== IncomingVerse.verseText) { + /** + * handle conflict detection coniditons + * conflict only if + * - both have valid string ([a-zA-Z0-9]) and not same + * - valid content in incoming , current can be anything + * */ + if ((content.verseText !== IncomingVerse.verseText) && (/[a-zA-Z0-9]/.test(IncomingVerse.verseText))) { // add incoming data content.current = JSON.parse(JSON.stringify(content)); content.incoming = IncomingVerse; From 1ea82996c85f7644dc4433bddf442ec5347f25f5 Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Thu, 2 May 2024 14:38:33 +0530 Subject: [PATCH 44/50] lint fix --- .../TranslationMergeUI copy.jsx | 468 ------------------ renderer/src/hooks/useGrammartoPerf.js | 3 +- renderer/src/layouts/projects/Layout.js | 2 +- 3 files changed, 3 insertions(+), 470 deletions(-) delete mode 100644 renderer/src/components/TextTranslationMerge/TranslationMergeUI copy.jsx diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI copy.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI copy.jsx deleted file mode 100644 index fcd664a81..000000000 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI copy.jsx +++ /dev/null @@ -1,468 +0,0 @@ -/* eslint-disable no-nested-ternary */ -import React, { - useRef, Fragment, useState, useEffect, useContext, useMemo, -} from 'react'; -import { Dialog, Transition } from '@headlessui/react'; -import { AutographaContext } from '@/components/context/AutographaContext'; -import { useTranslation } from 'react-i18next'; -import { XMarkIcon } from '@heroicons/react/24/outline'; -import ConfirmationModal from '@/layouts/editor/ConfirmationModal'; -import { readUsfmFile } from '@/core/projects/userSettings'; -import DiffMatchPatch from 'diff-match-patch'; -import localforage from 'localforage'; -import TranslationMergNavBar from './TranslationMergNavBar'; -import * as logger from '../../logger'; -import useGetCurrentProjectMeta from '../Sync/hooks/useGetCurrentProjectMeta'; -import LoadingScreen from '../Loading/LoadingScreen'; -import ImportUsfmUI from './ImportUsfmUI'; -import UsfmConflictEditor from './UsfmConflictEditor'; -import { processAndIdentiyVerseChangeinUSFMJsons } from './processUsfmObjs'; -import packageInfo from '../../../../package.json'; - -const grammar = require('usfm-grammar'); - -function TranslationMergeUI({ conflictData, setConflictPopup }) { - console.log({ conflictData }); - const [importedUsfmFolderPath, setImportedUsfmFolderPath] = useState([]); - const [usfmJsons, setUsfmJsons] = useState({ - imported: null, - current: null, - }); - const [selectedChapter, setSelectedChapter] = useState(1); - const [selectedBookId, setSelectedBookId] = useState(null); - const [conflictedChapters, setConflictedChapters] = useState([]); - const [resolvedChapters, setResolvedChapters] = useState([]); - const [chapterResolveDone, setChapterResolveDone] = useState(false); - - const [savedConflictsBooks, setSavedConflictsBooks] = useState([]); - const [existImportedBook, setExistImportedBook] = useState({ status: false, bookId: null }); - - const [loading, setLoading] = useState(false); - const [error, setError] = useState(''); - const [finishedConflict, setFinishedConflict] = useState(false); - - const { t } = useTranslation(); - const cancelButtonRef = useRef(null); - const [model, setModel] = React.useState({ - openModel: false, - title: '', - confirmMessage: '', - buttonName: '', - }); - - const { - state: { currentProjectMeta }, - actions: { getProjectMeta }, - } = useGetCurrentProjectMeta(); - - console.log({ - currentProjectMeta, selectedBookId, usfmJsons, - }); - - const modalClose = () => { - setModel({ - openModel: false, - title: '', - confirmMessage: '', - buttonName: '', - }); - }; - - const handleStartOver = () => { - console.log('start over called ----'); - setExistImportedBook({ status: false, bookId: null }); - modalClose(); - }; - - const handleOnAbortMerge = (buttonName) => { - console.log({ buttonName }, model); - if (model.buttonName === t('label-abort')) { - setError(''); - setUsfmJsons({}); - setImportedUsfmFolderPath([]); - setOpenTextTranslationMerge({ open: false, meta: null }); - modalClose(); - } else { - handleStartOver(); - } - }; - - const removeSection = async (abort = false) => { - if (abort === false) { - // pass - } else { - // popup with warning - setModel({ - openModel: true, - title: t('modal-title-abort-conflict-resolution'), - confirmMessage: t('msg-abort-conflict-resolution'), - buttonName: t('label-abort'), - }); - } - }; - - const readMergeDirOrSingleFile = async (readDir = true, fileName = null) => { - const fs = window.require('fs'); - const { id, name } = openTextTranslationMerge.meta; - const _projectName = `${name}_${id[0]}`; - const newpath = localStorage.getItem('userPath'); - const path = require('path'); - - const user = await localforage.getItem('userProfile'); - if (user?.username) { - const USFMMergeDirPath = path.join(newpath, packageInfo.name, 'users', user?.username, '.merge-usfm'); - if (!fs.existsSync(path.join(USFMMergeDirPath, _projectName))) { - return null; - } - if (readDir) { - const files = fs.readdirSync(path.join(USFMMergeDirPath, _projectName)); - console.log({ files }); - return files; - } - // read file - json - let jsonFile = fs.readFileSync(path.join(USFMMergeDirPath, _projectName, fileName)); - jsonFile = JSON.parse(jsonFile); - return jsonFile; - } - console.error('no user : ', { user }); - }; - - useEffect(() => { - if (openTextTranslationMerge?.meta) { - const { id, name } = openTextTranslationMerge.meta; - (async () => { - await getProjectMeta(`${name}_${id[0]}`); - // check for existing merge and display ui based on that - const mergeDirContents = await readMergeDirOrSingleFile(); - setSavedConflictsBooks(mergeDirContents); - })(); - } - }, []); - - const openFileDialogSettingData = async () => { - logger.debug('translationMergeUI.js', 'Inside openFileDialogSettingData'); - const options = { - properties: ['openFile'], - filters: [{ name: 'usfm files', extensions: ['usfm', 'sfm', 'USFM', 'SFM'] }], - }; - const { dialog } = window.require('@electron/remote'); - const chosenFolder = await dialog.showOpenDialog(options); - if ((chosenFolder.filePaths).length > 0) { - logger.debug('translationMergeUI.js', 'Selected the files'); - setImportedUsfmFolderPath(chosenFolder.filePaths); - } else { - logger.debug('translationMergeUI.js', 'Didn\'t select any file'); - } - }; - - const handleImportUsfm = () => { - openFileDialogSettingData(); - }; - - const resumeConflictResolution = async (bookId) => { - // bookid (same as backendfilename) - > mat.json - console.log('book id : ', bookId); - const { usfmJsons } = await readMergeDirOrSingleFile(false, bookId); - setUsfmJsons(usfmJsons); - setExistImportedBook({ status: false, bookId: null }); - - const _conflictedBooks = []; - setSelectedBookId(usfmJsons.mergeJson.book.bookCode.toLowerCase()); - usfmJsons.mergeJson.chapters.forEach((chapter, index) => { - chapter.contents.forEach((content) => { - if (content.verseNumber) { - if (content?.resolved && !content?.resolved?.status) { - !_conflictedBooks.includes(chapter.chapterNumber) && _conflictedBooks.push(chapter.chapterNumber); - } - } - }); - }); - - setConflictedChapters(_conflictedBooks); - setFinishedConflict(false); - console.log({ usfmJsons }); - }; - - async function parseUsfm(usfm) { - const myUsfmParser = new grammar.USFMParser(usfm, grammar.LEVEL.RELAXED); - const isJsonValid = myUsfmParser.validate(); - return { valid: isJsonValid, data: myUsfmParser.toJSON() }; - } - - async function parseJsonToUsfm(json) { - const myUsfmParser = new grammar.JSONParser(json); - const usfm = myUsfmParser.toUSFM(); - return usfm; - } - - const parseFiles = async () => { - // parse imported - const fs = window.require('fs'); - const IncomingUsfm = fs.readFileSync(importedUsfmFolderPath[0], 'utf8'); - if (IncomingUsfm) { - const importedJson = await parseUsfm(IncomingUsfm); - // const normalisedIncomingUSFM = await parseJsonToUsfm(importedJson.data); - if (!importedJson.valid) { - setError('Imported Usfm is invalid'); - } else if (!Object.keys(currentProjectMeta?.type?.flavorType?.currentScope).includes(importedJson?.data?.book?.bookCode) - && !Object.keys(currentProjectMeta?.type?.flavorType?.currentScope).includes(importedJson?.data?.book?.bookCode?.toLowerCase())) { - setError('Imported USFM is not in the scope of Current Project'); - } else { - // Parse current project same book - const importedBookCode = `${importedJson.data.book.bookCode.toLowerCase()}.usfm`; - - setError(''); - setUsfmJsons((prev) => ({ ...prev, imported: importedJson.data })); - setSelectedBookId(importedJson.data.book.bookCode.toLowerCase()); - const currentBookPath = Object.keys(currentProjectMeta?.ingredients).find((code) => code.toLowerCase().endsWith(importedBookCode)); - const { id, name } = openTextTranslationMerge.meta; - const currentBookUsfm = await readUsfmFile(currentBookPath, `${name}_${id[0]}`); - // console.log('FOUND ====> ', { currentBookPath, currentBookUsfm }); - if (currentBookUsfm) { - const currentJson = await parseUsfm(currentBookUsfm); - // const currentNormalisedUsfm = await parseJsonToUsfm(currentJson.data); - - // generate the merge object with current , incoming , merge verses - // const mergeJson = JSON.parse(JSON.stringify(currentJson.data)); - const processOutArr = await processAndIdentiyVerseChangeinUSFMJsons(importedJson.data, currentJson.data).catch((err) => { - console.log('process usfm : ', err); - }); - const mergeJson = processOutArr[0]; - console.log('processOutArr[1] : ', processOutArr[1]); - setConflictedChapters(processOutArr[1]); - - if (savedConflictsBooks.includes(`${importedJson.data.book.bookCode.toLowerCase()}.json`)) { - setExistImportedBook({ status: true, bookId: importedJson.data.book.bookCode.toLowerCase() }); - console.log('existing book'); - setModel({ - openModel: true, - title: t('modal-title-abort-conflict-resolution'), - confirmMessage: t('msg-conflict-resolution-duplicate-book', { bookId: importedJson.data.book.bookCode.toUpperCase() }), - buttonName: t('label-startover'), - }); - } - - currentJson && currentJson?.valid && setUsfmJsons((prev) => ({ ...prev, current: currentJson.data, mergeJson })); - - // compare usfms to check conflcit or not - // const diffOut = await dmp.diff_main(normalisedIncomingUSFM, currentNormalisedUsfm); - // setUsfmJsons((prev) => ({ ...prev, diffOut })); - } - } - } else { - setError('unable to read imported USFM'); - } - setLoading(false); - }; - - useEffect(() => { - // get usfm and parse - if (importedUsfmFolderPath.length === 1 && currentProjectMeta) { - setLoading(true); - parseFiles(); - setFinishedConflict(false); - } - }, [importedUsfmFolderPath, currentProjectMeta]); - - useEffect(() => { - if (conflictedChapters.length === resolvedChapters.length) { - setFinishedConflict(true); - } - }, [conflictedChapters.length, resolvedChapters.length]); - - const resolveAndMarkDoneChapter = () => { - setResolvedChapters((prev) => [...prev, selectedChapter]); - // store the jsons to the backend (/.merge/projectName/BookID.json) - const fs = window.require('fs'); - const { id, name } = openTextTranslationMerge.meta; - const _projectName = `${name}_${id[0]}`; - const newpath = localStorage.getItem('userPath'); - const path = require('path'); - localforage.getItem('userProfile').then((user) => { - const USFMMergeDirPath = path.join(newpath, packageInfo.name, 'users', user?.username, '.merge-usfm'); - if (!fs.existsSync(path.join(USFMMergeDirPath, _projectName))) { - fs.mkdirSync(path.join(USFMMergeDirPath, _projectName), { recursive: true }); - } - console.log('write this book :', `${selectedBookId}.json`); - fs.writeFileSync(path.join(USFMMergeDirPath, _projectName, `${selectedBookId}.json`), JSON.stringify({ usfmJsons })); - }); - }; - - const handleFinishedResolution = async () => { - try { - const path = require('path'); - const fs = window.require('fs'); - - const { id, name } = openTextTranslationMerge.meta; - const _projectName = `${name}_${id[0]}`; - const newpath = localStorage.getItem('userPath'); - - const user = await localforage.getItem('userProfile'); - if (user?.username) { - const USFMMergeDirPath = path.join(newpath, packageInfo.name, 'users', user?.username, '.merge-usfm'); - const currentJsonFile = `${existImportedBook.bookId}.json`; - const OrgProjectFilePath = path.join(newpath, packageInfo.name, 'users', user?.username, 'projects', _projectName, 'ingredients', existImportedBook.bookId.toUpperCase()); - - // convert usfmJson.mergeJson to norml parsedJson and convert to usfm - - const resolvedTempJson = JSON.parse(JSON.stringify(usfmJsons.mergeJson)); - - for (let index = 0; index < resolvedTempJson.chapters.length; index++) { - const chObjContents = usfmJsons.mergeJson.chapters[index].contents; - for (let j = 0; j < chObjContents.length; j++) { - let verseObj = chObjContents[j]; - if (verseObj?.resolved) { - const tempResolvedContent = verseObj.resolved.resolvedContent; - verseObj = { ...tempResolvedContent }; - } - } - } - - const usfm = await parseJsonToUsfm(resolvedTempJson); - fs.writeFileSync(OrgProjectFilePath, usfm, 'utf-8'); - - // delete saved json in merge dir - check if it is the last one then delete folder too - if (!fs.existsSync(path.join(USFMMergeDirPath, _projectName))) { - const files = fs.readdirSync(path.join(USFMMergeDirPath, _projectName)); - if (files?.length > 1) { - // delete single file - await fs.unlinkSync(path.join(USFMMergeDirPath, currentJsonFile)); - } else { - // delete dir - await fs.rmdirSync(USFMMergeDirPath, { recursive: true }, (err) => { - if (err) { - throw new Error(`Error delete .usfm-merge dir : ${err}`); - } - }); - } - } - } - } catch (err) { - console.log('error : finishd move file ---> ', err); - } - }; - - return ( - <> - - removeSection(true)} - > - - -
    -
    -

    {t('label-resolve-conflict')}

    -
    - {/* close btn section */} - -
    - - {/* contents section */} -
    -
    - - -
    -
    - - {loading ? () : ( - - (usfmJsons.current && usfmJsons.imported && !existImportedBook.status) ? ( -
    - -
    - ) - : ( - - ) - - )} - -
    -
    -

    {error}

    - {usfmJsons.current && usfmJsons.imported && ( - finishedConflict ? ( - - - ) : ( - - - ) - )} -
    -
    -
    -
    -
    -
    -
    - - modalClose()} - confirmMessage={model.confirmMessage} - buttonName={model.buttonName} - closeModal={() => handleOnAbortMerge(model.buttonName)} - /> - - ); -} - -export default TranslationMergeUI; diff --git a/renderer/src/hooks/useGrammartoPerf.js b/renderer/src/hooks/useGrammartoPerf.js index 097acde51..aa7c787f8 100644 --- a/renderer/src/hooks/useGrammartoPerf.js +++ b/renderer/src/hooks/useGrammartoPerf.js @@ -41,7 +41,8 @@ export const useGrammartoPerf = (perfArr = [], selectedBook = '', setGeneratedPe console.log({ selectedDocument }); - const { bookCode, h: bookName } = selectedDocument || {}; + // const { bookCode, h: bookName } = selectedDocument || {}; + const { bookCode } = selectedDocument || {}; const ready = (docSetId && bookCode) || false; console.log({ bookCode, ready }); diff --git a/renderer/src/layouts/projects/Layout.js b/renderer/src/layouts/projects/Layout.js index b85d064a6..580a3695e 100644 --- a/renderer/src/layouts/projects/Layout.js +++ b/renderer/src/layouts/projects/Layout.js @@ -9,11 +9,11 @@ import { } from '@heroicons/react/24/outline'; import { useTranslation } from 'react-i18next'; import { ProjectContext } from '@/components/context/ProjectContext'; +import TranslationMergeUI from '@/components/TextTranslationMerge/TranslationMergeUI.jsx'; import SideBar from './SideBar'; import TopMenuBar from './TopMenuBar'; import ImportProjectPopUp from './ImportProjectPopUp'; import ConflictResolverUI from './Import/ConflictResolverUI'; -import TranslationMergeUI from '@/components/TextTranslationMerge/TranslationMergeUI'; export default function ProjectsLayout(props) { const { From 8a4c72d0756a7120765ca82d66a614930a9b01b7 Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Fri, 3 May 2024 10:20:29 +0530 Subject: [PATCH 45/50] folder and import data exit after close issue fixed --- .../components/TextTranslationMerge/TranslationMergeUI.jsx | 1 + renderer/src/layouts/projects/ImportProjectPopUp.js | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index 587c0f995..8f6f139d0 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -434,6 +434,7 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) const sourceMeta = fs.readFileSync(path.join(sourceIngredientPath, 'metadata.json')); const sourceMetaJson = JSON.parse(sourceMeta); sourceMetaJson.ingredients[selectedBook].checksum.md5 = md5(generatedPerfUSFM); + console.log('Updated MD5 ================================> ', { selectedBook }, md5(generatedPerfUSFM)); sourceMetaJson.ingredients[selectedBook].size = stat.size; fs.writeFileSync(path.join(sourceIngredientPath, 'metadata.json'), JSON.stringify(sourceMetaJson)); diff --git a/renderer/src/layouts/projects/ImportProjectPopUp.js b/renderer/src/layouts/projects/ImportProjectPopUp.js index bea400db0..8e5e50782 100644 --- a/renderer/src/layouts/projects/ImportProjectPopUp.js +++ b/renderer/src/layouts/projects/ImportProjectPopUp.js @@ -83,7 +83,6 @@ export default function ImportProjectPopUp(props) { } const openFileDialogSettingData = async () => { - setFolderPath() logger.debug('ImportProjectPopUp.js', 'Inside openFileDialogSettingData'); // const options = { properties: ['openFile','openDirectory'] }; const options = importingIsZip ? { properties: ['openFile'], filters: [{name:'zip file', extensions:["zip"]}] } : { properties: ['openDirectory'] }; @@ -115,6 +114,7 @@ export default function ImportProjectPopUp(props) { } else { logger.debug('ImportProjectPopUp.js', 'Didn\'t select any project'); setSbData({}); + setFolderPath() close("else"); } setFolderPath(selectedFolderPath); @@ -172,6 +172,7 @@ export default function ImportProjectPopUp(props) { if (status[0].type === 'success') { setSbData({}); close("Success"); + setFolderPath() FetchProjects(); router.push('/projects'); } @@ -350,7 +351,7 @@ export default function ImportProjectPopUp(props) { {t('label-import-project')}
  • ) - - // (usfmJsons.current && usfmJsons.imported && !existImportedBook.status) ? ( - //
    - // - //
    - // ) - // : ( - // - // ) - )}
    From 5db0a77da8aea12973db0d6e51eab3adbe4330b4 Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Tue, 9 Jul 2024 11:37:07 +0530 Subject: [PATCH 48/50] fixes for auto conflict --- renderer/src/components/SnackBar/SnackBar.js | 4 +- .../TranslationMergeUI.jsx | 100 ++++++++++-------- 2 files changed, 59 insertions(+), 45 deletions(-) diff --git a/renderer/src/components/SnackBar/SnackBar.js b/renderer/src/components/SnackBar/SnackBar.js index 28484b239..b31c43583 100644 --- a/renderer/src/components/SnackBar/SnackBar.js +++ b/renderer/src/components/SnackBar/SnackBar.js @@ -5,7 +5,9 @@ import { XMarkIcon } from '@heroicons/react/24/outline'; import { Popover, Transition } from '@headlessui/react'; import PropTypes from 'prop-types'; -const colors = { success: '#82E0AA', failure: '#F5B7B1', warning: '#F8C471' }; +const colors = { + success: '#82E0AA', failure: '#F5B7B1', warning: '#F8C471', info: '#17a2b8', +}; const SnackBar = ({ openSnackBar, snackText, diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index bcfb28c81..4b18eb101 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -100,50 +100,6 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) return usfm; } - const checkForConflictInSelectedBook = async (selectedBook) => { - // parse imported - const fs = window.require('fs'); - const IncomingUsfm = fs.readFileSync(path.join(usfmJsons.conflictMeta.incomingPath, selectedBook), 'utf8'); - if (IncomingUsfm) { - const importedJson = await parseUsfm(IncomingUsfm); - if (!importedJson.valid) { - setError('Imported Usfm is invalid'); - } else { - // Parse current project same book - const importedBookCode = `${importedJson.data.book.bookCode.toLowerCase()}.usfm`; - - setError(''); - - setUsfmJsons((prev) => ({ ...prev, [selectedBook]: { ...prev[selectedBook], imported: importedJson.data } })); - - // setSelectedBookId(importedJson.data.book.bookCode.toLowerCase()); - // const currentBookPath = Object.keys(usfmJsons.conflictMeta.currentMeta.ingredients).find((code) => code.toLowerCase().endsWith(importedBookCode)); - const { projectFullName } = usfmJsons.conflictMeta; - const currentBookUsfm = await readUsfmFile(selectedBook, projectFullName); - // console.log('FOUND ====> ', { currentBookPath, currentBookUsfm }); - if (currentBookUsfm) { - const currentJson = await parseUsfm(currentBookUsfm); - // generate the merge object with current , incoming , merge verses - const processOutArr = await processAndIdentiyVerseChangeinUSFMJsons(currentJson.data, importedJson.data).catch((err) => { - console.log('process usfm : ', err); - }); - const mergeJson = processOutArr[0]; - const conflcitedChapters = processOutArr[1]; - console.log('processOutArr[1] : ', processOutArr[1]); - currentJson && currentJson?.valid && setUsfmJsons((prev) => ({ ...prev, [selectedBook]: { ...prev[selectedBook], current: currentJson.data, mergeJson } })); - setConflictedChapters((prev) => ({ ...prev, [selectedBook]: processOutArr[1] })); - if (conflcitedChapters && conflcitedChapters?.length > 0) { - setSelectedChapter(conflcitedChapters[0]); - } - setLoading(false); - } - } - } else { - setError('unable to read imported USFM'); - } - setLoading(false); - }; - // INFO : Previous function to handle all books together ( JSON => usfm all together at the end ) // const handleFinishedResolution = async () => { // const fs = window.require('fs'); @@ -291,6 +247,62 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) } }; + /** + * + * @param {*} selectedBook + * function checks the conflict in the book , indenitify the conflicted chapters, generate usfmJson + */ + const checkForConflictInSelectedBook = async (selectedBook) => { + // parse imported + const fs = window.require('fs'); + const IncomingUsfm = fs.readFileSync(path.join(usfmJsons.conflictMeta.incomingPath, selectedBook), 'utf8'); + if (IncomingUsfm) { + const importedJson = await parseUsfm(IncomingUsfm); + if (!importedJson.valid) { + setError('Imported Usfm is invalid'); + } else { + // Parse current project same book + const importedBookCode = `${importedJson.data.book.bookCode.toLowerCase()}.usfm`; + + setError(''); + + setUsfmJsons((prev) => ({ ...prev, [selectedBook]: { ...prev[selectedBook], imported: importedJson.data } })); + + // setSelectedBookId(importedJson.data.book.bookCode.toLowerCase()); + // const currentBookPath = Object.keys(usfmJsons.conflictMeta.currentMeta.ingredients).find((code) => code.toLowerCase().endsWith(importedBookCode)); + const { projectFullName } = usfmJsons.conflictMeta; + const currentBookUsfm = await readUsfmFile(selectedBook, projectFullName); + // console.log('FOUND ====> ', { currentBookPath, currentBookUsfm }); + if (currentBookUsfm) { + const currentJson = await parseUsfm(currentBookUsfm); + // generate the merge object with current , incoming , merge verses + const processOutArr = await processAndIdentiyVerseChangeinUSFMJsons(currentJson.data, importedJson.data).catch((err) => { + console.log('process usfm : ', err); + }); + const mergeJson = processOutArr[0]; + const conflcitedChapters = processOutArr[1]; + console.log('processOutArr[1] : ', processOutArr[1]); + currentJson && currentJson?.valid && setUsfmJsons((prev) => ({ ...prev, [selectedBook]: { ...prev[selectedBook], current: currentJson.data, mergeJson } })); + // if processOutArr leng = 0 ; there is not actual conflict on content. so do auto resolve for the book + if (conflcitedChapters?.length > 0) { + setConflictedChapters((prev) => ({ ...prev, [selectedBook]: processOutArr[1] })); + if (conflcitedChapters && conflcitedChapters?.length > 0) { + setSelectedChapter(conflcitedChapters[0]); + } + } else { + // resolve the book automatically ; the conflict in md5 only not on content + await resolveAndMarkDoneChapter(); + triggerSnackBar('info', 'No conflict in verse level. The conflict may be because of extra tags.'); + } + setLoading(false); + } + } + } else { + setError('unable to read imported USFM'); + } + setLoading(false); + }; + /** * existing project merge * read usfm json data from backend From 527ac23b05aeeb44bf96164004063fd48207b5a3 Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Tue, 9 Jul 2024 15:35:22 +0530 Subject: [PATCH 49/50] auto check and mark done --- .../TranslationMergeUI.jsx | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index 4b18eb101..827ea07c1 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -171,7 +171,7 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) const handleFinishedBookResolution = async () => { const resolvedBooks = { ...usfmJsons }; delete resolvedBooks.conflictMeta; - + console.log('handle finish book resolution ===> ', resolvedBooks); // work on single book const resolvedMergeJson = resolvedBooks[selectedBook]?.mergeJson; const generatedUSFM = await parseJsonToUsfm(resolvedMergeJson); @@ -213,9 +213,12 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) setChapterResolveDone(false); // remove current chapter from conflicted list const restOfTheChapters = conflictedChapters[selectedBook]?.filter((chNo) => chNo !== selectedChapter); - setConflictedChapters((prev) => ({ ...prev, [selectedBook]: restOfTheChapters })); + setConflictedChapters((prev) => ({ ...prev, [selectedBook]: restOfTheChapters || [] })); let isBookResolved = false; - if (restOfTheChapters?.length === 0) { + if (!restOfTheChapters) { + setResolvedBooks((prev) => [...prev, selectedBook]); + // isBookResolved = true; + } else if (restOfTheChapters?.length === 0) { // completed conflicts for that particualr book flushSync(() => { setLoading(true); @@ -262,7 +265,7 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) setError('Imported Usfm is invalid'); } else { // Parse current project same book - const importedBookCode = `${importedJson.data.book.bookCode.toLowerCase()}.usfm`; + // const importedBookCode = `${importedJson.data.book.bookCode.toLowerCase()}.usfm`; setError(''); @@ -285,7 +288,7 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) currentJson && currentJson?.valid && setUsfmJsons((prev) => ({ ...prev, [selectedBook]: { ...prev[selectedBook], current: currentJson.data, mergeJson } })); // if processOutArr leng = 0 ; there is not actual conflict on content. so do auto resolve for the book if (conflcitedChapters?.length > 0) { - setConflictedChapters((prev) => ({ ...prev, [selectedBook]: processOutArr[1] })); + setConflictedChapters((prev) => ({ ...prev, [selectedBook]: processOutArr[1] || [] })); if (conflcitedChapters && conflcitedChapters?.length > 0) { setSelectedChapter(conflcitedChapters[0]); } @@ -312,7 +315,6 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) if (fs.existsSync(path.join(data.projectMergePath, 'usfmJsons.json'))) { let usfmJsonsContent = fs.readFileSync(path.join(data.projectMergePath, 'usfmJsons.json'), 'utf8'); usfmJsonsContent = JSON.parse(usfmJsonsContent); - console.log({ usfmJsonsContent }); if (usfmJsonsContent) { setUsfmJsons(usfmJsonsContent); // check the books is already resolved or not => then select current book and unresolved chapters @@ -332,7 +334,7 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) if (currentBook.isBookResolved) { resolvedBooksArr.push(book); } - conflictedChsOfBooks[book] = currentBook.conflictedChapters; + conflictedChsOfBooks[book] = currentBook.conflictedChapters || []; } } @@ -437,7 +439,7 @@ function TranslationMergeUI({ conflictData, closeMergeWindow, triggerSnackBar }) // if (!loading && usfmJsons?.conflictMeta && selectedBook) { (async () => { setLoading(true); - if (conflictedChapters[selectedBook]) { + if (conflictedChapters[selectedBook]?.length > 0) { // Auto Select first Chapter of the selected Book if (conflictedChapters[selectedBook] && conflictedChapters[selectedBook].length > 0) { setSelectedChapter(conflictedChapters[selectedBook][0]); From f48c80316ebb42328a5b24c0f94b4a0c55bd7417 Mon Sep 17 00:00:00 2001 From: sijumoncy <72241997+sijumoncy@users.noreply.github.com> Date: Wed, 17 Jul 2024 12:12:32 +0530 Subject: [PATCH 50/50] lint: fixed lint issue --- .../components/TextTranslationMerge/TranslationMergNavBar.jsx | 4 ++-- .../components/TextTranslationMerge/TranslationMergeUI.jsx | 3 ++- .../components/TextTranslationMerge/UsfmConflictEditor.jsx | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergNavBar.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergNavBar.jsx index 827a9f121..68d541cca 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergNavBar.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergNavBar.jsx @@ -1,10 +1,10 @@ // import { Cog8ToothIcon } from '@heroicons/react/24/outline'; -import { useTranslation } from 'react-i18next'; +// import { useTranslation } from 'react-i18next'; function TranslationMergNavBar({ conflictedBooks, selectedBook, setSelectedBook, resolvedBooks, disableSelection, conflictedChapters, selectedChapter, setSelectedChapter, }) { - const { t } = useTranslation(); + // const { t } = useTranslation(); return (
    diff --git a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx index 827ea07c1..510f3f9b8 100644 --- a/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx +++ b/renderer/src/components/TextTranslationMerge/TranslationMergeUI.jsx @@ -10,12 +10,13 @@ import { readUsfmFile } from '@/core/projects/userSettings'; import localforage from 'localforage'; import { flushSync } from 'react-dom'; import TranslationMergNavBar from './TranslationMergNavBar'; -import * as logger from '../../logger'; +// import * as logger from '../../logger'; import LoadingScreen from '../Loading/LoadingScreen'; import UsfmConflictEditor from './UsfmConflictEditor'; import { processAndIdentiyVerseChangeinUSFMJsons } from './processUsfmObjs'; import packageInfo from '../../../../package.json'; import { commitChanges } from '../Sync/Isomorphic/utils'; +/* eslint-disable import/no-unresolved , import/extensions */ import { useGrammartoPerf } from '@/hooks2/useGrammartoPerf'; const grammar = require('usfm-grammar'); diff --git a/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx b/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx index 97120a278..d1ca1c3ff 100644 --- a/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx +++ b/renderer/src/components/TextTranslationMerge/UsfmConflictEditor.jsx @@ -2,9 +2,10 @@ import React, { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { - ArrowSmallDownIcon, ArrowSmallUpIcon, ArrowsUpDownIcon, ArrowPathRoundedSquareIcon, + ArrowSmallDownIcon, ArrowSmallUpIcon, ArrowPathRoundedSquareIcon, } from '@heroicons/react/20/solid'; +/* eslint-disable no-unused-vars */ function UsfmConflictEditor({ usfmJsons, currentProjectMeta, selectedChapter, setUsfmJsons, setChapterResolveDone, resolvedChapters, selectedBook, resolvedBooks, conflictedChapters, }) {