chore: add relocate jan data folder function to new FE (#5043)
* chore: typo * fix: linter issues * chore: fix linter * chore: fix linter * chore: add relocate data folder
This commit is contained in:
parent
e4168a4c17
commit
6676e0ced8
@ -19,7 +19,7 @@ export abstract class HardwareManagementExtension extends BaseExtension {
|
|||||||
/**
|
/**
|
||||||
* @returns A Promise that resolves to an object of set active gpus.
|
* @returns A Promise that resolves to an object of set active gpus.
|
||||||
*/
|
*/
|
||||||
abstract setAvtiveGpu(data: { gpus: number[] }): Promise<{
|
abstract setActiveGpu(data: { gpus: number[] }): Promise<{
|
||||||
message: string
|
message: string
|
||||||
activated_gpus: number[]
|
activated_gpus: number[]
|
||||||
}>
|
}>
|
||||||
|
|||||||
@ -51,7 +51,7 @@ export default class JSONHardwareManagementExtension extends HardwareManagementE
|
|||||||
/**
|
/**
|
||||||
* @returns A Promise that resolves to an object of set gpu activate.
|
* @returns A Promise that resolves to an object of set gpu activate.
|
||||||
*/
|
*/
|
||||||
async setAvtiveGpu(data: { gpus: number[] }): Promise<{
|
async setActiveGpu(data: { gpus: number[] }): Promise<{
|
||||||
message: string
|
message: string
|
||||||
activated_gpus: number[]
|
activated_gpus: number[]
|
||||||
}> {
|
}> {
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "yarn workspace jan lint && yarn workspace @janhq/web lint",
|
"lint": "yarn workspace @janhq/web-app lint",
|
||||||
"test:unit": "jest",
|
"test:unit": "jest",
|
||||||
"test:coverage": "yarn workspace @janhq/web-app test",
|
"test:coverage": "yarn workspace @janhq/web-app test",
|
||||||
"test": "yarn workspace @janhq/web-app test",
|
"test": "yarn workspace @janhq/web-app test",
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{fs, path::PathBuf};
|
use std::{fs, path::PathBuf, io};
|
||||||
use tauri::{AppHandle, Manager, Runtime, State};
|
use tauri::{AppHandle, Manager, Runtime, State};
|
||||||
|
|
||||||
use super::{server, setup, state::AppState};
|
use super::{server, setup, state::AppState};
|
||||||
@ -267,6 +267,65 @@ pub fn get_user_home_path(app: AppHandle) -> String {
|
|||||||
return get_app_configurations(app.clone()).data_folder;
|
return get_app_configurations(app.clone()).data_folder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Recursively copy a directory from src to dst
|
||||||
|
fn copy_dir_recursive(src: &PathBuf, dst: &PathBuf) -> Result<(), io::Error> {
|
||||||
|
if !dst.exists() {
|
||||||
|
fs::create_dir_all(dst)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
for entry in fs::read_dir(src)? {
|
||||||
|
let entry = entry?;
|
||||||
|
let file_type = entry.file_type()?;
|
||||||
|
let src_path = entry.path();
|
||||||
|
let dst_path = dst.join(entry.file_name());
|
||||||
|
|
||||||
|
if file_type.is_dir() {
|
||||||
|
copy_dir_recursive(&src_path, &dst_path)?;
|
||||||
|
} else {
|
||||||
|
fs::copy(&src_path, &dst_path)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub fn change_app_data_folder(
|
||||||
|
app_handle: tauri::AppHandle,
|
||||||
|
new_data_folder: String,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
// Get current data folder path
|
||||||
|
let current_data_folder = get_jan_data_folder_path(app_handle.clone());
|
||||||
|
let new_data_folder_path = PathBuf::from(&new_data_folder);
|
||||||
|
|
||||||
|
// Create the new data folder if it doesn't exist
|
||||||
|
if !new_data_folder_path.exists() {
|
||||||
|
fs::create_dir_all(&new_data_folder_path)
|
||||||
|
.map_err(|e| format!("Failed to create new data folder: {}", e))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy all files from the old folder to the new one
|
||||||
|
if current_data_folder.exists() {
|
||||||
|
log::info!(
|
||||||
|
"Copying data from {:?} to {:?}",
|
||||||
|
current_data_folder,
|
||||||
|
new_data_folder_path
|
||||||
|
);
|
||||||
|
|
||||||
|
copy_dir_recursive(¤t_data_folder, &new_data_folder_path)
|
||||||
|
.map_err(|e| format!("Failed to copy data to new folder: {}", e))?;
|
||||||
|
} else {
|
||||||
|
log::info!("Current data folder does not exist, nothing to copy");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the configuration to point to the new folder
|
||||||
|
let mut configuration = get_app_configurations(app_handle.clone());
|
||||||
|
configuration.data_folder = new_data_folder;
|
||||||
|
|
||||||
|
// Save the updated configuration
|
||||||
|
update_app_configuration(app_handle, configuration)
|
||||||
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn app_token(state: State<'_, AppState>) -> Option<String> {
|
pub fn app_token(state: State<'_, AppState>) -> Option<String> {
|
||||||
state.app_token.clone()
|
state.app_token.clone()
|
||||||
|
|||||||
@ -46,6 +46,7 @@ pub fn run() {
|
|||||||
core::cmd::start_server,
|
core::cmd::start_server,
|
||||||
core::cmd::stop_server,
|
core::cmd::stop_server,
|
||||||
core::cmd::read_logs,
|
core::cmd::read_logs,
|
||||||
|
core::cmd::change_app_data_folder,
|
||||||
// MCP commands
|
// MCP commands
|
||||||
core::mcp::get_tools,
|
core::mcp::get_tools,
|
||||||
core::mcp::call_tool,
|
core::mcp::call_tool,
|
||||||
|
|||||||
@ -20,7 +20,6 @@ export default function LanguageSwitcher() {
|
|||||||
|
|
||||||
const changeLanguage = (lng: string) => {
|
const changeLanguage = (lng: string) => {
|
||||||
i18n.changeLanguage(lng)
|
i18n.changeLanguage(lng)
|
||||||
// @ts-ignore
|
|
||||||
setCurrentLanguage(lng as Language)
|
setCurrentLanguage(lng as Language)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -41,7 +41,6 @@ export function ModelSetting({ model, provider }: ModelSettingProps) {
|
|||||||
[key]: {
|
[key]: {
|
||||||
...(model.settings?.[key] != null ? model.settings?.[key] : {}),
|
...(model.settings?.[key] != null ? model.settings?.[key] : {}),
|
||||||
controller_props: {
|
controller_props: {
|
||||||
// @ts-ignore
|
|
||||||
...(model.settings?.[key]?.controller_props ?? {}),
|
...(model.settings?.[key]?.controller_props ?? {}),
|
||||||
value: value,
|
value: value,
|
||||||
},
|
},
|
||||||
@ -67,7 +66,6 @@ export function ModelSetting({ model, provider }: ModelSettingProps) {
|
|||||||
updateModel({
|
updateModel({
|
||||||
id: model.id,
|
id: model.id,
|
||||||
settings: Object.entries(updatedModel.settings).map(([key, value]) => ({
|
settings: Object.entries(updatedModel.settings).map(([key, value]) => ({
|
||||||
// @ts-ignore
|
|
||||||
[key]: value.controller_props?.value,
|
[key]: value.controller_props?.value,
|
||||||
})) as ModelSettingParams,
|
})) as ModelSettingParams,
|
||||||
})
|
})
|
||||||
|
|||||||
@ -8,8 +8,8 @@ import {
|
|||||||
// Dropdown component
|
// Dropdown component
|
||||||
type DropdownControlProps = {
|
type DropdownControlProps = {
|
||||||
value: string
|
value: string
|
||||||
options?: Array<{ value: string; name: string }>
|
options?: Array<{ value: number | string; name: string }>
|
||||||
onChange: (value: string) => void
|
onChange: (value: number | string) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DropdownControl({
|
export function DropdownControl({
|
||||||
|
|||||||
@ -10,12 +10,12 @@ type DynamicControllerProps = {
|
|||||||
title?: string
|
title?: string
|
||||||
className?: string
|
className?: string
|
||||||
description?: string
|
description?: string
|
||||||
controllerType: 'input' | 'checkbox' | 'dropdown' | 'textarea' | 'slider'
|
controllerType: 'input' | 'checkbox' | 'dropdown' | 'textarea' | 'slider' | string
|
||||||
controllerProps: {
|
controllerProps: {
|
||||||
value?: string | boolean | number
|
value?: string | boolean | number
|
||||||
placeholder?: string
|
placeholder?: string
|
||||||
type?: string
|
type?: string
|
||||||
options?: Array<{ value: string; name: string }>
|
options?: Array<{ value: number | string; name: string }>
|
||||||
input_actions?: string[]
|
input_actions?: string[]
|
||||||
rows?: number
|
rows?: number
|
||||||
min?: number
|
min?: number
|
||||||
|
|||||||
@ -3,11 +3,9 @@ import { persist, createJSONStorage } from 'zustand/middleware'
|
|||||||
import { localStorageKey } from '@/constants/localStorage'
|
import { localStorageKey } from '@/constants/localStorage'
|
||||||
|
|
||||||
type LeftPanelStoreState = {
|
type LeftPanelStoreState = {
|
||||||
// @ts-ignore
|
|
||||||
currentLanguage: Language
|
currentLanguage: Language
|
||||||
spellCheckChatInput: boolean
|
spellCheckChatInput: boolean
|
||||||
setSpellCheckChatInput: (value: boolean) => void
|
setSpellCheckChatInput: (value: boolean) => void
|
||||||
// @ts-ignore
|
|
||||||
setCurrentLanguage: (value: Language) => void
|
setCurrentLanguage: (value: Language) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -182,7 +182,7 @@ export const useHardware = create<HardwareStore>()(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
setActiveGpus({
|
setActiveGpus({
|
||||||
gpus: newGPUs.filter((e) => e.activated).map((e) => e.id as unknown as number),
|
gpus: newGPUs.filter((e) => e.activated).map((e) => parseInt(e.id)),
|
||||||
})
|
})
|
||||||
return {
|
return {
|
||||||
hardwareData: {
|
hardwareData: {
|
||||||
|
|||||||
@ -283,8 +283,7 @@ export const postMessageProcessing = async (
|
|||||||
? JSON.parse(toolCall.function.arguments)
|
? JSON.parse(toolCall.function.arguments)
|
||||||
: {},
|
: {},
|
||||||
})
|
})
|
||||||
// @ts-ignore
|
if ('error' in result && result.error) break
|
||||||
if (result.error) break
|
|
||||||
|
|
||||||
message.metadata = {
|
message.metadata = {
|
||||||
...(message.metadata ?? {}),
|
...(message.metadata ?? {}),
|
||||||
@ -300,7 +299,6 @@ export const postMessageProcessing = async (
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
// @ts-ignore
|
|
||||||
builder.addToolMessage(result.content[0]?.text ?? '', toolCall.id)
|
builder.addToolMessage(result.content[0]?.text ?? '', toolCall.id)
|
||||||
// update message metadata
|
// update message metadata
|
||||||
return message
|
return message
|
||||||
|
|||||||
@ -27,6 +27,7 @@ export const AppRoutes = [
|
|||||||
'restartMcpServers',
|
'restartMcpServers',
|
||||||
'getConnectedServers',
|
'getConnectedServers',
|
||||||
'readLogs',
|
'readLogs',
|
||||||
|
'changeAppDataFolder',
|
||||||
]
|
]
|
||||||
// Define API routes based on different route types
|
// Define API routes based on different route types
|
||||||
export const Routes = [...CoreRoutes, ...APIRoutes, ...AppRoutes].map((r) => ({
|
export const Routes = [...CoreRoutes, ...APIRoutes, ...AppRoutes].map((r) => ({
|
||||||
|
|||||||
@ -21,7 +21,11 @@ import {
|
|||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
} from '@/components/ui/dialog'
|
} from '@/components/ui/dialog'
|
||||||
import { factoryReset, getJanDataFolder } from '@/services/app'
|
import {
|
||||||
|
factoryReset,
|
||||||
|
getJanDataFolder,
|
||||||
|
relocateJanDataFolder,
|
||||||
|
} from '@/services/app'
|
||||||
import { IconFolder } from '@tabler/icons-react'
|
import { IconFolder } from '@tabler/icons-react'
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
@ -115,6 +119,8 @@ function General() {
|
|||||||
if (selectedPath === janDataFolder) return
|
if (selectedPath === janDataFolder) return
|
||||||
if (selectedPath !== null) {
|
if (selectedPath !== null) {
|
||||||
setJanDataFolder(selectedPath)
|
setJanDataFolder(selectedPath)
|
||||||
|
await relocateJanDataFolder(selectedPath)
|
||||||
|
window.core?.api?.relaunch()
|
||||||
// TODO: we need function to move everything into new folder selectedPath
|
// TODO: we need function to move everything into new folder selectedPath
|
||||||
// eg like this
|
// eg like this
|
||||||
// await window.core?.api?.moveDataFolder(selectedPath)
|
// await window.core?.api?.moveDataFolder(selectedPath)
|
||||||
|
|||||||
@ -64,3 +64,12 @@ export const getJanDataFolder = async (): Promise<string | undefined> => {
|
|||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description This function is used to relocate the Jan data folder.
|
||||||
|
* It will change the app data folder to the specified path.
|
||||||
|
* @param path The new path for the Jan data folder
|
||||||
|
*/
|
||||||
|
export const relocateJanDataFolder = async (path: string) => {
|
||||||
|
window.core?.api?.changeAppDataFolder({ newDataFolder: path })
|
||||||
|
}
|
||||||
|
|||||||
@ -36,7 +36,7 @@ export const setActiveGpus = async (data: { gpus: number[] }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await extension.setAvtiveGpu(data)
|
const response = await extension.setActiveGpu(data)
|
||||||
return response
|
return response
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to install engine variant:', error)
|
console.error('Failed to install engine variant:', error)
|
||||||
|
|||||||
@ -36,6 +36,6 @@ export const getConnectedServers = (): Promise<string[]> => {
|
|||||||
export const callTool = (args: {
|
export const callTool = (args: {
|
||||||
toolName: string
|
toolName: string
|
||||||
arguments: object
|
arguments: object
|
||||||
}): Promise<unknown> => {
|
}): Promise<{ error: string; content: { text: string }[] }> => {
|
||||||
return window.core?.api?.callTool(args)
|
return window.core?.api?.callTool(args)
|
||||||
}
|
}
|
||||||
|
|||||||
1
web-app/src/types/app.d.ts
vendored
Normal file
1
web-app/src/types/app.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
type Language = 'en' | 'id' | 'vn'
|
||||||
21
web-app/src/types/global.d.ts
vendored
21
web-app/src/types/global.d.ts
vendored
@ -1,23 +1,22 @@
|
|||||||
import { ExtensionManager } from '@/lib/extension'
|
export {}
|
||||||
|
|
||||||
type Language = 'en' | 'id' | 'vn'
|
|
||||||
declare module 'react-syntax-highlighter-virtualized-renderer'
|
declare module 'react-syntax-highlighter-virtualized-renderer'
|
||||||
|
|
||||||
type AppCore = {
|
type AppCore = {
|
||||||
api: APIs
|
api: APIs
|
||||||
extensionManager: ExtensionManager | undefined
|
extensionManager: ExtensionManager | undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
declare const IS_TAURI: boolean
|
||||||
|
declare const IS_MACOS: boolean
|
||||||
|
declare const IS_WINDOWS: boolean
|
||||||
|
declare const IS_LINUX: boolean
|
||||||
|
declare const IS_IOS: boolean
|
||||||
|
declare const IS_ANDROID: boolean
|
||||||
|
declare const PLATFORM: string
|
||||||
|
declare const VERSION: string
|
||||||
interface Window {
|
interface Window {
|
||||||
core: AppCore | undefined
|
core: AppCore | undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
let IS_TAURI: boolean
|
|
||||||
let IS_MACOS: boolean
|
|
||||||
let IS_WINDOWS: boolean
|
|
||||||
let IS_LINUX: boolean
|
|
||||||
let IS_IOS: boolean
|
|
||||||
let IS_ANDROID: boolean
|
|
||||||
let PLATFORM: string
|
|
||||||
let VERSION: string
|
|
||||||
}
|
}
|
||||||
6
web-app/src/types/modelProviders.d.ts
vendored
6
web-app/src/types/modelProviders.d.ts
vendored
@ -5,7 +5,7 @@ type ControllerProps = {
|
|||||||
value?: string | boolean | number
|
value?: string | boolean | number
|
||||||
placeholder?: string
|
placeholder?: string
|
||||||
type?: string
|
type?: string
|
||||||
options?: Array<{ value: string; name: string }>
|
options?: Array<{ value: number | string; name: string }>
|
||||||
input_actions?: string[]
|
input_actions?: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ type ProviderSetting = {
|
|||||||
key: string
|
key: string
|
||||||
title: string
|
title: string
|
||||||
description: string
|
description: string
|
||||||
controller_type: 'input' | 'checkbox' | 'dropdown' | 'slider'
|
controller_type: 'input' | 'checkbox' | 'dropdown' | 'slider' | string
|
||||||
controller_props: ControllerProps
|
controller_props: ControllerProps
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ type Model = {
|
|||||||
description?: string
|
description?: string
|
||||||
format?: string
|
format?: string
|
||||||
capabilities?: string[]
|
capabilities?: string[]
|
||||||
settings?: Record<string, unknown>
|
settings?: Record<string, ProviderSetting>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user