通讯操作
This commit is contained in:
parent
9876c1cbcb
commit
c4b47d117c
@ -1,6 +1,6 @@
|
||||
export function sendMessage(action: string, params?: any): Promise<any> {
|
||||
export function sendMessage(action: string, data?: any): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
chrome.runtime.sendMessage({ action, data: params }, (res) => {
|
||||
chrome.runtime.sendMessage({ action, data }, (res) => {
|
||||
if (res.code) {
|
||||
console.error(res);
|
||||
reject(res.message);
|
||||
@ -11,10 +11,10 @@ export function sendMessage(action: string, params?: any): Promise<any> {
|
||||
});
|
||||
}
|
||||
|
||||
export function connect(action: string, params?: any): Promise<chrome.runtime.Port> {
|
||||
export function connect(action: string, data?: any): Promise<chrome.runtime.Port> {
|
||||
return new Promise((resolve) => {
|
||||
const port = chrome.runtime.connect();
|
||||
port.postMessage({ action, data: params });
|
||||
port.postMessage({ action, data });
|
||||
resolve(port);
|
||||
});
|
||||
}
|
||||
|
@ -2,17 +2,20 @@ import EventEmitter from "eventemitter3";
|
||||
import { connect } from "./client";
|
||||
import { ApiFunction, Server } from "./server";
|
||||
|
||||
export type SubscribeCallback = (message: any) => void;
|
||||
|
||||
export class Broker {
|
||||
constructor() {}
|
||||
|
||||
// 订阅
|
||||
async subscribe(topic: string, handler: (message: any) => void) {
|
||||
async subscribe(topic: string, handler: SubscribeCallback): Promise<chrome.runtime.Port> {
|
||||
const con = await connect("messageQueue", { action: "subscribe", topic });
|
||||
con.onMessage.addListener((msg: { action: string; topic: string; message: any }) => {
|
||||
if (msg.action === "message") {
|
||||
handler(msg.message);
|
||||
}
|
||||
});
|
||||
return con;
|
||||
}
|
||||
|
||||
// 发布
|
||||
|
99
packages/message/window_message.ts
Normal file
99
packages/message/window_message.ts
Normal file
@ -0,0 +1,99 @@
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
// 通过 window.postMessage/onmessage 实现通信
|
||||
|
||||
import EventEmitter from "eventemitter3";
|
||||
|
||||
// 消息体
|
||||
export type WindowMessageBody = {
|
||||
messageId: string; // 消息id
|
||||
type: "sendMessage" | "respMessage" | "connect"; // 消息类型
|
||||
data: any; // 消息数据
|
||||
};
|
||||
|
||||
export class WindowMessage {
|
||||
EE: EventEmitter = new EventEmitter();
|
||||
|
||||
// source: Window 消息来源
|
||||
// target: Window 消息目标
|
||||
constructor(
|
||||
private source: Window,
|
||||
private target: Window
|
||||
) {
|
||||
// 监听消息
|
||||
this.source.addEventListener("message", (e) => {
|
||||
if (e.source === this.target) {
|
||||
this.messageHandle(e.data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
messageHandle(data: WindowMessageBody) {
|
||||
// 处理消息
|
||||
if (data.type === "sendMessage") {
|
||||
// 接收到消息
|
||||
this.EE.emit("message", data.data, (resp: any) => {
|
||||
// 发送响应消息
|
||||
const body: WindowMessageBody = {
|
||||
messageId: data.messageId,
|
||||
type: "respMessage",
|
||||
data: resp,
|
||||
};
|
||||
this.target.postMessage(body, "*");
|
||||
});
|
||||
} else if (data.type === "respMessage") {
|
||||
// 接收到响应消息
|
||||
this.EE.emit("response:" + data.messageId, data);
|
||||
} else if (data.type === "connect") {
|
||||
this.EE.emit("connect", data.data, new WindowMessageConnect(data.messageId, this.EE, this.target));
|
||||
} else if (data.type === "disconnect") {
|
||||
this.EE.emit("disconnect", data.data, new WindowMessageConnect(data.messageId, this.EE, this.target));
|
||||
} else if (data.type === "connectMessage") {
|
||||
this.EE.emit("connectMessage", data.data, new WindowMessageConnect(data.messageId, this.EE, this.target));
|
||||
}
|
||||
}
|
||||
|
||||
onConnect(callback: (data: any, con: WindowMessageConnect) => void) {
|
||||
this.EE.addListener("connect", callback);
|
||||
}
|
||||
|
||||
connect(action: string, data?: any): Promise<WindowMessageConnect> {
|
||||
return new Promise((resolve) => {
|
||||
const body: WindowMessageBody = {
|
||||
messageId: uuidv4(),
|
||||
type: "connect",
|
||||
data: { action, data },
|
||||
};
|
||||
this.target.postMessage(body, "*");
|
||||
resolve(new WindowMessageConnect(body.messageId, this.EE, this.target));
|
||||
});
|
||||
}
|
||||
|
||||
onMessage(callback: (data: any, sendResponse: (data: any) => void) => void) {
|
||||
this.EE.addListener("message", callback);
|
||||
}
|
||||
|
||||
sendMessage(action: string, data?: any): Promise<any> {
|
||||
return new Promise((resolve) => {
|
||||
const body: WindowMessageBody = {
|
||||
messageId: uuidv4(),
|
||||
type: "sendMessage",
|
||||
data: { action, data },
|
||||
};
|
||||
const callback = (body: WindowMessageBody) => {
|
||||
this.EE.removeListener("response:" + body.messageId, callback);
|
||||
resolve(body.data);
|
||||
};
|
||||
this.EE.addListener("response:" + body.messageId, callback);
|
||||
this.target.postMessage(body, "*");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class WindowMessageConnect {
|
||||
constructor(
|
||||
private messageId: string,
|
||||
private EE: EventEmitter,
|
||||
private target: Window
|
||||
) {}
|
||||
}
|
@ -9,20 +9,15 @@ export const SCRIPT_TYPE_NORMAL: SCRIPT_TYPE = 1;
|
||||
export const SCRIPT_TYPE_CRONTAB: SCRIPT_TYPE = 2;
|
||||
export const SCRIPT_TYPE_BACKGROUND: SCRIPT_TYPE = 3;
|
||||
|
||||
export type SCRIPT_STATUS = 1 | 2 | 3 | 4;
|
||||
export type SCRIPT_STATUS = 1 | 2;
|
||||
|
||||
export const SCRIPT_STATUS_ENABLE: SCRIPT_STATUS = 1;
|
||||
export const SCRIPT_STATUS_DISABLE: SCRIPT_STATUS = 2;
|
||||
// 弃用
|
||||
export const SCRIPT_STATUS_ERROR: SCRIPT_STATUS = 3;
|
||||
export const SCRIPT_STATUS_DELETE: SCRIPT_STATUS = 4;
|
||||
|
||||
export type SCRIPT_RUN_STATUS = "running" | "complete" | "error" | "retry";
|
||||
export type SCRIPT_RUN_STATUS = "running" | "complete" | "error";
|
||||
export const SCRIPT_RUN_STATUS_RUNNING: SCRIPT_RUN_STATUS = "running";
|
||||
export const SCRIPT_RUN_STATUS_COMPLETE: SCRIPT_RUN_STATUS = "complete";
|
||||
export const SCRIPT_RUN_STATUS_ERROR: SCRIPT_RUN_STATUS = "error";
|
||||
// 弃用
|
||||
export const SCRIPT_RUN_STATUS_RETRY: SCRIPT_RUN_STATUS = "retry";
|
||||
|
||||
export type Metadata = { [key: string]: string[] };
|
||||
|
||||
|
@ -1,11 +1,17 @@
|
||||
import { Server } from "@Packages/message/server";
|
||||
import { ScriptService } from "./script";
|
||||
import { MessageQueue } from "@Packages/message/message_queue";
|
||||
|
||||
// offscreen环境的管理器
|
||||
export class OffscreenManager {
|
||||
private api: Server = new Server("offscreen");
|
||||
|
||||
private mq: MessageQueue = new MessageQueue(this.api);
|
||||
|
||||
initManager() {
|
||||
// 监听消息
|
||||
|
||||
const group = this.api.group("serviceWorker");
|
||||
const script = new ScriptService(group.group("script"), this.mq);
|
||||
script.init();
|
||||
}
|
||||
}
|
||||
|
20
src/app/service/offscreen/script.ts
Normal file
20
src/app/service/offscreen/script.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import LoggerCore from "@App/app/logger/core";
|
||||
import Logger from "@App/app/logger/logger";
|
||||
import { MessageQueue } from "@Packages/message/message_queue";
|
||||
import { Group } from "@Packages/message/server";
|
||||
|
||||
export class ScriptService {
|
||||
logger: Logger;
|
||||
|
||||
constructor(
|
||||
private group: Group,
|
||||
private mq: MessageQueue
|
||||
) {
|
||||
this.logger = LoggerCore.logger().with({ service: "script" });
|
||||
}
|
||||
|
||||
init() {
|
||||
// 初始化, 执行所有的后台脚本, 设置定时脚本计时器
|
||||
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
import { Script } from "@App/app/repo/scripts";
|
||||
import { Client } from "@Packages/message/client";
|
||||
import { InstallSource } from ".";
|
||||
import { Broker } from "@Packages/message/message_queue";
|
||||
|
||||
export class ScriptClient extends Client {
|
||||
constructor() {
|
||||
@ -12,7 +13,26 @@ export class ScriptClient extends Client {
|
||||
return this.do("getInstallInfo", uuid);
|
||||
}
|
||||
|
||||
installScript(script: Script, upsertBy: InstallSource = "user") {
|
||||
return this.do("installScript", { script, upsertBy });
|
||||
install(script: Script, upsertBy: InstallSource = "user") {
|
||||
return this.do("install", { script, upsertBy });
|
||||
}
|
||||
|
||||
delete(uuid: string) {
|
||||
return this.do("delete", uuid);
|
||||
}
|
||||
|
||||
enable(uuid: string, enable: boolean) {
|
||||
return this.do("enable", { uuid, enable });
|
||||
}
|
||||
}
|
||||
|
||||
export function subscribeScriptInstall(
|
||||
border: Broker,
|
||||
callback: (message: { script: Script; update: boolean }) => void
|
||||
) {
|
||||
return border.subscribe("installScript", callback);
|
||||
}
|
||||
|
||||
export function subscribeScriptDelete(border: Broker, callback: (message: { uuid: string }) => void) {
|
||||
return border.subscribe("deleteScript", callback);
|
||||
}
|
||||
|
@ -6,7 +6,14 @@ import LoggerCore from "@App/app/logger/core";
|
||||
import Cache from "@App/app/cache";
|
||||
import CacheKey from "@App/app/cache_key";
|
||||
import { openInCurrentTab } from "@App/pkg/utils/utils";
|
||||
import { Script, ScriptDAO } from "@App/app/repo/scripts";
|
||||
import {
|
||||
Script,
|
||||
SCRIPT_RUN_STATUS_COMPLETE,
|
||||
SCRIPT_RUN_STATUS_RUNNING,
|
||||
SCRIPT_STATUS_DISABLE,
|
||||
SCRIPT_STATUS_ENABLE,
|
||||
ScriptDAO,
|
||||
} from "@App/app/repo/scripts";
|
||||
import { MessageQueue } from "@Packages/message/message_queue";
|
||||
import { InstallSource } from ".";
|
||||
|
||||
@ -145,11 +152,13 @@ export class ScriptService {
|
||||
version: script.metadata.version[0],
|
||||
upsertBy,
|
||||
});
|
||||
let update = false;
|
||||
const dao = new ScriptDAO();
|
||||
// 判断是否已经安装
|
||||
const oldScript = await dao.findByUUID(script.uuid);
|
||||
if (oldScript) {
|
||||
// 执行更新逻辑
|
||||
update = true;
|
||||
script.selfMetadata = oldScript.selfMetadata;
|
||||
}
|
||||
return dao
|
||||
@ -157,7 +166,7 @@ export class ScriptService {
|
||||
.then(() => {
|
||||
logger.info("install success");
|
||||
// 广播一下
|
||||
this.mq.publish("installScript", script);
|
||||
this.mq.publish("installScript", { script, update });
|
||||
return {};
|
||||
})
|
||||
.catch((e) => {
|
||||
@ -166,10 +175,54 @@ export class ScriptService {
|
||||
});
|
||||
}
|
||||
|
||||
async deleteScript(uuid: string) {
|
||||
const logger = this.logger.with({ uuid });
|
||||
const dao = new ScriptDAO();
|
||||
const script = await dao.findByUUID(uuid);
|
||||
if (!script) {
|
||||
logger.error("script not found");
|
||||
throw new Error("script not found");
|
||||
}
|
||||
return dao
|
||||
.delete(uuid)
|
||||
.then(() => {
|
||||
logger.info("delete success");
|
||||
this.mq.publish("deleteScript", { uuid });
|
||||
return {};
|
||||
})
|
||||
.catch((e) => {
|
||||
logger.error("delete error", Logger.E(e));
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
|
||||
async enableScript(param: { uuid: string; enable: boolean }) {
|
||||
const logger = this.logger.with({ uuid: param.uuid, enable: param.enable });
|
||||
const dao = new ScriptDAO();
|
||||
const script = await dao.findByUUID(param.uuid);
|
||||
if (!script) {
|
||||
logger.error("script not found");
|
||||
throw new Error("script not found");
|
||||
}
|
||||
return dao
|
||||
.update(param.uuid, { status: param.enable ? SCRIPT_STATUS_ENABLE : SCRIPT_STATUS_DISABLE })
|
||||
.then(() => {
|
||||
logger.info("enable success");
|
||||
this.mq.publish("enableScript", { uuid: param.uuid, enable: param.enable });
|
||||
return {};
|
||||
})
|
||||
.catch((e) => {
|
||||
logger.error("enable error", Logger.E(e));
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
|
||||
init() {
|
||||
this.listenerScriptInstall();
|
||||
|
||||
this.group.on("getInstallInfo", this.getInstallInfo);
|
||||
this.group.on("installScript", this.installScript.bind(this));
|
||||
this.group.on("install", this.installScript.bind(this));
|
||||
this.group.on("delete", this.deleteScript.bind(this));
|
||||
this.group.on("enable", this.enableScript.bind(this));
|
||||
}
|
||||
}
|
||||
|
@ -246,7 +246,7 @@ function App() {
|
||||
return;
|
||||
}
|
||||
new ScriptClient()
|
||||
.installScript(upsertScript as Script)
|
||||
.install(upsertScript as Script)
|
||||
.then(() => {
|
||||
if (isUpdate) {
|
||||
Message.success(t("install.update_success")!);
|
||||
|
@ -68,10 +68,21 @@ import CloudScriptPlan from "@App/pages/components/CloudScriptPlan";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { nextTime, semTime } from "@App/pkg/utils/utils";
|
||||
import { i18nName } from "@App/locales/locales";
|
||||
import { ListHomeRender, ScriptIcons } from "./utils";
|
||||
import { getValues, ListHomeRender, ScriptIcons } from "./utils";
|
||||
import { useAppDispatch, useAppSelector } from "@App/store/hooks";
|
||||
import { fetchScriptList, selectScripts } from "@App/store/features/script";
|
||||
import {
|
||||
deleteScript,
|
||||
requestEnableScript,
|
||||
fetchAndSortScriptList,
|
||||
requestDeleteScript,
|
||||
ScriptLoading,
|
||||
selectScripts,
|
||||
sortScript,
|
||||
upsertScript,
|
||||
} from "@App/store/features/script";
|
||||
import { selectScriptListColumnWidth } from "@App/store/features/setting";
|
||||
import { Broker } from "@Packages/message/message_queue";
|
||||
import { subscribeScriptDelete, subscribeScriptInstall } from "@App/app/service/service_worker/client";
|
||||
|
||||
type ListType = Script & { loading?: boolean };
|
||||
|
||||
@ -87,7 +98,7 @@ function ScriptList() {
|
||||
const scriptListColumnWidth = useAppSelector(selectScriptListColumnWidth);
|
||||
const inputRef = useRef<RefInputType>(null);
|
||||
const navigate = useNavigate();
|
||||
const openUserConfig = parseInt(useSearchParams()[0].get("userConfig") || "", 10);
|
||||
const openUserConfig = useSearchParams()[0].get("userConfig") || "";
|
||||
const [showAction, setShowAction] = useState(false);
|
||||
const [action, setAction] = useState("");
|
||||
const [select, setSelect] = useState<Script[]>([]);
|
||||
@ -96,9 +107,24 @@ function ScriptList() {
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(fetchScriptList());
|
||||
dispatch(fetchAndSortScriptList());
|
||||
// 监听脚本安装/运行
|
||||
// Monitor script running status
|
||||
const border = new Broker();
|
||||
const subCon: chrome.runtime.Port[] = [];
|
||||
|
||||
subscribeScriptInstall(border, (message) => {
|
||||
dispatch(upsertScript(message.script));
|
||||
}).then((con) => subCon.push(con));
|
||||
|
||||
subscribeScriptDelete(border, (message) => {
|
||||
dispatch(deleteScript(message.uuid));
|
||||
}).then((con) => subCon.push(con));
|
||||
|
||||
return () => {
|
||||
subCon.forEach((con) => {
|
||||
con.disconnect();
|
||||
});
|
||||
};
|
||||
// const channel = runtimeCtrl.watchRunStatus();
|
||||
// channel.setHandler(([id, status]: any) => {
|
||||
// setScriptList((list) => {
|
||||
@ -123,6 +149,9 @@ function ScriptList() {
|
||||
key: "#",
|
||||
sorter: (a, b) => a.sort - b.sort,
|
||||
render(col) {
|
||||
if (col < 0) {
|
||||
return "-";
|
||||
}
|
||||
return col + 1;
|
||||
},
|
||||
},
|
||||
@ -146,34 +175,14 @@ function ScriptList() {
|
||||
},
|
||||
],
|
||||
onFilter: (value, row) => row.status === value,
|
||||
render: (col, item: ListType) => {
|
||||
render: (col, item: ScriptLoading) => {
|
||||
return (
|
||||
<Switch
|
||||
checked={item.status === SCRIPT_STATUS_ENABLE}
|
||||
loading={item.loading}
|
||||
disabled={item.loading}
|
||||
loading={item.enableLoading}
|
||||
disabled={item.enableLoading}
|
||||
onChange={(checked) => {
|
||||
// setScriptList((list) => {
|
||||
// const index = list.findIndex((script) => script.id === item.id);
|
||||
// list[index].loading = true;
|
||||
// let p: Promise<any>;
|
||||
// if (checked) {
|
||||
// p = scriptCtrl.enable(item.id).then(() => {
|
||||
// list[index].status = SCRIPT_STATUS_ENABLE;
|
||||
// });
|
||||
// } else {
|
||||
// p = scriptCtrl.disable(item.id).then(() => {
|
||||
// list[index].status = SCRIPT_STATUS_DISABLE;
|
||||
// });
|
||||
// }
|
||||
// p.catch((err) => {
|
||||
// Message.error(err);
|
||||
// }).finally(() => {
|
||||
// list[index].loading = false;
|
||||
// setScriptList([...list]);
|
||||
// });
|
||||
// return list;
|
||||
// });
|
||||
dispatch(requestEnableScript({ uuid: item.uuid, enable: checked }));
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@ -466,7 +475,7 @@ function ScriptList() {
|
||||
dataIndex: "action",
|
||||
key: "action",
|
||||
width: 160,
|
||||
render(col, item: Script) {
|
||||
render(col, item: ScriptLoading) {
|
||||
return (
|
||||
<Button.Group>
|
||||
<Link to={`/script/editor/${item.uuid}`}>
|
||||
@ -482,18 +491,13 @@ function ScriptList() {
|
||||
title={t("confirm_delete_script")}
|
||||
icon={<RiDeleteBin5Fill />}
|
||||
onOk={() => {
|
||||
// setScriptList((list) => {
|
||||
// return list.filter((i) => i.id !== item.id);
|
||||
// });
|
||||
// scriptCtrl.delete(item.id).catch((e) => {
|
||||
// Message.error(`${t("delete_failed")}: ${e}`);
|
||||
// });
|
||||
dispatch(requestDeleteScript(item.uuid));
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
type="text"
|
||||
icon={<RiDeleteBin5Fill />}
|
||||
onClick={() => {}}
|
||||
loading={item.actionLoading}
|
||||
style={{
|
||||
color: "var(--color-text-2)",
|
||||
}}
|
||||
@ -504,13 +508,39 @@ function ScriptList() {
|
||||
type="text"
|
||||
icon={<RiSettings3Fill />}
|
||||
onClick={() => {
|
||||
// Get value
|
||||
// getValues(item).then((newValues) => {
|
||||
// setUserConfig({
|
||||
// userConfig: { ...item.config! },
|
||||
// script: item,
|
||||
// values: newValues,
|
||||
// });
|
||||
getValues(item).then((newValues) => {
|
||||
setUserConfig({
|
||||
userConfig: { ...item.config! },
|
||||
script: item,
|
||||
values: newValues,
|
||||
});
|
||||
});
|
||||
}}
|
||||
style={{
|
||||
color: "var(--color-text-2)",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{item.type !== SCRIPT_TYPE_NORMAL && (
|
||||
<Button
|
||||
type="text"
|
||||
icon={item.runStatus === SCRIPT_RUN_STATUS_RUNNING ? <RiStopFill /> : <RiPlayFill />}
|
||||
loading={item.actionLoading}
|
||||
onClick={async () => {
|
||||
if (item.runStatus === SCRIPT_RUN_STATUS_RUNNING) {
|
||||
// Stop script
|
||||
}
|
||||
console.log(item.runStatus);
|
||||
// Stop script
|
||||
// Message.loading({
|
||||
// id: "script-stop",
|
||||
// content: t("stopping_script"),
|
||||
// });
|
||||
// await runtimeCtrl.stopScript(item.id);
|
||||
// Message.success({
|
||||
// id: "script-stop",
|
||||
// content: t("script_stopped"),
|
||||
// duration: 3000,
|
||||
// });
|
||||
}}
|
||||
style={{
|
||||
@ -518,59 +548,6 @@ function ScriptList() {
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{item.type !== SCRIPT_TYPE_NORMAL &&
|
||||
(item.runStatus === SCRIPT_RUN_STATUS_RUNNING ? (
|
||||
<Button
|
||||
type="text"
|
||||
icon={<RiStopFill />}
|
||||
onClick={async () => {
|
||||
// Stop script
|
||||
// Message.loading({
|
||||
// id: "script-stop",
|
||||
// content: t("stopping_script"),
|
||||
// });
|
||||
// await runtimeCtrl.stopScript(item.id);
|
||||
// Message.success({
|
||||
// id: "script-stop",
|
||||
// content: t("script_stopped"),
|
||||
// duration: 3000,
|
||||
// });
|
||||
}}
|
||||
style={{
|
||||
color: "var(--color-text-2)",
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<Button
|
||||
type="text"
|
||||
icon={<RiPlayFill />}
|
||||
onClick={async () => {
|
||||
// Start script
|
||||
// Message.loading({
|
||||
// id: "script-run",
|
||||
// content: t("starting_script"),
|
||||
// });
|
||||
// await runtimeCtrl.startScript(item.id);
|
||||
// Message.success({
|
||||
// id: "script-run",
|
||||
// content: t("script_started"),
|
||||
// duration: 3000,
|
||||
// });
|
||||
// setScriptList((list) => {
|
||||
// for (let i = 0; i < list.length; i += 1) {
|
||||
// if (list[i].id === item.id) {
|
||||
// list[i].runStatus = SCRIPT_RUN_STATUS_RUNNING;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// return [...list];
|
||||
// });
|
||||
}}
|
||||
style={{
|
||||
color: "var(--color-text-2)",
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
{item.metadata.cloudcat && (
|
||||
<Button
|
||||
type="text"
|
||||
@ -591,28 +568,20 @@ function ScriptList() {
|
||||
|
||||
const [newColumns, setNewColumns] = useState<ColumnProps[]>([]);
|
||||
|
||||
// 设置列和排序
|
||||
// 设置列和判断是否打开用户配置
|
||||
useEffect(() => {
|
||||
// const dao = new ScriptDAO();
|
||||
// dao.table
|
||||
// .orderBy("sort")
|
||||
// .toArray()
|
||||
// .then(async (scripts) => {
|
||||
// // Sort when a new script is added (-1)
|
||||
// scriptListSort(scripts);
|
||||
// // Open user config panel
|
||||
// if (openUserConfig) {
|
||||
// const script = scripts.find((item) => item.id === openUserConfig);
|
||||
// if (script && script.config) {
|
||||
// setUserConfig({
|
||||
// script,
|
||||
// userConfig: script.config,
|
||||
// values: await getValues(script),
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// setScriptList(scripts);
|
||||
// });
|
||||
if (openUserConfig) {
|
||||
const script = scriptList.find((item) => item.uuid === openUserConfig);
|
||||
if (script && script.config) {
|
||||
getValues(script).then((values) => {
|
||||
setUserConfig({
|
||||
script,
|
||||
userConfig: script.config!,
|
||||
values: values,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
setNewColumns(
|
||||
columns.map((item) => {
|
||||
item.width = scriptListColumnWidth[item.key!] ?? item.width;
|
||||
@ -640,24 +609,21 @@ function ScriptList() {
|
||||
return;
|
||||
}
|
||||
if (active.id !== over.id) {
|
||||
// setScriptList((items) => {
|
||||
// let oldIndex = 0;
|
||||
// let newIndex = 0;
|
||||
// items.forEach((item, index) => {
|
||||
// if (item.id === active.id) {
|
||||
// oldIndex = index;
|
||||
// } else if (item.id === over.id) {
|
||||
// newIndex = index;
|
||||
// }
|
||||
// });
|
||||
// const newItems = arrayMove(items, oldIndex, newIndex);
|
||||
// scriptListSort(newItems);
|
||||
// return newItems;
|
||||
// });
|
||||
console.log(active);
|
||||
let oldIndex = 0;
|
||||
let newIndex = 0;
|
||||
scriptList.forEach((item, index) => {
|
||||
if (item.uuid === active.id) {
|
||||
oldIndex = index;
|
||||
} else if (item.uuid === over.id) {
|
||||
newIndex = index;
|
||||
}
|
||||
});
|
||||
dispatch(sortScript({ uuid: active.id as string, newIndex, oldIndex }));
|
||||
}
|
||||
}}
|
||||
>
|
||||
<SortableContext items={scriptList} strategy={verticalListSortingStrategy}>
|
||||
<SortableContext items={scriptList.map((s) => ({ ...s, id: s.uuid }))} strategy={verticalListSortingStrategy}>
|
||||
<table ref={ref} {...props} />
|
||||
</SortableContext>
|
||||
</DndContext>
|
||||
@ -970,7 +936,7 @@ function ScriptList() {
|
||||
<Table
|
||||
className="arco-drag-table-container"
|
||||
components={components}
|
||||
rowKey="id"
|
||||
rowKey="uuid"
|
||||
tableLayoutFixed
|
||||
columns={dealColumns}
|
||||
data={scriptList}
|
||||
|
@ -148,7 +148,7 @@ export function ListHomeRender({ script }: { script: Script }) {
|
||||
}
|
||||
|
||||
export function getValues(script: Script) {
|
||||
return {};
|
||||
return Promise.resolve({});
|
||||
}
|
||||
|
||||
export type ScriptIconsProps = {
|
||||
|
@ -1,3 +1,23 @@
|
||||
function main() {}
|
||||
import LoggerCore from "./app/logger/core";
|
||||
import DBWriter from "./app/logger/db_writer";
|
||||
import MessageWriter from "./app/logger/message_writer";
|
||||
import { LoggerDAO } from "./app/repo/logger";
|
||||
import { OffscreenManager } from "./app/service/offscreen";
|
||||
|
||||
function main() {
|
||||
// 建立与offscreen页面的连接
|
||||
|
||||
// 初始化日志组件
|
||||
const loggerCore = new LoggerCore({
|
||||
debug: process.env.NODE_ENV === "development",
|
||||
writer: new MessageWriter(connectSandbox),
|
||||
labels: { env: "sandbox" },
|
||||
});
|
||||
loggerCore.logger().debug("offscreen start");
|
||||
|
||||
// 初始化管理器
|
||||
const manager = new OffscreenManager();
|
||||
manager.initManager();
|
||||
}
|
||||
|
||||
main();
|
||||
|
@ -1,31 +1,99 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import { createAsyncThunk, PayloadAction } from "@reduxjs/toolkit";
|
||||
import { createAppSlice } from "../hooks";
|
||||
import { Script, ScriptDAO } from "@App/app/repo/scripts";
|
||||
import { Script, SCRIPT_STATUS_DISABLE, SCRIPT_STATUS_ENABLE, ScriptDAO } from "@App/app/repo/scripts";
|
||||
import { arrayMove } from "@dnd-kit/sortable";
|
||||
import { ScriptClient } from "@App/app/service/service_worker/client";
|
||||
|
||||
export const fetchScriptList = createAsyncThunk("script/fetchScriptList", () => {
|
||||
return new ScriptDAO().all();
|
||||
export const fetchAndSortScriptList = createAsyncThunk("script/fetchScriptList", async () => {
|
||||
// 排序
|
||||
const dao = new ScriptDAO();
|
||||
const scripts = await dao.all();
|
||||
scripts.sort((a, b) => a.sort - b.sort);
|
||||
for (let i = 0; i < scripts.length; i += 1) {
|
||||
if (scripts[i].sort !== i) {
|
||||
dao.update(scripts[i].uuid, { sort: i });
|
||||
scripts[i].sort = i;
|
||||
}
|
||||
}
|
||||
return scripts;
|
||||
});
|
||||
|
||||
export const requestEnableScript = createAsyncThunk(
|
||||
"script/enableScript",
|
||||
(param: { uuid: string; enable: boolean }) => {
|
||||
return new ScriptClient().enable(param.uuid, param.enable);
|
||||
}
|
||||
);
|
||||
|
||||
export const requestDeleteScript = createAsyncThunk("script/deleteScript", async (uuid: string) => {
|
||||
return new ScriptClient().delete(uuid);
|
||||
});
|
||||
|
||||
export type ScriptLoading = Script & { enableLoading?: boolean; actionLoading?: boolean };
|
||||
|
||||
const updateScript = (scripts: ScriptLoading[], uuid: string, update: (s: ScriptLoading) => void) => {
|
||||
const script = scripts.find((s) => s.uuid === uuid);
|
||||
if (script) {
|
||||
update(script);
|
||||
}
|
||||
};
|
||||
|
||||
export const scriptSlice = createAppSlice({
|
||||
name: "script",
|
||||
initialState: {
|
||||
scripts: [] as Script[],
|
||||
scripts: [] as ScriptLoading[],
|
||||
},
|
||||
reducers: {
|
||||
upsertScript: (state, action: PayloadAction<Script>) => {
|
||||
const script = state.scripts.find((s) => s.uuid === action.payload.uuid);
|
||||
if (script) {
|
||||
Object.assign(script, action.payload);
|
||||
} else {
|
||||
// 放到第一
|
||||
state.scripts.splice(0, 0, action.payload);
|
||||
}
|
||||
},
|
||||
deleteScript: (state, action: PayloadAction<string>) => {
|
||||
state.scripts = state.scripts.filter((s) => s.uuid !== action.payload);
|
||||
},
|
||||
sortScript: (state, action: PayloadAction<{ uuid: string; newIndex: number; oldIndex: number }>) => {
|
||||
const dao = new ScriptDAO();
|
||||
const newItems = arrayMove(state.scripts, action.payload.oldIndex, action.payload.newIndex);
|
||||
for (let i = 0; i < state.scripts.length; i += 1) {
|
||||
if (newItems[i].sort !== i) {
|
||||
dao.update(newItems[i].uuid, { sort: i });
|
||||
newItems[i].sort = i;
|
||||
}
|
||||
}
|
||||
state.scripts = newItems;
|
||||
},
|
||||
},
|
||||
reducers: {},
|
||||
extraReducers: (builder) => {
|
||||
builder.addCase(fetchScriptList.fulfilled, (state, action) => {
|
||||
const newScripts: Script[] = [];
|
||||
action.payload.forEach((item) => {
|
||||
newScripts.push(item);
|
||||
});
|
||||
state.scripts = newScripts;
|
||||
});
|
||||
builder
|
||||
.addCase(fetchAndSortScriptList.fulfilled, (state, action) => {
|
||||
state.scripts = action.payload;
|
||||
})
|
||||
.addCase(requestEnableScript.fulfilled, (state, action) => {
|
||||
updateScript(state.scripts, action.meta.arg.uuid, (script) => {
|
||||
script.enableLoading = false;
|
||||
script.status = action.meta.arg.enable ? SCRIPT_STATUS_ENABLE : SCRIPT_STATUS_DISABLE;
|
||||
});
|
||||
})
|
||||
.addCase(requestEnableScript.pending, (state, action) =>
|
||||
updateScript(state.scripts, action.meta.arg.uuid, (s) => (s.enableLoading = true))
|
||||
)
|
||||
.addCase(requestDeleteScript.fulfilled, (state, action) => {
|
||||
state.scripts = state.scripts.filter((s) => s.uuid !== action.meta.arg);
|
||||
})
|
||||
.addCase(requestDeleteScript.pending, (state, action) =>
|
||||
updateScript(state.scripts, action.meta.arg, (s) => (s.actionLoading = true))
|
||||
);
|
||||
},
|
||||
selectors: {
|
||||
selectScripts: (state) => state.scripts,
|
||||
},
|
||||
});
|
||||
|
||||
// export const {} = scriptSlice.actions;
|
||||
export const { sortScript, upsertScript, deleteScript } = scriptSlice.actions;
|
||||
|
||||
export const { selectScripts } = scriptSlice.selectors;
|
||||
|
Loading…
x
Reference in New Issue
Block a user