popup细节
Some checks failed
test / Run tests (push) Failing after 3s
build / Build (push) Failing after 5s

This commit is contained in:
2025-04-08 18:04:48 +08:00
parent 42975d47cf
commit d97a64c644
12 changed files with 166 additions and 126 deletions

View File

@ -9,8 +9,20 @@
// @grant GM_unregisterMenuCommand // @grant GM_unregisterMenuCommand
// ==/UserScript== // ==/UserScript==
const id = GM_registerMenuCommand(
const id = GM_registerMenuCommand("测试菜单", () => { "测试菜单",
() => {
console.log(id); console.log(id);
GM_unregisterMenuCommand(id); GM_unregisterMenuCommand(id);
}, "h"); },
"h"
);
const id2 = GM_registerMenuCommand(
"测试菜单2",
() => {
console.log(id2);
GM_unregisterMenuCommand(id2);
},
"j"
);

View File

@ -143,11 +143,9 @@ export default class Cache {
if (promise) { if (promise) {
await promise; await promise;
} }
promise = this.get(key) promise = this.get(key)
.then((result) => set(result)) .then((result) => set(result))
.then((value) => { .then((value) => {
console.log("tx", key, value);
if (value) { if (value) {
return this.set(key, value); return this.set(key, value);
} }

View File

@ -48,6 +48,10 @@ export class ScriptClient extends Client {
getScriptRunResource(script: Script): Promise<ScriptRunResouce> { getScriptRunResource(script: Script): Promise<ScriptRunResouce> {
return this.do("getScriptRunResource", script); return this.do("getScriptRunResource", script);
} }
excludeUrl(uuid: string, url: string, remove: boolean) {
return this.do("excludeUrl", { uuid, url, remove });
}
} }
export class ResourceClient extends Client { export class ResourceClient extends Client {

View File

@ -10,6 +10,7 @@ import {
Script, Script,
ScriptDAO, ScriptDAO,
SCRIPT_TYPE_NORMAL, SCRIPT_TYPE_NORMAL,
SCRIPT_RUN_STATUS_RUNNING,
} from "@App/app/repo/scripts"; } from "@App/app/repo/scripts";
import { import {
ScriptMenuRegisterCallbackValue, ScriptMenuRegisterCallbackValue,
@ -54,9 +55,11 @@ export class PopupService {
) {} ) {}
genScriptMenuByTabMap(menu: ScriptMenu[]) { genScriptMenuByTabMap(menu: ScriptMenu[]) {
let n = 0;
menu.forEach((script) => { menu.forEach((script) => {
// 创建脚本菜单 // 创建脚本菜单
if (script.menus.length) { if (script.menus.length) {
n += script.menus.length;
chrome.contextMenus.create({ chrome.contextMenus.create({
id: `scriptMenu_` + script.uuid, id: `scriptMenu_` + script.uuid,
title: script.name, title: script.name,
@ -65,7 +68,6 @@ export class PopupService {
}); });
script.menus.forEach((menu) => { script.menus.forEach((menu) => {
// 创建菜单 // 创建菜单
console.log("create menu", menu);
chrome.contextMenus.create({ chrome.contextMenus.create({
id: `scriptMenu_menu_${script.uuid}_${menu.id}`, id: `scriptMenu_menu_${script.uuid}_${menu.id}`,
title: menu.name, title: menu.name,
@ -75,6 +77,7 @@ export class PopupService {
}); });
} }
}); });
return n;
} }
// 生成chrome菜单 // 生成chrome菜单
@ -86,6 +89,7 @@ export class PopupService {
if (!menu.length && !backgroundMenu.length) { if (!menu.length && !backgroundMenu.length) {
return; return;
} }
let n = 0;
// 创建根菜单 // 创建根菜单
chrome.contextMenus.create({ chrome.contextMenus.create({
id: "scriptMenu", id: "scriptMenu",
@ -93,18 +97,21 @@ export class PopupService {
contexts: ["all"], contexts: ["all"],
}); });
if (menu) { if (menu) {
this.genScriptMenuByTabMap(menu); n += this.genScriptMenuByTabMap(menu);
} }
// 后台脚本的菜单 // 后台脚本的菜单
if (backgroundMenu) { if (backgroundMenu) {
this.genScriptMenuByTabMap(backgroundMenu); n += this.genScriptMenuByTabMap(backgroundMenu);
}
if (n === 0) {
// 如果没有菜单,删除菜单
chrome.contextMenus.remove("scriptMenu");
} }
} }
async registerMenuCommand(message: ScriptMenuRegisterCallbackValue) { async registerMenuCommand(message: ScriptMenuRegisterCallbackValue) {
// 给脚本添加菜单 // 给脚本添加菜单
return this.txUpdateScriptMenu(message.tabId, async (data) => { return this.txUpdateScriptMenu(message.tabId, async (data) => {
console.log("register menu", message, data);
const script = data.find((item) => item.uuid === message.uuid); const script = data.find((item) => item.uuid === message.uuid);
if (script) { if (script) {
const menu = script.menus.find((item) => item.id === message.id); const menu = script.menus.find((item) => item.id === message.id);
@ -165,7 +172,7 @@ export class PopupService {
hasUserConfig: !!script.config, hasUserConfig: !!script.config,
metadata: script.metadata, metadata: script.metadata,
runStatus: script.runStatus, runStatus: script.runStatus,
runNum: 0, runNum: script.type === SCRIPT_TYPE_NORMAL ? 0 : script.runStatus === SCRIPT_RUN_STATUS_RUNNING ? 1 : 0,
runNumByIframe: 0, runNumByIframe: 0,
menus: [], menus: [],
customExclude: (script as ScriptMatchInfo).customizeExcludeMatches || [], customExclude: (script as ScriptMatchInfo).customizeExcludeMatches || [],
@ -175,21 +182,21 @@ export class PopupService {
// 获取popup页面数据 // 获取popup页面数据
async getPopupData(req: GetPopupDataReq): Promise<GetPopupDataRes> { async getPopupData(req: GetPopupDataReq): Promise<GetPopupDataRes> {
// 获取当前tabId // 获取当前tabId
const scriptUuid = await this.runtime.getPageScriptByUrl(req.url); const script = await this.runtime.getPageScriptByUrl(req.url, true);
// 与运行时脚本进行合并 // 与运行时脚本进行合并
const runScript = await this.getScriptMenu(req.tabId); const runScript = await this.getScriptMenu(req.tabId);
// 筛选出未运行的脚本 // 合并数据
const notRunScript = scriptUuid.filter((script) => { const scriptMenu = script.map((script) => {
return !runScript.find((item) => item.uuid === script.uuid); const run = runScript.find((item) => item.uuid === script.uuid);
}); if (run) {
// 将未运行的脚本转换为菜单 // 如果脚本已经存在,则不添加,赋值状态
const scriptList = notRunScript.map((script): ScriptMenu => { run.enable = script.status === SCRIPT_STATUS_ENABLE;
return run;
}
return this.scriptToMenu(script); return this.scriptToMenu(script);
}); });
runScript.push(...scriptList);
// 后台脚本只显示开启或者运行中的脚本 // 后台脚本只显示开启或者运行中的脚本
return { scriptList: scriptMenu, backScriptList: await this.getScriptMenu(-1) };
return { scriptList: runScript, backScriptList: await this.getScriptMenu(-1) };
} }
async getScriptMenu(tabId: number) { async getScriptMenu(tabId: number) {
@ -263,17 +270,17 @@ export class PopupService {
return; return;
} }
return this.txUpdateScriptMenu(-1, async (menu) => { return this.txUpdateScriptMenu(-1, async (menu) => {
const scriptMenu = menu.find((item) => item.uuid === uuid); const index = menu.findIndex((item) => item.uuid === uuid);
if (script.status === SCRIPT_STATUS_ENABLE) { if (script.status === SCRIPT_STATUS_ENABLE) {
// 加入菜单 // 加入菜单
if (!scriptMenu) { if (index === -1) {
const item = this.scriptToMenu(script); const item = this.scriptToMenu(script);
menu.push(item); menu.push(item);
} }
} else { } else {
// 移出菜单 // 移出菜单
if (scriptMenu) { if (index !== -1) {
menu.splice(menu.indexOf(scriptMenu), 1); menu.splice(index, 1);
} }
} }
return menu; return menu;
@ -281,9 +288,9 @@ export class PopupService {
}); });
subscribeScriptDelete(this.mq, async ({ uuid }) => { subscribeScriptDelete(this.mq, async ({ uuid }) => {
return this.txUpdateScriptMenu(-1, async (menu) => { return this.txUpdateScriptMenu(-1, async (menu) => {
const scriptMenu = menu.find((item) => item.uuid === uuid); const index = menu.findIndex((item) => item.uuid === uuid);
if (scriptMenu) { if (index !== -1) {
menu.splice(menu.indexOf(scriptMenu), 1); menu.splice(index, 1);
return menu; return menu;
} }
return null; return null;
@ -293,6 +300,7 @@ export class PopupService {
return this.txUpdateScriptMenu(-1, async (menu) => { return this.txUpdateScriptMenu(-1, async (menu) => {
const scriptMenu = menu.find((item) => item.uuid === uuid); const scriptMenu = menu.find((item) => item.uuid === uuid);
if (scriptMenu) { if (scriptMenu) {
scriptMenu.runNum = 1;
scriptMenu.runStatus = runStatus; scriptMenu.runStatus = runStatus;
return menu; return menu;
} }

View File

@ -67,7 +67,7 @@ export class RuntimeService {
// 加载页面脚本 // 加载页面脚本
await this.loadPageScript(script); await this.loadPageScript(script);
if (!data.enable) { if (!data.enable) {
await this.unregistryPageScript(script); await this.unregistryPageScript(script.uuid);
} }
} }
}); });
@ -82,15 +82,9 @@ export class RuntimeService {
} }
}); });
// 监听脚本删除 // 监听脚本删除
subscribeScriptDelete(this.mq, async (data) => { subscribeScriptDelete(this.mq, async ({ uuid }) => {
const script = await this.scriptDAO.get(data.uuid); await this.unregistryPageScript(uuid);
if (!script) { this.deleteScriptMatch(uuid);
return;
}
if (script.type === SCRIPT_TYPE_NORMAL) {
await this.unregistryPageScript(script);
this.deleteScriptMatch(script.uuid);
}
}); });
// 将开启的脚本发送一次enable消息 // 将开启的脚本发送一次enable消息
@ -138,24 +132,29 @@ export class RuntimeService {
return sendMessage(new ExtensionContentMessageSend(tabId, options), "content/runtime/" + action, data); return sendMessage(new ExtensionContentMessageSend(tabId, options), "content/runtime/" + action, data);
} }
async getPageScriptUuidByUrl(url: string) { async getPageScriptUuidByUrl(url: string, includeCustomize?: boolean) {
const match = await this.loadScriptMatchInfo(); const match = await this.loadScriptMatchInfo();
// 匹配当前页面的脚本 // 匹配当前页面的脚本
const matchScriptUuid = match.match(url!); const matchScriptUuid = match.match(url!);
// 排除自定义匹配 // 包含自定义排除的脚本
const excludeScriptUuid = this.scriptCustomizeMatch.match(url!); if (includeCustomize) {
const excludeMatch = new Set<string>(); const excludeScriptUuid = this.scriptCustomizeMatch.match(url!);
excludeScriptUuid.forEach((uuid) => { const match = new Set<string>();
excludeMatch.add(uuid); excludeScriptUuid.forEach((uuid) => {
}); match.add(uuid);
return matchScriptUuid.filter((value) => { });
// 过滤掉自定义排除的脚本 matchScriptUuid.forEach((uuid) => {
return !excludeMatch.has(value); match.add(uuid);
}); });
// 转化为数组
console.log("matchScriptUuid", matchScriptUuid);
return Array.from(match);
}
return matchScriptUuid;
} }
async getPageScriptByUrl(url: string) { async getPageScriptByUrl(url: string, includeCustomize?: boolean) {
const matchScriptUuid = await this.getPageScriptUuidByUrl(url); const matchScriptUuid = await this.getPageScriptUuidByUrl(url, includeCustomize);
return matchScriptUuid.map((uuid) => { return matchScriptUuid.map((uuid) => {
return Object.assign({}, this.scriptMatchCache?.get(uuid)); return Object.assign({}, this.scriptMatchCache?.get(uuid));
}); });
@ -266,15 +265,7 @@ export class RuntimeService {
Object.keys(data).forEach((key) => { Object.keys(data).forEach((key) => {
const item = data[key]; const item = data[key];
cache.set(item.uuid, item); cache.set(item.uuid, item);
item.matches.forEach((match) => { this.syncAddScriptMatch(item);
this.scriptMatch.add(match, item.uuid);
});
item.excludeMatches.forEach((match) => {
this.scriptMatch.exclude(match, item.uuid);
});
item.customizeExcludeMatches.forEach((match) => {
this.scriptCustomizeMatch.exclude(match, item.uuid);
});
}); });
} }
}); });
@ -305,6 +296,11 @@ export class RuntimeService {
await this.loadScriptMatchInfo(); await this.loadScriptMatchInfo();
} }
this.scriptMatchCache!.set(item.uuid, item); this.scriptMatchCache!.set(item.uuid, item);
this.syncAddScriptMatch(item);
this.saveScriptMatchInfo();
}
syncAddScriptMatch(item: ScriptMatchInfo) {
// 清理一下老数据 // 清理一下老数据
this.scriptMatch.del(item.uuid); this.scriptMatch.del(item.uuid);
this.scriptCustomizeMatch.del(item.uuid); this.scriptCustomizeMatch.del(item.uuid);
@ -316,9 +312,8 @@ export class RuntimeService {
this.scriptMatch.exclude(match, item.uuid); this.scriptMatch.exclude(match, item.uuid);
}); });
item.customizeExcludeMatches.forEach((match) => { item.customizeExcludeMatches.forEach((match) => {
this.scriptCustomizeMatch.exclude(match, item.uuid); this.scriptCustomizeMatch.add(match, item.uuid);
}); });
this.saveScriptMatchInfo();
} }
async updateScriptStatus(uuid: string, status: SCRIPT_STATUS) { async updateScriptStatus(uuid: string, status: SCRIPT_STATUS) {
@ -329,11 +324,11 @@ export class RuntimeService {
this.saveScriptMatchInfo(); this.saveScriptMatchInfo();
} }
deleteScriptMatch(uuid: string) { async deleteScriptMatch(uuid: string) {
if (!this.scriptMatchCache) { if (!this.scriptMatchCache) {
return; await this.loadScriptMatchInfo();
} }
this.scriptMatchCache.delete(uuid); this.scriptMatchCache!.delete(uuid);
this.scriptMatch.del(uuid); this.scriptMatch.del(uuid);
this.scriptCustomizeMatch.del(uuid); this.scriptCustomizeMatch.del(uuid);
this.saveScriptMatchInfo(); this.saveScriptMatchInfo();
@ -394,24 +389,28 @@ export class RuntimeService {
if (script.metadata["run-at"]) { if (script.metadata["run-at"]) {
registerScript.runAt = getRunAt(script.metadata["run-at"]); registerScript.runAt = getRunAt(script.metadata["run-at"]);
} }
await chrome.userScripts.register([registerScript]); if (await Cache.getInstance().get("registryScript:" + script.uuid)) {
await chrome.userScripts.update([registerScript]);
} else {
await chrome.userScripts.register([registerScript]);
}
await Cache.getInstance().set("registryScript:" + script.uuid, true); await Cache.getInstance().set("registryScript:" + script.uuid, true);
} }
} }
async unregistryPageScript(script: Script) { async unregistryPageScript(uuid: string) {
if (!(await Cache.getInstance().get("registryScript:" + script.uuid))) { if (!(await Cache.getInstance().get("registryScript:" + uuid))) {
return; return;
} }
chrome.userScripts.unregister( chrome.userScripts.unregister(
{ {
ids: [script.uuid], ids: [uuid],
}, },
() => { () => {
// 删除缓存 // 删除缓存
Cache.getInstance().del("registryScript:" + script.uuid); Cache.getInstance().del("registryScript:" + uuid);
// 修改脚本状态为disable // 修改脚本状态为disable
this.updateScriptStatus(script.uuid, SCRIPT_STATUS_DISABLE); this.updateScriptStatus(uuid, SCRIPT_STATUS_DISABLE);
} }
); );
} }

View File

@ -198,7 +198,7 @@ export class ScriptService {
.then(() => { .then(() => {
logger.info("delete success"); logger.info("delete success");
this.mq.publish("deleteScript", { uuid }); this.mq.publish("deleteScript", { uuid });
return {}; return true;
}) })
.catch((e) => { .catch((e) => {
logger.error("delete error", Logger.E(e)); logger.error("delete error", Logger.E(e));
@ -279,6 +279,32 @@ export class ScriptService {
return Promise.resolve(ret); return Promise.resolve(ret);
} }
async excludeUrl({ uuid, url, remove }: { uuid: string; url: string; remove: boolean }) {
const script = await this.scriptDAO.get(uuid);
if (!script) {
throw new Error("script not found");
}
script.selfMetadata = script.selfMetadata || {};
let excludes = script.selfMetadata.exclude || script.metadata.exclude || [];
if (remove) {
excludes = excludes.filter((item) => item !== url);
} else {
excludes.push(url);
}
script.selfMetadata.exclude = excludes;
return this.scriptDAO
.update(uuid, script)
.then(() => {
// 广播一下
this.mq.publish("installScript", { script, update: true });
return true;
})
.catch((e) => {
this.logger.error("exclude url error", Logger.E(e));
throw e;
});
}
init() { init() {
this.listenerScriptInstall(); this.listenerScriptInstall();
@ -290,5 +316,6 @@ export class ScriptService {
this.group.on("updateRunStatus", this.updateRunStatus.bind(this)); this.group.on("updateRunStatus", this.updateRunStatus.bind(this));
this.group.on("getCode", this.getCode.bind(this)); this.group.on("getCode", this.getCode.bind(this));
this.group.on("getScriptRunResource", this.buildScriptRunResource.bind(this)); this.group.on("getScriptRunResource", this.buildScriptRunResource.bind(this));
this.group.on("excludeUrl", this.excludeUrl.bind(this));
} }
} }

View File

@ -46,13 +46,13 @@ dayjs.extend(relativeTime);
export function i18nName(script: { name: string; metadata: Metadata }) { export function i18nName(script: { name: string; metadata: Metadata }) {
return script.metadata[`name:${i18n.language.toLowerCase()}`] return script.metadata[`name:${i18n.language.toLowerCase()}`]
? script.metadata[`name:${i18n.language.toLowerCase()}`][0] ? script.metadata[`name:${i18n.language.toLowerCase()}`]![0]
: script.name; : script.name;
} }
export function i18nDescription(script: { metadata: Metadata }) { export function i18nDescription(script: { metadata: Metadata }) {
return script.metadata[`description:${i18n.language.toLowerCase()}`] return script.metadata[`description:${i18n.language.toLowerCase()}`]
? script.metadata[`description:${i18n.language.toLowerCase()}`][0] ? script.metadata[`description:${i18n.language.toLowerCase()}`]![0]
: script.metadata.description; : script.metadata.description;
} }

View File

@ -31,6 +31,7 @@
"webRequest", "webRequest",
"userScripts", "userScripts",
"contextMenus", "contextMenus",
"unlimitedStorage",
"declarativeNetRequest" "declarativeNetRequest"
], ],
"host_permissions": [ "host_permissions": [

View File

@ -14,10 +14,12 @@ import { RiPlayFill, RiStopFill } from "react-icons/ri";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { ScriptIcons } from "@App/pages/options/routes/utils"; import { ScriptIcons } from "@App/pages/options/routes/utils";
import { ScriptMenu, ScriptMenuItem } from "@App/app/service/service_worker/popup"; import { ScriptMenu, ScriptMenuItem } from "@App/app/service/service_worker/popup";
import { MessageSender } from "@Packages/message/server";
import { selectMenuExpandNum } from "@App/pages/store/features/setting"; import { selectMenuExpandNum } from "@App/pages/store/features/setting";
import { useAppSelector } from "@App/pages/store/hooks"; import { useAppSelector } from "@App/pages/store/hooks";
import { popupClient } from "@App/pages/store/features/script"; import { popupClient, runtimeClient, scriptClient } from "@App/pages/store/features/script";
import { i18nName } from "@App/locales/locales";
import { subscribeScriptRunStatus } from "@App/app/service/queue";
import { messageQueue } from "@App/pages/store/global";
const CollapseItem = Collapse.Item; const CollapseItem = Collapse.Item;
@ -26,7 +28,7 @@ function isExclude(script: ScriptMenu, host: string) {
return false; return false;
} }
for (let i = 0; i < script.customExclude.length; i += 1) { for (let i = 0; i < script.customExclude.length; i += 1) {
if (script.customExclude[i] === `*://${host}*`) { if (script.customExclude[i] === `*://${host}/*`) {
return true; return true;
} }
} }
@ -56,32 +58,28 @@ const ScriptMenuList: React.FC<{
setList(script); setList(script);
}, [script]); }, [script]);
// useEffect(() => { useEffect(() => {
// // 监听脚本运行状态 // 监听脚本运行状态
// const channel = runtimeCtrl.watchRunStatus(); const unsub = subscribeScriptRunStatus(messageQueue, ({ uuid, runStatus }) => {
// channel.setHandler(([id, status]: any) => { setList((prev) => {
// setList((prev) => { const newList = [...prev];
// const newList = [...prev]; const index = newList.findIndex((item) => item.uuid === uuid);
// const index = newList.findIndex((item) => item.id === id); if (index !== -1) {
// if (index !== -1) { newList[index].runStatus = runStatus;
// newList[index].runStatus = status; }
// } return newList;
// return newList; });
// }); });
// }); return () => {
// return () => { unsub();
// channel.disChannel(); };
// }; }, []);
// }, []);
const sendMenuAction = (uuid: string, menu: ScriptMenuItem) => { const sendMenuAction = (uuid: string, menu: ScriptMenuItem) => {
popupClient.menuClick(uuid, menu).then(() => { popupClient.menuClick(uuid, menu).then(() => {
window.close(); window.close();
}); });
}; };
// 监听菜单按键
// 菜单展开
return ( return (
<> <>
@ -110,21 +108,15 @@ const ScriptMenuList: React.FC<{
size="small" size="small"
checked={item.enable} checked={item.enable}
onChange={(checked) => { onChange={(checked) => {
let p: Promise<any>; scriptClient
if (checked) { .enable(item.uuid, checked)
p = scriptCtrl.enable(item.id).then(() => { .then(() => {
item.enable = true; item.enable = checked;
setList([...list]);
})
.catch((err) => {
Message.error(err);
}); });
} else {
p = scriptCtrl.disable(item.id).then(() => {
item.enable = false;
});
}
p.catch((err) => {
Message.error(err);
}).finally(() => {
setList([...list]);
});
}} }}
/> />
<span <span
@ -138,7 +130,7 @@ const ScriptMenuList: React.FC<{
}} }}
> >
<ScriptIcons script={item} size={20} /> <ScriptIcons script={item} size={20} />
{item.name} {i18nName(item)}
</span> </span>
</Space> </Space>
</div> </div>
@ -154,9 +146,9 @@ const ScriptMenuList: React.FC<{
icon={item.runStatus !== SCRIPT_RUN_STATUS_RUNNING ? <RiPlayFill /> : <RiStopFill />} icon={item.runStatus !== SCRIPT_RUN_STATUS_RUNNING ? <RiPlayFill /> : <RiStopFill />}
onClick={() => { onClick={() => {
if (item.runStatus !== SCRIPT_RUN_STATUS_RUNNING) { if (item.runStatus !== SCRIPT_RUN_STATUS_RUNNING) {
runtimeCtrl.startScript(item.id); runtimeClient.runScript(item.uuid);
} else { } else {
runtimeCtrl.stopScript(item.id); runtimeClient.stopScript(item.uuid);
} }
}} }}
> >
@ -168,7 +160,7 @@ const ScriptMenuList: React.FC<{
type="secondary" type="secondary"
icon={<IconEdit />} icon={<IconEdit />}
onClick={() => { onClick={() => {
window.open(`/src/options.html#/script/editor/${item.id}`, "_blank"); window.open(`/src/options.html#/script/editor/${item.uuid}`, "_blank");
window.close(); window.close();
}} }}
> >
@ -181,7 +173,7 @@ const ScriptMenuList: React.FC<{
type="secondary" type="secondary"
icon={<IconMinus />} icon={<IconMinus />}
onClick={() => { onClick={() => {
scriptCtrl.exclude(item.id, `*://${url.host}*`, isExclude(item, url.host)).finally(() => { scriptClient.excludeUrl(item.uuid, `*://${url.host}/*`, isExclude(item, url.host)).finally(() => {
window.close(); window.close();
}); });
}} }}
@ -194,8 +186,8 @@ const ScriptMenuList: React.FC<{
title={t("confirm_delete_script")} title={t("confirm_delete_script")}
icon={<IconDelete />} icon={<IconDelete />}
onOk={() => { onOk={() => {
setList(list.filter((i) => i.id !== item.id)); setList(list.filter((i) => i.uuid !== item.uuid));
scriptCtrl.delete(item.id).catch((e) => { scriptClient.delete(item.uuid).catch((e) => {
Message.error(`{t('delete_failed')}: ${e}`); Message.error(`{t('delete_failed')}: ${e}`);
}); });
}} }}
@ -259,7 +251,7 @@ const ScriptMenuList: React.FC<{
type="secondary" type="secondary"
icon={<IconSettings />} icon={<IconSettings />}
onClick={() => { onClick={() => {
window.open(`/src/options.html#/?userConfig=${item.id}`, "_blank"); window.open(`/src/options.html#/?userConfig=${item.uuid}`, "_blank");
window.close(); window.close();
}} }}
> >

View File

@ -71,22 +71,16 @@ import { i18nName } from "@App/locales/locales";
import { getValues, ListHomeRender, ScriptIcons } from "./utils"; import { getValues, ListHomeRender, ScriptIcons } from "./utils";
import { useAppDispatch, useAppSelector } from "@App/pages/store/hooks"; import { useAppDispatch, useAppSelector } from "@App/pages/store/hooks";
import { import {
deleteScript,
requestEnableScript, requestEnableScript,
fetchAndSortScriptList, fetchAndSortScriptList,
requestDeleteScript, requestDeleteScript,
ScriptLoading, ScriptLoading,
selectScripts, selectScripts,
sortScript, sortScript,
upsertScript,
requestStopScript, requestStopScript,
requestRunScript, requestRunScript,
} from "@App/pages/store/features/script"; } from "@App/pages/store/features/script";
import { selectScriptListColumnWidth } from "@App/pages/store/features/setting"; import { selectScriptListColumnWidth } from "@App/pages/store/features/setting";
import { MessageQueue, Unsubscribe } from "@Packages/message/message_queue";
import { subscribeScriptDelete, subscribeScriptInstall, subscribeScriptRunStatus } from "@App/app/service/queue";
import { RuntimeClient } from "@App/app/service/service_worker/client";
import { ExtensionMessage, ExtensionMessageSend } from "@Packages/message/extension_message";
type ListType = Script & { loading?: boolean }; type ListType = Script & { loading?: boolean };

View File

@ -17,6 +17,7 @@ import ScriptStorage from "@App/pages/components/ScriptStorage";
import ScriptResource from "@App/pages/components/ScriptResource"; import ScriptResource from "@App/pages/components/ScriptResource";
import ScriptSetting from "@App/pages/components/ScriptSetting"; import ScriptSetting from "@App/pages/components/ScriptSetting";
import { scriptClient } from "@App/pages/store/features/script"; import { scriptClient } from "@App/pages/store/features/script";
import { i18nName } from "@App/locales/locales";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
const { Row } = Grid; const { Row } = Grid;
@ -377,7 +378,7 @@ function ScriptEditor() {
}); });
useEffect(() => { useEffect(() => {
scriptDAO.all().then(async (scripts) => { scriptDAO.all().then(async (scripts) => {
setScriptList(scripts); setScriptList(scripts.sort((a, b) => a.sort - b.sort));
// 如果有id则打开对应的脚本 // 如果有id则打开对应的脚本
if (uuid) { if (uuid) {
for (let i = 0; i < scripts.length; i += 1) { for (let i = 0; i < scripts.length; i += 1) {
@ -734,7 +735,7 @@ function ScriptEditor() {
} }
}} }}
> >
{script.name} {i18nName(script)}
</Button> </Button>
))} ))}
</div> </div>

View File

@ -65,6 +65,10 @@ function App() {
const list = resp.scriptList; const list = resp.scriptList;
list.sort((a, b) => { list.sort((a, b) => {
if (a.enable === b.enable) { if (a.enable === b.enable) {
// 根据菜单数排序
if (a.menus.length !== b.menus.length) {
return b.menus.length - a.menus.length;
}
if (a.runNum !== b.runNum) { if (a.runNum !== b.runNum) {
return b.runNum - a.runNum; return b.runNum - a.runNum;
} }