编辑器
Some checks failed
test / Run tests (push) Failing after 9s
build / Build (push) Failing after 14s
Some checks failed
test / Run tests (push) Failing after 9s
build / Build (push) Failing after 14s
This commit is contained in:
parent
98c86d61f1
commit
d682b4d566
@ -2,13 +2,12 @@ import * as path from "path";
|
||||
import { defineConfig } from "@rspack/cli";
|
||||
import { rspack } from "@rspack/core";
|
||||
import { version } from "./package.json";
|
||||
import CompressionPlugin from "compression-webpack-plugin";
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
const CompressionPlugin = require("compression-webpack-plugin");
|
||||
|
||||
const isDev = process.env.NODE_ENV === "development";
|
||||
const isBeta = version.includes("-");
|
||||
|
||||
console.log(CompressionPlugin);
|
||||
|
||||
// Target browsers, see: https://github.com/browserslist/browserslist
|
||||
const targets = ["chrome >= 87", "edge >= 88", "firefox >= 78", "safari >= 14"];
|
||||
|
||||
|
@ -25,7 +25,7 @@ export class ScriptClient extends Client {
|
||||
return this.do("getInstallInfo", uuid);
|
||||
}
|
||||
|
||||
install(script: Script, code: string, upsertBy: InstallSource = "user") {
|
||||
install(script: Script, code: string, upsertBy: InstallSource = "user"): Promise<{ update: boolean }> {
|
||||
return this.do("install", { script, code, upsertBy });
|
||||
}
|
||||
|
||||
|
@ -178,7 +178,7 @@ export class ScriptService {
|
||||
logger.info("install success");
|
||||
// 广播一下
|
||||
this.mq.publish("installScript", { script, update });
|
||||
return Promise.resolve(true);
|
||||
return Promise.resolve({ update });
|
||||
})
|
||||
.catch((e: any) => {
|
||||
logger.error("install error", Logger.E(e));
|
||||
|
@ -31,6 +31,10 @@
|
||||
"sync_delete": "同步删除",
|
||||
"enable_script_sync_to": "启用脚本同步至",
|
||||
"save": "保存",
|
||||
"save_as": "另存为",
|
||||
"file": "文件",
|
||||
"run": "运行",
|
||||
"debug": "调试",
|
||||
"cloud_sync_account_verification": "云同步账号信息验证中...",
|
||||
"cloud_sync_verification_failed": "云同步账号信息验证失败",
|
||||
"save_success": "保存成功",
|
||||
@ -358,5 +362,6 @@
|
||||
"collapse": "收起",
|
||||
"expand": "展开",
|
||||
"menu_expand_num_before": "菜单项超过",
|
||||
"menu_expand_num_after": "个时,自动隐藏"
|
||||
"menu_expand_num_after": "个时,自动隐藏",
|
||||
"script_name_cannot_be_set_to_empty": "脚本name不可以设置为空"
|
||||
}
|
@ -12,12 +12,12 @@ type Props = {
|
||||
code?: string;
|
||||
};
|
||||
|
||||
const CodeEditor: React.ForwardRefRenderFunction<{ editor: editor.ICodeEditor | undefined }, Props> = (
|
||||
const CodeEditor: React.ForwardRefRenderFunction<{ editor: editor.IStandaloneCodeEditor | undefined }, Props> = (
|
||||
{ id, className, code, diffCode, editable },
|
||||
ref
|
||||
) => {
|
||||
const settings = useAppSelector((state) => state.setting);
|
||||
const [monacoEditor, setEditor] = useState<editor.ICodeEditor>();
|
||||
const [monacoEditor, setEditor] = useState<editor.IStandaloneCodeEditor>();
|
||||
const div = useRef<HTMLDivElement>(null);
|
||||
useImperativeHandle(ref, () => ({
|
||||
editor: monacoEditor,
|
||||
|
@ -44,7 +44,7 @@ function App() {
|
||||
permission.push({
|
||||
label: t("subscribe_install_label"),
|
||||
color: "#ff0000",
|
||||
value: metadata.scripturl,
|
||||
value: metadata.scripturl!,
|
||||
});
|
||||
}
|
||||
if (metadata.match) {
|
||||
@ -311,8 +311,8 @@ function App() {
|
||||
<div>
|
||||
<Space>
|
||||
{oldScript && (
|
||||
<Tooltip content={`${t("current_version")}: v${oldScript.metadata.version[0]}`}>
|
||||
<Tag bordered>{oldScript.metadata.version[0]}</Tag>
|
||||
<Tooltip content={`${t("current_version")}: v${oldScript.metadata.version![0]}`}>
|
||||
<Tag bordered>{oldScript.metadata.version![0]}</Tag>
|
||||
</Tooltip>
|
||||
)}
|
||||
{metadata.version && (
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Script, ScriptAndCode, ScriptCodeDAO, ScriptDAO } from "@App/app/repo/scripts";
|
||||
import CodeEditor from "@App/pages/components/CodeEditor";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { useNavigate, useParams, useSearchParams } from "react-router-dom";
|
||||
import { editor, KeyCode, KeyMod } from "monaco-editor";
|
||||
import { Button, Dropdown, Grid, Menu, Message, Tabs, Tooltip } from "@arco-design/web-react";
|
||||
@ -16,14 +16,15 @@ import { prepareScriptByCode } from "@App/pkg/utils/script";
|
||||
import ScriptStorage from "@App/pages/components/ScriptStorage";
|
||||
import ScriptResource from "@App/pages/components/ScriptResource";
|
||||
import ScriptSetting from "@App/pages/components/ScriptSetting";
|
||||
import { scriptClient } from "@App/pages/store/features/script";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const { Row } = Grid;
|
||||
const { Col } = Grid;
|
||||
|
||||
// 声明一个Map存储Script
|
||||
const ScriptMap = new Map();
|
||||
|
||||
type HotKey = {
|
||||
id: string;
|
||||
title: string;
|
||||
hotKey: number;
|
||||
action: (script: Script, codeEditor: editor.IStandaloneCodeEditor) => void;
|
||||
};
|
||||
@ -35,51 +36,59 @@ const Editor: React.FC<{
|
||||
callbackEditor: (e: editor.IStandaloneCodeEditor) => void;
|
||||
onChange: (code: string) => void;
|
||||
}> = ({ id, script, hotKeys, callbackEditor, onChange }) => {
|
||||
const [init, setInit] = useState(false);
|
||||
const codeEditor = useRef<{ editor: editor.IStandaloneCodeEditor }>(null);
|
||||
// Script.uuid为key,Script为value,储存Script
|
||||
ScriptMap.set(script.uuid, script);
|
||||
const [node, setNode] = useState<{ editor: editor.IStandaloneCodeEditor }>();
|
||||
const ref = useCallback<(node: { editor: editor.IStandaloneCodeEditor }) => void>(
|
||||
(inlineNode) => {
|
||||
if (inlineNode && inlineNode.editor && !node) {
|
||||
setNode(inlineNode);
|
||||
}
|
||||
},
|
||||
[node]
|
||||
);
|
||||
useEffect(() => {
|
||||
if (!codeEditor.current || !codeEditor.current.editor) {
|
||||
return () => {};
|
||||
if (!node || !node.editor) {
|
||||
return;
|
||||
}
|
||||
console.log(codeEditor);
|
||||
// 初始化editor时将Script的uuid绑定到editor上
|
||||
// @ts-ignore
|
||||
if (!codeEditor.current.editor.uuid) {
|
||||
if (!node.editor.uuid) {
|
||||
// @ts-ignore
|
||||
codeEditor.current.editor.uuid = script.uuid;
|
||||
node.editor.uuid = script.uuid;
|
||||
}
|
||||
//@ts-ignore
|
||||
console.log(node.editor.uuid);
|
||||
hotKeys.forEach((item) => {
|
||||
codeEditor.current?.editor.addCommand(item.hotKey, () => {
|
||||
// 获取当前激活的editor(通过editor._focusTracker._hasFocus判断editor激活状态 可能有更好的方法)
|
||||
const activeEditor = editor
|
||||
.getEditors()
|
||||
node.editor.addAction({
|
||||
id: item.id,
|
||||
label: item.title,
|
||||
keybindings: [item.hotKey],
|
||||
run(editor) {
|
||||
// @ts-ignore
|
||||
.find((i) => i._focusTracker._hasFocus);
|
||||
|
||||
// 仅在获取到激活的editor时,通过editor上绑定的uuid获取Script,并指定激活的editor执行快捷键action
|
||||
if (activeEditor) {
|
||||
// @ts-ignore
|
||||
item.action(ScriptMap.get(activeEditor.uuid), activeEditor);
|
||||
}
|
||||
item.action(script, editor);
|
||||
},
|
||||
});
|
||||
});
|
||||
codeEditor.current.editor.onKeyUp(() => {
|
||||
onChange(codeEditor.current?.editor.getValue() || "");
|
||||
node.editor.onKeyUp(() => {
|
||||
onChange(node.editor.getValue() || "");
|
||||
});
|
||||
callbackEditor(codeEditor.current.editor);
|
||||
return () => {};
|
||||
}, []);
|
||||
|
||||
return <CodeEditor id={id} ref={codeEditor} code={script.code} diffCode="" editable />;
|
||||
callbackEditor(node.editor);
|
||||
return () => {
|
||||
node.editor.dispose();
|
||||
};
|
||||
}, [node?.editor]);
|
||||
|
||||
return <CodeEditor key={id} id={id} ref={ref} code={script.code} diffCode="" editable />;
|
||||
};
|
||||
|
||||
const WarpEditor = React.memo(Editor, (prev, next) => {
|
||||
return prev.script.uuid === next.script.uuid;
|
||||
});
|
||||
|
||||
type EditorMenu = {
|
||||
title: string;
|
||||
tooltip?: string;
|
||||
action?: (script: Script, e: editor.IStandaloneCodeEditor) => void;
|
||||
items?: {
|
||||
id: string;
|
||||
title: string;
|
||||
tooltip?: string;
|
||||
hotKey?: number;
|
||||
@ -140,10 +149,6 @@ const popstate = () => {
|
||||
};
|
||||
|
||||
function ScriptEditor() {
|
||||
const scriptDAO = new ScriptDAO();
|
||||
const scriptCodeDAO = new ScriptCodeDAO();
|
||||
const template = useSearchParams()[0].get("template") || "";
|
||||
const target = useSearchParams()[0].get("target") || "";
|
||||
const navigate = useNavigate();
|
||||
const [visible, setVisible] = useState<{ [key: string]: boolean }>({});
|
||||
const [editors, setEditors] = useState<
|
||||
@ -164,6 +169,11 @@ function ScriptEditor() {
|
||||
selectSciptButtonAndTab: string;
|
||||
}>();
|
||||
const { uuid } = useParams();
|
||||
const { t } = useTranslation();
|
||||
const template = useSearchParams()[0].get("template") || "";
|
||||
const target = useSearchParams()[0].get("target") || "";
|
||||
const scriptDAO = new ScriptDAO();
|
||||
const scriptCodeDAO = new ScriptCodeDAO();
|
||||
|
||||
const setShow = (key: visibleItem, show: boolean) => {
|
||||
Object.keys(visible).forEach((k) => {
|
||||
@ -175,17 +185,17 @@ function ScriptEditor() {
|
||||
|
||||
const save = (script: Script, e: editor.IStandaloneCodeEditor): Promise<Script> => {
|
||||
// 解析code生成新的script并更新
|
||||
return new Promise((resolve) => {
|
||||
return new Promise(() => {
|
||||
prepareScriptByCode(e.getValue(), script.origin || "", script.uuid)
|
||||
.then((prepareScript) => {
|
||||
const newScript = prepareScript.script;
|
||||
scriptCtrl.upsert(newScript).then(
|
||||
() => {
|
||||
if (!newScript.name) {
|
||||
Message.warning("脚本name不可以设置为空");
|
||||
Message.warning(t("script_name_cannot_be_set_to_empty"));
|
||||
return;
|
||||
}
|
||||
if (newScript.id === 0) {
|
||||
scriptClient.install(newScript, e.getValue()).then(
|
||||
(update) => {
|
||||
if (!update) {
|
||||
Message.success("新建成功,请注意后台脚本不会默认开启");
|
||||
// 保存的时候如何左侧没有脚本即新建
|
||||
setScriptList((prev) => {
|
||||
@ -207,17 +217,16 @@ function ScriptEditor() {
|
||||
setEditors((prev) => {
|
||||
for (let i = 0; i < prev.length; i += 1) {
|
||||
if (prev[i].script.uuid === newScript.uuid) {
|
||||
prev[i].code = newScript.code;
|
||||
prev[i].script.code = newScript.code;
|
||||
prev[i].isChanged = false;
|
||||
prev[i].script.name = newScript.name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
resolve(newScript);
|
||||
return [...prev];
|
||||
});
|
||||
},
|
||||
(err) => {
|
||||
(err: any) => {
|
||||
Message.error(`保存失败: ${err}`);
|
||||
}
|
||||
);
|
||||
@ -255,16 +264,18 @@ function ScriptEditor() {
|
||||
};
|
||||
const menu: EditorMenu[] = [
|
||||
{
|
||||
title: "文件",
|
||||
title: t("file"),
|
||||
items: [
|
||||
{
|
||||
title: "保存",
|
||||
id: "save",
|
||||
title: t("save"),
|
||||
hotKey: KeyMod.CtrlCmd | KeyCode.KeyS,
|
||||
hotKeyString: "Ctrl+S",
|
||||
action: save,
|
||||
},
|
||||
{
|
||||
title: "另存为",
|
||||
id: "saveAs",
|
||||
title: t("save_as"),
|
||||
hotKey: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyS,
|
||||
hotKeyString: "Ctrl+Shift+S",
|
||||
action: saveAs,
|
||||
@ -272,10 +283,11 @@ function ScriptEditor() {
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "运行",
|
||||
title: t("run"),
|
||||
items: [
|
||||
{
|
||||
title: "调试",
|
||||
id: "debug",
|
||||
title: t("debug"),
|
||||
hotKey: KeyMod.CtrlCmd | KeyCode.F5,
|
||||
hotKeyString: "Ctrl+F5",
|
||||
tooltip: "只有后台脚本/定时脚本才能调试, 且调试模式下不对进行权限校验(例如@connect)",
|
||||
@ -312,6 +324,7 @@ function ScriptEditor() {
|
||||
title: "工具",
|
||||
items: [
|
||||
{
|
||||
id: "scriptStorage",
|
||||
title: "脚本储存",
|
||||
tooltip: "可以管理脚本GM_value的储存数据",
|
||||
action(script) {
|
||||
@ -320,6 +333,7 @@ function ScriptEditor() {
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "scriptResource",
|
||||
title: "脚本资源",
|
||||
tooltip: "管理@resource,@require下载的资源",
|
||||
action(script) {
|
||||
@ -353,6 +367,8 @@ function ScriptEditor() {
|
||||
item.items.forEach((menuItem) => {
|
||||
if (menuItem.hotKey) {
|
||||
hotKeys.push({
|
||||
id: menuItem.id,
|
||||
title: menuItem.title,
|
||||
hotKey: menuItem.hotKey,
|
||||
action: menuItem.action,
|
||||
});
|
||||
@ -361,7 +377,6 @@ function ScriptEditor() {
|
||||
});
|
||||
useEffect(() => {
|
||||
scriptDAO.all().then(async (scripts) => {
|
||||
scripts.sort((a, b) => a.sort - b.sort);
|
||||
setScriptList(scripts);
|
||||
// 如果有id则打开对应的脚本
|
||||
if (uuid) {
|
||||
@ -703,15 +718,20 @@ function ScriptEditor() {
|
||||
}
|
||||
if (!flag) {
|
||||
// 如果没有打开则打开
|
||||
// 获取code
|
||||
scriptCodeDAO.findByUUID(script.uuid).then((code) => {
|
||||
if (!code) {
|
||||
return;
|
||||
}
|
||||
editors.push({
|
||||
script,
|
||||
code: script.code,
|
||||
script: Object.assign(script, code),
|
||||
active: true,
|
||||
hotKeys,
|
||||
isChanged: false,
|
||||
});
|
||||
}
|
||||
setEditors([...editors]);
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
{script.name}
|
||||
@ -850,7 +870,8 @@ function ScriptEditor() {
|
||||
display: item.active ? "block" : "none",
|
||||
}}
|
||||
>
|
||||
<Editor
|
||||
<WarpEditor
|
||||
key={`e_${item.script.uuid}`}
|
||||
id={`e_${item.script.uuid}`}
|
||||
script={item.script}
|
||||
hotKeys={item.hotKeys}
|
||||
|
@ -8,12 +8,14 @@ import {
|
||||
SCRIPT_TYPE_BACKGROUND,
|
||||
SCRIPT_TYPE_CRONTAB,
|
||||
SCRIPT_TYPE_NORMAL,
|
||||
ScriptAndCode,
|
||||
ScriptCode,
|
||||
ScriptCodeDAO,
|
||||
ScriptDAO,
|
||||
UserConfig,
|
||||
} from "@App/app/repo/scripts";
|
||||
import YAML from "yaml";
|
||||
import { Subscribe, SUBSCRIBE_STATUS_ENABLE, SubscribeDAO } from "@App/app/repo/subscribe";
|
||||
import { Subscribe, SUBSCRIBE_STATUS_ENABLE, SubscribeDAO, Metadata as SubMetadata } from "@App/app/repo/subscribe";
|
||||
import { nextTime } from "./utils";
|
||||
import { InstallSource } from "@App/app/service/service_worker";
|
||||
|
||||
@ -137,7 +139,7 @@ export async function fetchScriptInfo(
|
||||
return ret;
|
||||
}
|
||||
|
||||
export function copyScript(script: Script, old: Script): Script {
|
||||
export function copyScript(script: ScriptAndCode, old: Script): ScriptAndCode {
|
||||
const ret = script;
|
||||
ret.uuid = old.uuid;
|
||||
ret.createtime = old.createtime;
|
||||
@ -204,7 +206,7 @@ export function prepareScriptByCode(
|
||||
url: string,
|
||||
uuid?: string,
|
||||
override?: boolean
|
||||
): Promise<{ script: Script; oldScript?: Script; oldScriptCode?: string }> {
|
||||
): Promise<{ script: ScriptAndCode; oldScript?: ScriptAndCode }> {
|
||||
const dao = new ScriptDAO();
|
||||
return new Promise((resolve, reject) => {
|
||||
const metadata = parseMetadata(code);
|
||||
@ -253,9 +255,10 @@ export function prepareScriptByCode(
|
||||
} else {
|
||||
newUUID = uuidv4();
|
||||
}
|
||||
let script: Script = {
|
||||
let script: ScriptAndCode = {
|
||||
uuid: newUUID,
|
||||
name: metadata.name[0],
|
||||
code: code,
|
||||
author: metadata.author && metadata.author[0],
|
||||
namespace: metadata.namespace && metadata.namespace[0],
|
||||
originDomain: domain,
|
||||
@ -275,7 +278,7 @@ export function prepareScriptByCode(
|
||||
};
|
||||
const handler = async () => {
|
||||
let old: Script | undefined;
|
||||
let oldCode: string | undefined;
|
||||
let oldCode: ScriptCode | undefined;
|
||||
if (uuid) {
|
||||
old = await dao.get(uuid);
|
||||
if (!old && override) {
|
||||
@ -297,7 +300,7 @@ export function prepareScriptByCode(
|
||||
reject(new Error("旧的脚本代码不存在"));
|
||||
return;
|
||||
}
|
||||
oldCode = scriptCode.code;
|
||||
oldCode = scriptCode;
|
||||
script = copyScript(script, old);
|
||||
} else {
|
||||
// 前台脚本默认开启
|
||||
@ -306,7 +309,7 @@ export function prepareScriptByCode(
|
||||
}
|
||||
script.checktime = new Date().getTime();
|
||||
}
|
||||
resolve({ script, oldScript: old, oldScriptCode: oldCode });
|
||||
resolve({ script, oldScript: old ? Object.assign(old, oldCode) : undefined });
|
||||
};
|
||||
handler();
|
||||
});
|
||||
@ -317,8 +320,8 @@ export async function prepareSubscribeByCode(
|
||||
url: string
|
||||
): Promise<{ subscribe: Subscribe; oldSubscribe?: Subscribe }> {
|
||||
const dao = new SubscribeDAO();
|
||||
const metadata = parseMetadata(code);
|
||||
if (metadata == null) {
|
||||
const metadata = parseMetadata(code) as SubMetadata;
|
||||
if (!metadata) {
|
||||
throw new Error("MetaData信息错误");
|
||||
}
|
||||
if (metadata.name === undefined) {
|
||||
@ -329,9 +332,9 @@ export async function prepareSubscribeByCode(
|
||||
url,
|
||||
name: metadata.name[0],
|
||||
code,
|
||||
author: metadata.author && metadata.author[0],
|
||||
author: (metadata.author && metadata.author[0]) || "",
|
||||
scripts: {},
|
||||
metadata,
|
||||
metadata: metadata,
|
||||
status: SUBSCRIBE_STATUS_ENABLE,
|
||||
createtime: Date.now(),
|
||||
updatetime: Date.now(),
|
||||
|
Loading…
x
Reference in New Issue
Block a user