From 5e13fd2f53bb6127770b053f1a922db2eb428999 Mon Sep 17 00:00:00 2001
From: Faisal Amir
Date: Tue, 30 Jan 2024 16:36:58 +0700
Subject: [PATCH 1/4] fix: loader error change folder
---
web/containers/Layout/index.tsx | 3 +-
web/hooks/useVaultDirectory.ts | 87 -------------------
.../DataFolder/ModalSameDirectory.tsx | 15 +++-
.../Settings/Advanced/DataFolder/index.tsx | 5 +-
web/screens/Settings/index.tsx | 4 +-
5 files changed, 20 insertions(+), 94 deletions(-)
delete mode 100644 web/hooks/useVaultDirectory.ts
diff --git a/web/containers/Layout/index.tsx b/web/containers/Layout/index.tsx
index e7bde49c0..77a1fe971 100644
--- a/web/containers/Layout/index.tsx
+++ b/web/containers/Layout/index.tsx
@@ -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
diff --git a/web/hooks/useVaultDirectory.ts b/web/hooks/useVaultDirectory.ts
deleted file mode 100644
index 9d7adf2ab..000000000
--- a/web/hooks/useVaultDirectory.ts
+++ /dev/null
@@ -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,
- }
-}
diff --git a/web/screens/Settings/Advanced/DataFolder/ModalSameDirectory.tsx b/web/screens/Settings/Advanced/DataFolder/ModalSameDirectory.tsx
index 8b2d90c61..1909e6428 100644
--- a/web/screens/Settings/Advanced/DataFolder/ModalSameDirectory.tsx
+++ b/web/screens/Settings/Advanced/DataFolder/ModalSameDirectory.tsx
@@ -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 = () => {
-
diff --git a/web/screens/Settings/Advanced/DataFolder/index.tsx b/web/screens/Settings/Advanced/DataFolder/index.tsx
index 4b242f235..e653e4b9b 100644
--- a/web/screens/Settings/Advanced/DataFolder/index.tsx
+++ b/web/screens/Settings/Advanced/DataFolder/index.tsx
@@ -7,7 +7,7 @@ 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,
@@ -67,6 +67,7 @@ const DataFolder = () => {
await window.core?.api?.relaunch()
} catch (e) {
console.error(`Error: ${e}`)
+ setShowLoader(false)
setShowChangeFolderError(true)
}
}, [destinationPath, setShowChangeFolderError])
@@ -107,7 +108,7 @@ const DataFolder = () => {
-
+
{
const [activeStaticMenu, setActiveStaticMenu] = useState('My Models')
const [menus, setMenus] = useState([])
From 00c4397be66901545353b11e56a67fbb549b734e Mon Sep 17 00:00:00 2001
From: Faisal Amir
Date: Tue, 30 Jan 2024 16:43:58 +0700
Subject: [PATCH 2/4] fix: loader error change folder
---
.../Advanced/DataFolder/ModalErrorSetDestGlobal.tsx | 7 +++++--
web/screens/Settings/Advanced/DataFolder/index.tsx | 9 +++++++--
2 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/web/screens/Settings/Advanced/DataFolder/ModalErrorSetDestGlobal.tsx b/web/screens/Settings/Advanced/DataFolder/ModalErrorSetDestGlobal.tsx
index 3729dc0d8..125cd18bd 100644
--- a/web/screens/Settings/Advanced/DataFolder/ModalErrorSetDestGlobal.tsx
+++ b/web/screens/Settings/Advanced/DataFolder/ModalErrorSetDestGlobal.tsx
@@ -10,13 +10,15 @@ import {
ModalClose,
Button,
} from '@janhq/uikit'
-import { atom, useAtom } from 'jotai'
+import { atom, useAtom, useAtomValue } from 'jotai'
+
+import { errorAtom } from '.'
export const showChangeFolderErrorAtom = atom(false)
const ModalErrorSetDestGlobal = () => {
const [show, setShow] = useAtom(showChangeFolderErrorAtom)
-
+ const error = useAtomValue(errorAtom)
return (
@@ -28,6 +30,7 @@ const ModalErrorSetDestGlobal = () => {
Oops! Something went wrong. Jan data folder remains the same. Please
try again.
+ {error}
setShow(false)}>
diff --git a/web/screens/Settings/Advanced/DataFolder/index.tsx b/web/screens/Settings/Advanced/DataFolder/index.tsx
index e653e4b9b..b7bb88cdd 100644
--- a/web/screens/Settings/Advanced/DataFolder/index.tsx
+++ b/web/screens/Settings/Advanced/DataFolder/index.tsx
@@ -2,7 +2,7 @@ import { Fragment, useCallback, useEffect, useState } from 'react'
import { fs, AppConfiguration } from '@janhq/core'
import { Button, Input } from '@janhq/uikit'
-import { useSetAtom } from 'jotai'
+import { atom, useSetAtom } from 'jotai'
import { PencilIcon, FolderOpenIcon } from 'lucide-react'
import Loader from '@/containers/Loader'
@@ -18,6 +18,8 @@ import ModalErrorSetDestGlobal, {
import ModalSameDirectory, { showSamePathModalAtom } from './ModalSameDirectory'
+export const errorAtom = atom('')
+
const DataFolder = () => {
const [janDataFolderPath, setJanDataFolderPath] = useState('')
const [showLoader, setShowLoader] = useState(false)
@@ -25,6 +27,7 @@ const DataFolder = () => {
const setShowSameDirectory = useSetAtom(showSamePathModalAtom)
const setShowChangeFolderError = useSetAtom(showChangeFolderErrorAtom)
const [destinationPath, setDestinationPath] = useState(undefined)
+ const setError = useSetAtom(errorAtom)
useEffect(() => {
window.core?.api
@@ -65,8 +68,10 @@ const DataFolder = () => {
setShowLoader(false)
}, 1200)
await window.core?.api?.relaunch()
- } catch (e) {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ } catch (e: any) {
console.error(`Error: ${e}`)
+ setError(e.message)
setShowLoader(false)
setShowChangeFolderError(true)
}
From 96aded6b035a284e1b12c0c23325dcb53c0cd2e3 Mon Sep 17 00:00:00 2001
From: Faisal Amir
Date: Tue, 30 Jan 2024 17:04:56 +0700
Subject: [PATCH 3/4] fix: showing catch error on modal when change folder
---
.../Settings/Advanced/DataFolder/ModalErrorSetDestGlobal.tsx | 2 +-
web/screens/Settings/Advanced/DataFolder/index.tsx | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/web/screens/Settings/Advanced/DataFolder/ModalErrorSetDestGlobal.tsx b/web/screens/Settings/Advanced/DataFolder/ModalErrorSetDestGlobal.tsx
index 125cd18bd..d80e34f3c 100644
--- a/web/screens/Settings/Advanced/DataFolder/ModalErrorSetDestGlobal.tsx
+++ b/web/screens/Settings/Advanced/DataFolder/ModalErrorSetDestGlobal.tsx
@@ -30,7 +30,7 @@ const ModalErrorSetDestGlobal = () => {
Oops! Something went wrong. Jan data folder remains the same. Please
try again.
- {error}
+ {error}
setShow(false)}>
diff --git a/web/screens/Settings/Advanced/DataFolder/index.tsx b/web/screens/Settings/Advanced/DataFolder/index.tsx
index b7bb88cdd..1704cd964 100644
--- a/web/screens/Settings/Advanced/DataFolder/index.tsx
+++ b/web/screens/Settings/Advanced/DataFolder/index.tsx
@@ -75,7 +75,7 @@ const DataFolder = () => {
setShowLoader(false)
setShowChangeFolderError(true)
}
- }, [destinationPath, setShowChangeFolderError])
+ }, [destinationPath, setError, setShowChangeFolderError])
return (
From 282dd58d0519c92ab5a335b3c5b1f60f8fe6f262 Mon Sep 17 00:00:00 2001
From: James
Date: Tue, 30 Jan 2024 23:03:20 +0700
Subject: [PATCH 4/4] fix: not allow user to choose sub directory as jan data
folder
Signed-off-by: James
---
core/src/api/index.ts | 1 +
core/src/core.ts | 20 ++++++++++++++--
electron/handlers/app.ts | 23 ++++++++++++++++++-
.../DataFolder/ModalErrorSetDestGlobal.tsx | 6 +----
.../Settings/Advanced/DataFolder/index.tsx | 22 ++++++++++--------
5 files changed, 55 insertions(+), 17 deletions(-)
diff --git a/core/src/api/index.ts b/core/src/api/index.ts
index a232c4090..0adc8b7e2 100644
--- a/core/src/api/index.ts
+++ b/core/src/api/index.ts
@@ -12,6 +12,7 @@ export enum AppRoute {
updateAppConfiguration = 'updateAppConfiguration',
relaunch = 'relaunch',
joinPath = 'joinPath',
+ isSubdirectory = 'isSubdirectory',
baseName = 'baseName',
startServer = 'startServer',
stopServer = 'stopServer',
diff --git a/core/src/core.ts b/core/src/core.ts
index aa545e10e..24053e55c 100644
--- a/core/src/core.ts
+++ b/core/src/core.ts
@@ -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} A promise that resolves when the file is downloaded.
*/
-const downloadFile: (url: string, fileName: string, network?: { proxy?: string, ignoreSSL?: boolean }) => Promise = (url, fileName, network) => {
+const downloadFile: (
+ url: string,
+ fileName: string,
+ network?: { proxy?: string; ignoreSSL?: boolean }
+) => Promise = (url, fileName, network) => {
return global.core?.api?.downloadFile(url, fileName, network)
}
@@ -87,6 +91,17 @@ const getResourcePath: () => Promise = () => 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} - A promise that resolves with a boolean indicating whether the path is a subdirectory.
+ */
+const isSubdirectory: (from: string, to: string) => Promise = (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,
}
diff --git a/electron/handlers/app.ts b/electron/handlers/app.ts
index bdb70047a..c1f431ef3 100644
--- a/electron/handlers/app.ts
+++ b/electron/handlers/app.ts
@@ -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} - 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.
*/
diff --git a/web/screens/Settings/Advanced/DataFolder/ModalErrorSetDestGlobal.tsx b/web/screens/Settings/Advanced/DataFolder/ModalErrorSetDestGlobal.tsx
index d80e34f3c..84646e735 100644
--- a/web/screens/Settings/Advanced/DataFolder/ModalErrorSetDestGlobal.tsx
+++ b/web/screens/Settings/Advanced/DataFolder/ModalErrorSetDestGlobal.tsx
@@ -10,15 +10,12 @@ import {
ModalClose,
Button,
} from '@janhq/uikit'
-import { atom, useAtom, useAtomValue } from 'jotai'
-
-import { errorAtom } from '.'
+import { atom, useAtom } from 'jotai'
export const showChangeFolderErrorAtom = atom(false)
const ModalErrorSetDestGlobal = () => {
const [show, setShow] = useAtom(showChangeFolderErrorAtom)
- const error = useAtomValue(errorAtom)
return (
@@ -30,7 +27,6 @@ const ModalErrorSetDestGlobal = () => {
Oops! Something went wrong. Jan data folder remains the same. Please
try again.
- {error}
setShow(false)}>
diff --git a/web/screens/Settings/Advanced/DataFolder/index.tsx b/web/screens/Settings/Advanced/DataFolder/index.tsx
index 1704cd964..5abd5390b 100644
--- a/web/screens/Settings/Advanced/DataFolder/index.tsx
+++ b/web/screens/Settings/Advanced/DataFolder/index.tsx
@@ -1,8 +1,8 @@
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 { atom, useSetAtom } from 'jotai'
+import { useSetAtom } from 'jotai'
import { PencilIcon, FolderOpenIcon } from 'lucide-react'
import Loader from '@/containers/Loader'
@@ -18,8 +18,6 @@ import ModalErrorSetDestGlobal, {
import ModalSameDirectory, { showSamePathModalAtom } from './ModalSameDirectory'
-export const errorAtom = atom('')
-
const DataFolder = () => {
const [janDataFolderPath, setJanDataFolderPath] = useState('')
const [showLoader, setShowLoader] = useState(false)
@@ -27,7 +25,6 @@ const DataFolder = () => {
const setShowSameDirectory = useSetAtom(showSamePathModalAtom)
const setShowChangeFolderError = useSetAtom(showChangeFolderErrorAtom)
const [destinationPath, setDestinationPath] = useState(undefined)
- const setError = useSetAtom(errorAtom)
useEffect(() => {
window.core?.api
@@ -46,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])
@@ -68,14 +74,12 @@ const DataFolder = () => {
setShowLoader(false)
}, 1200)
await window.core?.api?.relaunch()
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- } catch (e: any) {
+ } catch (e) {
console.error(`Error: ${e}`)
- setError(e.message)
setShowLoader(false)
setShowChangeFolderError(true)
}
- }, [destinationPath, setError, setShowChangeFolderError])
+ }, [destinationPath, setShowChangeFolderError])
return (