Skip to content

Commit

Permalink
Fix/unable factory reset windows nitro running (janhq#2422)
Browse files Browse the repository at this point in the history
* fix: unable to factory reset when nitro is running on windows

---------

Signed-off-by: James <[email protected]>
  • Loading branch information
namchuai authored Mar 19, 2024
1 parent 26c2c6a commit b8d86df
Show file tree
Hide file tree
Showing 9 changed files with 119 additions and 53 deletions.
2 changes: 1 addition & 1 deletion core/src/node/api/processors/fsExt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export class FSExt implements Processor {
})
}

rmdir(path: string): Promise<void> {
rm(path: string): Promise<void> {
return new Promise((resolve, reject) => {
fs.rm(path, { recursive: true }, (err) => {
if (err) {
Expand Down
4 changes: 2 additions & 2 deletions extensions/conversational-extension/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ export default class JSONConversationalExtension extends ConversationalExtension
* Called when the extension is loaded.
*/
async onLoad() {
if (!(await fs.existsSync(JSONConversationalExtension._threadFolder)))
if (!(await fs.existsSync(JSONConversationalExtension._threadFolder))) {
await fs.mkdirSync(JSONConversationalExtension._threadFolder)
console.debug('JSONConversationalExtension loaded')
}
}

/**
Expand Down
14 changes: 13 additions & 1 deletion web/containers/Providers/DataLoader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@

import { Fragment, ReactNode, useEffect } from 'react'

import { AppConfiguration } from '@janhq/core'
import { AppConfiguration, getUserHomePath, joinPath } from '@janhq/core'
import { useSetAtom } from 'jotai'

import useAssistants from '@/hooks/useAssistants'
import useGetSystemResources from '@/hooks/useGetSystemResources'
import useModels from '@/hooks/useModels'
import useThreads from '@/hooks/useThreads'

import { defaultJanDataFolderAtom } from '@/helpers/atoms/App.atom'
import {
janDataFolderPathAtom,
quickAskEnabledAtom,
Expand All @@ -22,6 +23,7 @@ type Props = {
const DataLoader: React.FC<Props> = ({ children }) => {
const setJanDataFolderPath = useSetAtom(janDataFolderPathAtom)
const setQuickAskEnabled = useSetAtom(quickAskEnabledAtom)
const setJanDefaultDataFolder = useSetAtom(defaultJanDataFolderAtom)

useModels()
useThreads()
Expand All @@ -37,6 +39,16 @@ const DataLoader: React.FC<Props> = ({ children }) => {
})
}, [setJanDataFolderPath, setQuickAskEnabled])

useEffect(() => {
async function getDefaultJanDataFolder() {
const homePath = await getUserHomePath()
const defaultJanDataFolder = await joinPath([homePath, 'jan'])

setJanDefaultDataFolder(defaultJanDataFolder)
}
getDefaultJanDataFolder()
}, [setJanDefaultDataFolder])

console.debug('Load Data...')

return <Fragment>{children}</Fragment>
Expand Down
2 changes: 2 additions & 0 deletions web/helpers/atoms/App.atom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ import { atom } from 'jotai'
import { MainViewState } from '@/constants/screens'

export const mainViewStateAtom = atom<MainViewState>(MainViewState.Thread)

export const defaultJanDataFolderAtom = atom<string>('')
7 changes: 3 additions & 4 deletions web/hooks/useActiveModel.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useRef } from 'react'
import { useCallback, useEffect, useRef } from 'react'

import { events, Model, ModelEvent } from '@janhq/core'
import { atom, useAtom, useAtomValue, useSetAtom } from 'jotai'
Expand Down Expand Up @@ -86,13 +86,12 @@ export function useActiveModel() {
events.emit(ModelEvent.OnModelInit, model)
}

const stopModel = async () => {
const stopModel = useCallback(async () => {
if (activeModel) {
setActiveModel(undefined)
setStateModel({ state: 'stop', loading: true, model: activeModel.id })
events.emit(ModelEvent.OnModelStop, activeModel)
}
}
}, [activeModel, setStateModel])

return { activeModel, startModel, stopModel, stateModel }
}
95 changes: 57 additions & 38 deletions web/hooks/useFactoryReset.ts
Original file line number Diff line number Diff line change
@@ -1,49 +1,68 @@
import { useEffect, useState } from 'react'
import { useCallback } from 'react'

import { fs, AppConfiguration, joinPath, getUserHomePath } from '@janhq/core'
import { fs, AppConfiguration } from '@janhq/core'
import { atom, useAtomValue, useSetAtom } from 'jotai'

import { useActiveModel } from './useActiveModel'

import { defaultJanDataFolderAtom } from '@/helpers/atoms/App.atom'

export enum FactoryResetState {
Idle = 'idle',
Starting = 'starting',
StoppingModel = 'stopping_model',
DeletingData = 'deleting_data',
ClearLocalStorage = 'clear_local_storage',
}

export const factoryResetStateAtom = atom(FactoryResetState.Idle)

export default function useFactoryReset() {
const [defaultJanDataFolder, setdefaultJanDataFolder] = useState('')

useEffect(() => {
async function getDefaultJanDataFolder() {
const homePath = await getUserHomePath()
const defaultJanDataFolder = await joinPath([homePath, 'jan'])
setdefaultJanDataFolder(defaultJanDataFolder)
}
getDefaultJanDataFolder()
}, [])

const resetAll = async (keepCurrentFolder?: boolean) => {
// read the place of jan data folder
const appConfiguration: AppConfiguration | undefined =
await window.core?.api?.getAppConfigurations()

if (!appConfiguration) {
console.debug('Failed to get app configuration')
}

console.debug('appConfiguration: ', appConfiguration)
const janDataFolderPath = appConfiguration!.data_folder

if (!keepCurrentFolder) {
// set the default jan data folder to user's home directory
const configuration: AppConfiguration = {
data_folder: defaultJanDataFolder,
quick_ask: appConfiguration?.quick_ask ?? false,
const defaultJanDataFolder = useAtomValue(defaultJanDataFolderAtom)
const { activeModel, stopModel } = useActiveModel()
const setFactoryResetState = useSetAtom(factoryResetStateAtom)

const resetAll = useCallback(
async (keepCurrentFolder?: boolean) => {
setFactoryResetState(FactoryResetState.Starting)
// read the place of jan data folder
const appConfiguration: AppConfiguration | undefined =
await window.core?.api?.getAppConfigurations()

if (!appConfiguration) {
console.debug('Failed to get app configuration')
}
await window.core?.api?.updateAppConfiguration(configuration)
}
await fs.rmdirSync(janDataFolderPath, { recursive: true })

// reset the localStorage
localStorage.clear()
const janDataFolderPath = appConfiguration!.data_folder

await window.core?.api?.relaunch()
}
if (!keepCurrentFolder) {
// set the default jan data folder to user's home directory
const configuration: AppConfiguration = {
data_folder: defaultJanDataFolder,
quick_ask: appConfiguration?.quick_ask ?? false,
}
await window.core?.api?.updateAppConfiguration(configuration)
}

if (activeModel) {
setFactoryResetState(FactoryResetState.StoppingModel)
await stopModel()
await new Promise((resolve) => setTimeout(resolve, 4000))
}

setFactoryResetState(FactoryResetState.DeletingData)
await fs.rm(janDataFolderPath)

setFactoryResetState(FactoryResetState.ClearLocalStorage)
// reset the localStorage
localStorage.clear()

await window.core?.api?.relaunch()
},
[defaultJanDataFolder, activeModel, stopModel, setFactoryResetState]
)

return {
defaultJanDataFolder,
resetAll,
}
}
17 changes: 10 additions & 7 deletions web/screens/Settings/Advanced/FactoryReset/ModalConfirmReset.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,25 @@ import {
Checkbox,
Input,
} from '@janhq/uikit'
import { atom, useAtom } from 'jotai'
import { atom, useAtom, useAtomValue } from 'jotai'

import useFactoryReset from '@/hooks/useFactoryReset'

import { defaultJanDataFolderAtom } from '@/helpers/atoms/App.atom'

export const modalValidationAtom = atom(false)

const ModalConfirmReset = () => {
const [modalValidation, setModalValidation] = useAtom(modalValidationAtom)
const { resetAll, defaultJanDataFolder } = useFactoryReset()
const defaultJanDataFolder = useAtomValue(defaultJanDataFolderAtom)
const { resetAll } = useFactoryReset()
const [inputValue, setInputValue] = useState('')
const [currentDirectoryChecked, setCurrentDirectoryChecked] = useState(true)
const onFactoryResetClick = useCallback(
() => resetAll(currentDirectoryChecked),
[currentDirectoryChecked, resetAll]
)

const onFactoryResetClick = useCallback(() => {
setModalValidation(false)
resetAll(currentDirectoryChecked)
}, [currentDirectoryChecked, resetAll, setModalValidation])

return (
<Modal
Expand Down Expand Up @@ -65,7 +69,6 @@ const ModalConfirmReset = () => {
</label>
<p className="mt-2 leading-relaxed">
Otherwise it will reset back to its original location at:{' '}
{/* TODO should be from system */}
<span className="font-medium">{defaultJanDataFolder}</span>
</p>
</div>
Expand Down
29 changes: 29 additions & 0 deletions web/screens/Settings/Advanced/FactoryReset/ResettingModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Modal, ModalContent, ModalHeader, ModalTitle } from '@janhq/uikit'
import { atom, useAtomValue } from 'jotai'

import {
FactoryResetState,
factoryResetStateAtom,
} from '@/hooks/useFactoryReset'

const resetModalVisibilityAtom = atom((get) => {
const visible = get(factoryResetStateAtom) !== FactoryResetState.Idle
return visible
})

const ResettingModal: React.FC = () => {
const visibility = useAtomValue(resetModalVisibilityAtom)

return (
<Modal open={visibility}>
<ModalContent>
<ModalHeader>
<ModalTitle>Factory reset in progress..</ModalTitle>
</ModalHeader>
<p className="text-muted-foreground">Resetting..</p>
</ModalContent>
</Modal>
)
}

export default ResettingModal
2 changes: 2 additions & 0 deletions web/screens/Settings/Advanced/FactoryReset/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Button } from '@janhq/uikit'
import { useSetAtom } from 'jotai'

import ModalValidation, { modalValidationAtom } from './ModalConfirmReset'
import ResettingModal from './ResettingModal'

const FactoryReset = () => {
const setModalValidation = useSetAtom(modalValidationAtom)
Expand Down Expand Up @@ -30,6 +31,7 @@ const FactoryReset = () => {
Reset
</Button>
<ModalValidation />
<ResettingModal />
</div>
)
}
Expand Down

0 comments on commit b8d86df

Please sign in to comment.