Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions src/app/service/service_worker/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@ import { type FileSystemType } from "@Packages/filesystem/factory";
import { type ResourceBackup } from "@App/pkg/backup/struct";
import { type VSCodeConnect } from "../offscreen/vscode-connect";
import { type ScriptInfo } from "@App/pkg/utils/scriptInstall";
import type { ScriptService, TCheckScriptUpdateOption, TOpenBatchUpdatePageOption } from "./script";
import type {
ScriptService,
TCheckScriptUpdateOption,
TOpenBatchUpdatePageOption,
TScriptInstallParam,
TScriptInstallReturn,
} from "./script";
import { encodeRValue, type TKeyValuePair } from "@App/pkg/utils/message_value";
import { type TSetValuesParams } from "./value";

Expand Down Expand Up @@ -40,15 +46,9 @@ export class ScriptClient extends Client {
return this.do<[boolean, ScriptInfo, { byWebRequest?: boolean }]>("getInstallInfo", uuid);
}

install(params: {
script: Script;
code: string;
upsertBy?: InstallSource;
createtime?: number;
updatetime?: number;
}): Promise<{ update: boolean }> {
install(params: TScriptInstallParam): Promise<TScriptInstallReturn> {
if (!params.upsertBy) params.upsertBy = "user";
return this.doThrow("install", { ...params });
return this.doThrow("install", { ...params } satisfies TScriptInstallParam);
}

// delete(uuid: string) {
Expand Down
23 changes: 15 additions & 8 deletions src/app/service/service_worker/script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,19 @@ export type TCheckScriptUpdateOption = Partial<

export type TOpenBatchUpdatePageOption = { q: string; dontCheckNow: boolean };

export type TScriptInstallParam = {
script: Script;
code: string;
upsertBy?: InstallSource;
createtime?: number; // Import 用
updatetime?: number; // Import 用
};

export type TScriptInstallReturn = {
update: boolean;
updatetime: number | undefined;
};

export class ScriptService {
logger: Logger;
scriptCodeDAO: ScriptCodeDAO = new ScriptCodeDAO();
Expand Down Expand Up @@ -371,13 +384,7 @@ export class ScriptService {
}

// 安装脚本 / 更新腳本
async installScript(param: {
script: Script;
code: string;
upsertBy?: InstallSource;
createtime?: number;
updatetime?: number;
}) {
async installScript(param: TScriptInstallParam): Promise<TScriptInstallReturn> {
param.upsertBy = param.upsertBy || "user";
const { script, upsertBy, createtime, updatetime } = param;
// 删 storage cache
Expand Down Expand Up @@ -424,7 +431,7 @@ export class ScriptService {
// Runtime 會負責更新 CompiledResource
this.publishInstallScript(script, { update, upsertBy });

return { update };
return { update, updatetime: script.updatetime };
})
.catch((e: any) => {
logger.error("install error", Logger.E(e));
Expand Down
3 changes: 3 additions & 0 deletions src/locales/ach-UG/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,9 @@
"menu_expand_num_before": "crwdns8608:0crwdne8608:0",
"menu_expand_num_after": "crwdns8610:0crwdne8610:0",
"script_name_cannot_be_set_to_empty": "crwdns8612:0crwdne8612:0",
"edit_conflict": "Edit Conflict",
"confirm_override_when_edit_conflict": "This script was edited in another instance. Replacing it will overwrite those changes. Would you like to keep this version instead?",
"save_abort_when_edit_conflict": "The script was edited in another instance. Save aborted.",
"eslint_config_format_error": "crwdns8614:0crwdne8614:0",
"export_success": "crwdns8616:0crwdne8616:0",
"get_backup_dir_url_failed": "crwdns8618:0crwdne8618:0",
Expand Down
3 changes: 3 additions & 0 deletions src/locales/de-DE/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,9 @@
"menu_expand_num_before": "Wenn Menüelemente mehr als",
"menu_expand_num_after": "sind, automatisch verbergen",
"script_name_cannot_be_set_to_empty": "Skriptname kann nicht leer gesetzt werden",
"edit_conflict": "Bearbeitungskonflikt",
"confirm_override_when_edit_conflict": "Dieses Skript wurde in einer anderen Instanz bearbeitet. Beim Ersetzen werden diese Änderungen überschrieben. Möchten Sie stattdessen diese Version behalten?",
"save_abort_when_edit_conflict": "Dieses Skript wurde in einer anderen Instanz bearbeitet. Speichern abgebrochen.",
"eslint_config_format_error": "eslint-Konfigurationsformat-Fehler",
"export_success": "Export erfolgreich",
"get_backup_dir_url_failed": "Backup-Verzeichnis-Adresse abrufen fehlgeschlagen",
Expand Down
3 changes: 3 additions & 0 deletions src/locales/en-US/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,9 @@
"menu_expand_num_before": "Menu items more than",
"menu_expand_num_after": "will be hidden.",
"script_name_cannot_be_set_to_empty": "Script name cannot be empty",
"edit_conflict": "Edit Conflict",
"confirm_override_when_edit_conflict": "This script was edited in another instance. Replacing it will overwrite those changes. Would you like to keep this version instead?",
"save_abort_when_edit_conflict": "The script was edited in another instance. Save aborted.",
"eslint_config_format_error": "eslint configuration format error",
"export_success": "Dump success saved",
"get_backup_dir_url_failed": "Failed to get backup directory address",
Expand Down
3 changes: 3 additions & 0 deletions src/locales/ja-JP/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,9 @@
"menu_expand_num_before": "メニュー項目が",
"menu_expand_num_after": "個を超えると自動的に非表示",
"script_name_cannot_be_set_to_empty": "スクリプト名を空に設定することはできません",
"edit_conflict": "編集の競合",
"confirm_override_when_edit_conflict": "このスクリプトは別のインスタンスで編集されています。置き換えるとその変更は上書きされます。このバージョンを保持しますか?",
"save_abort_when_edit_conflict": "このスクリプトは別のインスタンスで編集されています。保存は中止されました。",
"eslint_config_format_error": "ESLint設定フォーマットエラー",
"export_success": "エクスポートに成功しました",
"get_backup_dir_url_failed": "バックアップディレクトリアドレスの取得に失敗しました",
Expand Down
3 changes: 3 additions & 0 deletions src/locales/ru-RU/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,9 @@
"menu_expand_num_before": "Когда пунктов меню больше",
"menu_expand_num_after": ", автоматически скрывать",
"script_name_cannot_be_set_to_empty": "Имя скрипта не может быть пустым",
"edit_conflict": "Конфликт редактирования",
"confirm_override_when_edit_conflict": "Этот скрипт был изменён в другом экземпляре. Замена приведёт к перезаписи этих изменений. Хотите сохранить эту версию?",
"save_abort_when_edit_conflict": "Скрипт был изменён в другом экземпляре. Сохранение отменено.",
"eslint_config_format_error": "Ошибка формата конфигурации ESLint",
"export_success": "Экспорт успешен",
"get_backup_dir_url_failed": "Ошибка получения адреса папки резервных копий",
Expand Down
3 changes: 3 additions & 0 deletions src/locales/vi-VN/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,9 @@
"menu_expand_num_before": "Các mục menu nhiều hơn",
"menu_expand_num_after": "sẽ bị ẩn.",
"script_name_cannot_be_set_to_empty": "Tên script không được để trống",
"edit_conflict": "Xung đột chỉnh sửa",
"confirm_override_when_edit_conflict": "Tập lệnh này đã được chỉnh sửa ở một phiên bản khác. Việc thay thế sẽ ghi đè các thay đổi đó. Bạn có muốn giữ phiên bản này không?",
"save_abort_when_edit_conflict": "Tập lệnh đã được chỉnh sửa ở một phiên bản khác. Đã hủy lưu.",
"eslint_config_format_error": "Lỗi định dạng cấu hình eslint",
"export_success": "Đổ dữ liệu thành công đã lưu",
"get_backup_dir_url_failed": "Không thể lấy địa chỉ thư mục sao lưu",
Expand Down
3 changes: 3 additions & 0 deletions src/locales/zh-CN/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,9 @@
"menu_expand_num_before": "菜单项超过",
"menu_expand_num_after": "个时,自动隐藏",
"script_name_cannot_be_set_to_empty": "脚本name不可以设置为空",
"edit_conflict": "编辑冲突",
"confirm_override_when_edit_conflict": "此脚本已在其他实例中被修改。替换将覆盖这些更改。是否要保留此版本?",
"save_abort_when_edit_conflict": "该脚本已在其他实例中被修改,保存已中止。",
"eslint_config_format_error": "ESLint配置格式错误",
"export_success": "导出成功",
"get_backup_dir_url_failed": "获取备份目录地址失败",
Expand Down
3 changes: 3 additions & 0 deletions src/locales/zh-TW/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,9 @@
"menu_expand_num_before": "選單項目超過",
"menu_expand_num_after": "個時,自動隱藏",
"script_name_cannot_be_set_to_empty": "腳本名稱不可設定為空",
"edit_conflict": "編輯衝突",
"confirm_override_when_edit_conflict": "此腳本已在其他實例中被修改。替換將覆蓋這些變更。是否要保留此版本?",
"save_abort_when_edit_conflict": "此腳本已在其他實例中被修改,已中止儲存。",
"eslint_config_format_error": "ESLint設定格式錯誤",
"export_success": "匯出成功",
"get_backup_dir_url_failed": "取得備份目錄網址失敗",
Expand Down
94 changes: 66 additions & 28 deletions src/pages/options/routes/script/ScriptEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { Script } from "@App/app/repo/scripts";
import { SCRIPT_TYPE_NORMAL, ScriptCodeDAO, ScriptDAO } from "@App/app/repo/scripts";
import CodeEditor from "@App/pages/components/CodeEditor";
import React, { useCallback, useEffect, useMemo, useState } from "react";
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useParams, useSearchParams } from "react-router-dom";
import type { editor } from "monaco-editor";
import { KeyCode, KeyMod } from "monaco-editor";
Expand Down Expand Up @@ -31,18 +31,18 @@
id: string;
title: string;
hotKey: number;
action: (script: Script, codeEditor: editor.IStandaloneCodeEditor) => void;
action: (script: Script, codeEditor: editor.ICodeEditor) => void;
};

const Editor: React.FC<{
id: string;
script: Script;
getScript: (uuid: string) => Script | undefined;
code: string;
hotKeys: HotKey[];
callbackEditor: (e: editor.IStandaloneCodeEditor) => void;
callbackEditor: (e: editor.ICodeEditor) => void;
onChange: (code: string) => void;
className: string;
}> = ({ id, script, code, hotKeys, callbackEditor, onChange, className }) => {
}> = ({ id, getScript, code, hotKeys, callbackEditor, onChange, className }) => {
const [node, setNode] = useState<{ editor: editor.IStandaloneCodeEditor }>();
const ref = useCallback<(node: { editor: editor.IStandaloneCodeEditor }) => void>(
(inlineNode) => {
Expand All @@ -59,16 +59,18 @@
// @ts-ignore
if (!node.editor.uuid) {
// @ts-ignore
node.editor.uuid = script.uuid;
node.editor.uuid = id;
}
hotKeys.forEach((item) => {
node.editor.addAction({
id: item.id,
label: item.title,
keybindings: [item.hotKey],
run(editor) {
// @ts-ignore
item.action(script, editor);
const script = getScript(id);
if (script) {
item.action(script, editor);
}
},
});
});
Expand All @@ -77,26 +79,26 @@
});
callbackEditor(node.editor);
return node.editor.dispose.bind(node.editor);
}, [node?.editor]);

Check warning on line 82 in src/pages/options/routes/script/ScriptEditor.tsx

View workflow job for this annotation

GitHub Actions / Run tests

React Hook useEffect has missing dependencies: 'callbackEditor', 'getScript', 'hotKeys', 'id', 'node', and 'onChange'. Either include them or remove the dependency array. If 'callbackEditor' changes too often, find the parent component that defines it and wrap that definition in useCallback

return <CodeEditor key={id} id={id} ref={ref} className={className} code={code} diffCode="" editable />;
};

const WarpEditor = React.memo(Editor, (prev, next) => {
return prev.script.uuid === next.script.uuid;
return prev.id === next.id;
});

type EditorMenu = {
title: string;
tooltip?: string;
action?: (script: Script, e: editor.IStandaloneCodeEditor) => void;
action?: (script: Script, e: editor.ICodeEditor) => void;
items?: {
id: string;
title: string;
tooltip?: string;
hotKey?: number;
hotKeyString?: string;
action: (script: Script, e: editor.IStandaloneCodeEditor) => void;
action: (script: Script, e: editor.ICodeEditor) => void;
}[];
};

Expand Down Expand Up @@ -180,21 +182,30 @@
return false;
};

type EditorState = {
script: Script;
code: string;
active: boolean;
hotKeys: HotKey[];
editor?: editor.ICodeEditor;
isChanged: boolean;
};

function ScriptEditor() {
const [visible, setVisible] = useState<{ [key: string]: boolean }>({});
const [searchKeyword, setSearchKeyword] = useState<string>("");
const [showSearchInput, setShowSearchInput] = useState<boolean>(false);
const [modal, contextHolder] = Modal.useModal();
const [editors, setEditors] = useState<
{
script: Script;
code: string;
active: boolean;
hotKeys: HotKey[];
editor?: editor.IStandaloneCodeEditor;
isChanged: boolean;
}[]
>([]);
const [editors, setEditors] = useState<EditorState[]>([]);
const editorStateRef = useRef<EditorState[]>([]); // 取出资料用
// getScript 是稳定不变的 state
const getScript = useCallback((uuid: string) => {
return editorStateRef.current!.find((e) => e.script.uuid === uuid)?.script;
}, []);
// 更新取出资料用的 editorStateRef
useEffect(() => {
editorStateRef.current = editors;
}, [editors]);
const [scriptList, setScriptList] = useState<Script[]>([]);
const [currentScript, setCurrentScript] = useState<Script>();
const [selectSciptButtonAndTab, setSelectSciptButtonAndTab] = useState<string>("");
Expand Down Expand Up @@ -222,12 +233,12 @@
setVisible({ ...visible });
};

const save = (existingScript: Script, e: editor.IStandaloneCodeEditor): Promise<Script> => {
const save = (existingScript: Script, e: editor.ICodeEditor): Promise<Script> => {
// 解析code生成新的script并更新
const code = e.getValue();
const targetUUID = existingScript.uuid;
return prepareScriptByCode(code, existingScript.origin || "", targetUUID, false, scriptDAO, { byEditor: true })
.then((prepareScript) => {
.then(async (prepareScript) => {
const { script, oldScript } = prepareScript;
if (targetUUID) {
if (existingScript.createtime !== 0) {
Expand All @@ -243,11 +254,36 @@
Message.warning(t("script_name_cannot_be_set_to_empty"));
return Promise.reject(new Error("script name cannot be empty"));
}
const currentEditorUpdateTime = existingScript.updatetime;
const latestUpdateTime = oldScript?.updatetime;

if (currentEditorUpdateTime !== latestUpdateTime) {
const modalResult = await new Promise((resolve) => {
modal.confirm!({
focusLock: false,
closable: true,
title: t("edit_conflict"),
content: t("confirm_override_when_edit_conflict"),
onOk: () => {
resolve("yes");
},
onCancel: () => {
resolve("no");
},
});
});
setTimeout(e.focus.bind(e), 50);
if (modalResult === "no") {
Message.warning(t("save_abort_when_edit_conflict"));
return Promise.reject(new Error("The script was edited in another instance. Save Aborted."));
}
}

if (script.ignoreVersion) script.ignoreVersion = "";
return scriptClient
.install({ script, code })
.then((update): Script => {
if (!update) {
.then((result): Script => {
if (!result.update) {
Message.success(t("create_success_note"));
// 保存的时候如何左侧没有脚本即新建
setScriptList((prev) => {
Expand All @@ -263,6 +299,7 @@
? {
...script,
name,
updatetime: result.updatetime || script.updatetime,
}
: script
)
Expand All @@ -281,6 +318,7 @@
script: {
...item.script,
name,
updatetime: result.updatetime || item.script.updatetime,
},
}
: item
Expand All @@ -299,7 +337,7 @@
});
};

const saveAs = (script: Script, e: editor.IStandaloneCodeEditor) => {
const saveAs = (script: Script, e: editor.ICodeEditor) => {
return new Promise<void>((resolve) => {
chrome.downloads.download(
{
Expand Down Expand Up @@ -476,7 +514,7 @@
return () => {
document.title = "Home - ScriptCat";
};
}, []);

Check warning on line 517 in src/pages/options/routes/script/ScriptEditor.tsx

View workflow job for this annotation

GitHub Actions / Run tests

React Hook useEffect has missing dependencies: 'pageInit', 'pageUrlSearchParams', 'scriptDAO', and 'setPageUrlSearchParams'. Either include them or remove the dependency array

const memoUrlQueryString = useMemo(() => {
return `${pageUrlParams.uuid || ""}|${pageUrlSearchParams.get("template") || ""}|${pageUrlSearchParams.get("target") || ""}|${pageUrlSearchParams.get("d") || ""}`;
Expand Down Expand Up @@ -1127,8 +1165,8 @@
<WarpEditor
className="script-code-editor"
key={`e_${item.script.uuid}`}
id={`e_${item.script.uuid}`}
script={item.script}
id={`${item.script.uuid}`}
getScript={getScript}
code={item.code}
hotKeys={item.hotKeys}
callbackEditor={(e) => {
Expand Down
Loading