setMore(!more)}
>
@@ -60,7 +64,7 @@ export default function CardSidebar({
{more && (
),
- state: MainViewState.Setting,
+ state: MainViewState.Settings,
},
]
return (
diff --git a/web/containers/Layout/TopBar/CommandSearch/index.tsx b/web/containers/Layout/TopBar/CommandSearch/index.tsx
index 814ffbcbd7..d83feb22e0 100644
--- a/web/containers/Layout/TopBar/CommandSearch/index.tsx
+++ b/web/containers/Layout/TopBar/CommandSearch/index.tsx
@@ -38,7 +38,7 @@ export default function CommandSearch() {
{
name: 'Settings',
icon:
,
- state: MainViewState.Setting,
+ state: MainViewState.Settings,
shortcut:
,
},
]
@@ -51,7 +51,7 @@ export default function CommandSearch() {
}
if (e.key === ',' && (e.metaKey || e.ctrlKey)) {
e.preventDefault()
- setMainViewState(MainViewState.Setting)
+ setMainViewState(MainViewState.Settings)
}
}
document.addEventListener('keydown', down)
diff --git a/web/containers/Layout/TopBar/index.tsx b/web/containers/Layout/TopBar/index.tsx
index da3768c762..aa7912bd3d 100644
--- a/web/containers/Layout/TopBar/index.tsx
+++ b/web/containers/Layout/TopBar/index.tsx
@@ -27,7 +27,7 @@ const TopBar = () => {
return activeThread ? activeThread?.title : 'New Thread'
default:
- return MainViewState[viewStateName].replace(/([A-Z])/g, ' $1').trim()
+ return MainViewState[viewStateName]?.replace(/([A-Z])/g, ' $1').trim()
}
}
diff --git a/web/containers/Toast/index.tsx b/web/containers/Toast/index.tsx
index 9833f99d95..c5e5f03da2 100644
--- a/web/containers/Toast/index.tsx
+++ b/web/containers/Toast/index.tsx
@@ -16,7 +16,7 @@ export function toaster(props: Props) {
return (
(null)
+ const [toggle, setToggle] = useState
(null)
+ useClickOutside(() => setMore(false), null, [menu, toggle])
+
+ const { activeModel, startModel, stopModel, stateModel } = useActiveModel()
+ const { deleteModel } = useDeleteModel()
+
+ const isActiveModel = stateModel.model === props.data.id
+
+ const onModelActionClick = (modelId: string) => {
+ if (activeModel && activeModel.id === modelId) {
+ stopModel(modelId)
+ } else {
+ startModel(modelId)
+ }
+ }
+
+ return (
+
+ {props.data.name} |
+ {props.data.id} |
+
+
+ {toGigabytes(props.data.metadata.size)}
+
+ |
+
+ v{props.data.version}
+ |
+
+ {stateModel.loading && stateModel.model === props.data.id ? (
+
+
+
+ {stateModel.state === 'start' ? 'Starting...' : 'Stopping...'}
+
+
+ ) : activeModel && activeModel.id === props.data.id ? (
+
+
+ Active
+
+ ) : (
+
+
+ Inactive
+
+ )}
+ |
+
+ {
+ setMore(!more)
+ }}
+ >
+
+
+ {more && (
+
+ {
+ onModelActionClick(props.data.id)
+ setMore(false)
+ }}
+ >
+ {activeModel && activeModel.id === props.data.id ? (
+
+ ) : (
+
+ )}
+
+ {isActiveModel ? stateModel.state : 'Start'}
+ Model
+
+
+ {
+ setTimeout(async () => {
+ await stopModel(props.data.id)
+ deleteModel(props.data)
+ }, 500)
+ setMore(false)
+ }}
+ >
+
+
+ Delete Model
+
+
+
+ )}
+ |
+
+ )
+}
diff --git a/web/screens/Settings/Models/index.tsx b/web/screens/Settings/Models/index.tsx
new file mode 100644
index 0000000000..79859c2758
--- /dev/null
+++ b/web/screens/Settings/Models/index.tsx
@@ -0,0 +1,65 @@
+import { useState } from 'react'
+
+import { Input } from '@janhq/uikit'
+
+import { SearchIcon } from 'lucide-react'
+
+import { useGetDownloadedModels } from '@/hooks/useGetDownloadedModels'
+
+import RowModel from './Row'
+
+const Column = ['Name', 'Model ID', 'Size', 'Version', 'Status', '']
+
+export default function Models() {
+ const { downloadedModels } = useGetDownloadedModels()
+ const [searchValue, setsearchValue] = useState('')
+
+ const filteredDownloadedModels = downloadedModels.filter((x) => {
+ return x.name.toLowerCase().includes(searchValue.toLowerCase())
+ })
+
+ return (
+
+
+
+
+ {
+ setsearchValue(e.target.value)
+ }}
+ />
+
+
+
+
+
+
+ {Column.map((col, i) => {
+ return (
+
+ {col}
+ |
+ )
+ })}
+
+
+
+ {filteredDownloadedModels
+ ? filteredDownloadedModels.map((x, i) => {
+ return
+ })
+ : null}
+
+
+
+
+ )
+}
diff --git a/web/screens/Settings/index.tsx b/web/screens/Settings/index.tsx
index b14039f749..77e70d33b9 100644
--- a/web/screens/Settings/index.tsx
+++ b/web/screens/Settings/index.tsx
@@ -12,6 +12,8 @@ import AppearanceOptions from '@/screens/Settings/Appearance'
import ExtensionCatalog from '@/screens/Settings/CoreExtensions/ExtensionsCatalog'
import PreferenceExtensions from '@/screens/Settings/CoreExtensions/PreferenceExtensions'
+import Models from '@/screens/Settings/Models'
+
import { formatExtensionsName } from '@/utils/converter'
const SettingsScreen = () => {
@@ -24,7 +26,7 @@ const SettingsScreen = () => {
const menu = ['Appearance']
if (typeof window !== 'undefined' && window.electronAPI) {
- menu.push('Core Extensions')
+ menu.push('Extensions')
}
menu.push('Advanced')
setMenus(menu)
@@ -40,7 +42,7 @@ const SettingsScreen = () => {
const handleShowOptions = (menu: string) => {
switch (menu) {
- case 'Core Extensions':
+ case 'Extensions':
return
case 'Appearance':
@@ -49,6 +51,9 @@ const SettingsScreen = () => {
case 'Advanced':
return
+ case 'Models':
+ return
+
default:
return (
{
{menus.map((menu, i) => {
@@ -135,6 +140,38 @@ const SettingsScreen = () => {
})}
+
+
+
+
+
+
{
+ setActiveStaticMenu('Models')
+ setActivePreferenceExtension('')
+ }}
+ className="block w-full cursor-pointer"
+ >
+
+ Models
+
+
+ {activeStaticMenu === 'Models' && (
+
+ )}
+
+
+
diff --git a/web/screens/SystemMonitor/index.tsx b/web/screens/SystemMonitor/index.tsx
index a1e511b86b..51547f2926 100644
--- a/web/screens/SystemMonitor/index.tsx
+++ b/web/screens/SystemMonitor/index.tsx
@@ -30,7 +30,7 @@ export default function SystemMonitorScreen() {
ram ({Math.round((usedRam / totalRam) * 100)}%)
-
+
{toGigabytes(usedRam)} GB of {toGigabytes(totalRam)} GB used
@@ -46,7 +46,7 @@ export default function SystemMonitorScreen() {