feat: export old setting

This commit is contained in:
Gabe
2025-09-25 12:53:46 +08:00
parent 393f1a29d5
commit 533a0e2d5b
9 changed files with 79 additions and 25 deletions

6
.env
View File

@@ -11,9 +11,9 @@ REACT_APP_OPTIONSPAGE_DEV=http://localhost:3000/options.html
REACT_APP_LOGOURL=https://fishjar.github.io/kiss-translator/images/logo192.png REACT_APP_LOGOURL=https://fishjar.github.io/kiss-translator/images/logo192.png
REACT_APP_RULESURL=https://fishjar.github.io/kiss-rules/kiss-rules.json REACT_APP_RULESURL=https://fishjar.github.io/kiss-rules/kiss-rules_v2.json
REACT_APP_RULESURL_ON=https://fishjar.github.io/kiss-rules/kiss-rules-on.json REACT_APP_RULESURL_ON=https://fishjar.github.io/kiss-rules/kiss-rules-on_v2.json
REACT_APP_RULESURL_OFF=https://fishjar.github.io/kiss-rules/kiss-rules-off.json REACT_APP_RULESURL_OFF=https://fishjar.github.io/kiss-rules/kiss-rules-off_v2.json
REACT_APP_USERSCRIPT_DOWNLOADURL=https://fishjar.github.io/kiss-translator/kiss-translator.user.js REACT_APP_USERSCRIPT_DOWNLOADURL=https://fishjar.github.io/kiss-translator/kiss-translator.user.js
REACT_APP_USERSCRIPT_IOS_DOWNLOADURL=https://fishjar.github.io/kiss-translator/kiss-translator-ios-safari.user.js REACT_APP_USERSCRIPT_IOS_DOWNLOADURL=https://fishjar.github.io/kiss-translator/kiss-translator-ios-safari.user.js

View File

@@ -7,5 +7,7 @@ export const APP_CONSTS = {
boxID: `${APP_LCNAME}-box`, boxID: `${APP_LCNAME}-box`,
}; };
export const APP_VERSION = process.env.REACT_APP_VERSION.split(".");
export const THEME_LIGHT = "light"; export const THEME_LIGHT = "light";
export const THEME_DARK = "dark"; export const THEME_DARK = "dark";

View File

@@ -1402,4 +1402,9 @@ export const I18N = {
en: `Whether to pre-initialize`, en: `Whether to pre-initialize`,
zh_TW: `是否預初始化`, zh_TW: `是否預初始化`,
}, },
export_old: {
zh: `导出旧版`,
en: `Export old version`,
zh_TW: `匯出舊版`,
},
}; };

View File

@@ -1,16 +1,18 @@
import { APP_NAME } from "./app"; import { APP_NAME, APP_VERSION } from "./app";
export const KV_RULES_KEY = "kiss-rules.json"; export const KV_RULES_KEY = `kiss-rules_v${APP_VERSION[0]}.json`;
export const KV_WORDS_KEY = "kiss-words.json"; export const KV_WORDS_KEY = "kiss-words.json";
export const KV_RULES_SHARE_KEY = "kiss-rules-share.json"; export const KV_RULES_SHARE_KEY = `kiss-rules-share_v${APP_VERSION[0]}.json`;
export const KV_SETTING_KEY = "kiss-setting.json"; export const KV_SETTING_KEY = `kiss-setting_v${APP_VERSION[0]}.json`;
export const KV_SALT_SYNC = "KISS-Translator-SYNC"; export const KV_SALT_SYNC = "KISS-Translator-SYNC";
export const KV_SALT_SHARE = "KISS-Translator-SHARE"; export const KV_SALT_SHARE = "KISS-Translator-SHARE";
export const STOKEY_MSAUTH = `${APP_NAME}_msauth`; export const STOKEY_MSAUTH = `${APP_NAME}_msauth`;
export const STOKEY_BDAUTH = `${APP_NAME}_bdauth`; export const STOKEY_BDAUTH = `${APP_NAME}_bdauth`;
export const STOKEY_SETTING = `${APP_NAME}_setting`; export const STOKEY_SETTING_OLD = `${APP_NAME}_setting`;
export const STOKEY_RULES = `${APP_NAME}_rules`; export const STOKEY_RULES_OLD = `${APP_NAME}_rules`;
export const STOKEY_SETTING = `${APP_NAME}_setting_v${APP_VERSION[0]}`;
export const STOKEY_RULES = `${APP_NAME}_rules_v${APP_VERSION[0]}`;
export const STOKEY_WORDS = `${APP_NAME}_words`; export const STOKEY_WORDS = `${APP_NAME}_words`;
export const STOKEY_SYNC = `${APP_NAME}_sync`; export const STOKEY_SYNC = `${APP_NAME}_sync`;
export const STOKEY_FAB = `${APP_NAME}_fab`; export const STOKEY_FAB = `${APP_NAME}_fab`;

View File

@@ -1,4 +1,11 @@
import { createContext, useContext, useState, forwardRef } from "react"; import {
createContext,
useContext,
useState,
forwardRef,
useCallback,
useMemo,
} from "react";
import Snackbar from "@mui/material/Snackbar"; import Snackbar from "@mui/material/Snackbar";
import MuiAlert from "@mui/material/Alert"; import MuiAlert from "@mui/material/Alert";
@@ -18,32 +25,37 @@ export function AlertProvider({ children }) {
const horizontal = "center"; const horizontal = "center";
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [severity, setSeverity] = useState("info"); const [severity, setSeverity] = useState("info");
const [message, setMessage] = useState(""); const [message, setMessage] = useState(null);
const showAlert = (msg, type) => { const showAlert = useCallback((msg, type) => {
setOpen(true); setOpen(true);
setMessage(msg); setMessage(msg);
setSeverity(type); setSeverity(type);
}; }, []);
const handleClose = (_, reason) => { const handleClose = useCallback((_, reason) => {
if (reason === "clickaway") { if (reason === "clickaway") {
return; return;
} }
setOpen(false); setOpen(false);
}; }, []);
const error = (msg) => showAlert(msg, "error"); const value = useMemo(
const warning = (msg) => showAlert(msg, "warning"); () => ({
const info = (msg) => showAlert(msg, "info"); error: (msg) => showAlert(msg, "error"),
const success = (msg) => showAlert(msg, "success"); warning: (msg) => showAlert(msg, "warning"),
info: (msg) => showAlert(msg, "info"),
success: (msg) => showAlert(msg, "success"),
}),
[showAlert]
);
return ( return (
<AlertContext.Provider value={{ error, warning, info, success }}> <AlertContext.Provider value={value}>
{children} {children}
<Snackbar <Snackbar
open={open} open={open}
autoHideDuration={3000} autoHideDuration={10000}
onClose={handleClose} onClose={handleClose}
anchorOrigin={{ vertical, horizontal }} anchorOrigin={{ vertical, horizontal }}
> >

View File

@@ -1,6 +1,8 @@
import { import {
STOKEY_SETTING, STOKEY_SETTING,
STOKEY_SETTING_OLD,
STOKEY_RULES, STOKEY_RULES,
STOKEY_RULES_OLD,
STOKEY_WORDS, STOKEY_WORDS,
STOKEY_FAB, STOKEY_FAB,
STOKEY_SYNC, STOKEY_SYNC,
@@ -60,7 +62,12 @@ async function trySetObj(key, obj) {
async function getObj(key) { async function getObj(key) {
const val = await get(key); const val = await get(key);
return val && JSON.parse(val); try {
return JSON.parse(val);
} catch (err) {
kissLog("parse json: ", key);
}
return null;
} }
async function putObj(key, obj) { async function putObj(key, obj) {
@@ -86,6 +93,7 @@ export const storage = {
* 设置信息 * 设置信息
*/ */
export const getSetting = () => getObj(STOKEY_SETTING); export const getSetting = () => getObj(STOKEY_SETTING);
export const getSettingOld = () => getObj(STOKEY_SETTING_OLD);
export const getSettingWithDefault = async () => ({ export const getSettingWithDefault = async () => ({
...DEFAULT_SETTING, ...DEFAULT_SETTING,
...((await getSetting()) || {}), ...((await getSetting()) || {}),
@@ -97,6 +105,7 @@ export const putSetting = (obj) => putObj(STOKEY_SETTING, obj);
* 规则列表 * 规则列表
*/ */
export const getRules = () => getObj(STOKEY_RULES); export const getRules = () => getObj(STOKEY_RULES);
export const getRulesOld = () => getObj(STOKEY_RULES_OLD);
export const getRulesWithDefault = async () => export const getRulesWithDefault = async () =>
(await getRules()) || DEFAULT_RULES; (await getRules()) || DEFAULT_RULES;
export const setRules = (val) => setObj(STOKEY_RULES, val); export const setRules = (val) => setObj(STOKEY_RULES, val);

View File

@@ -45,7 +45,11 @@ import { loadOrFetchSubRules } from "../../libs/subRules";
import { useAlert } from "../../hooks/Alert"; import { useAlert } from "../../hooks/Alert";
import { syncShareRules } from "../../libs/sync"; import { syncShareRules } from "../../libs/sync";
import { debounce } from "../../libs/utils"; import { debounce } from "../../libs/utils";
import { delSubRules, getSyncWithDefault } from "../../libs/storage"; import {
delSubRules,
getSyncWithDefault,
getRulesOld,
} from "../../libs/storage";
import OwSubRule from "./OwSubRule"; import OwSubRule from "./OwSubRule";
import ClearAllIcon from "@mui/icons-material/ClearAll"; import ClearAllIcon from "@mui/icons-material/ClearAll";
import HelpButton from "./HelpButton"; import HelpButton from "./HelpButton";
@@ -901,6 +905,11 @@ function UserRules({ subRules, rules }) {
text={i18n("export")} text={i18n("export")}
fileName={`kiss-rules_${Date.now()}.json`} fileName={`kiss-rules_${Date.now()}.json`}
/> />
<DownloadButton
handleData={async () => JSON.stringify(await getRulesOld(), null, 2)}
text={i18n("export_old")}
fileName={`kiss-rules_v1_${Date.now()}.json`}
/>
<ShareButton <ShareButton
rules={rules} rules={rules}
@@ -979,6 +988,7 @@ function SubRulesItem({
deleteDataCache, deleteDataCache,
}) { }) {
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const alert = useAlert();
const handleDel = async () => { const handleDel = async () => {
try { try {
@@ -1000,6 +1010,12 @@ function SubRulesItem({
await updateDataCache(url); await updateDataCache(url);
} catch (err) { } catch (err) {
kissLog("sync sub rules", err); kissLog("sync sub rules", err);
alert.error(
<>
<p>Sync Error:</p>
<pre>{err.message}</pre>
</>
);
} finally { } finally {
setLoading(false); setLoading(false);
} }

View File

@@ -32,6 +32,7 @@ import { sendBgMsg } from "../../libs/msg";
import { kissLog } from "../../libs/log"; import { kissLog } from "../../libs/log";
import UploadButton from "./UploadButton"; import UploadButton from "./UploadButton";
import DownloadButton from "./DownloadButton"; import DownloadButton from "./DownloadButton";
import { getSettingOld } from "../../libs/storage";
function ShortcutItem({ action, label }) { function ShortcutItem({ action, label }) {
const { shortcut, setShortcut } = useShortcut(action); const { shortcut, setShortcut } = useShortcut(action);
@@ -137,6 +138,13 @@ export default function Settings() {
text={i18n("export")} text={i18n("export")}
fileName={`kiss-setting_${Date.now()}.json`} fileName={`kiss-setting_${Date.now()}.json`}
/> />
<DownloadButton
handleData={async () =>
JSON.stringify(await getSettingOld(), null, 2)
}
text={i18n("export_old")}
fileName={`kiss-setting_v1_${Date.now()}.json`}
/>
</Stack> </Stack>
<Box> <Box>

View File

@@ -189,7 +189,7 @@ export default function SyncSetting() {
</LoadingButton> </LoadingButton>
<Button <Button
size="small" size="small"
variant="contained" variant="outlined"
onClick={handleGenerateShareString} onClick={handleGenerateShareString}
startIcon={<ContentCopyIcon />} startIcon={<ContentCopyIcon />}
> >
@@ -198,7 +198,7 @@ export default function SyncSetting() {
<Button <Button
onClick={handleImportFromClipboard} onClick={handleImportFromClipboard}
size="small" size="small"
variant="contained" variant="outlined"
startIcon={<ContentPasteIcon />} startIcon={<ContentPasteIcon />}
> >
{i18n("import", "import")} {i18n("import", "import")}