Merge pull request #1870 from janhq/fix/loader-change-folder
fix: loader show while error global when change folder
This commit is contained in:
commit
0e17f776fe
@ -12,6 +12,7 @@ export enum AppRoute {
|
|||||||
updateAppConfiguration = 'updateAppConfiguration',
|
updateAppConfiguration = 'updateAppConfiguration',
|
||||||
relaunch = 'relaunch',
|
relaunch = 'relaunch',
|
||||||
joinPath = 'joinPath',
|
joinPath = 'joinPath',
|
||||||
|
isSubdirectory = 'isSubdirectory',
|
||||||
baseName = 'baseName',
|
baseName = 'baseName',
|
||||||
startServer = 'startServer',
|
startServer = 'startServer',
|
||||||
stopServer = 'stopServer',
|
stopServer = 'stopServer',
|
||||||
|
|||||||
@ -22,7 +22,11 @@ const executeOnMain: (extension: string, method: string, ...args: any[]) => Prom
|
|||||||
* @param {object} network - Optional object to specify proxy/whether to ignore SSL certificates.
|
* @param {object} network - Optional object to specify proxy/whether to ignore SSL certificates.
|
||||||
* @returns {Promise<any>} A promise that resolves when the file is downloaded.
|
* @returns {Promise<any>} A promise that resolves when the file is downloaded.
|
||||||
*/
|
*/
|
||||||
const downloadFile: (url: string, fileName: string, network?: { proxy?: string, ignoreSSL?: boolean }) => Promise<any> = (url, fileName, network) => {
|
const downloadFile: (
|
||||||
|
url: string,
|
||||||
|
fileName: string,
|
||||||
|
network?: { proxy?: string; ignoreSSL?: boolean }
|
||||||
|
) => Promise<any> = (url, fileName, network) => {
|
||||||
return global.core?.api?.downloadFile(url, fileName, network)
|
return global.core?.api?.downloadFile(url, fileName, network)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,6 +91,17 @@ const getResourcePath: () => Promise<string> = () => global.core.api?.getResourc
|
|||||||
const log: (message: string, fileName?: string) => void = (message, fileName) =>
|
const log: (message: string, fileName?: string) => void = (message, fileName) =>
|
||||||
global.core.api?.log(message, fileName)
|
global.core.api?.log(message, fileName)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the path is a subdirectory of another path.
|
||||||
|
*
|
||||||
|
* @param from - The path to check.
|
||||||
|
* @param to - The path to check against.
|
||||||
|
*
|
||||||
|
* @returns {Promise<boolean>} - A promise that resolves with a boolean indicating whether the path is a subdirectory.
|
||||||
|
*/
|
||||||
|
const isSubdirectory: (from: string, to: string) => Promise<boolean> = (from: string, to: string) =>
|
||||||
|
global.core.api?.isSubdirectory(from, to)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register extension point function type definition
|
* Register extension point function type definition
|
||||||
*/
|
*/
|
||||||
@ -94,7 +109,7 @@ export type RegisterExtensionPoint = (
|
|||||||
extensionName: string,
|
extensionName: string,
|
||||||
extensionId: string,
|
extensionId: string,
|
||||||
method: Function,
|
method: Function,
|
||||||
priority?: number,
|
priority?: number
|
||||||
) => void
|
) => void
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -111,5 +126,6 @@ export {
|
|||||||
openExternalUrl,
|
openExternalUrl,
|
||||||
baseName,
|
baseName,
|
||||||
log,
|
log,
|
||||||
|
isSubdirectory,
|
||||||
FileStat,
|
FileStat,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { app, ipcMain, dialog, shell } from 'electron'
|
import { app, ipcMain, dialog, shell } from 'electron'
|
||||||
import { join, basename } from 'path'
|
import { join, basename, relative as getRelative, isAbsolute } from 'path'
|
||||||
import { WindowManager } from './../managers/window'
|
import { WindowManager } from './../managers/window'
|
||||||
import { getResourcePath } from './../utils/path'
|
import { getResourcePath } from './../utils/path'
|
||||||
import { AppRoute, AppConfiguration } from '@janhq/core'
|
import { AppRoute, AppConfiguration } from '@janhq/core'
|
||||||
@ -50,6 +50,27 @@ export function handleAppIPCs() {
|
|||||||
join(...paths)
|
join(...paths)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given path is a subdirectory of the given directory.
|
||||||
|
*
|
||||||
|
* @param _event - The IPC event object.
|
||||||
|
* @param from - The path to check.
|
||||||
|
* @param to - The directory to check against.
|
||||||
|
*
|
||||||
|
* @returns {Promise<boolean>} - A promise that resolves with the result.
|
||||||
|
*/
|
||||||
|
ipcMain.handle(
|
||||||
|
AppRoute.isSubdirectory,
|
||||||
|
async (_event, from: string, to: string) => {
|
||||||
|
const relative = getRelative(from, to)
|
||||||
|
const isSubdir =
|
||||||
|
relative && !relative.startsWith('..') && !isAbsolute(relative)
|
||||||
|
|
||||||
|
if (isSubdir === '') return false
|
||||||
|
else return isSubdir
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve basename from given path, respect to the current OS.
|
* Retrieve basename from given path, respect to the current OS.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -12,7 +12,8 @@ import TopBar from '@/containers/Layout/TopBar'
|
|||||||
import { MainViewState } from '@/constants/screens'
|
import { MainViewState } from '@/constants/screens'
|
||||||
|
|
||||||
import { useMainViewState } from '@/hooks/useMainViewState'
|
import { useMainViewState } from '@/hooks/useMainViewState'
|
||||||
import { SUCCESS_SET_NEW_DESTINATION } from '@/hooks/useVaultDirectory'
|
|
||||||
|
import { SUCCESS_SET_NEW_DESTINATION } from '@/screens/Settings/Advanced/DataFolder'
|
||||||
|
|
||||||
const BaseLayout = (props: PropsWithChildren) => {
|
const BaseLayout = (props: PropsWithChildren) => {
|
||||||
const { children } = props
|
const { children } = props
|
||||||
|
|||||||
@ -1,87 +0,0 @@
|
|||||||
import { useEffect, useState } from 'react'
|
|
||||||
|
|
||||||
import { fs, AppConfiguration } from '@janhq/core'
|
|
||||||
|
|
||||||
export const SUCCESS_SET_NEW_DESTINATION = 'successSetNewDestination'
|
|
||||||
|
|
||||||
export function useVaultDirectory() {
|
|
||||||
const [isSameDirectory, setIsSameDirectory] = useState(false)
|
|
||||||
const [isDirectoryConfirm, setIsDirectoryConfirm] = useState(false)
|
|
||||||
const [isErrorSetNewDest, setIsErrorSetNewDest] = useState(false)
|
|
||||||
const [currentPath, setCurrentPath] = useState('')
|
|
||||||
const [newDestinationPath, setNewDestinationPath] = useState('')
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
window.core?.api
|
|
||||||
?.getAppConfigurations()
|
|
||||||
?.then((appConfig: AppConfiguration) => {
|
|
||||||
setCurrentPath(appConfig.data_folder)
|
|
||||||
})
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const setNewDestination = async () => {
|
|
||||||
const destFolder = await window.core?.api?.selectDirectory()
|
|
||||||
setNewDestinationPath(destFolder)
|
|
||||||
|
|
||||||
if (destFolder) {
|
|
||||||
console.debug(`Destination folder selected: ${destFolder}`)
|
|
||||||
try {
|
|
||||||
const appConfiguration: AppConfiguration =
|
|
||||||
await window.core?.api?.getAppConfigurations()
|
|
||||||
const currentJanDataFolder = appConfiguration.data_folder
|
|
||||||
|
|
||||||
if (currentJanDataFolder === destFolder) {
|
|
||||||
console.debug(
|
|
||||||
`Destination folder is the same as current folder. Ignore..`
|
|
||||||
)
|
|
||||||
setIsSameDirectory(true)
|
|
||||||
setIsDirectoryConfirm(false)
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
setIsSameDirectory(false)
|
|
||||||
setIsDirectoryConfirm(true)
|
|
||||||
}
|
|
||||||
setIsErrorSetNewDest(false)
|
|
||||||
} catch (e) {
|
|
||||||
console.error(`Error: ${e}`)
|
|
||||||
setIsErrorSetNewDest(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const applyNewDestination = async () => {
|
|
||||||
try {
|
|
||||||
const appConfiguration: AppConfiguration =
|
|
||||||
await window.core?.api?.getAppConfigurations()
|
|
||||||
const currentJanDataFolder = appConfiguration.data_folder
|
|
||||||
|
|
||||||
appConfiguration.data_folder = newDestinationPath
|
|
||||||
|
|
||||||
await fs.syncFile(currentJanDataFolder, newDestinationPath)
|
|
||||||
await window.core?.api?.updateAppConfiguration(appConfiguration)
|
|
||||||
console.debug(
|
|
||||||
`File sync finished from ${currentPath} to ${newDestinationPath}`
|
|
||||||
)
|
|
||||||
|
|
||||||
setIsErrorSetNewDest(false)
|
|
||||||
localStorage.setItem(SUCCESS_SET_NEW_DESTINATION, 'true')
|
|
||||||
await window.core?.api?.relaunch()
|
|
||||||
} catch (e) {
|
|
||||||
console.error(`Error: ${e}`)
|
|
||||||
setIsErrorSetNewDest(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
setNewDestination,
|
|
||||||
newDestinationPath,
|
|
||||||
applyNewDestination,
|
|
||||||
isSameDirectory,
|
|
||||||
setIsDirectoryConfirm,
|
|
||||||
isDirectoryConfirm,
|
|
||||||
setIsSameDirectory,
|
|
||||||
currentPath,
|
|
||||||
isErrorSetNewDest,
|
|
||||||
setIsErrorSetNewDest,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -16,7 +16,6 @@ export const showChangeFolderErrorAtom = atom(false)
|
|||||||
|
|
||||||
const ModalErrorSetDestGlobal = () => {
|
const ModalErrorSetDestGlobal = () => {
|
||||||
const [show, setShow] = useAtom(showChangeFolderErrorAtom)
|
const [show, setShow] = useAtom(showChangeFolderErrorAtom)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal open={show} onOpenChange={setShow}>
|
<Modal open={show} onOpenChange={setShow}>
|
||||||
<ModalPortal />
|
<ModalPortal />
|
||||||
|
|||||||
@ -15,7 +15,11 @@ import { atom, useAtom } from 'jotai'
|
|||||||
|
|
||||||
export const showSamePathModalAtom = atom(false)
|
export const showSamePathModalAtom = atom(false)
|
||||||
|
|
||||||
const ModalSameDirectory = () => {
|
type Props = {
|
||||||
|
onChangeFolderClick: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const ModalSameDirectory = ({ onChangeFolderClick }: Props) => {
|
||||||
const [show, setShow] = useAtom(showSamePathModalAtom)
|
const [show, setShow] = useAtom(showSamePathModalAtom)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -34,7 +38,14 @@ const ModalSameDirectory = () => {
|
|||||||
<Button themes="ghost">Cancel</Button>
|
<Button themes="ghost">Cancel</Button>
|
||||||
</ModalClose>
|
</ModalClose>
|
||||||
<ModalClose asChild>
|
<ModalClose asChild>
|
||||||
<Button themes="danger" onClick={() => setShow(false)} autoFocus>
|
<Button
|
||||||
|
themes="danger"
|
||||||
|
onClick={() => {
|
||||||
|
setShow(false)
|
||||||
|
onChangeFolderClick()
|
||||||
|
}}
|
||||||
|
autoFocus
|
||||||
|
>
|
||||||
Choose a different folder
|
Choose a different folder
|
||||||
</Button>
|
</Button>
|
||||||
</ModalClose>
|
</ModalClose>
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
import { Fragment, useCallback, useEffect, useState } from 'react'
|
import { Fragment, useCallback, useEffect, useState } from 'react'
|
||||||
|
|
||||||
import { fs, AppConfiguration } from '@janhq/core'
|
import { fs, AppConfiguration, isSubdirectory } from '@janhq/core'
|
||||||
import { Button, Input } from '@janhq/uikit'
|
import { Button, Input } from '@janhq/uikit'
|
||||||
import { useSetAtom } from 'jotai'
|
import { useSetAtom } from 'jotai'
|
||||||
import { PencilIcon, FolderOpenIcon } from 'lucide-react'
|
import { PencilIcon, FolderOpenIcon } from 'lucide-react'
|
||||||
|
|
||||||
import Loader from '@/containers/Loader'
|
import Loader from '@/containers/Loader'
|
||||||
|
|
||||||
import { SUCCESS_SET_NEW_DESTINATION } from '@/hooks/useVaultDirectory'
|
export const SUCCESS_SET_NEW_DESTINATION = 'successSetNewDestination'
|
||||||
|
|
||||||
import ModalChangeDirectory, {
|
import ModalChangeDirectory, {
|
||||||
showDirectoryConfirmModalAtom,
|
showDirectoryConfirmModalAtom,
|
||||||
@ -43,6 +43,15 @@ const DataFolder = () => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const appConfiguration: AppConfiguration =
|
||||||
|
await window.core?.api?.getAppConfigurations()
|
||||||
|
const currentJanDataFolder = appConfiguration.data_folder
|
||||||
|
|
||||||
|
if (await isSubdirectory(currentJanDataFolder, destFolder)) {
|
||||||
|
setShowSameDirectory(true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
setDestinationPath(destFolder)
|
setDestinationPath(destFolder)
|
||||||
setShowDirectoryConfirm(true)
|
setShowDirectoryConfirm(true)
|
||||||
}, [janDataFolderPath, setShowSameDirectory, setShowDirectoryConfirm])
|
}, [janDataFolderPath, setShowSameDirectory, setShowDirectoryConfirm])
|
||||||
@ -67,6 +76,7 @@ const DataFolder = () => {
|
|||||||
await window.core?.api?.relaunch()
|
await window.core?.api?.relaunch()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(`Error: ${e}`)
|
console.error(`Error: ${e}`)
|
||||||
|
setShowLoader(false)
|
||||||
setShowChangeFolderError(true)
|
setShowChangeFolderError(true)
|
||||||
}
|
}
|
||||||
}, [destinationPath, setShowChangeFolderError])
|
}, [destinationPath, setShowChangeFolderError])
|
||||||
@ -107,7 +117,7 @@ const DataFolder = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ModalSameDirectory />
|
<ModalSameDirectory onChangeFolderClick={onChangeFolderClick} />
|
||||||
<ModalChangeDirectory
|
<ModalChangeDirectory
|
||||||
destinationPath={destinationPath ?? ''}
|
destinationPath={destinationPath ?? ''}
|
||||||
onUserConfirmed={onUserConfirmed}
|
onUserConfirmed={onUserConfirmed}
|
||||||
|
|||||||
@ -7,14 +7,14 @@ import { motion as m } from 'framer-motion'
|
|||||||
|
|
||||||
import { twMerge } from 'tailwind-merge'
|
import { twMerge } from 'tailwind-merge'
|
||||||
|
|
||||||
import { SUCCESS_SET_NEW_DESTINATION } from '@/hooks/useVaultDirectory'
|
|
||||||
|
|
||||||
import Advanced from '@/screens/Settings/Advanced'
|
import Advanced from '@/screens/Settings/Advanced'
|
||||||
import AppearanceOptions from '@/screens/Settings/Appearance'
|
import AppearanceOptions from '@/screens/Settings/Appearance'
|
||||||
import ExtensionCatalog from '@/screens/Settings/CoreExtensions'
|
import ExtensionCatalog from '@/screens/Settings/CoreExtensions'
|
||||||
|
|
||||||
import Models from '@/screens/Settings/Models'
|
import Models from '@/screens/Settings/Models'
|
||||||
|
|
||||||
|
import { SUCCESS_SET_NEW_DESTINATION } from './Advanced/DataFolder'
|
||||||
|
|
||||||
const SettingsScreen = () => {
|
const SettingsScreen = () => {
|
||||||
const [activeStaticMenu, setActiveStaticMenu] = useState('My Models')
|
const [activeStaticMenu, setActiveStaticMenu] = useState('My Models')
|
||||||
const [menus, setMenus] = useState<any[]>([])
|
const [menus, setMenus] = useState<any[]>([])
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user