Merge pull request #5386 from ConnectAI-E/feature/safeLocalStorage

fix: safaLocalStorage
This commit is contained in:
Dogtiti 2024-09-09 16:48:25 +08:00 committed by GitHub
commit 35f77f45a2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 96 additions and 26 deletions

View File

@ -67,6 +67,7 @@ import {
isVisionModel, isVisionModel,
isDalle3, isDalle3,
showPlugins, showPlugins,
safeLocalStorage,
} from "../utils"; } from "../utils";
import { uploadImage as uploadImageRemote } from "@/app/utils/chat"; import { uploadImage as uploadImageRemote } from "@/app/utils/chat";
@ -109,6 +110,8 @@ import { getClientConfig } from "../config/client";
import { useAllModels } from "../utils/hooks"; import { useAllModels } from "../utils/hooks";
import { MultimodalContent } from "../client/api"; import { MultimodalContent } from "../client/api";
const localStorage = safeLocalStorage();
const Markdown = dynamic(async () => (await import("./markdown")).Markdown, { const Markdown = dynamic(async () => (await import("./markdown")).Markdown, {
loading: () => <LoadingIcon />, loading: () => <LoadingIcon />,
}); });
@ -941,7 +944,7 @@ function _Chat() {
.onUserInput(userInput, attachImages) .onUserInput(userInput, attachImages)
.then(() => setIsLoading(false)); .then(() => setIsLoading(false));
setAttachImages([]); setAttachImages([]);
localStorage.setItem(LAST_INPUT_KEY, userInput); chatStore.setLastInput(userInput);
setUserInput(""); setUserInput("");
setPromptHints([]); setPromptHints([]);
if (!isMobileScreen) inputRef.current?.focus(); if (!isMobileScreen) inputRef.current?.focus();
@ -1007,7 +1010,7 @@ function _Chat() {
userInput.length <= 0 && userInput.length <= 0 &&
!(e.metaKey || e.altKey || e.ctrlKey) !(e.metaKey || e.altKey || e.ctrlKey)
) { ) {
setUserInput(localStorage.getItem(LAST_INPUT_KEY) ?? ""); setUserInput(chatStore.lastInput ?? "");
e.preventDefault(); e.preventDefault();
return; return;
} }

View File

@ -8,6 +8,7 @@ import { ISSUE_URL } from "../constant";
import Locale from "../locales"; import Locale from "../locales";
import { showConfirm } from "./ui-lib"; import { showConfirm } from "./ui-lib";
import { useSyncStore } from "../store/sync"; import { useSyncStore } from "../store/sync";
import { useChatStore } from "../store/chat";
interface IErrorBoundaryState { interface IErrorBoundaryState {
hasError: boolean; hasError: boolean;
@ -30,8 +31,7 @@ export class ErrorBoundary extends React.Component<any, IErrorBoundaryState> {
try { try {
useSyncStore.getState().export(); useSyncStore.getState().export();
} finally { } finally {
localStorage.clear(); useChatStore.getState().clearAllData();
location.reload();
} }
} }

View File

@ -426,16 +426,7 @@ export function MaskPage() {
const maskStore = useMaskStore(); const maskStore = useMaskStore();
const chatStore = useChatStore(); const chatStore = useChatStore();
const [filterLang, setFilterLang] = useState<Lang | undefined>( const filterLang = maskStore.language;
() => localStorage.getItem("Mask-language") as Lang | undefined,
);
useEffect(() => {
if (filterLang) {
localStorage.setItem("Mask-language", filterLang);
} else {
localStorage.removeItem("Mask-language");
}
}, [filterLang]);
const allMasks = maskStore const allMasks = maskStore
.getAll() .getAll()
@ -542,9 +533,9 @@ export function MaskPage() {
onChange={(e) => { onChange={(e) => {
const value = e.currentTarget.value; const value = e.currentTarget.value;
if (value === Locale.Settings.Lang.All) { if (value === Locale.Settings.Lang.All) {
setFilterLang(undefined); maskStore.setLanguage(undefined);
} else { } else {
setFilterLang(value as Lang); maskStore.setLanguage(value as Lang);
} }
}} }}
> >

View File

@ -18,10 +18,13 @@ import ar from "./ar";
import bn from "./bn"; import bn from "./bn";
import sk from "./sk"; import sk from "./sk";
import { merge } from "../utils/merge"; import { merge } from "../utils/merge";
import { safeLocalStorage } from "@/app/utils";
import type { LocaleType } from "./cn"; import type { LocaleType } from "./cn";
export type { LocaleType, PartialLocaleType } from "./cn"; export type { LocaleType, PartialLocaleType } from "./cn";
const localStorage = safeLocalStorage();
const ALL_LANGS = { const ALL_LANGS = {
cn, cn,
en, en,
@ -82,17 +85,11 @@ merge(fallbackLang, targetLang);
export default fallbackLang as LocaleType; export default fallbackLang as LocaleType;
function getItem(key: string) { function getItem(key: string) {
try { return localStorage.getItem(key);
return localStorage.getItem(key);
} catch {
return null;
}
} }
function setItem(key: string, value: string) { function setItem(key: string, value: string) {
try { localStorage.setItem(key, value);
localStorage.setItem(key, value);
} catch {}
} }
function getLanguage() { function getLanguage() {

View File

@ -26,9 +26,11 @@ import { nanoid } from "nanoid";
import { createPersistStore } from "../utils/store"; import { createPersistStore } from "../utils/store";
import { collectModelsWithDefaultModel } from "../utils/model"; import { collectModelsWithDefaultModel } from "../utils/model";
import { useAccessStore } from "./access"; import { useAccessStore } from "./access";
import { isDalle3 } from "../utils"; import { isDalle3, safeLocalStorage } from "../utils";
import { indexedDBStorage } from "@/app/utils/indexedDB-storage"; import { indexedDBStorage } from "@/app/utils/indexedDB-storage";
const localStorage = safeLocalStorage();
export type ChatMessageTool = { export type ChatMessageTool = {
id: string; id: string;
index?: number; index?: number;
@ -179,6 +181,7 @@ function fillTemplateWith(input: string, modelConfig: ModelConfig) {
const DEFAULT_CHAT_STATE = { const DEFAULT_CHAT_STATE = {
sessions: [createEmptySession()], sessions: [createEmptySession()],
currentSessionIndex: 0, currentSessionIndex: 0,
lastInput: "",
}; };
export const useChatStore = createPersistStore( export const useChatStore = createPersistStore(
@ -701,6 +704,11 @@ export const useChatStore = createPersistStore(
localStorage.clear(); localStorage.clear();
location.reload(); location.reload();
}, },
setLastInput(lastInput: string) {
set({
lastInput,
});
},
}; };
return methods; return methods;

View File

@ -23,9 +23,12 @@ export type Mask = {
export const DEFAULT_MASK_STATE = { export const DEFAULT_MASK_STATE = {
masks: {} as Record<string, Mask>, masks: {} as Record<string, Mask>,
language: undefined as Lang | undefined,
}; };
export type MaskState = typeof DEFAULT_MASK_STATE; export type MaskState = typeof DEFAULT_MASK_STATE & {
language?: Lang | undefined;
};
export const DEFAULT_MASK_AVATAR = "gpt-bot"; export const DEFAULT_MASK_AVATAR = "gpt-bot";
export const createEmptyMask = () => export const createEmptyMask = () =>
@ -102,6 +105,11 @@ export const useMaskStore = createPersistStore(
search(text: string) { search(text: string) {
return Object.values(get().masks); return Object.values(get().masks);
}, },
setLanguage(language: Lang | undefined) {
set({
language,
});
},
}), }),
{ {
name: StoreKey.Mask, name: StoreKey.Mask,

View File

@ -318,3 +318,63 @@ export function adapter(config: Record<string, unknown>) {
: path; : path;
return fetch(fetchUrl as string, { ...rest, responseType: "text" }); return fetch(fetchUrl as string, { ...rest, responseType: "text" });
} }
export function safeLocalStorage(): {
getItem: (key: string) => string | null;
setItem: (key: string, value: string) => void;
removeItem: (key: string) => void;
clear: () => void;
} {
let storage: Storage | null;
try {
if (typeof window !== "undefined" && window.localStorage) {
storage = window.localStorage;
} else {
storage = null;
}
} catch (e) {
console.error("localStorage is not available:", e);
storage = null;
}
return {
getItem(key: string): string | null {
if (storage) {
return storage.getItem(key);
} else {
console.warn(
`Attempted to get item "${key}" from localStorage, but localStorage is not available.`,
);
return null;
}
},
setItem(key: string, value: string): void {
if (storage) {
storage.setItem(key, value);
} else {
console.warn(
`Attempted to set item "${key}" in localStorage, but localStorage is not available.`,
);
}
},
removeItem(key: string): void {
if (storage) {
storage.removeItem(key);
} else {
console.warn(
`Attempted to remove item "${key}" from localStorage, but localStorage is not available.`,
);
}
},
clear(): void {
if (storage) {
storage.clear();
} else {
console.warn(
"Attempted to clear localStorage, but localStorage is not available.",
);
}
},
};
}

View File

@ -1,5 +1,8 @@
import { StateStorage } from "zustand/middleware"; import { StateStorage } from "zustand/middleware";
import { get, set, del, clear } from "idb-keyval"; import { get, set, del, clear } from "idb-keyval";
import { safeLocalStorage } from "@/app/utils";
const localStorage = safeLocalStorage();
class IndexedDBStorage implements StateStorage { class IndexedDBStorage implements StateStorage {
public async getItem(name: string): Promise<string | null> { public async getItem(name: string): Promise<string | null> {