添加包
This commit is contained in:
parent
82e2c29937
commit
4b7957256e
@ -16,6 +16,7 @@
|
|||||||
"lint-fix": "eslint --fix ."
|
"lint-fix": "eslint --fix ."
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@reduxjs/toolkit": "^2.3.0",
|
||||||
"cron": "^3.2.1",
|
"cron": "^3.2.1",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
"dexie": "^4.0.10",
|
"dexie": "^4.0.10",
|
||||||
@ -24,6 +25,7 @@
|
|||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-i18next": "^15.1.0",
|
"react-i18next": "^15.1.0",
|
||||||
|
"react-redux": "^9.1.2",
|
||||||
"semver": "^7.6.3",
|
"semver": "^7.6.3",
|
||||||
"uuid": "^11.0.3",
|
"uuid": "^11.0.3",
|
||||||
"yaml": "^2.6.1"
|
"yaml": "^2.6.1"
|
||||||
@ -38,13 +40,17 @@
|
|||||||
"@types/react-dom": "^18.2.18",
|
"@types/react-dom": "^18.2.18",
|
||||||
"@types/semver": "^7.5.8",
|
"@types/semver": "^7.5.8",
|
||||||
"@vitest/coverage-v8": "2.1.4",
|
"@vitest/coverage-v8": "2.1.4",
|
||||||
|
"autoprefixer": "^10.4.20",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"eslint": "^9.12.0",
|
"eslint": "^9.12.0",
|
||||||
"eslint-plugin-react": "^7.37.1",
|
"eslint-plugin-react": "^7.37.1",
|
||||||
"eslint-plugin-react-hooks": "^5.0.0",
|
"eslint-plugin-react-hooks": "^5.0.0",
|
||||||
"globals": "^15.11.0",
|
"globals": "^15.11.0",
|
||||||
"jsdom": "^25.0.1",
|
"jsdom": "^25.0.1",
|
||||||
|
"postcss": "^8.4.49",
|
||||||
|
"postcss-loader": "^8.1.1",
|
||||||
"prettier": "^3.3.3",
|
"prettier": "^3.3.3",
|
||||||
|
"tailwindcss": "^3.4.15",
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
"typescript": "^5.6.3",
|
"typescript": "^5.6.3",
|
||||||
"typescript-eslint": "^8.8.1",
|
"typescript-eslint": "^8.8.1",
|
||||||
|
644
pnpm-lock.yaml
generated
644
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -27,6 +27,7 @@ export default defineConfig({
|
|||||||
offscreen: `${src}/offscreen.ts`,
|
offscreen: `${src}/offscreen.ts`,
|
||||||
sandbox: `${src}/sandbox.ts`,
|
sandbox: `${src}/sandbox.ts`,
|
||||||
popup: `${src}/pages/popup/main.tsx`,
|
popup: `${src}/pages/popup/main.tsx`,
|
||||||
|
install: `${src}/pages/install/main.tsx`,
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
path: `${dist}/ext/src`,
|
path: `${dist}/ext/src`,
|
||||||
@ -45,6 +46,23 @@ export default defineConfig({
|
|||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: "postcss-loader",
|
||||||
|
options: {
|
||||||
|
postcssOptions: {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: "css",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
test: /\.(svg|png)$/,
|
test: /\.(svg|png)$/,
|
||||||
type: "asset",
|
type: "asset",
|
||||||
@ -101,6 +119,14 @@ export default defineConfig({
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
new rspack.HtmlRspackPlugin({
|
||||||
|
filename: `${dist}/ext/src/install.html`,
|
||||||
|
template: `${src}/pages/install/index.html`,
|
||||||
|
inject: "head",
|
||||||
|
title: "Install - ScriptCat",
|
||||||
|
minify: true,
|
||||||
|
chunks: ["install"],
|
||||||
|
}),
|
||||||
new rspack.HtmlRspackPlugin({
|
new rspack.HtmlRspackPlugin({
|
||||||
filename: `${dist}/ext/src/popup.html`,
|
filename: `${dist}/ext/src/popup.html`,
|
||||||
template: `${src}/pages/popup/index.html`,
|
template: `${src}/pages/popup/index.html`,
|
||||||
|
@ -13,8 +13,8 @@ export default class Manager {
|
|||||||
|
|
||||||
listenerScriptInstall() {
|
listenerScriptInstall() {
|
||||||
// 初始化脚本安装监听
|
// 初始化脚本安装监听
|
||||||
chrome.webRequest.onBeforeRequest.addListener(
|
chrome.webRequest.onCompleted.addListener(
|
||||||
(req: chrome.webRequest.WebRequestBodyDetails) => {
|
(req: chrome.webRequest.WebResponseCacheDetails) => {
|
||||||
// 处理url, 实现安装脚本
|
// 处理url, 实现安装脚本
|
||||||
if (req.method !== "GET") {
|
if (req.method !== "GET") {
|
||||||
return;
|
return;
|
||||||
@ -30,20 +30,41 @@ export default class Manager {
|
|||||||
}
|
}
|
||||||
// 获取url参数
|
// 获取url参数
|
||||||
const targetUrl = url.hash.split("url=")[1];
|
const targetUrl = url.hash.split("url=")[1];
|
||||||
// 判断是否有bypass参数
|
|
||||||
if (url.hash.includes("bypass=true")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 读取脚本url内容, 进行安装
|
// 读取脚本url内容, 进行安装
|
||||||
LoggerCore.getInstance().logger().debug("install script", { url: targetUrl });
|
LoggerCore.getInstance().logger().debug("install script", { url: targetUrl });
|
||||||
this.openInstallPageByUrl(targetUrl).catch(() => {
|
this.openInstallPageByUrl(targetUrl).catch(() => {
|
||||||
// 如果打开失败, 则重定向到安装页
|
// 如果打开失败, 则重定向到安装页
|
||||||
chrome.scripting.executeScript({
|
chrome.scripting.executeScript({
|
||||||
target: { tabId: req.tabId },
|
target: { tabId: req.tabId },
|
||||||
func: () => {
|
func: function () {
|
||||||
history.back();
|
history.back();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
// 并不再重定向当前url
|
||||||
|
chrome.declarativeNetRequest.updateDynamicRules(
|
||||||
|
{
|
||||||
|
removeRuleIds: [2],
|
||||||
|
addRules: [
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
priority: 1,
|
||||||
|
action: {
|
||||||
|
type: chrome.declarativeNetRequest.RuleActionType.ALLOW,
|
||||||
|
},
|
||||||
|
condition: {
|
||||||
|
regexFilter: targetUrl,
|
||||||
|
resourceTypes: [chrome.declarativeNetRequest.ResourceType.MAIN_FRAME],
|
||||||
|
requestMethods: [chrome.declarativeNetRequest.RequestMethod.GET],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
if (chrome.runtime.lastError) {
|
||||||
|
console.error(chrome.runtime.lastError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -54,37 +75,6 @@ export default class Manager {
|
|||||||
types: ["main_frame"],
|
types: ["main_frame"],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
// 屏蔽某个tab都安装脚本
|
|
||||||
this.connect.on("install_script", (data: { req: chrome.webRequest.WebRequestBodyDetails }) => {
|
|
||||||
chrome.declarativeNetRequest.updateDynamicRules(
|
|
||||||
{
|
|
||||||
removeRuleIds: [2],
|
|
||||||
addRules: [
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
priority: 1,
|
|
||||||
action: {
|
|
||||||
type: chrome.declarativeNetRequest.RuleActionType.ALLOW,
|
|
||||||
redirect: {
|
|
||||||
regexSubstitution: "https://docs.scriptcat.org/docs/script_installation#url=\\0",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
condition: {
|
|
||||||
regexFilter: "^([^#]+?)\\.user(\\.bg|\\.sub)?\\.js((\\?).*|$)",
|
|
||||||
resourceTypes: [chrome.declarativeNetRequest.ResourceType.MAIN_FRAME],
|
|
||||||
requestMethods: [chrome.declarativeNetRequest.RequestMethod.GET],
|
|
||||||
tabIds: [data.req.tabId],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
if (chrome.runtime.lastError) {
|
|
||||||
console.error(chrome.runtime.lastError);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
// 重定向到脚本安装页
|
// 重定向到脚本安装页
|
||||||
chrome.declarativeNetRequest.updateDynamicRules(
|
chrome.declarativeNetRequest.updateDynamicRules(
|
||||||
{
|
{
|
||||||
|
3
src/index.css
Normal file
3
src/index.css
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
@ -20,6 +20,7 @@
|
|||||||
"permissions": [
|
"permissions": [
|
||||||
"offscreen",
|
"offscreen",
|
||||||
"scripting",
|
"scripting",
|
||||||
|
"activeTab",
|
||||||
"webRequest",
|
"webRequest",
|
||||||
"declarativeNetRequest"
|
"declarativeNetRequest"
|
||||||
],
|
],
|
||||||
|
9
src/pages/install/App.tsx
Normal file
9
src/pages/install/App.tsx
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
function App() {
|
||||||
|
return (
|
||||||
|
<div className="h-full">
|
||||||
|
<p className="text-lg">aa</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App;
|
468
src/pages/install/description.tsx
Normal file
468
src/pages/install/description.tsx
Normal file
@ -0,0 +1,468 @@
|
|||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import {
|
||||||
|
Avatar,
|
||||||
|
Button,
|
||||||
|
Grid,
|
||||||
|
Message,
|
||||||
|
Space,
|
||||||
|
Switch,
|
||||||
|
Tag,
|
||||||
|
Tooltip,
|
||||||
|
Typography,
|
||||||
|
} from "@arco-design/web-react";
|
||||||
|
import ScriptController from "@App/app/service/script/controller";
|
||||||
|
import {
|
||||||
|
prepareScriptByCode,
|
||||||
|
prepareSubscribeByCode,
|
||||||
|
ScriptInfo,
|
||||||
|
} from "@App/pkg/utils/script";
|
||||||
|
import {
|
||||||
|
Metadata,
|
||||||
|
Script,
|
||||||
|
SCRIPT_STATUS_DISABLE,
|
||||||
|
SCRIPT_STATUS_ENABLE,
|
||||||
|
} from "@App/app/repo/scripts";
|
||||||
|
import { nextTime } from "@App/pkg/utils/utils";
|
||||||
|
import IoC from "@App/app/ioc";
|
||||||
|
import { Subscribe, SUBSCRIBE_STATUS_ENABLE } from "@App/app/repo/subscribe";
|
||||||
|
import SubscribeController from "@App/app/service/subscribe/controller";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { i18nDescription, i18nName } from "@App/locales/locales";
|
||||||
|
import CodeEditor from "../components/CodeEditor";
|
||||||
|
|
||||||
|
type Permission = { label: string; color?: string; value: string[] }[];
|
||||||
|
|
||||||
|
const closeWindow = () => {
|
||||||
|
window.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function Description() {
|
||||||
|
const [permission, setPermission] = useState<Permission>([]);
|
||||||
|
const [metadata, setMetadata] = useState<Metadata>({});
|
||||||
|
// 脚本信息包括脚本代码、下载url,但是不包括解析代码后得到的metadata,通过background的缓存获取
|
||||||
|
const [info, setInfo] = useState<ScriptInfo>();
|
||||||
|
// 对脚本详细的描述
|
||||||
|
const [description, setDescription] = useState<any>();
|
||||||
|
// 是系统检测到脚本更新时打开的窗口会有一个倒计时
|
||||||
|
const [countdown, setCountdown] = useState<number>(-1);
|
||||||
|
// 是否为更新
|
||||||
|
const [isUpdate, setIsUpdate] = useState<boolean>(false);
|
||||||
|
// 脚本信息
|
||||||
|
const [upsertScript, setUpsertScript] = useState<Script | Subscribe>();
|
||||||
|
// 更新的情况下会有老版本的脚本信息
|
||||||
|
const [oldScript, setOldScript] = useState<Script | Subscribe>();
|
||||||
|
// 脚本开启状态
|
||||||
|
const [enable, setEnable] = useState<boolean>(false);
|
||||||
|
const scriptCtrl = IoC.instance(ScriptController) as ScriptController;
|
||||||
|
const subscribeCtrl = IoC.instance(
|
||||||
|
SubscribeController
|
||||||
|
) as SubscribeController;
|
||||||
|
const [isSub, setIsSub] = useState<boolean>(false);
|
||||||
|
// 按钮文案
|
||||||
|
const [btnText, setBtnText] = useState<string>();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
// 不推荐的内容标签与描述
|
||||||
|
const antifeatures: {
|
||||||
|
[key: string]: { color: string; title: string; description: string };
|
||||||
|
} = {
|
||||||
|
"referral-link": {
|
||||||
|
color: "purple",
|
||||||
|
title: t("antifeature_referral_link_title"),
|
||||||
|
description: t("antifeature_referral_link_description"),
|
||||||
|
},
|
||||||
|
ads: {
|
||||||
|
color: "orange",
|
||||||
|
title: t("antifeature_ads_title"),
|
||||||
|
description: t("antifeature_ads_description"),
|
||||||
|
},
|
||||||
|
payment: {
|
||||||
|
color: "magenta",
|
||||||
|
title: t("antifeature_payment_title"),
|
||||||
|
description: t("antifeature_payment_description"),
|
||||||
|
},
|
||||||
|
miner: {
|
||||||
|
color: "orangered",
|
||||||
|
title: t("antifeature_miner_title"),
|
||||||
|
description: t("antifeature_miner_description"),
|
||||||
|
},
|
||||||
|
membership: {
|
||||||
|
color: "blue",
|
||||||
|
title: t("antifeature_membership_title"),
|
||||||
|
description: t("antifeature_membership_description"),
|
||||||
|
},
|
||||||
|
tracking: {
|
||||||
|
color: "pinkpurple",
|
||||||
|
title: t("antifeature_tracking_title"),
|
||||||
|
description: t("antifeature_tracking_description"),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isSub) {
|
||||||
|
setBtnText(isUpdate ? t("update_subscribe")! : t("install_subscribe")!);
|
||||||
|
} else {
|
||||||
|
setBtnText(isUpdate ? t("update_script")! : t("install_script")!);
|
||||||
|
}
|
||||||
|
}, [isSub, isUpdate]);
|
||||||
|
useEffect(() => {
|
||||||
|
if (countdown === -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setTimeout(() => {
|
||||||
|
setCountdown((time) => {
|
||||||
|
if (time > 0) {
|
||||||
|
return time - 1;
|
||||||
|
}
|
||||||
|
if (time === 0) {
|
||||||
|
closeWindow();
|
||||||
|
}
|
||||||
|
return time;
|
||||||
|
});
|
||||||
|
}, 1000);
|
||||||
|
}, [countdown]);
|
||||||
|
|
||||||
|
const url = new URL(window.location.href);
|
||||||
|
const uuid = url.searchParams.get("uuid");
|
||||||
|
if (!uuid) {
|
||||||
|
return <p>{t("invalid_link")}</p>;
|
||||||
|
}
|
||||||
|
useEffect(() => {
|
||||||
|
scriptCtrl.fetchScriptInfo(uuid).then(async (resp: ScriptInfo) => {
|
||||||
|
if (!resp) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let prepare:
|
||||||
|
| { script: Script; oldScript?: Script }
|
||||||
|
| { subscribe: Subscribe; oldSubscribe?: Subscribe };
|
||||||
|
let action: Script | Subscribe;
|
||||||
|
if (resp.isSubscribe) {
|
||||||
|
setIsSub(true);
|
||||||
|
prepare = await prepareSubscribeByCode(resp.code, resp.url);
|
||||||
|
action = prepare.subscribe;
|
||||||
|
setOldScript(prepare.oldSubscribe);
|
||||||
|
delete prepare.oldSubscribe;
|
||||||
|
} else {
|
||||||
|
if (resp.isUpdate) {
|
||||||
|
prepare = await prepareScriptByCode(resp.code, resp.url, resp.uuid);
|
||||||
|
} else {
|
||||||
|
prepare = await prepareScriptByCode(resp.code, resp.url);
|
||||||
|
}
|
||||||
|
action = prepare.script;
|
||||||
|
setOldScript(prepare.oldScript);
|
||||||
|
delete prepare.oldScript;
|
||||||
|
}
|
||||||
|
setEnable(action.status === SUBSCRIBE_STATUS_ENABLE);
|
||||||
|
if (resp.source === "system") {
|
||||||
|
setCountdown(60);
|
||||||
|
}
|
||||||
|
const meta = action.metadata;
|
||||||
|
if (!meta) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const perm: Permission = [];
|
||||||
|
if (resp.isSubscribe) {
|
||||||
|
perm.push({
|
||||||
|
label: t("subscribe_install_label"),
|
||||||
|
color: "#ff0000",
|
||||||
|
value: meta.scripturl,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (meta.match) {
|
||||||
|
perm.push({ label: t("script_runs_in"), value: meta.match });
|
||||||
|
}
|
||||||
|
if (meta.connect) {
|
||||||
|
perm.push({
|
||||||
|
label: t("script_has_full_access_to"),
|
||||||
|
color: "#F9925A",
|
||||||
|
value: meta.connect,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (meta.require) {
|
||||||
|
perm.push({ label: t("script_requires"), value: meta.require });
|
||||||
|
}
|
||||||
|
setUpsertScript(action);
|
||||||
|
if (action.id !== 0) {
|
||||||
|
setIsUpdate(true);
|
||||||
|
}
|
||||||
|
setPermission(perm);
|
||||||
|
setMetadata(meta);
|
||||||
|
setInfo(resp);
|
||||||
|
const desList = [];
|
||||||
|
let isCookie = false;
|
||||||
|
metadata.grant?.forEach((val) => {
|
||||||
|
if (val === "GM_cookie") {
|
||||||
|
isCookie = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (isCookie) {
|
||||||
|
desList.push(
|
||||||
|
<Typography.Text type="error" key="cookie">
|
||||||
|
{t("cookie_warning")}
|
||||||
|
</Typography.Text>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (meta.crontab) {
|
||||||
|
desList.push(
|
||||||
|
<Typography.Text key="crontab">
|
||||||
|
{t("scheduled_script_description_1")}
|
||||||
|
</Typography.Text>
|
||||||
|
);
|
||||||
|
desList.push(
|
||||||
|
<Typography.Text key="cronta-nexttime">
|
||||||
|
{t("scheduled_script_description_2", {
|
||||||
|
expression: meta.crontab[0],
|
||||||
|
time: nextTime(meta.crontab[0]),
|
||||||
|
})}
|
||||||
|
</Typography.Text>
|
||||||
|
);
|
||||||
|
} else if (meta.background) {
|
||||||
|
desList.push(
|
||||||
|
<Typography.Text key="background">
|
||||||
|
{t("background_script_description")}
|
||||||
|
</Typography.Text>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (desList.length) {
|
||||||
|
setDescription(<div>{desList.map((item) => item)}</div>);
|
||||||
|
}
|
||||||
|
// 修改网页显示title
|
||||||
|
document.title = `${
|
||||||
|
action.id === 0 ? t("install_script") : t("update_script")
|
||||||
|
} - ${meta.name} - ScriptCat`;
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
return (
|
||||||
|
<div className="h-full">
|
||||||
|
<Grid.Row gutter={8}>
|
||||||
|
<Grid.Col flex={1} className="flex-col p-8px">
|
||||||
|
<Space direction="vertical">
|
||||||
|
<div>
|
||||||
|
{upsertScript?.metadata.icon && (
|
||||||
|
<Avatar size={32} shape="square" style={{ marginRight: "8px" }}>
|
||||||
|
<img
|
||||||
|
src={upsertScript.metadata.icon[0]}
|
||||||
|
alt={upsertScript?.name}
|
||||||
|
/>
|
||||||
|
</Avatar>
|
||||||
|
)}
|
||||||
|
<Typography.Text bold className="text-size-lg">
|
||||||
|
{upsertScript && i18nName(upsertScript)}
|
||||||
|
<Tooltip
|
||||||
|
content={
|
||||||
|
isSub
|
||||||
|
? t("subscribe_source_tooltip")
|
||||||
|
: t("script_status_tooltip")
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Switch
|
||||||
|
style={{ marginLeft: "8px" }}
|
||||||
|
checked={enable}
|
||||||
|
onChange={(checked) => {
|
||||||
|
setUpsertScript((script) => {
|
||||||
|
if (!script) {
|
||||||
|
return script;
|
||||||
|
}
|
||||||
|
script.status = checked
|
||||||
|
? SCRIPT_STATUS_ENABLE
|
||||||
|
: SCRIPT_STATUS_DISABLE;
|
||||||
|
setEnable(checked);
|
||||||
|
return script;
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
</Typography.Text>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Typography.Text bold>
|
||||||
|
{upsertScript && i18nDescription(upsertScript)}
|
||||||
|
</Typography.Text>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Typography.Text bold>
|
||||||
|
{t("author")}: {metadata.author}
|
||||||
|
</Typography.Text>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Typography.Text
|
||||||
|
bold
|
||||||
|
style={{
|
||||||
|
overflowWrap: "break-word",
|
||||||
|
wordBreak: "break-all",
|
||||||
|
maxHeight: "70px",
|
||||||
|
display: "block",
|
||||||
|
overflowY: "auto",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("source")}: {info?.url}
|
||||||
|
</Typography.Text>
|
||||||
|
</div>
|
||||||
|
<div className="text-end">
|
||||||
|
<Space>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
size="small"
|
||||||
|
onClick={() => {
|
||||||
|
if (!upsertScript) {
|
||||||
|
Message.error(t("script_info_load_failed")!);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isSub) {
|
||||||
|
subscribeCtrl
|
||||||
|
.upsert(upsertScript as Subscribe)
|
||||||
|
.then(() => {
|
||||||
|
Message.success(t("subscribe_success")!);
|
||||||
|
setBtnText(t("subscribe_success")!);
|
||||||
|
setTimeout(() => {
|
||||||
|
closeWindow();
|
||||||
|
}, 200);
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
Message.error(`${t("subscribe_failed")}: ${e}`);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
scriptCtrl
|
||||||
|
.upsert(upsertScript as Script)
|
||||||
|
.then(() => {
|
||||||
|
if (isUpdate) {
|
||||||
|
Message.success(t("install.update_success")!);
|
||||||
|
setBtnText(t("install.update_success")!);
|
||||||
|
} else {
|
||||||
|
Message.success(t("install_success")!);
|
||||||
|
setBtnText(t("install_success")!);
|
||||||
|
}
|
||||||
|
setTimeout(() => {
|
||||||
|
closeWindow();
|
||||||
|
}, 200);
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
Message.error(`${t("install_failed")}: ${e}`);
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{btnText}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
status="danger"
|
||||||
|
size="small"
|
||||||
|
onClick={() => {
|
||||||
|
if (countdown === -1) {
|
||||||
|
closeWindow();
|
||||||
|
} else {
|
||||||
|
setCountdown(-1);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{countdown === -1
|
||||||
|
? t("close")
|
||||||
|
: `${t("stop")} (${countdown})`}
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
</Space>
|
||||||
|
</Grid.Col>
|
||||||
|
<Grid.Col flex={1} className="p-8px">
|
||||||
|
<Space direction="vertical">
|
||||||
|
<div>
|
||||||
|
<Space>
|
||||||
|
{oldScript && (
|
||||||
|
<Tooltip
|
||||||
|
content={`${t("current_version")}: v${
|
||||||
|
oldScript.metadata.version[0]
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<Tag bordered>{oldScript.metadata.version[0]}</Tag>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
{metadata.version && (
|
||||||
|
<Tooltip
|
||||||
|
color="red"
|
||||||
|
content={`${t("update_version")}: v${metadata.version[0]}`}
|
||||||
|
>
|
||||||
|
<Tag bordered color="red">
|
||||||
|
{metadata.version[0]}
|
||||||
|
</Tag>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
{(metadata.background || metadata.crontab) && (
|
||||||
|
<Tooltip color="green" content={t("background_script_tag")}>
|
||||||
|
<Tag bordered color="green">
|
||||||
|
{t("background_script")}
|
||||||
|
</Tag>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
{metadata.crontab && (
|
||||||
|
<Tooltip color="green" content={t("scheduled_script_tag")}>
|
||||||
|
<Tag bordered color="green">
|
||||||
|
{t("scheduled_script")}
|
||||||
|
</Tag>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
{metadata.antifeature &&
|
||||||
|
metadata.antifeature.map((antifeature) => {
|
||||||
|
const item = antifeature.split(" ")[0];
|
||||||
|
return (
|
||||||
|
antifeatures[item] && (
|
||||||
|
<Tooltip
|
||||||
|
color={antifeatures[item].color}
|
||||||
|
content={antifeatures[item].description}
|
||||||
|
>
|
||||||
|
<Tag bordered color={antifeatures[item].color}>
|
||||||
|
{antifeatures[item].title}
|
||||||
|
</Tag>
|
||||||
|
</Tooltip>
|
||||||
|
)
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
{description && description}
|
||||||
|
<div>
|
||||||
|
<Typography.Text type="error">
|
||||||
|
{t("install_from_legitimate_sources_warning")}
|
||||||
|
</Typography.Text>
|
||||||
|
</div>
|
||||||
|
</Space>
|
||||||
|
</Grid.Col>
|
||||||
|
<Grid.Col span={24}>
|
||||||
|
<Grid.Row>
|
||||||
|
{permission.map((item) => (
|
||||||
|
<Grid.Col
|
||||||
|
key={item.label}
|
||||||
|
span={8}
|
||||||
|
style={{
|
||||||
|
maxHeight: "200px",
|
||||||
|
overflowY: "auto",
|
||||||
|
overflowX: "auto",
|
||||||
|
boxSizing: "border-box",
|
||||||
|
}}
|
||||||
|
className="p-8px"
|
||||||
|
>
|
||||||
|
<Typography.Text bold color={item.color}>
|
||||||
|
{item.label}
|
||||||
|
</Typography.Text>
|
||||||
|
{item.value.map((v) => (
|
||||||
|
<div key={v}>
|
||||||
|
<Typography.Text
|
||||||
|
style={{ wordBreak: "unset", color: item.color }}
|
||||||
|
>
|
||||||
|
{v}
|
||||||
|
</Typography.Text>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</Grid.Col>
|
||||||
|
))}
|
||||||
|
</Grid.Row>
|
||||||
|
</Grid.Col>
|
||||||
|
</Grid.Row>
|
||||||
|
<CodeEditor
|
||||||
|
id="show-code"
|
||||||
|
code={upsertScript?.code || undefined}
|
||||||
|
diffCode={oldScript?.code || ""}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
30
src/pages/install/index.html
Normal file
30
src/pages/install/index.html
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
|
||||||
|
<title><%= htmlRspackPlugin.options.title %></title>
|
||||||
|
<style>
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
background-color: var(--color-bg-2);
|
||||||
|
color: var(--color-text-1);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
</body>
|
||||||
|
<% if rspackConfig.mode=="script" { %>
|
||||||
|
<script type="text/javascript" src="/_locales/i18n.js"></script>
|
||||||
|
<script type="text/javascript" src="https://cdn.crowdin.com/jipt/jipt.js"></script>
|
||||||
|
<% } %>
|
||||||
|
</html>
|
10
src/pages/install/main.tsx
Normal file
10
src/pages/install/main.tsx
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import React from "react";
|
||||||
|
import ReactDOM from "react-dom/client";
|
||||||
|
import App from "./App.tsx";
|
||||||
|
import "@App/index.css";
|
||||||
|
|
||||||
|
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
|
||||||
|
<React.StrictMode>
|
||||||
|
<App />
|
||||||
|
</React.StrictMode>
|
||||||
|
);
|
9
tailwind.config.js
Normal file
9
tailwind.config.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
/* eslint-disable no-undef */
|
||||||
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
module.exports = {
|
||||||
|
content: ["./src/**/*.{html,tsx}"],
|
||||||
|
theme: {
|
||||||
|
extend: {},
|
||||||
|
},
|
||||||
|
plugins: [],
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user