mirror of
https://github.com/tiddly-gittly/TidGi-Desktop.git
synced 2025-12-06 02:30:47 -08:00
feat: show better error message when html extract failed
This commit is contained in:
parent
494e688b00
commit
d6109f1540
8 changed files with 99 additions and 54 deletions
|
|
@ -39,11 +39,9 @@ export function ImportHtmlWikiForm({
|
||||||
if (filePaths?.length > 0) {
|
if (filePaths?.length > 0) {
|
||||||
wikiHtmlPathSetter(filePaths[0]);
|
wikiHtmlPathSetter(filePaths[0]);
|
||||||
const fileName = await window.service.native.path('basename', filePaths[0]);
|
const fileName = await window.service.native.path('basename', filePaths[0]);
|
||||||
// DEBUG: console
|
|
||||||
console.log(`fileName`, filePaths, fileName);
|
|
||||||
if (fileName !== undefined) {
|
if (fileName !== undefined) {
|
||||||
// use html file name as default wiki name
|
// use html file name as default wiki name
|
||||||
wikiFolderNameSetter(fileName);
|
wikiFolderNameSetter(fileName.split('.')[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { IErrorInWhichComponent, IWikiWorkspaceForm } from './useForm';
|
import { IErrorInWhichComponent, IWikiWorkspaceForm } from './useForm';
|
||||||
|
import { updateErrorInWhichComponentSetterByErrorMessage } from './useIndicator';
|
||||||
import { useValidateNewWiki, useNewWiki } from './useNewWiki';
|
import { useValidateNewWiki, useNewWiki } from './useNewWiki';
|
||||||
|
|
||||||
export function useValidateHtmlWiki(
|
export function useValidateHtmlWiki(
|
||||||
|
|
@ -16,17 +17,15 @@ export function useValidateHtmlWiki(
|
||||||
useValidateNewWiki(isCreateMainWorkspace, isCreateSyncedWorkspace, form, errorInWhichComponentSetter);
|
useValidateNewWiki(isCreateMainWorkspace, isCreateSyncedWorkspace, form, errorInWhichComponentSetter);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!form.wikiHtmlPath) {
|
if (!form.wikiHtmlPath) {
|
||||||
// 判断wikiHtmlPath是否存在
|
|
||||||
wikiCreationMessageSetter(`${t('AddWorkspace.NotFilled')}:${t('AddWorkspace.LocalWikiHtml')}`);
|
wikiCreationMessageSetter(`${t('AddWorkspace.NotFilled')}:${t('AddWorkspace.LocalWikiHtml')}`);
|
||||||
errorInWhichComponentSetter({ wikiHtmlPath: true });
|
errorInWhichComponentSetter({ wikiHtmlPath: true });
|
||||||
hasErrorSetter(true);
|
hasErrorSetter(true);
|
||||||
|
} else {
|
||||||
|
wikiCreationMessageSetter('');
|
||||||
|
errorInWhichComponentSetter({});
|
||||||
|
hasErrorSetter(false);
|
||||||
}
|
}
|
||||||
}, [
|
}, [t, form.wikiHtmlPath, form.parentFolderLocation, form.wikiFolderName, errorInWhichComponentSetter]);
|
||||||
t,
|
|
||||||
// 监听wikiHtmlPath,如果不存在就在提示用户。
|
|
||||||
form.wikiHtmlPath,
|
|
||||||
errorInWhichComponentSetter,
|
|
||||||
]);
|
|
||||||
|
|
||||||
return [hasError, wikiCreationMessage, wikiCreationMessageSetter, hasErrorSetter];
|
return [hasError, wikiCreationMessage, wikiCreationMessageSetter, hasErrorSetter];
|
||||||
}
|
}
|
||||||
|
|
@ -48,6 +47,7 @@ export function useImportHtmlWiki(
|
||||||
wikiCreationMessageSetter,
|
wikiCreationMessageSetter,
|
||||||
hasErrorSetter,
|
hasErrorSetter,
|
||||||
errorInWhichComponentSetter,
|
errorInWhichComponentSetter,
|
||||||
|
{ noCopyTemplate: true },
|
||||||
);
|
);
|
||||||
|
|
||||||
const onSubmit = useCallback(async () => {
|
const onSubmit = useCallback(async () => {
|
||||||
|
|
@ -60,16 +60,15 @@ export function useImportHtmlWiki(
|
||||||
}
|
}
|
||||||
wikiCreationMessageSetter(t('AddWorkspace.Processing'));
|
wikiCreationMessageSetter(t('AddWorkspace.Processing'));
|
||||||
try {
|
try {
|
||||||
// 如果是HTML文件,即使转换错误,删掉在执行一次也不会出错。
|
const extractSuccess = await window.service.wiki.extractWikiHTML(wikiHtmlPath, wikiFolderLocation);
|
||||||
// 我希望判断用户输入的是否是HTML文件,如果不是就不予执行。然后在判断如果失败了就删除这个数据并且提示错误信息。如果输入的是html类型的文件是不会出错的,即使是非wiki类型的文件。如果输出的目录非空,那么会导致异常闪退。
|
if (extractSuccess === false) {
|
||||||
const extractState = await window.service.wiki.extractWikiHTML(wikiHtmlPath, wikiFolderLocation);
|
|
||||||
if (!extractState) {
|
|
||||||
hasErrorSetter(true);
|
hasErrorSetter(true);
|
||||||
wikiCreationMessageSetter(t('AddWorkspace.BadWikiHtml'));
|
wikiCreationMessageSetter(t('AddWorkspace.BadWikiHtml'));
|
||||||
errorInWhichComponentSetter({ wikiHtmlPath: true });
|
errorInWhichComponentSetter({ wikiHtmlPath: true });
|
||||||
return;
|
return;
|
||||||
|
} else if (typeof extractSuccess === 'string') {
|
||||||
|
updateErrorInWhichComponentSetterByErrorMessage(t, extractSuccess, errorInWhichComponentSetter);
|
||||||
}
|
}
|
||||||
// 我希望在解压成功后设置好工作区的信息,执行打开解压后的wiki文件夹的操作。
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
wikiCreationMessageSetter(`${t('AddWorkspace.BadWikiHtml')}${(error as Error).message}`);
|
wikiCreationMessageSetter(`${t('AddWorkspace.BadWikiHtml')}${(error as Error).message}`);
|
||||||
errorInWhichComponentSetter({ wikiHtmlPath: true });
|
errorInWhichComponentSetter({ wikiHtmlPath: true });
|
||||||
|
|
|
||||||
|
|
@ -50,4 +50,7 @@ export function updateErrorInWhichComponentSetterByErrorMessage(
|
||||||
if (message.includes(t('AddWorkspace.ThisPathIsNotAWikiFolder').replace(/".*"/, ''))) {
|
if (message.includes(t('AddWorkspace.ThisPathIsNotAWikiFolder').replace(/".*"/, ''))) {
|
||||||
errorInWhichComponentSetter({ wikiFolderName: true, wikiFolderLocation: true });
|
errorInWhichComponentSetter({ wikiFolderName: true, wikiFolderLocation: true });
|
||||||
}
|
}
|
||||||
|
if (message.includes('The unpackwiki command requires that the output wiki folder be empty')) {
|
||||||
|
errorInWhichComponentSetter({ wikiFolderName: true, wikiFolderLocation: true });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ export function useNewWiki(
|
||||||
wikiCreationMessageSetter: (m: string) => void,
|
wikiCreationMessageSetter: (m: string) => void,
|
||||||
hasErrorSetter: (m: boolean) => void,
|
hasErrorSetter: (m: boolean) => void,
|
||||||
errorInWhichComponentSetter: (errors: IErrorInWhichComponent) => void,
|
errorInWhichComponentSetter: (errors: IErrorInWhichComponent) => void,
|
||||||
|
options?: { noCopyTemplate?: boolean },
|
||||||
): () => Promise<void> {
|
): () => Promise<void> {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
|
@ -72,7 +73,9 @@ export function useNewWiki(
|
||||||
try {
|
try {
|
||||||
const newWorkspaceConfig = workspaceConfigFromForm(form, isCreateMainWorkspace, isCreateSyncedWorkspace);
|
const newWorkspaceConfig = workspaceConfigFromForm(form, isCreateMainWorkspace, isCreateSyncedWorkspace);
|
||||||
if (isCreateMainWorkspace) {
|
if (isCreateMainWorkspace) {
|
||||||
|
if (options?.noCopyTemplate !== true) {
|
||||||
await window.service.wiki.copyWikiTemplate(form.parentFolderLocation, form.wikiFolderName);
|
await window.service.wiki.copyWikiTemplate(form.parentFolderLocation, form.wikiFolderName);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
await window.service.wiki.createSubWiki(form.parentFolderLocation, form.wikiFolderName, form.mainWikiToLink?.wikiFolderLocation, form.tagName);
|
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);
|
updateErrorInWhichComponentSetterByErrorMessage(t, (error as Error).message, errorInWhichComponentSetter);
|
||||||
hasErrorSetter(true);
|
hasErrorSetter(true);
|
||||||
}
|
}
|
||||||
}, [wikiCreationMessageSetter, t, hasErrorSetter, form, isCreateMainWorkspace, isCreateSyncedWorkspace, errorInWhichComponentSetter]);
|
}, [
|
||||||
|
wikiCreationMessageSetter,
|
||||||
|
t,
|
||||||
|
hasErrorSetter,
|
||||||
|
form,
|
||||||
|
isCreateMainWorkspace,
|
||||||
|
isCreateSyncedWorkspace,
|
||||||
|
options?.noCopyTemplate,
|
||||||
|
errorInWhichComponentSetter,
|
||||||
|
]);
|
||||||
|
|
||||||
return onSubmit;
|
return onSubmit;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -168,20 +168,31 @@ export class Wiki implements IWikiService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async extractWikiHTML(htmlWikiPath: string, saveWikiFolderPath: string): Promise<boolean> {
|
public async extractWikiHTML(htmlWikiPath: string, saveWikiFolderPath: string): Promise<boolean | string> {
|
||||||
// hope saveWikiFolderPath = ParentFolderPath + wikifolderPath
|
// 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.
|
// 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<WikiWorker>(new Worker(workerURL as string), { timeout: 1000 * 60 });
|
const worker = await spawn<WikiWorker>(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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async packetHTMLFromWikiFolder(folderWikiPath: string, saveWikiHtmlFolder: string): Promise<void> {
|
public async packetHTMLFromWikiFolder(folderWikiPath: string, saveWikiHtmlFolder: string): Promise<void> {
|
||||||
const worker = await spawn<WikiWorker>(new Worker(workerURL as string), { timeout: 1000 * 60 });
|
const worker = await spawn<WikiWorker>(new Worker(workerURL as string), { timeout: 1000 * 60 });
|
||||||
await worker.packetHTMLFromWikiFolder(folderWikiPath, saveWikiHtmlFolder);
|
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<void> {
|
public async stopWiki(wikiFolderLocation: string): Promise<void> {
|
||||||
|
|
@ -667,7 +678,7 @@ export class Wiki implements IWikiService {
|
||||||
|
|
||||||
public async getWikiLogs(homePath: string): Promise<{ content: string; filePath: string }> {
|
public async getWikiLogs(homePath: string): Promise<{ content: string; filePath: string }> {
|
||||||
const filePath = getWikiLogFilePath(homePath);
|
const filePath = getWikiLogFilePath(homePath);
|
||||||
const content = await fs.readFile(filePath, 'utf-8');
|
const content = await fs.readFile(filePath, 'utf8');
|
||||||
return {
|
return {
|
||||||
content,
|
content,
|
||||||
filePath,
|
filePath,
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ export interface IWikiService {
|
||||||
*/
|
*/
|
||||||
createSubWiki(parentFolderLocation: string, folderName: string, mainWikiPath: string, tagName?: string, onlyLink?: boolean): Promise<void>;
|
createSubWiki(parentFolderLocation: string, folderName: string, mainWikiPath: string, tagName?: string, onlyLink?: boolean): Promise<void>;
|
||||||
ensureWikiExist(wikiPath: string, shouldBeMainWiki: boolean): Promise<void>;
|
ensureWikiExist(wikiPath: string, shouldBeMainWiki: boolean): Promise<void>;
|
||||||
extractWikiHTML(htmlWikiPath: string, saveWikiFolderPath: string): Promise<boolean>;
|
extractWikiHTML(htmlWikiPath: string, saveWikiFolderPath: string): Promise<boolean | string>;
|
||||||
getSubWikiPluginContent(mainWikiPath: string): Promise<ISubWikiPluginContent[]>;
|
getSubWikiPluginContent(mainWikiPath: string): Promise<ISubWikiPluginContent[]>;
|
||||||
getTiddlerText(workspace: IWorkspace, title: string): Promise<string | undefined>;
|
getTiddlerText(workspace: IWorkspace, title: string): Promise<string | undefined>;
|
||||||
getWikiLogs(homePath: string): Promise<{ content: string; filePath: string }>;
|
getWikiLogs(homePath: string): Promise<{ content: string; filePath: string }>;
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import { Observable } from 'rxjs';
|
||||||
import intercept from 'intercept-stdout';
|
import intercept from 'intercept-stdout';
|
||||||
import { fork } from 'child_process';
|
import { fork } from 'child_process';
|
||||||
import { tmpdir } from 'os';
|
import { tmpdir } from 'os';
|
||||||
|
import fs from 'fs';
|
||||||
import { mkdtemp, writeFile } from 'fs-extra';
|
import { mkdtemp, writeFile } from 'fs-extra';
|
||||||
|
|
||||||
import { fixPath } from '@services/libs/fixPath';
|
import { fixPath } from '@services/libs/fixPath';
|
||||||
|
|
@ -131,22 +132,33 @@ function executeZxScript(file: IZxFileInput, zxPath: string): Observable<IZxWork
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function extractWikiHTML(htmlWikiPath: string, saveWikiFolderPath: string): boolean {
|
// eslint-disable-next-line @typescript-eslint/promise-function-async
|
||||||
|
function extractWikiHTML(htmlWikiPath: string, saveWikiFolderPath: string): Promise<boolean> {
|
||||||
// tiddlywiki --load ./mywiki.html --savewikifolder ./mywikifolder
|
// tiddlywiki --load ./mywiki.html --savewikifolder ./mywikifolder
|
||||||
// --savewikifolder <wikifolderpath> [<filter>]
|
// --savewikifolder <wikifolderpath> [<filter>]
|
||||||
// . /mywikifolder is the path where the tiddlder and plugins folders are stored
|
// . /mywikifolder is the path where the tiddlder and plugins folders are stored
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
let extractState = false;
|
let extractState = false;
|
||||||
// eslint-disable-next-line prefer-regex-literals
|
// eslint-disable-next-line prefer-regex-literals
|
||||||
const reg = new RegExp(/(?:html|htm|Html|HTML|HTM)$/);
|
const reg = new RegExp(/(?:html|htm|Html|HTML|HTM)$/);
|
||||||
const isHtmlWiki = reg.test(htmlWikiPath);
|
const isHtmlWiki = reg.test(htmlWikiPath);
|
||||||
if (!isHtmlWiki) {
|
if (!isHtmlWiki) {
|
||||||
console.error('Please enter the path to the tiddlywiki.html file. But the current path is: ' + htmlWikiPath);
|
const message = 'Please enter the path to the tiddlywiki.html file. But the current path is: ' + htmlWikiPath;
|
||||||
return extractState;
|
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 {
|
} else {
|
||||||
try {
|
try {
|
||||||
const wikiInstance = TiddlyWiki();
|
const wikiInstance = TiddlyWiki();
|
||||||
wikiInstance.boot.argv = ['--load', htmlWikiPath, '--savewikifolder', saveWikiFolderPath];
|
wikiInstance.boot.argv = ['--load', htmlWikiPath, '--savewikifolder', saveWikiFolderPath];
|
||||||
wikiInstance.boot.startup({});
|
wikiInstance.boot.startup({
|
||||||
|
callback: () => {
|
||||||
|
resolve(true);
|
||||||
|
},
|
||||||
|
});
|
||||||
// eslint-disable-next-line security-node/detect-crlf
|
// eslint-disable-next-line security-node/detect-crlf
|
||||||
console.log('Extract Wiki Html Successful: ' + saveWikiFolderPath);
|
console.log('Extract Wiki Html Successful: ' + saveWikiFolderPath);
|
||||||
extractState = true;
|
extractState = true;
|
||||||
|
|
@ -156,26 +168,35 @@ function extractWikiHTML(htmlWikiPath: string, saveWikiFolderPath: string): bool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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<boolean> {
|
||||||
// tiddlywiki ./mywikifolder --rendertiddler '$:/core/save/all' mywiki.html text/plain
|
// 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
|
// . /mywikifolder is the path to the wiki folder, which generally contains the tiddlder and plugins directories
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
const wikiInstance = TiddlyWiki();
|
const wikiInstance = TiddlyWiki();
|
||||||
wikiInstance.boot.argv = [folderWikiPath, '--rendertiddler', '$:/core/save/all', saveWikiHtmlFolder, 'text/plain'];
|
wikiInstance.boot.argv = [folderWikiPath, '--rendertiddler', '$:/core/save/all', saveWikiHtmlFolder, 'text/plain'];
|
||||||
wikiInstance.boot.startup({});
|
wikiInstance.boot.startup({
|
||||||
|
callback: () => {
|
||||||
|
resolve(true);
|
||||||
|
},
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const message = `Tiddlywiki packetHTMLFromWikiFolder with error ${(error as Error).message} ${(error as Error).stack ?? ''}`;
|
const message = `Tiddlywiki packetHTMLFromWikiFolder with error ${(error as Error).message} ${(error as Error).stack ?? ''}`;
|
||||||
console.error(message);
|
console.error(message);
|
||||||
|
reject(message);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const wikiWorker = {
|
const wikiWorker = {
|
||||||
startNodeJSWiki,
|
startNodeJSWiki,
|
||||||
getTiddlerFileMetadata: (tiddlerTitle: string) => wikiInstance?.boot?.files?.[tiddlerTitle],
|
getTiddlerFileMetadata: (tiddlerTitle: string) => wikiInstance?.boot?.files?.[tiddlerTitle],
|
||||||
executeZxScript,
|
executeZxScript,
|
||||||
ExtractWikiHTMLAndGetExtractState: (htmlWikiPath: string, saveWikiFolderPath: string) => extractWikiHTML(htmlWikiPath, saveWikiFolderPath),
|
extractWikiHTML,
|
||||||
packetHTMLFromWikiFolder,
|
packetHTMLFromWikiFolder,
|
||||||
};
|
};
|
||||||
export type WikiWorker = typeof wikiWorker;
|
export type WikiWorker = typeof wikiWorker;
|
||||||
|
|
|
||||||
1
tiddlers/subwiki/tiddlywiki
Symbolic link
1
tiddlers/subwiki/tiddlywiki
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
/var/folders/23/77bfg9k134q78g5v66qr0_jr0000gp/T/tidgi-dev/tiddlywiki
|
||||||
Loading…
Add table
Add a link
Reference in a new issue