value设置
This commit is contained in:
parent
d200809fee
commit
d761c62500
34
example/gm_value/gm_value.js
Normal file
34
example/gm_value/gm_value.js
Normal file
@ -0,0 +1,34 @@
|
||||
// ==UserScript==
|
||||
// @name gm value
|
||||
// @namespace https://bbs.tampermonkey.net.cn/
|
||||
// @version 0.1.0
|
||||
// @description 可以持久化存储数据, 并且可以监听数据变化
|
||||
// @author You
|
||||
// @match https://bbs.tampermonkey.net.cn/
|
||||
// @run-at document-start
|
||||
// @grant GM_setValue
|
||||
// @grant GM_getValue
|
||||
// @grant GM_addValueChangeListener
|
||||
// @grant GM_listValues
|
||||
// @grant GM_deleteValue
|
||||
// @grant GM_cookie
|
||||
// ==/UserScript==
|
||||
|
||||
GM_addValueChangeListener("test_set", function (name, oldval, newval, remote) {
|
||||
console.log("test_set change", name, oldval, newval, remote);
|
||||
});
|
||||
|
||||
setInterval(() => {
|
||||
console.log(GM_getValue("test_set"));
|
||||
console.log(GM_listValues());
|
||||
}, 2000);
|
||||
|
||||
setTimeout(() => {
|
||||
GM_deleteValue("test_set");
|
||||
}, 3000);
|
||||
|
||||
GM_setValue("test_set", new Date().getTime());
|
||||
|
||||
console.log(GM_getValue("test_set2"));
|
||||
|
||||
GM_setValue("test_set2", new Date().getTime());
|
@ -36,9 +36,8 @@ function renameField() {
|
||||
// export是0.10.x时的兼容性处理
|
||||
export: "++id,&scriptId",
|
||||
});
|
||||
const v = 36;
|
||||
// 将脚本数据迁移到chrome.storage
|
||||
db.version(v).upgrade(() => {
|
||||
db.version(18).upgrade(() => {
|
||||
// 默认使用的事务,这里加个延时,用db.open()打开数据库后,再执行
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
|
@ -159,10 +159,11 @@ export default class GMApi {
|
||||
}
|
||||
if (value === undefined) {
|
||||
delete this.scriptRes.value[key];
|
||||
return this.sendMessage("GM_setValue", [key]);
|
||||
} else {
|
||||
this.scriptRes.value[key] = value;
|
||||
return this.sendMessage("GM_setValue", [key, value]);
|
||||
}
|
||||
return this.sendMessage("GM_setValue", [key, value]);
|
||||
}
|
||||
|
||||
@GMContext.API({ depend: ["GM_setValue"] })
|
||||
|
@ -72,6 +72,10 @@ export class ResourceClient extends Client {
|
||||
getScriptResources(script: Script): Promise<{ [key: string]: Resource }> {
|
||||
return this.do("getScriptResources", script);
|
||||
}
|
||||
|
||||
deleteResource(url: string) {
|
||||
return this.do("deleteResource", url);
|
||||
}
|
||||
}
|
||||
|
||||
export class ValueClient extends Client {
|
||||
@ -79,7 +83,7 @@ export class ValueClient extends Client {
|
||||
super(msg, "serviceWorker/value");
|
||||
}
|
||||
|
||||
getScriptValue(script: Script) {
|
||||
getScriptValue(script: Script): Promise<{ [key: string]: any }> {
|
||||
return this.do("getScriptValue", script);
|
||||
}
|
||||
|
||||
|
@ -242,7 +242,7 @@ export default class GMApi {
|
||||
|
||||
@PermissionVerify.API()
|
||||
async GM_setValue(request: Request, sender: GetSender) {
|
||||
if (!request.params || request.params.length !== 2) {
|
||||
if (!request.params || request.params.length < 1) {
|
||||
throw new Error("param is failed");
|
||||
}
|
||||
const [key, value] = request.params;
|
||||
|
@ -305,7 +305,12 @@ export class ResourceService {
|
||||
return { url: urls[0], hash };
|
||||
}
|
||||
|
||||
deleteResource(url: string) {
|
||||
return this.resourceDAO.delete(url);
|
||||
}
|
||||
|
||||
init() {
|
||||
this.group.on("getScriptResources", this.getScriptResources.bind(this));
|
||||
this.group.on("deleteResource", this.deleteResource.bind(this));
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ export class ValueService {
|
||||
const storageName = getStorageName(script);
|
||||
let oldValue;
|
||||
// 使用事务来保证数据一致性
|
||||
console.log("setValue", key, value);
|
||||
await Cache.getInstance().tx("setValue:" + storageName, async () => {
|
||||
const valueModel = await this.valueDAO.get(storageName);
|
||||
if (!valueModel) {
|
||||
@ -54,7 +55,11 @@ export class ValueService {
|
||||
});
|
||||
} else {
|
||||
oldValue = valueModel.data[key];
|
||||
valueModel.data[key] = value;
|
||||
if (value === undefined) {
|
||||
delete valueModel.data[key];
|
||||
} else {
|
||||
valueModel.data[key] = value;
|
||||
}
|
||||
await this.valueDAO.save(storageName, valueModel);
|
||||
}
|
||||
return true;
|
||||
|
@ -68,6 +68,7 @@
|
||||
"confirm_delete_backup_file": "确认删除备份文件",
|
||||
"confirm_update": "确认更新",
|
||||
"delete_success": "删除成功",
|
||||
"deleting": "删除中",
|
||||
"backup_strategy": "备份策略",
|
||||
"under_construction": "建设中",
|
||||
"development_debugging": "开发调试",
|
||||
|
@ -1,22 +1,12 @@
|
||||
import { Resource } from "@App/app/repo/resource";
|
||||
import { Script } from "@App/app/repo/scripts";
|
||||
import { ResourceClient } from "@App/app/service/service_worker/client";
|
||||
import { message } from "@App/pages/store/global";
|
||||
import { base64ToBlob } from "@App/pkg/utils/script";
|
||||
import {
|
||||
Button,
|
||||
Drawer,
|
||||
Input,
|
||||
Message,
|
||||
Popconfirm,
|
||||
Space,
|
||||
Table,
|
||||
} from "@arco-design/web-react";
|
||||
import { Button, Drawer, Input, Message, Popconfirm, Space, Table } from "@arco-design/web-react";
|
||||
import { RefInputType } from "@arco-design/web-react/es/Input/interface";
|
||||
import { ColumnProps } from "@arco-design/web-react/es/Table";
|
||||
import {
|
||||
IconDelete,
|
||||
IconDownload,
|
||||
IconSearch,
|
||||
} from "@arco-design/web-react/icon";
|
||||
import { IconDelete, IconDownload, IconSearch } from "@arco-design/web-react/icon";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
@ -34,12 +24,13 @@ const ScriptResource: React.FC<{
|
||||
const [data, setData] = useState<ResourceListItem[]>([]);
|
||||
const inputRef = useRef<RefInputType>(null);
|
||||
const { t } = useTranslation();
|
||||
const resourceClient = new ResourceClient(message);
|
||||
|
||||
useEffect(() => {
|
||||
if (!script) {
|
||||
return () => {};
|
||||
}
|
||||
resourceCtrl.getResource(script).then((res) => {
|
||||
resourceClient.getScriptResources(script).then((res) => {
|
||||
const arr: ResourceListItem[] = [];
|
||||
Object.keys(res).forEach((key) => {
|
||||
// @ts-ignore
|
||||
@ -119,10 +110,21 @@ const ScriptResource: React.FC<{
|
||||
title={t("confirm_delete_resource")}
|
||||
onOk={() => {
|
||||
Message.info({
|
||||
content: t("delete_success"),
|
||||
content: t("deleting"),
|
||||
});
|
||||
resourceCtrl.deleteResource(value.id);
|
||||
setData(data.filter((_, i) => i !== index));
|
||||
resourceClient
|
||||
.deleteResource(value.url)
|
||||
.then(() => {
|
||||
Message.info({
|
||||
content: t("delete_success"),
|
||||
});
|
||||
setData(data.filter((_, i) => i !== index));
|
||||
})
|
||||
.catch((e) => {
|
||||
Message.error({
|
||||
content: t("delete_failed") + ": " + e.message,
|
||||
});
|
||||
});
|
||||
}}
|
||||
>
|
||||
<Button type="text" iconOnly icon={<IconDelete />} />
|
||||
@ -153,7 +155,7 @@ const ScriptResource: React.FC<{
|
||||
onOk={() => {
|
||||
setData((prev) => {
|
||||
prev.forEach((v) => {
|
||||
resourceCtrl.deleteResource(v.id);
|
||||
resourceClient.deleteResource(v.url);
|
||||
});
|
||||
Message.info({
|
||||
content: t("clear_success"),
|
||||
|
@ -1,15 +1,7 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Script } from "@App/app/repo/scripts";
|
||||
import {
|
||||
Space,
|
||||
Popconfirm,
|
||||
Button,
|
||||
Divider,
|
||||
Typography,
|
||||
Modal,
|
||||
Input,
|
||||
} from "@arco-design/web-react";
|
||||
import { Script, ScriptDAO } from "@App/app/repo/scripts";
|
||||
import { Space, Popconfirm, Button, Divider, Typography, Modal, Input } from "@arco-design/web-react";
|
||||
import Table, { ColumnProps } from "@arco-design/web-react/es/Table";
|
||||
import { IconDelete } from "@arco-design/web-react/icon";
|
||||
|
||||
@ -25,7 +17,7 @@ type MatchItem = {
|
||||
const Match: React.FC<{
|
||||
script: Script;
|
||||
}> = ({ script }) => {
|
||||
// const scriptCtrl = IoC.instance(ScriptController) as ScriptController;
|
||||
const scriptDAO = new ScriptDAO();
|
||||
const [match, setMatch] = useState<MatchItem[]>([]);
|
||||
const [exclude, setExclude] = useState<MatchItem[]>([]);
|
||||
const [matchValue, setMatchValue] = useState<string>("");
|
||||
@ -37,7 +29,7 @@ const Match: React.FC<{
|
||||
useEffect(() => {
|
||||
if (script) {
|
||||
// 从数据库中获取是简单处理数据一致性的问题
|
||||
scriptCtrl.scriptDAO.findById(script.id).then((res) => {
|
||||
scriptDAO.get(script.uuid).then((res) => {
|
||||
if (!res) {
|
||||
return;
|
||||
}
|
||||
@ -68,8 +60,7 @@ const Match: React.FC<{
|
||||
});
|
||||
setMatch(v);
|
||||
|
||||
const excludeArr =
|
||||
res.selfMetadata?.exclude || res.metadata.exclude || [];
|
||||
const excludeArr = res.selfMetadata?.exclude || res.metadata.exclude || [];
|
||||
const excludeMap = new Map<string, boolean>();
|
||||
res.metadata.exclude?.forEach((m) => {
|
||||
excludeMap.set(m, true);
|
||||
@ -125,9 +116,7 @@ const Match: React.FC<{
|
||||
return (
|
||||
<Space>
|
||||
<Popconfirm
|
||||
title={`${t("confirm_delete_exclude")}${
|
||||
item.hasMatch ? ` ${t("after_deleting_match_item")}` : ""
|
||||
}`}
|
||||
title={`${t("confirm_delete_exclude")}${item.hasMatch ? ` ${t("after_deleting_match_item")}` : ""}`}
|
||||
onOk={() => {
|
||||
exclude.splice(exclude.indexOf(item), 1);
|
||||
scriptCtrl
|
||||
@ -159,9 +148,7 @@ const Match: React.FC<{
|
||||
return (
|
||||
<Space>
|
||||
<Popconfirm
|
||||
title={`${t("confirm_delete_match")}${
|
||||
item.self ? "" : ` ${t("after_deleting_exclude_item")}`
|
||||
}`}
|
||||
title={`${t("confirm_delete_match")}${item.self ? "" : ` ${t("after_deleting_exclude_item")}`}`}
|
||||
onOk={() => {
|
||||
match.splice(match.indexOf(item), 1);
|
||||
scriptCtrl
|
||||
|
@ -19,9 +19,6 @@ import { IconDelete } from "@arco-design/web-react/icon";
|
||||
const PermissionManager: React.FC<{
|
||||
script: Script;
|
||||
}> = ({ script }) => {
|
||||
// const permissionCtrl = IoC.instance(
|
||||
// PermissionController
|
||||
// ) as PermissionController;
|
||||
const [permission, setPermission] = useState<Permission[]>([]);
|
||||
const [permissionVisible, setPermissionVisible] = useState<boolean>(false);
|
||||
const [permissionValue, setPermissionValue] = useState<Permission>();
|
||||
|
@ -1,13 +1,6 @@
|
||||
import { Script } from "@App/app/repo/scripts";
|
||||
import { Script, ScriptDAO } from "@App/app/repo/scripts";
|
||||
import { formatUnixTime } from "@App/pkg/utils/utils";
|
||||
import {
|
||||
Descriptions,
|
||||
Divider,
|
||||
Drawer,
|
||||
Empty,
|
||||
Input,
|
||||
Message,
|
||||
} from "@arco-design/web-react";
|
||||
import { Descriptions, Divider, Drawer, Empty, Input, Message } from "@arco-design/web-react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import Match from "./Match";
|
||||
@ -19,14 +12,14 @@ const ScriptSetting: React.FC<{
|
||||
onOk: () => void;
|
||||
onCancel: () => void;
|
||||
}> = ({ script, visible, onCancel, onOk }) => {
|
||||
// const scriptCtrl = IoC.instance(ScriptController) as ScriptController;
|
||||
const scriptDAO = new ScriptDAO();
|
||||
const [checkUpdateUrl, setCheckUpdateUrl] = useState<string>("");
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
if (script) {
|
||||
scriptCtrl.scriptDAO.findById(script.id).then((v) => {
|
||||
scriptDAO.get(script.uuid).then((v) => {
|
||||
setCheckUpdateUrl(v?.downloadUrl || "");
|
||||
});
|
||||
}
|
||||
@ -56,9 +49,7 @@ const ScriptSetting: React.FC<{
|
||||
data={[
|
||||
{
|
||||
label: t("last_updated"),
|
||||
value: formatUnixTime(
|
||||
(script?.updatetime || script?.createtime || 0) / 1000
|
||||
),
|
||||
value: formatUnixTime((script?.updatetime || script?.createtime || 0) / 1000),
|
||||
},
|
||||
{
|
||||
label: "UUID",
|
||||
@ -83,8 +74,8 @@ const ScriptSetting: React.FC<{
|
||||
setCheckUpdateUrl(e);
|
||||
}}
|
||||
onBlur={() => {
|
||||
scriptCtrl
|
||||
.updateCheckUpdateUrl(script!.id, checkUpdateUrl)
|
||||
scriptDAO
|
||||
.update(script.uuid, { downloadUrl: checkUpdateUrl, checkUpdateUrl: checkUpdateUrl })
|
||||
.then(() => {
|
||||
Message.success(t("update_success")!);
|
||||
});
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { Script } from "@App/app/repo/scripts";
|
||||
import { Value } from "@App/app/repo/value";
|
||||
import { valueClient } from "@App/pages/store/features/script";
|
||||
import { valueType } from "@App/pkg/utils/utils";
|
||||
import { Button, Drawer, Form, Input, Message, Modal, Popconfirm, Select, Space, Table } from "@arco-design/web-react";
|
||||
import { RefInputType } from "@arco-design/web-react/es/Input/interface";
|
||||
@ -10,16 +11,20 @@ import { useTranslation } from "react-i18next";
|
||||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
interface ValueModel {
|
||||
key: string;
|
||||
value: any;
|
||||
}
|
||||
|
||||
const ScriptStorage: React.FC<{
|
||||
// eslint-disable-next-line react/require-default-props
|
||||
script?: Script;
|
||||
visible: boolean;
|
||||
onOk: () => void;
|
||||
onCancel: () => void;
|
||||
}> = ({ script, visible, onCancel, onOk }) => {
|
||||
const [data, setData] = useState<Value[]>([]);
|
||||
const [data, setData] = useState<ValueModel[]>([]);
|
||||
const inputRef = useRef<RefInputType>(null);
|
||||
const [currentValue, setCurrentValue] = useState<Value>();
|
||||
const [currentValue, setCurrentValue] = useState<ValueModel>();
|
||||
const [visibleEdit, setVisibleEdit] = useState(false);
|
||||
const [form] = Form.useForm();
|
||||
const { t } = useTranslation();
|
||||
@ -28,31 +33,13 @@ const ScriptStorage: React.FC<{
|
||||
if (!script) {
|
||||
return () => {};
|
||||
}
|
||||
// valueCtrl.getValues(script).then((values) => {
|
||||
// setData(values);
|
||||
// });
|
||||
// Monitor value changes
|
||||
// const channel = valueCtrl.watchValue(script);
|
||||
// channel.setHandler((value: Value) => {
|
||||
// setData((prev) => {
|
||||
// const index = prev.findIndex((item) => item.key === value.key);
|
||||
// if (index === -1) {
|
||||
// if (value.value === undefined) {
|
||||
// return prev;
|
||||
// }
|
||||
// return [value, ...prev];
|
||||
// }
|
||||
// if (value.value === undefined) {
|
||||
// prev.splice(index, 1);
|
||||
// return [...prev];
|
||||
// }
|
||||
// prev[index] = value;
|
||||
// return [...prev];
|
||||
// });
|
||||
// });
|
||||
return () => {
|
||||
// channel.disChannel();
|
||||
};
|
||||
valueClient.getScriptValue(script).then((value) => {
|
||||
setData(
|
||||
Object.keys(value).map((key) => {
|
||||
return { key: key, value: value[key] };
|
||||
})
|
||||
);
|
||||
});
|
||||
}, [script]);
|
||||
const columns: ColumnProps[] = [
|
||||
{
|
||||
@ -61,7 +48,6 @@ const ScriptStorage: React.FC<{
|
||||
key: "key",
|
||||
filterIcon: <IconSearch />,
|
||||
width: 140,
|
||||
// eslint-disable-next-line react/no-unstable-nested-components
|
||||
filterDropdown: ({ filterKeys, setFilterKeys, confirm }: any) => {
|
||||
return (
|
||||
<div className="arco-table-custom-filter">
|
||||
@ -120,7 +106,7 @@ const ScriptStorage: React.FC<{
|
||||
},
|
||||
{
|
||||
title: t("action"),
|
||||
render(_col, value: Value, index) {
|
||||
render(_col, value: { key: string; value: string }, index) {
|
||||
return (
|
||||
<Space>
|
||||
<Button
|
||||
@ -136,7 +122,7 @@ const ScriptStorage: React.FC<{
|
||||
iconOnly
|
||||
icon={<IconDelete />}
|
||||
onClick={() => {
|
||||
valueCtrl.setValue(script!.id, value.key, undefined);
|
||||
valueClient.setScriptValue(script!.uuid, value.key, undefined);
|
||||
Message.info({
|
||||
content: t("delete_success"),
|
||||
});
|
||||
@ -179,7 +165,7 @@ const ScriptStorage: React.FC<{
|
||||
default:
|
||||
break;
|
||||
}
|
||||
valueCtrl.setValue(script!.id, value.key, value.value);
|
||||
valueClient.setScriptValue(script!.uuid, value.key, value.value);
|
||||
if (currentValue) {
|
||||
Message.info({
|
||||
content: t("update_success"),
|
||||
@ -201,13 +187,8 @@ const ScriptStorage: React.FC<{
|
||||
});
|
||||
setData([
|
||||
{
|
||||
id: 0,
|
||||
scriptId: script!.id,
|
||||
storageName: (script?.metadata.storagename && script?.metadata.storagename[0]) || "",
|
||||
key: value.key,
|
||||
value: value.value,
|
||||
createtime: Date.now(),
|
||||
updatetime: 0,
|
||||
},
|
||||
...data,
|
||||
]);
|
||||
@ -254,7 +235,7 @@ const ScriptStorage: React.FC<{
|
||||
onOk={() => {
|
||||
setData((prev) => {
|
||||
prev.forEach((v) => {
|
||||
valueCtrl.setValue(script!.id, v.key, undefined);
|
||||
valueClient.setScriptValue(script!.uuid, v.key, undefined);
|
||||
});
|
||||
Message.info({
|
||||
content: t("clear_success"),
|
||||
|
Loading…
x
Reference in New Issue
Block a user