diff --git a/src/pages/AddWorkspace/ImportHtmlWikiForm.tsx b/src/pages/AddWorkspace/ImportHtmlWikiForm.tsx index 2234ffb1..37f1e5e1 100644 --- a/src/pages/AddWorkspace/ImportHtmlWikiForm.tsx +++ b/src/pages/AddWorkspace/ImportHtmlWikiForm.tsx @@ -39,11 +39,9 @@ export function ImportHtmlWikiForm({ if (filePaths?.length > 0) { wikiHtmlPathSetter(filePaths[0]); const fileName = await window.service.native.path('basename', filePaths[0]); - // DEBUG: console - console.log(`fileName`, filePaths, fileName); if (fileName !== undefined) { // use html file name as default wiki name - wikiFolderNameSetter(fileName); + wikiFolderNameSetter(fileName.split('.')[0]); } } }} diff --git a/src/pages/AddWorkspace/useImportHtmlWiki.ts b/src/pages/AddWorkspace/useImportHtmlWiki.ts index c6947220..053674ff 100644 --- a/src/pages/AddWorkspace/useImportHtmlWiki.ts +++ b/src/pages/AddWorkspace/useImportHtmlWiki.ts @@ -2,6 +2,7 @@ import { useCallback, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { IErrorInWhichComponent, IWikiWorkspaceForm } from './useForm'; +import { updateErrorInWhichComponentSetterByErrorMessage } from './useIndicator'; import { useValidateNewWiki, useNewWiki } from './useNewWiki'; export function useValidateHtmlWiki( @@ -16,17 +17,15 @@ export function useValidateHtmlWiki( useValidateNewWiki(isCreateMainWorkspace, isCreateSyncedWorkspace, form, errorInWhichComponentSetter); useEffect(() => { if (!form.wikiHtmlPath) { - // 判断wikiHtmlPath是否存在 wikiCreationMessageSetter(`${t('AddWorkspace.NotFilled')}:${t('AddWorkspace.LocalWikiHtml')}`); errorInWhichComponentSetter({ wikiHtmlPath: true }); hasErrorSetter(true); + } else { + wikiCreationMessageSetter(''); + errorInWhichComponentSetter({}); + hasErrorSetter(false); } - }, [ - t, - // 监听wikiHtmlPath,如果不存在就在提示用户。 - form.wikiHtmlPath, - errorInWhichComponentSetter, - ]); + }, [t, form.wikiHtmlPath, form.parentFolderLocation, form.wikiFolderName, errorInWhichComponentSetter]); return [hasError, wikiCreationMessage, wikiCreationMessageSetter, hasErrorSetter]; } @@ -48,6 +47,7 @@ export function useImportHtmlWiki( wikiCreationMessageSetter, hasErrorSetter, errorInWhichComponentSetter, + { noCopyTemplate: true }, ); const onSubmit = useCallback(async () => { @@ -60,16 +60,15 @@ export function useImportHtmlWiki( } wikiCreationMessageSetter(t('AddWorkspace.Processing')); try { - // 如果是HTML文件,即使转换错误,删掉在执行一次也不会出错。 - // 我希望判断用户输入的是否是HTML文件,如果不是就不予执行。然后在判断如果失败了就删除这个数据并且提示错误信息。如果输入的是html类型的文件是不会出错的,即使是非wiki类型的文件。如果输出的目录非空,那么会导致异常闪退。 - const extractState = await window.service.wiki.extractWikiHTML(wikiHtmlPath, wikiFolderLocation); - if (!extractState) { + const extractSuccess = await window.service.wiki.extractWikiHTML(wikiHtmlPath, wikiFolderLocation); + if (extractSuccess === false) { hasErrorSetter(true); wikiCreationMessageSetter(t('AddWorkspace.BadWikiHtml')); errorInWhichComponentSetter({ wikiHtmlPath: true }); return; + } else if (typeof extractSuccess === 'string') { + updateErrorInWhichComponentSetterByErrorMessage(t, extractSuccess, errorInWhichComponentSetter); } - // 我希望在解压成功后设置好工作区的信息,执行打开解压后的wiki文件夹的操作。 } catch (error) { wikiCreationMessageSetter(`${t('AddWorkspace.BadWikiHtml')}${(error as Error).message}`); errorInWhichComponentSetter({ wikiHtmlPath: true }); diff --git a/src/pages/AddWorkspace/useIndicator.ts b/src/pages/AddWorkspace/useIndicator.ts index f6431329..7052170a 100644 --- a/src/pages/AddWorkspace/useIndicator.ts +++ b/src/pages/AddWorkspace/useIndicator.ts @@ -50,4 +50,7 @@ export function updateErrorInWhichComponentSetterByErrorMessage( if (message.includes(t('AddWorkspace.ThisPathIsNotAWikiFolder').replace(/".*"/, ''))) { errorInWhichComponentSetter({ wikiFolderName: true, wikiFolderLocation: true }); } + if (message.includes('The unpackwiki command requires that the output wiki folder be empty')) { + errorInWhichComponentSetter({ wikiFolderName: true, wikiFolderLocation: true }); + } } diff --git a/src/pages/AddWorkspace/useNewWiki.ts b/src/pages/AddWorkspace/useNewWiki.ts index 546c294c..b5cfb860 100644 --- a/src/pages/AddWorkspace/useNewWiki.ts +++ b/src/pages/AddWorkspace/useNewWiki.ts @@ -63,6 +63,7 @@ export function useNewWiki( wikiCreationMessageSetter: (m: string) => void, hasErrorSetter: (m: boolean) => void, errorInWhichComponentSetter: (errors: IErrorInWhichComponent) => void, + options?: { noCopyTemplate?: boolean }, ): () => Promise { const { t } = useTranslation(); @@ -72,7 +73,9 @@ export function useNewWiki( try { const newWorkspaceConfig = workspaceConfigFromForm(form, isCreateMainWorkspace, isCreateSyncedWorkspace); if (isCreateMainWorkspace) { - await window.service.wiki.copyWikiTemplate(form.parentFolderLocation, form.wikiFolderName); + if (options?.noCopyTemplate !== true) { + await window.service.wiki.copyWikiTemplate(form.parentFolderLocation, form.wikiFolderName); + } } else { await window.service.wiki.createSubWiki(form.parentFolderLocation, form.wikiFolderName, form.mainWikiToLink?.wikiFolderLocation, form.tagName); } @@ -82,7 +85,16 @@ export function useNewWiki( updateErrorInWhichComponentSetterByErrorMessage(t, (error as Error).message, errorInWhichComponentSetter); hasErrorSetter(true); } - }, [wikiCreationMessageSetter, t, hasErrorSetter, form, isCreateMainWorkspace, isCreateSyncedWorkspace, errorInWhichComponentSetter]); + }, [ + wikiCreationMessageSetter, + t, + hasErrorSetter, + form, + isCreateMainWorkspace, + isCreateSyncedWorkspace, + options?.noCopyTemplate, + errorInWhichComponentSetter, + ]); return onSubmit; } diff --git a/src/services/wiki/index.ts b/src/services/wiki/index.ts index f6629c92..cfe8e81d 100644 --- a/src/services/wiki/index.ts +++ b/src/services/wiki/index.ts @@ -168,20 +168,31 @@ export class Wiki implements IWikiService { }); } - public async extractWikiHTML(htmlWikiPath: string, saveWikiFolderPath: string): Promise { + public async extractWikiHTML(htmlWikiPath: string, saveWikiFolderPath: string): Promise { // hope saveWikiFolderPath = ParentFolderPath + wikifolderPath - // await fs.remove(saveWikiFolderPath); removes the folder function that failed to convert. // We want the folder where the WIKI is saved to be empty, and we want the input htmlWiki to be an HTML file even if it is a non-wikiHTML file. Otherwise the program will exit abnormally. - // this.wikiWorkers[saveWikiFolderPath] = worker; - // Then, you can use this.getWorker (saveWikiFolderPath) method to call this wikiWorker that belongs to the HTMLWIKI after decompression const worker = await spawn(new Worker(workerURL as string), { timeout: 1000 * 60 }); - const result = await worker.ExtractWikiHTMLAndGetExtractState(htmlWikiPath, saveWikiFolderPath); + let result: boolean | string = false; + try { + result = await worker.extractWikiHTML(htmlWikiPath, saveWikiFolderPath); + } catch (error) { + result = (error as Error).message; + logger.error(result, { worker: 'NodeJSWiki', method: 'extractWikiHTML', htmlWikiPath, saveWikiFolderPath }); + // removes the folder function that failed to convert. + try { + await fs.remove(saveWikiFolderPath); + } catch {} + } + // this worker is only for one time use. we will spawn a new one for starting wiki later. + await Thread.terminate(worker); return result; } public async packetHTMLFromWikiFolder(folderWikiPath: string, saveWikiHtmlFolder: string): Promise { const worker = await spawn(new Worker(workerURL as string), { timeout: 1000 * 60 }); await worker.packetHTMLFromWikiFolder(folderWikiPath, saveWikiHtmlFolder); + // this worker is only for one time use. we will spawn a new one for starting wiki later. + await Thread.terminate(worker); } public async stopWiki(wikiFolderLocation: string): Promise { @@ -667,7 +678,7 @@ export class Wiki implements IWikiService { public async getWikiLogs(homePath: string): Promise<{ content: string; filePath: string }> { const filePath = getWikiLogFilePath(homePath); - const content = await fs.readFile(filePath, 'utf-8'); + const content = await fs.readFile(filePath, 'utf8'); return { content, filePath, diff --git a/src/services/wiki/interface.ts b/src/services/wiki/interface.ts index b317cec7..0dcdc4db 100644 --- a/src/services/wiki/interface.ts +++ b/src/services/wiki/interface.ts @@ -35,7 +35,7 @@ export interface IWikiService { */ createSubWiki(parentFolderLocation: string, folderName: string, mainWikiPath: string, tagName?: string, onlyLink?: boolean): Promise; ensureWikiExist(wikiPath: string, shouldBeMainWiki: boolean): Promise; - extractWikiHTML(htmlWikiPath: string, saveWikiFolderPath: string): Promise; + extractWikiHTML(htmlWikiPath: string, saveWikiFolderPath: string): Promise; getSubWikiPluginContent(mainWikiPath: string): Promise; getTiddlerText(workspace: IWorkspace, title: string): Promise; getWikiLogs(homePath: string): Promise<{ content: string; filePath: string }>; diff --git a/src/services/wiki/wikiWorker.ts b/src/services/wiki/wikiWorker.ts index 91d73af6..e7ad72fb 100644 --- a/src/services/wiki/wikiWorker.ts +++ b/src/services/wiki/wikiWorker.ts @@ -6,6 +6,7 @@ import { Observable } from 'rxjs'; import intercept from 'intercept-stdout'; import { fork } from 'child_process'; import { tmpdir } from 'os'; +import fs from 'fs'; import { mkdtemp, writeFile } from 'fs-extra'; import { fixPath } from '@services/libs/fixPath'; @@ -131,51 +132,71 @@ function executeZxScript(file: IZxFileInput, zxPath: string): Observable { // tiddlywiki --load ./mywiki.html --savewikifolder ./mywikifolder // --savewikifolder [] // . /mywikifolder is the path where the tiddlder and plugins folders are stored - let extractState = false; - // eslint-disable-next-line prefer-regex-literals - const reg = new RegExp(/(?:html|htm|Html|HTML|HTM)$/); - const isHtmlWiki = reg.test(htmlWikiPath); - if (!isHtmlWiki) { - console.error('Please enter the path to the tiddlywiki.html file. But the current path is: ' + htmlWikiPath); - return extractState; - } else { - try { - const wikiInstance = TiddlyWiki(); - wikiInstance.boot.argv = ['--load', htmlWikiPath, '--savewikifolder', saveWikiFolderPath]; - wikiInstance.boot.startup({}); - // eslint-disable-next-line security-node/detect-crlf - console.log('Extract Wiki Html Successful: ' + saveWikiFolderPath); - extractState = true; - } catch (error) { - const message = `Tiddlywiki extractWikiHTML with error ${(error as Error).message} ${(error as Error).stack ?? ''}`; + return new Promise((resolve, reject) => { + let extractState = false; + // eslint-disable-next-line prefer-regex-literals + const reg = new RegExp(/(?:html|htm|Html|HTML|HTM)$/); + const isHtmlWiki = reg.test(htmlWikiPath); + if (!isHtmlWiki) { + const message = 'Please enter the path to the tiddlywiki.html file. But the current path is: ' + htmlWikiPath; console.error(message); + reject(message); + } else if (fs.existsSync(saveWikiFolderPath)) { + const message = 'Error: The unpackwiki command requires that the output wiki folder be empty: ' + htmlWikiPath; + console.error(message); + reject(message); + } else { + try { + const wikiInstance = TiddlyWiki(); + wikiInstance.boot.argv = ['--load', htmlWikiPath, '--savewikifolder', saveWikiFolderPath]; + wikiInstance.boot.startup({ + callback: () => { + resolve(true); + }, + }); + // eslint-disable-next-line security-node/detect-crlf + console.log('Extract Wiki Html Successful: ' + saveWikiFolderPath); + extractState = true; + } catch (error) { + const message = `Tiddlywiki extractWikiHTML with error ${(error as Error).message} ${(error as Error).stack ?? ''}`; + console.error(message); + } } - } - return extractState; + return extractState; + }); } -function packetHTMLFromWikiFolder(folderWikiPath: string, saveWikiHtmlFolder: string): void { +// eslint-disable-next-line @typescript-eslint/promise-function-async +function packetHTMLFromWikiFolder(folderWikiPath: string, saveWikiHtmlFolder: string): Promise { // tiddlywiki ./mywikifolder --rendertiddler '$:/core/save/all' mywiki.html text/plain // . /mywikifolder is the path to the wiki folder, which generally contains the tiddlder and plugins directories - try { - const wikiInstance = TiddlyWiki(); - wikiInstance.boot.argv = [folderWikiPath, '--rendertiddler', '$:/core/save/all', saveWikiHtmlFolder, 'text/plain']; - wikiInstance.boot.startup({}); - } catch (error) { - const message = `Tiddlywiki packetHTMLFromWikiFolder with error ${(error as Error).message} ${(error as Error).stack ?? ''}`; - console.error(message); - } + return new Promise((resolve, reject) => { + try { + const wikiInstance = TiddlyWiki(); + wikiInstance.boot.argv = [folderWikiPath, '--rendertiddler', '$:/core/save/all', saveWikiHtmlFolder, 'text/plain']; + wikiInstance.boot.startup({ + callback: () => { + resolve(true); + }, + }); + } catch (error) { + const message = `Tiddlywiki packetHTMLFromWikiFolder with error ${(error as Error).message} ${(error as Error).stack ?? ''}`; + console.error(message); + reject(message); + } + }); } const wikiWorker = { startNodeJSWiki, getTiddlerFileMetadata: (tiddlerTitle: string) => wikiInstance?.boot?.files?.[tiddlerTitle], executeZxScript, - ExtractWikiHTMLAndGetExtractState: (htmlWikiPath: string, saveWikiFolderPath: string) => extractWikiHTML(htmlWikiPath, saveWikiFolderPath), + extractWikiHTML, packetHTMLFromWikiFolder, }; export type WikiWorker = typeof wikiWorker; diff --git a/tiddlers/subwiki/tiddlywiki b/tiddlers/subwiki/tiddlywiki new file mode 120000 index 00000000..911d5f5d --- /dev/null +++ b/tiddlers/subwiki/tiddlywiki @@ -0,0 +1 @@ +/var/folders/23/77bfg9k134q78g5v66qr0_jr0000gp/T/tidgi-dev/tiddlywiki \ No newline at end of file