Merge pull request #5035 from menloresearch/chore/data-folder

chore: show location data folder and ui for let user change folder
This commit is contained in:
Faisal Amir 2025-05-20 14:42:21 +07:00 committed by GitHub
commit c4d32c72d1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 78 additions and 9 deletions

View File

@ -44,6 +44,7 @@ uuid = { version = "1.7", features = ["v4"] }
env = "1.0.1" env = "1.0.1"
futures-util = "0.3.31" futures-util = "0.3.31"
tokio-util = "0.7.14" tokio-util = "0.7.14"
tauri-plugin-dialog = "2.2.1"
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] [target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
tauri-plugin-updater = "2" tauri-plugin-updater = "2"

View File

@ -16,6 +16,7 @@
"core:window:allow-set-focus", "core:window:allow-set-focus",
"os:default", "os:default",
"log:default", "log:default",
"dialog:default",
"core:webview:allow-create-webview-window", "core:webview:allow-create-webview-window",
{ {
"identifier": "http:default", "identifier": "http:default",

View File

@ -16,6 +16,7 @@ use reqwest::blocking::Client;
pub fn run() { pub fn run() {
tauri::Builder::default() tauri::Builder::default()
.plugin(tauri_plugin_os::init()) .plugin(tauri_plugin_os::init())
.plugin(tauri_plugin_dialog::init())
.plugin(tauri_plugin_http::init()) .plugin(tauri_plugin_http::init())
.plugin(tauri_plugin_store::Builder::new().build()) .plugin(tauri_plugin_store::Builder::new().build())
.plugin(tauri_plugin_shell::init()) .plugin(tauri_plugin_shell::init())

View File

@ -30,6 +30,7 @@
"@tanstack/react-router": "^1.116.0", "@tanstack/react-router": "^1.116.0",
"@tanstack/react-router-devtools": "^1.116.0", "@tanstack/react-router-devtools": "^1.116.0",
"@tauri-apps/api": "^2.5.0", "@tauri-apps/api": "^2.5.0",
"@tauri-apps/plugin-dialog": "^2.2.1",
"@tauri-apps/plugin-os": "^2.2.1", "@tauri-apps/plugin-os": "^2.2.1",
"@types/react-syntax-highlighter": "^15.5.13", "@types/react-syntax-highlighter": "^15.5.13",
"@types/uuid": "^10.0.0", "@types/uuid": "^10.0.0",

View File

@ -8,6 +8,9 @@ import { Card, CardItem } from '@/containers/Card'
import LanguageSwitcher from '@/containers/LanguageSwitcher' import LanguageSwitcher from '@/containers/LanguageSwitcher'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useGeneralSetting } from '@/hooks/useGeneralSetting' import { useGeneralSetting } from '@/hooks/useGeneralSetting'
import { useEffect, useState } from 'react'
import { open } from '@tauri-apps/plugin-dialog'
import { import {
Dialog, Dialog,
DialogClose, DialogClose,
@ -18,7 +21,8 @@ import {
DialogTitle, DialogTitle,
DialogTrigger, DialogTrigger,
} from '@/components/ui/dialog' } from '@/components/ui/dialog'
import { factoryReset } from '@/services/app' import { factoryReset, getJanDataFolder } from '@/services/app'
import { IconFolder } from '@tabler/icons-react'
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
export const Route = createFileRoute(route.settings.general as any)({ export const Route = createFileRoute(route.settings.general as any)({
@ -28,6 +32,16 @@ export const Route = createFileRoute(route.settings.general as any)({
function General() { function General() {
const { t } = useTranslation() const { t } = useTranslation()
const { spellCheckChatInput, setSpellCheckChatInput } = useGeneralSetting() const { spellCheckChatInput, setSpellCheckChatInput } = useGeneralSetting()
const [janDataFolder, setJanDataFolder] = useState<string | undefined>()
useEffect(() => {
const fetchDataFolder = async () => {
const path = await getJanDataFolder()
setJanDataFolder(path)
}
fetchDataFolder()
}, [])
const resetApp = async () => { const resetApp = async () => {
// TODO: Loading indicator // TODO: Loading indicator
@ -71,10 +85,47 @@ function General() {
title={t('settings.dataFolder.appData', { title={t('settings.dataFolder.appData', {
ns: 'settings', ns: 'settings',
})} })}
description={t('settings.dataFolder.appDataDesc', { align="start"
description={
<>
<span>
{t('settings.dataFolder.appDataDesc', {
ns: 'settings', ns: 'settings',
})} })}
actions={<></>} </span>
<span
title={janDataFolder}
className="bg-main-view-fg/10 text-xs mt-1 px-1 py-0.5 rounded-sm text-main-view-fg/80 line-clamp-1"
>
{janDataFolder}
</span>
</>
}
actions={
<Button
variant="link"
size="sm"
className="hover:no-underline"
onClick={async () => {
const selectedPath = await open({
multiple: false,
directory: true,
defaultPath: janDataFolder,
})
if (selectedPath === janDataFolder) return
if (selectedPath !== null) {
setJanDataFolder(selectedPath)
// TODO: we need function to move everything into new folder selectedPath
// eg like this
// await window.core?.api?.moveDataFolder(selectedPath)
}
}}
>
<div className="size-6 cursor-pointer flex items-center justify-center rounded hover:bg-main-view-fg/15 bg-main-view-fg/10 transition-all duration-200 ease-in-out">
<IconFolder size={18} className="text-main-view-fg/50" />
</div>
</Button>
}
/> />
<CardItem <CardItem
title={t('settings.dataFolder.appLogs', { title={t('settings.dataFolder.appLogs', {

View File

@ -7,10 +7,7 @@ import { invoke } from '@tauri-apps/api/core'
* @returns {Promise<void>} * @returns {Promise<void>}
*/ */
export const factoryReset = async () => { export const factoryReset = async () => {
const appConfiguration: AppConfiguration | undefined = const janDataFolderPath = await getJanDataFolder()
await window.core?.api?.getAppConfigurations()
const janDataFolderPath = appConfiguration?.data_folder
if (janDataFolderPath) await fs.rm(janDataFolderPath) if (janDataFolderPath) await fs.rm(janDataFolderPath)
window.localStorage.clear() window.localStorage.clear()
await window.core?.api?.installExtensions() await window.core?.api?.installExtensions()
@ -50,3 +47,20 @@ export const parseLogLine = (line: string) => {
message, message,
} }
} }
/**
* @description This function is used to get the Jan data folder path.
* It retrieves the path from the app configuration.
* @returns {Promise<string | undefined>} The Jan data folder path or undefined if not found
*/
export const getJanDataFolder = async (): Promise<string | undefined> => {
try {
const appConfiguration: AppConfiguration | undefined =
await window.core?.api?.getAppConfigurations()
return appConfiguration?.data_folder
} catch (error) {
console.error('Failed to get Jan data folder:', error)
return undefined
}
}