Merge pull request #1870 from janhq/fix/loader-change-folder

fix: loader show while error global when change folder
This commit is contained in:
Faisal Amir 2024-01-31 10:29:40 +07:00 committed by GitHub
commit 0e17f776fe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 71 additions and 99 deletions

View File

@ -12,6 +12,7 @@ export enum AppRoute {
updateAppConfiguration = 'updateAppConfiguration',
relaunch = 'relaunch',
joinPath = 'joinPath',
isSubdirectory = 'isSubdirectory',
baseName = 'baseName',
startServer = 'startServer',
stopServer = 'stopServer',

View File

@ -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.
* @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)
}
@ -87,6 +91,17 @@ const getResourcePath: () => Promise<string> = () => global.core.api?.getResourc
const log: (message: string, fileName?: string) => void = (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
*/
@ -94,7 +109,7 @@ export type RegisterExtensionPoint = (
extensionName: string,
extensionId: string,
method: Function,
priority?: number,
priority?: number
) => void
/**
@ -111,5 +126,6 @@ export {
openExternalUrl,
baseName,
log,
isSubdirectory,
FileStat,
}

View File

@ -1,5 +1,5 @@
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 { getResourcePath } from './../utils/path'
import { AppRoute, AppConfiguration } from '@janhq/core'
@ -50,6 +50,27 @@ export function handleAppIPCs() {
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.
*/

View File

@ -12,7 +12,8 @@ import TopBar from '@/containers/Layout/TopBar'
import { MainViewState } from '@/constants/screens'
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 { children } = props

View File

@ -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,
}
}

View File

@ -16,7 +16,6 @@ export const showChangeFolderErrorAtom = atom(false)
const ModalErrorSetDestGlobal = () => {
const [show, setShow] = useAtom(showChangeFolderErrorAtom)
return (
<Modal open={show} onOpenChange={setShow}>
<ModalPortal />

View File

@ -15,7 +15,11 @@ import { atom, useAtom } from 'jotai'
export const showSamePathModalAtom = atom(false)
const ModalSameDirectory = () => {
type Props = {
onChangeFolderClick: () => void
}
const ModalSameDirectory = ({ onChangeFolderClick }: Props) => {
const [show, setShow] = useAtom(showSamePathModalAtom)
return (
@ -34,7 +38,14 @@ const ModalSameDirectory = () => {
<Button themes="ghost">Cancel</Button>
</ModalClose>
<ModalClose asChild>
<Button themes="danger" onClick={() => setShow(false)} autoFocus>
<Button
themes="danger"
onClick={() => {
setShow(false)
onChangeFolderClick()
}}
autoFocus
>
Choose a different folder
</Button>
</ModalClose>

View File

@ -1,13 +1,13 @@
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 { useSetAtom } from 'jotai'
import { PencilIcon, FolderOpenIcon } from 'lucide-react'
import Loader from '@/containers/Loader'
import { SUCCESS_SET_NEW_DESTINATION } from '@/hooks/useVaultDirectory'
export const SUCCESS_SET_NEW_DESTINATION = 'successSetNewDestination'
import ModalChangeDirectory, {
showDirectoryConfirmModalAtom,
@ -43,6 +43,15 @@ const DataFolder = () => {
return
}
const appConfiguration: AppConfiguration =
await window.core?.api?.getAppConfigurations()
const currentJanDataFolder = appConfiguration.data_folder
if (await isSubdirectory(currentJanDataFolder, destFolder)) {
setShowSameDirectory(true)
return
}
setDestinationPath(destFolder)
setShowDirectoryConfirm(true)
}, [janDataFolderPath, setShowSameDirectory, setShowDirectoryConfirm])
@ -67,6 +76,7 @@ const DataFolder = () => {
await window.core?.api?.relaunch()
} catch (e) {
console.error(`Error: ${e}`)
setShowLoader(false)
setShowChangeFolderError(true)
}
}, [destinationPath, setShowChangeFolderError])
@ -107,7 +117,7 @@ const DataFolder = () => {
</Button>
</div>
</div>
<ModalSameDirectory />
<ModalSameDirectory onChangeFolderClick={onChangeFolderClick} />
<ModalChangeDirectory
destinationPath={destinationPath ?? ''}
onUserConfirmed={onUserConfirmed}

View File

@ -7,14 +7,14 @@ import { motion as m } from 'framer-motion'
import { twMerge } from 'tailwind-merge'
import { SUCCESS_SET_NEW_DESTINATION } from '@/hooks/useVaultDirectory'
import Advanced from '@/screens/Settings/Advanced'
import AppearanceOptions from '@/screens/Settings/Appearance'
import ExtensionCatalog from '@/screens/Settings/CoreExtensions'
import Models from '@/screens/Settings/Models'
import { SUCCESS_SET_NEW_DESTINATION } from './Advanced/DataFolder'
const SettingsScreen = () => {
const [activeStaticMenu, setActiveStaticMenu] = useState('My Models')
const [menus, setMenus] = useState<any[]>([])