diff --git a/app/command.ts b/app/command.ts index e515e5f0bb4..fc349bfe201 100644 --- a/app/command.ts +++ b/app/command.ts @@ -1,6 +1,9 @@ import { useEffect } from "react"; import { useSearchParams } from "react-router-dom"; import Locale from "./locales"; +import { getClientConfig } from "@/app/config/client"; + +const isApp = !!getClientConfig()?.isApp; type Command = (param: string) => void; interface Commands { @@ -37,6 +40,7 @@ interface ChatCommands { newm?: Command; next?: Command; prev?: Command; + restart?: Command; clear?: Command; del?: Command; } @@ -44,6 +48,12 @@ interface ChatCommands { export const ChatCommandPrefix = ":"; export function useChatCommand(commands: ChatCommands = {}) { + const chatCommands = { ...commands }; + + if (!isApp) { + delete chatCommands.restart; + } + function extract(userInput: string) { return ( userInput.startsWith(ChatCommandPrefix) ? userInput.slice(1) : userInput @@ -53,7 +63,7 @@ export function useChatCommand(commands: ChatCommands = {}) { function search(userInput: string) { const input = extract(userInput); const desc = Locale.Chat.Commands; - return Object.keys(commands) + return Object.keys(chatCommands) .filter((c) => c.startsWith(input)) .map((c) => ({ title: desc[c as keyof ChatCommands], @@ -63,11 +73,11 @@ export function useChatCommand(commands: ChatCommands = {}) { function match(userInput: string) { const command = extract(userInput); - const matched = typeof commands[command] === "function"; + const matched = typeof chatCommands[command] === "function"; return { matched, - invoke: () => matched && commands[command]!(userInput), + invoke: () => matched && chatCommands[command]!(userInput), }; } diff --git a/app/components/chat.tsx b/app/components/chat.tsx index cca096eb874..f89a888270d 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -657,6 +657,7 @@ function _Chat() { newm: () => navigate(Path.NewChat), prev: () => chatStore.nextSession(-1), next: () => chatStore.nextSession(1), + restart: () => window.__TAURI__?.process.relaunch(), clear: () => chatStore.updateCurrentSession( (session) => (session.clearContextIndex = session.messages.length), diff --git a/app/components/settings.tsx b/app/components/settings.tsx index 8ed6b77383c..43bc4db7a40 100644 --- a/app/components/settings.tsx +++ b/app/components/settings.tsx @@ -565,6 +565,14 @@ export function Settings() { setCheckingUpdate(true); updateStore.getLatestVersion(force).then(() => { setCheckingUpdate(false); + window.__TAURI__?.updater.checkUpdate().then((updateResult) => { + if (updateResult.status === "DONE") { + window.__TAURI__?.updater.installUpdate(); + } + }).catch((e) => { + console.error("[Check Update Error]", e); + showToast(Locale.Settings.Update.Failed); + }); }); console.log("[Update] local version ", updateStore.version); @@ -683,9 +691,19 @@ export function Settings() { {checkingUpdate ? ( ) : hasNewVersion ? ( - - {Locale.Settings.Update.GoToUpdate} - + <> + {clientConfig?.isApp ? ( + } + text={Locale.Settings.Update.GoToUpdate} + onClick={() => checkUpdate(true)} + /> + ) : ( + + {Locale.Settings.Update.GoToUpdate} + + )} + ) : ( } diff --git a/app/global.d.ts b/app/global.d.ts index e0a2c3f0686..29dc0faf431 100644 --- a/app/global.d.ts +++ b/app/global.d.ts @@ -16,14 +16,31 @@ declare interface Window { invoke(command: string, payload?: Record): Promise; dialog: { save(options?: Record): Promise; + open(options?: OpenDialogOptions): Promise; + // support locale language + message(message: string, options?: string | MessageDialogOptions): Promise; + ask(message: string, options?: string | ConfirmDialogOptions): Promise; }; fs: { writeBinaryFile(path: string, data: Uint8Array): Promise; }; + process: { + relaunch(): Promise; + }; notification:{ requestPermission(): Promise; isPermissionGranted(): Promise; sendNotification(options: string | Options): void; }; + updater: { + checkUpdate(): Promise; + installUpdate(): Promise; + onUpdaterEvent(handler: (status: UpdateStatusResult) => void): Promise; + }; + // can do route in client app like CORS fetch, currently is not enabled yet only module added. + http: { + fetch(url: string, options?: FetchOptions): Promise>; + getClient(options?: ClientOptions): Promise; + }; }; } diff --git a/app/locales/cn.ts b/app/locales/cn.ts index 4cd963fb8e2..84b5f6e77c9 100644 --- a/app/locales/cn.ts +++ b/app/locales/cn.ts @@ -48,6 +48,7 @@ const cn = { newm: "从面具新建聊天", next: "下一个聊天", prev: "上一个聊天", + restart: "重新启动客户端", clear: "清除上下文", del: "删除聊天", }, @@ -167,6 +168,8 @@ const cn = { IsChecking: "正在检查更新...", FoundUpdate: (x: string) => `发现新版本:${x}`, GoToUpdate: "前往更新", + Success: "更新成功。", + Failed: "更新失败。", }, SendKey: "发送键", Theme: "主题", diff --git a/app/locales/en.ts b/app/locales/en.ts index 928c4b72d4e..17992ffa720 100644 --- a/app/locales/en.ts +++ b/app/locales/en.ts @@ -50,6 +50,7 @@ const en: LocaleType = { newm: "Start a new chat with mask", next: "Next Chat", prev: "Previous Chat", + restart: "Restart a client", clear: "Clear Context", del: "Delete Chat", }, @@ -169,6 +170,8 @@ const en: LocaleType = { IsChecking: "Checking update...", FoundUpdate: (x: string) => `Found new version: ${x}`, GoToUpdate: "Update", + Success: "Update Succesfull.", + Failed: "Update Failed.", }, SendKey: "Send Key", Theme: "Theme", diff --git a/app/locales/id.ts b/app/locales/id.ts index b5e4a70b751..9af946f8cdf 100644 --- a/app/locales/id.ts +++ b/app/locales/id.ts @@ -37,6 +37,7 @@ const id: PartialLocaleType = { newm: "Mulai Chat Baru dengan Masks", next: "Chat Selanjutnya", prev: "Chat Sebelumnya", + restart: "Restart klien", clear: "Bersihkan Percakapan", del: "Hapus Chat", }, @@ -156,6 +157,8 @@ const id: PartialLocaleType = { IsChecking: "Memeriksa pembaruan...", FoundUpdate: (x: string) => `Versi terbaru ditemukan: ${x}`, GoToUpdate: "Perbarui Sekarang", + Success: "Pembaruan Berhasil.", + Failed: "Pembaruan Gagal.", }, AutoGenerateTitle: { Title: "Hasilkan Judul Otomatis", diff --git a/app/store/update.ts b/app/store/update.ts index 2b088a13d7a..fb5805a6c1e 100644 --- a/app/store/update.ts +++ b/app/store/update.ts @@ -4,6 +4,7 @@ import { getClientConfig } from "../config/client"; import { createPersistStore } from "../utils/store"; import ChatGptIcon from "../icons/chatgpt.png"; import Locale from "../locales"; +import { showToast } from "../components/ui-lib"; const ONE_MINUTE = 60 * 1000; const isApp = !!getClientConfig()?.isApp; @@ -109,6 +110,15 @@ export const useUpdateStore = createPersistStore( icon: `${ChatGptIcon.src}`, sound: "Default" }); + // this a wild for updating client app + window.__TAURI__?.updater.checkUpdate().then((updateResult) => { + if (updateResult.status === "DONE") { + window.__TAURI__?.updater.installUpdate(); + } + }).catch((e) => { + console.error("[Check Update Error]", e); + showToast(Locale.Settings.Update.Failed); + }); } } }); diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 68f9c07c037..3e90120d420 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -93,7 +93,7 @@ "endpoints": [ "https://github.com/Yidadaa/ChatGPT-Next-Web/releases/latest/download/latest.json" ], - "dialog": false, + "dialog": true, "windows": { "installMode": "passive" },