diff --git a/src/components/profile/profile-item.tsx b/src/components/profile/profile-item.tsx index af4dc53..ebcf4ec 100644 --- a/src/components/profile/profile-item.tsx +++ b/src/components/profile/profile-item.tsx @@ -127,7 +127,7 @@ const ProfileItem = (props: Props) => { const urlModeMenu = [ { label: "Select", handler: onForceSelect }, { label: "Edit", handler: onEdit }, - { label: "View", handler: onView }, + { label: "File", handler: onView }, { label: "Update", handler: onUpdateWrapper(false) }, { label: "Update(Proxy)", handler: onUpdateWrapper(true) }, { label: "Delete", handler: onDelete }, @@ -135,7 +135,7 @@ const ProfileItem = (props: Props) => { const fileModeMenu = [ { label: "Select", handler: onForceSelect }, { label: "Edit", handler: onEdit }, - { label: "View", handler: onView }, + { label: "File", handler: onView }, { label: "Delete", handler: onDelete }, ]; diff --git a/src/components/profile/profile-more.tsx b/src/components/profile/profile-more.tsx index 03d6263..3c0b910 100644 --- a/src/components/profile/profile-more.tsx +++ b/src/components/profile/profile-more.tsx @@ -1,5 +1,5 @@ import dayjs from "dayjs"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import { alpha, Box, @@ -14,6 +14,7 @@ import { viewProfile } from "../../services/cmds"; import relativeTime from "dayjs/plugin/relativeTime"; import ProfileEdit from "./profile-edit"; import Notice from "../base/base-notice"; +import enhance from "../../services/enhance"; dayjs.extend(relativeTime); @@ -52,10 +53,17 @@ const ProfileMore = (props: Props) => { onEnhance, } = props; - const { type } = itemData; + const { uid, type } = itemData; const [anchorEl, setAnchorEl] = useState(null); const [position, setPosition] = useState({ left: 0, top: 0 }); const [editOpen, setEditOpen] = useState(false); + const [status, setStatus] = useState(enhance.status(uid)); + + // unlisten when unmount + useEffect(() => enhance.listen(uid, setStatus), [uid]); + + // error during enhanced mode + const hasError = status?.status === "error"; const onEdit = () => { setAnchorEl(null); @@ -80,16 +88,16 @@ const ProfileMore = (props: Props) => { { label: "Disable", handler: closeWrapper(onDisable) }, { label: "Refresh", handler: closeWrapper(onEnhance) }, { label: "Edit", handler: onEdit }, - { label: "View", handler: onView }, - { label: "To Top", handler: closeWrapper(onMoveTop) }, - { label: "To End", handler: closeWrapper(onMoveEnd) }, + { label: "File", handler: onView }, + { label: "To Top", show: !hasError, handler: closeWrapper(onMoveTop) }, + { label: "To End", show: !hasError, handler: closeWrapper(onMoveEnd) }, { label: "Delete", handler: closeWrapper(onDelete) }, ]; const disableMenu = [ { label: "Enable", handler: closeWrapper(onEnable) }, { label: "Edit", handler: onEdit }, - { label: "View", handler: onView }, + { label: "File", handler: onView }, { label: "Delete", handler: closeWrapper(onDelete) }, ]; @@ -105,15 +113,20 @@ const ProfileMore = (props: Props) => { <> { - const { mode, primary, text, grey } = palette; + // todo + // 区分 selected 和 error 和 mode 下各种颜色的排列组合 + const { mode, primary, text, grey, error } = palette; const key = `${mode}-${selected}`; + const bgkey = hasError ? `${mode}-err` : key; const bgcolor = { "light-true": alpha(primary.main, 0.15), "light-false": palette.background.paper, "dark-true": alpha(primary.main, 0.35), "dark-false": alpha(grey[700], 0.35), - }[key]!; + "light-err": alpha(error.main, 0.12), + "dark-err": alpha(error.main, 0.3), + }[bgkey]!; const color = { "light-true": text.secondary, @@ -160,13 +173,24 @@ const ProfileMore = (props: Props) => { - - {itemData.desc} - + {hasError ? ( + + {status.message} + + ) : ( + + {itemData.desc} + + )} { e.preventDefault(); }} > - {(selected ? enableMenu : disableMenu).map((item) => ( - - {item.label} - - ))} + {(selected ? enableMenu : disableMenu) + .filter((item: any) => item.show !== false) + .map((item) => ( + + {item.label} + + ))} {editOpen && ( diff --git a/src/main.tsx b/src/main.tsx index 2c0d0c4..7845c70 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -6,9 +6,9 @@ import ReactDOM from "react-dom"; import { RecoilRoot } from "recoil"; import { BrowserRouter } from "react-router-dom"; import Layout from "./pages/_layout"; -import setup from "./services/enhance"; +import enhance from "./services/enhance"; -setup(); +enhance.setup(); ReactDOM.render( diff --git a/src/services/enhance.ts b/src/services/enhance.ts index ac4b946..d25c6c8 100644 --- a/src/services/enhance.ts +++ b/src/services/enhance.ts @@ -1,6 +1,9 @@ import { emit, listen } from "@tauri-apps/api/event"; import { CmdType } from "./types"; +/** + * process the merge mode + */ function toMerge( merge: CmdType.ProfileMerge, data: CmdType.ProfileData @@ -42,6 +45,9 @@ function toMerge( return newData; } +/** + * process the script mode + */ function toScript( script: string, data: CmdType.ProfileData @@ -53,44 +59,89 @@ function toScript( const paramsName = `__verge${Math.floor(Math.random() * 1000)}`; const code = `'use strict';${script};return main(${paramsName});`; const func = new Function(paramsName, code); - return func(data); // support async main function + return func(data); } -export default function setup() { - listen("script-handler", async (event) => { - const payload = event.payload as CmdType.EnhancedPayload; - console.log(payload); +export type EStatus = { status: "ok" | "error"; message?: string }; +export type EListener = (status: EStatus) => void; +export type EUnlistener = () => void; - let pdata = payload.current || {}; +/** + * The service helps to + * implement enhanced profiles + */ +class Enhance { + private isSetup = false; + private listenMap: Map; + private resultMap: Map; - for (const each of payload.chain) { - try { - // process script - if (each.item.type === "script") { - pdata = await toScript(each.script!, pdata); + constructor() { + this.listenMap = new Map(); + this.resultMap = new Map(); + } + + // setup some listener + // for the enhanced running status + listen(uid: string, cb: EListener): EUnlistener { + this.listenMap.set(uid, cb); + return () => this.listenMap.delete(uid); + } + + // get the running status + status(uid: string): EStatus | undefined { + return this.resultMap.get(uid); + } + + // setup the handler + setup() { + if (this.isSetup) return; + this.isSetup = true; + + listen("script-handler", async (event) => { + const payload = event.payload as CmdType.EnhancedPayload; + let pdata = payload.current || {}; + + for (const each of payload.chain) { + const { uid, type = "" } = each.item; + + try { + // process script + if (type === "script") { + // support async main function + pdata = await toScript(each.script!, { ...pdata }); + } + + // process merge + else if (type === "merge") { + pdata = toMerge(each.merge!, { ...pdata }); + } + + // invalid type + else { + throw new Error(`invalid enhanced profile type "${type}"`); + } + + this.exec(uid, { status: "ok" }); + } catch (err: any) { + this.exec(uid, { + status: "error", + message: err.message || err.toString(), + }); + + console.error(err); } - - // process merge - else if (each.item.type === "merge") { - pdata = toMerge(each.merge!, pdata); - } - - // invalid type - else { - throw new Error(`invalid enhanced profile type "${each.item.type}"`); - } - - console.log("step", pdata); - } catch (err) { - console.error(err); } - } - const result: CmdType.EnhancedResult = { - data: pdata, - status: "success", - }; + const result = { data: pdata, status: "ok" }; + emit(payload.callback, JSON.stringify(result)).catch(console.error); + }); + } - emit(payload.callback, JSON.stringify(result)).catch(console.error); - }); + // exec the listener + private exec(uid: string, status: EStatus) { + this.resultMap.set(uid, status); + this.listenMap.get(uid)?.(status); + } } + +export default new Enhance();