Add tooltip on every action start and stop button while server is running
This commit is contained in:
parent
8b9d8e8301
commit
056cc8e722
@ -8,7 +8,7 @@ import {
|
|||||||
TooltipContent,
|
TooltipContent,
|
||||||
TooltipTrigger,
|
TooltipTrigger,
|
||||||
} from '@janhq/uikit'
|
} from '@janhq/uikit'
|
||||||
import { useAtomValue, useSetAtom } from 'jotai'
|
import { useAtom, useAtomValue, useSetAtom } from 'jotai'
|
||||||
|
|
||||||
import { FaGithub, FaDiscord } from 'react-icons/fa'
|
import { FaGithub, FaDiscord } from 'react-icons/fa'
|
||||||
|
|
||||||
@ -32,6 +32,8 @@ import { useGetDownloadedModels } from '@/hooks/useGetDownloadedModels'
|
|||||||
import useGetSystemResources from '@/hooks/useGetSystemResources'
|
import useGetSystemResources from '@/hooks/useGetSystemResources'
|
||||||
import { useMainViewState } from '@/hooks/useMainViewState'
|
import { useMainViewState } from '@/hooks/useMainViewState'
|
||||||
|
|
||||||
|
import { serverEnabledAtom } from '@/helpers/atoms/LocalServer.atom'
|
||||||
|
|
||||||
const menuLinks = [
|
const menuLinks = [
|
||||||
{
|
{
|
||||||
name: 'Discord',
|
name: 'Discord',
|
||||||
@ -53,6 +55,7 @@ const BottomBar = () => {
|
|||||||
const { setMainViewState } = useMainViewState()
|
const { setMainViewState } = useMainViewState()
|
||||||
const { downloadStates } = useDownloadState()
|
const { downloadStates } = useDownloadState()
|
||||||
const setShowSelectModelModal = useSetAtom(showSelectModelModalAtom)
|
const setShowSelectModelModal = useSetAtom(showSelectModelModalAtom)
|
||||||
|
const [serverEnabled] = useAtom(serverEnabledAtom)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed bottom-0 left-16 z-20 flex h-12 w-[calc(100%-64px)] items-center justify-between border-t border-border bg-background/80 px-3">
|
<div className="fixed bottom-0 left-16 z-20 flex h-12 w-[calc(100%-64px)] items-center justify-between border-t border-border bg-background/80 px-3">
|
||||||
@ -63,6 +66,7 @@ const BottomBar = () => {
|
|||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{!serverEnabled && (
|
||||||
<Badge
|
<Badge
|
||||||
themes="secondary"
|
themes="secondary"
|
||||||
className="cursor-pointer rounded-md border-none font-medium"
|
className="cursor-pointer rounded-md border-none font-medium"
|
||||||
@ -71,6 +75,7 @@ const BottomBar = () => {
|
|||||||
My Models
|
My Models
|
||||||
<ShortCut menu="E" />
|
<ShortCut menu="E" />
|
||||||
</Badge>
|
</Badge>
|
||||||
|
)}
|
||||||
|
|
||||||
{stateModel.state === 'start' && stateModel.loading && (
|
{stateModel.state === 'start' && stateModel.loading && (
|
||||||
<SystemItem
|
<SystemItem
|
||||||
|
|||||||
@ -22,10 +22,13 @@ import { useActiveModel } from '@/hooks/useActiveModel'
|
|||||||
import { useGetDownloadedModels } from '@/hooks/useGetDownloadedModels'
|
import { useGetDownloadedModels } from '@/hooks/useGetDownloadedModels'
|
||||||
import { useMainViewState } from '@/hooks/useMainViewState'
|
import { useMainViewState } from '@/hooks/useMainViewState'
|
||||||
|
|
||||||
|
import { serverEnabledAtom } from '@/helpers/atoms/LocalServer.atom'
|
||||||
|
|
||||||
export default function CommandListDownloadedModel() {
|
export default function CommandListDownloadedModel() {
|
||||||
const { setMainViewState } = useMainViewState()
|
const { setMainViewState } = useMainViewState()
|
||||||
const { downloadedModels } = useGetDownloadedModels()
|
const { downloadedModels } = useGetDownloadedModels()
|
||||||
const { activeModel, startModel, stopModel } = useActiveModel()
|
const { activeModel, startModel, stopModel } = useActiveModel()
|
||||||
|
const [serverEnabled] = useAtom(serverEnabledAtom)
|
||||||
const [showSelectModelModal, setShowSelectModelModal] = useAtom(
|
const [showSelectModelModal, setShowSelectModelModal] = useAtom(
|
||||||
showSelectModelModalAtom
|
showSelectModelModalAtom
|
||||||
)
|
)
|
||||||
@ -39,7 +42,7 @@ export default function CommandListDownloadedModel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const isNotDownloadedModel = downloadedModels.length === 0
|
const isNotDownloadedModel = downloadedModels.length === 0
|
||||||
if (isNotDownloadedModel) return null
|
if (isNotDownloadedModel || serverEnabled) return null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { toaster } from '@/containers/Toast'
|
|||||||
|
|
||||||
import { useGetDownloadedModels } from './useGetDownloadedModels'
|
import { useGetDownloadedModels } from './useGetDownloadedModels'
|
||||||
import { LAST_USED_MODEL_ID } from './useRecommendedModel'
|
import { LAST_USED_MODEL_ID } from './useRecommendedModel'
|
||||||
|
|
||||||
import { activeThreadAtom } from '@/helpers/atoms/Thread.atom'
|
import { activeThreadAtom } from '@/helpers/atoms/Thread.atom'
|
||||||
|
|
||||||
export const activeModelAtom = atom<Model | undefined>(undefined)
|
export const activeModelAtom = atom<Model | undefined>(undefined)
|
||||||
|
|||||||
@ -17,7 +17,6 @@
|
|||||||
"@hookform/resolvers": "^3.3.2",
|
"@hookform/resolvers": "^3.3.2",
|
||||||
"@janhq/core": "link:./core",
|
"@janhq/core": "link:./core",
|
||||||
"@janhq/uikit": "link:./uikit",
|
"@janhq/uikit": "link:./uikit",
|
||||||
"@janhq/server": "link:./server",
|
|
||||||
"autoprefixer": "10.4.16",
|
"autoprefixer": "10.4.16",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"framer-motion": "^10.16.4",
|
"framer-motion": "^10.16.4",
|
||||||
|
|||||||
@ -2,7 +2,15 @@
|
|||||||
import { useCallback, useMemo } from 'react'
|
import { useCallback, useMemo } from 'react'
|
||||||
|
|
||||||
import { Model } from '@janhq/core'
|
import { Model } from '@janhq/core'
|
||||||
import { Badge, Button } from '@janhq/uikit'
|
import {
|
||||||
|
Badge,
|
||||||
|
Button,
|
||||||
|
Tooltip,
|
||||||
|
TooltipArrow,
|
||||||
|
TooltipContent,
|
||||||
|
TooltipPortal,
|
||||||
|
TooltipTrigger,
|
||||||
|
} from '@janhq/uikit'
|
||||||
|
|
||||||
import { atom, useAtomValue } from 'jotai'
|
import { atom, useAtomValue } from 'jotai'
|
||||||
|
|
||||||
@ -23,6 +31,8 @@ import { useMainViewState } from '@/hooks/useMainViewState'
|
|||||||
|
|
||||||
import { toGibibytes } from '@/utils/converter'
|
import { toGibibytes } from '@/utils/converter'
|
||||||
|
|
||||||
|
import { serverEnabledAtom } from '@/helpers/atoms/LocalServer.atom'
|
||||||
|
|
||||||
import { totalRamAtom } from '@/helpers/atoms/SystemBar.atom'
|
import { totalRamAtom } from '@/helpers/atoms/SystemBar.atom'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@ -37,6 +47,7 @@ const ExploreModelItemHeader: React.FC<Props> = ({ model, onClick, open }) => {
|
|||||||
const { modelDownloadStateAtom, downloadStates } = useDownloadState()
|
const { modelDownloadStateAtom, downloadStates } = useDownloadState()
|
||||||
const { requestCreateNewThread } = useCreateNewThread()
|
const { requestCreateNewThread } = useCreateNewThread()
|
||||||
const totalRam = useAtomValue(totalRamAtom)
|
const totalRam = useAtomValue(totalRamAtom)
|
||||||
|
const serverEnabled = useAtomValue(serverEnabledAtom)
|
||||||
|
|
||||||
const downloadAtom = useMemo(
|
const downloadAtom = useMemo(
|
||||||
() => atom((get) => get(modelDownloadStateAtom)[model.id]),
|
() => atom((get) => get(modelDownloadStateAtom)[model.id]),
|
||||||
@ -68,13 +79,26 @@ const ExploreModelItemHeader: React.FC<Props> = ({ model, onClick, open }) => {
|
|||||||
|
|
||||||
if (isDownloaded) {
|
if (isDownloaded) {
|
||||||
downloadButton = (
|
downloadButton = (
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger>
|
||||||
<Button
|
<Button
|
||||||
themes="secondaryBlue"
|
themes="secondaryBlue"
|
||||||
className="min-w-[98px]"
|
className="min-w-[98px]"
|
||||||
onClick={onUseModelClick}
|
onClick={onUseModelClick}
|
||||||
|
disabled={serverEnabled}
|
||||||
>
|
>
|
||||||
Use
|
Use
|
||||||
</Button>
|
</Button>
|
||||||
|
</TooltipTrigger>
|
||||||
|
{serverEnabled && (
|
||||||
|
<TooltipPortal>
|
||||||
|
<TooltipContent side="top">
|
||||||
|
<span>Threads are disabled while the server is running</span>
|
||||||
|
<TooltipArrow />
|
||||||
|
</TooltipContent>
|
||||||
|
</TooltipPortal>
|
||||||
|
)}
|
||||||
|
</Tooltip>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
35
web/screens/LocalServer/Logs.tsx
Normal file
35
web/screens/LocalServer/Logs.tsx
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/naming-convention */
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import { useServerLog } from '@/hooks/useServerLog'
|
||||||
|
|
||||||
|
const Logs = () => {
|
||||||
|
const { getServerLog } = useServerLog()
|
||||||
|
const [logs, setLogs] = useState([])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getServerLog().then((log) => {
|
||||||
|
setLogs(log.split(/\r?\n|\r|\n/g))
|
||||||
|
})
|
||||||
|
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [logs])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="p-4">
|
||||||
|
<code className="text-xs">
|
||||||
|
{logs.map((log, i) => {
|
||||||
|
return (
|
||||||
|
<p key={i} className="my-2 leading-relaxed">
|
||||||
|
{log}
|
||||||
|
</p>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Logs
|
||||||
@ -1,5 +1,6 @@
|
|||||||
/* eslint-disable @typescript-eslint/naming-convention */
|
'use client'
|
||||||
import { useEffect, useState } from 'react'
|
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
@ -25,8 +26,11 @@ import { ExternalLinkIcon, InfoIcon } from 'lucide-react'
|
|||||||
import { twMerge } from 'tailwind-merge'
|
import { twMerge } from 'tailwind-merge'
|
||||||
|
|
||||||
import CardSidebar from '@/containers/CardSidebar'
|
import CardSidebar from '@/containers/CardSidebar'
|
||||||
import DropdownListSidebar from '@/containers/DropdownListSidebar'
|
import DropdownListSidebar, {
|
||||||
|
selectedModelAtom,
|
||||||
|
} from '@/containers/DropdownListSidebar'
|
||||||
|
|
||||||
|
import { useActiveModel } from '@/hooks/useActiveModel'
|
||||||
import { useServerLog } from '@/hooks/useServerLog'
|
import { useServerLog } from '@/hooks/useServerLog'
|
||||||
|
|
||||||
import { getConfigurationsData } from '@/utils/componentSettings'
|
import { getConfigurationsData } from '@/utils/componentSettings'
|
||||||
@ -37,6 +41,8 @@ import ModelSetting from '../Chat/ModelSetting'
|
|||||||
import settingComponentBuilder from '../Chat/ModelSetting/settingComponentBuilder'
|
import settingComponentBuilder from '../Chat/ModelSetting/settingComponentBuilder'
|
||||||
import { showRightSideBarAtom } from '../Chat/Sidebar'
|
import { showRightSideBarAtom } from '../Chat/Sidebar'
|
||||||
|
|
||||||
|
import Logs from './Logs'
|
||||||
|
|
||||||
import { serverEnabledAtom } from '@/helpers/atoms/LocalServer.atom'
|
import { serverEnabledAtom } from '@/helpers/atoms/LocalServer.atom'
|
||||||
import { getActiveThreadModelParamsAtom } from '@/helpers/atoms/Thread.atom'
|
import { getActiveThreadModelParamsAtom } from '@/helpers/atoms/Thread.atom'
|
||||||
|
|
||||||
@ -49,14 +55,10 @@ const LocalServerScreen = () => {
|
|||||||
const modelRuntimeParams = toRuntimeParams(activeModelParams)
|
const modelRuntimeParams = toRuntimeParams(activeModelParams)
|
||||||
const componentDataEngineSetting = getConfigurationsData(modelEngineParams)
|
const componentDataEngineSetting = getConfigurationsData(modelEngineParams)
|
||||||
const componentDataRuntimeSetting = getConfigurationsData(modelRuntimeParams)
|
const componentDataRuntimeSetting = getConfigurationsData(modelRuntimeParams)
|
||||||
const { getServerLog, openServerLog, clearServerLog } = useServerLog()
|
const { openServerLog, clearServerLog } = useServerLog()
|
||||||
const [logs, setLogs] = useState([])
|
const { activeModel, startModel } = useActiveModel()
|
||||||
|
|
||||||
useEffect(() => {
|
const [selectedModel] = useAtom(selectedModelAtom)
|
||||||
getServerLog().then((log) => {
|
|
||||||
setLogs(log.split(/\r?\n|\r|\n/g))
|
|
||||||
})
|
|
||||||
}, [getServerLog, logs])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full w-full">
|
<div className="flex h-full w-full">
|
||||||
@ -78,6 +80,9 @@ const LocalServerScreen = () => {
|
|||||||
window.core?.api?.stopServer()
|
window.core?.api?.stopServer()
|
||||||
setServerEnabled(false)
|
setServerEnabled(false)
|
||||||
} else {
|
} else {
|
||||||
|
if (!activeModel) {
|
||||||
|
startModel(String(selectedModel?.id))
|
||||||
|
}
|
||||||
window.core?.api?.startServer()
|
window.core?.api?.startServer()
|
||||||
setServerEnabled(true)
|
setServerEnabled(true)
|
||||||
}
|
}
|
||||||
@ -105,7 +110,11 @@ const LocalServerScreen = () => {
|
|||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
|
|
||||||
<Input className="w-[60px] flex-shrink-0" value="1337" />
|
<Input
|
||||||
|
className="w-[60px] flex-shrink-0"
|
||||||
|
value="1337"
|
||||||
|
disabled={serverEnabled}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label
|
<label
|
||||||
@ -195,17 +204,7 @@ const LocalServerScreen = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4">
|
<Logs />
|
||||||
<code className="text-xs">
|
|
||||||
{logs.map((log, i) => {
|
|
||||||
return (
|
|
||||||
<p key={i} className="my-2 leading-relaxed">
|
|
||||||
{log}
|
|
||||||
</p>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</code>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Right bar */}
|
{/* Right bar */}
|
||||||
|
|||||||
@ -1,8 +1,16 @@
|
|||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
|
|
||||||
import { InferenceEngine, Model } from '@janhq/core'
|
import { InferenceEngine, Model } from '@janhq/core'
|
||||||
import { Badge } from '@janhq/uikit'
|
import {
|
||||||
|
Badge,
|
||||||
|
Tooltip,
|
||||||
|
TooltipArrow,
|
||||||
|
TooltipContent,
|
||||||
|
TooltipPortal,
|
||||||
|
TooltipTrigger,
|
||||||
|
} from '@janhq/uikit'
|
||||||
|
|
||||||
|
import { useAtom } from 'jotai'
|
||||||
import {
|
import {
|
||||||
MoreVerticalIcon,
|
MoreVerticalIcon,
|
||||||
Trash2Icon,
|
Trash2Icon,
|
||||||
@ -10,6 +18,8 @@ import {
|
|||||||
StopCircleIcon,
|
StopCircleIcon,
|
||||||
} from 'lucide-react'
|
} from 'lucide-react'
|
||||||
|
|
||||||
|
import { twMerge } from 'tailwind-merge'
|
||||||
|
|
||||||
import { useActiveModel } from '@/hooks/useActiveModel'
|
import { useActiveModel } from '@/hooks/useActiveModel'
|
||||||
import { useClickOutside } from '@/hooks/useClickOutside'
|
import { useClickOutside } from '@/hooks/useClickOutside'
|
||||||
|
|
||||||
@ -17,6 +27,8 @@ import useDeleteModel from '@/hooks/useDeleteModel'
|
|||||||
|
|
||||||
import { toGibibytes } from '@/utils/converter'
|
import { toGibibytes } from '@/utils/converter'
|
||||||
|
|
||||||
|
import { serverEnabledAtom } from '@/helpers/atoms/LocalServer.atom'
|
||||||
|
|
||||||
type RowModelProps = {
|
type RowModelProps = {
|
||||||
data: Model
|
data: Model
|
||||||
}
|
}
|
||||||
@ -33,6 +45,8 @@ export default function RowModel(props: RowModelProps) {
|
|||||||
|
|
||||||
const isActiveModel = stateModel.model === props.data.id
|
const isActiveModel = stateModel.model === props.data.id
|
||||||
|
|
||||||
|
const [serverEnabled, setServerEnabled] = useAtom(serverEnabledAtom)
|
||||||
|
|
||||||
const isRemoteModel =
|
const isRemoteModel =
|
||||||
props.data.engine === InferenceEngine.openai ||
|
props.data.engine === InferenceEngine.openai ||
|
||||||
props.data.engine === InferenceEngine.triton_trtllm
|
props.data.engine === InferenceEngine.triton_trtllm
|
||||||
@ -40,10 +54,14 @@ export default function RowModel(props: RowModelProps) {
|
|||||||
const onModelActionClick = (modelId: string) => {
|
const onModelActionClick = (modelId: string) => {
|
||||||
if (activeModel && activeModel.id === modelId) {
|
if (activeModel && activeModel.id === modelId) {
|
||||||
stopModel()
|
stopModel()
|
||||||
|
window.core?.api?.stopServer()
|
||||||
|
setServerEnabled(false)
|
||||||
} else {
|
} else {
|
||||||
|
if (serverEnabled) {
|
||||||
startModel(modelId)
|
startModel(modelId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<tr className="relative border-b border-border last:border-none">
|
<tr className="relative border-b border-border last:border-none">
|
||||||
@ -113,15 +131,26 @@ export default function RowModel(props: RowModelProps) {
|
|||||||
className="absolute right-4 top-10 z-20 w-52 overflow-hidden rounded-lg border border-border bg-background py-2 shadow-lg"
|
className="absolute right-4 top-10 z-20 w-52 overflow-hidden rounded-lg border border-border bg-background py-2 shadow-lg"
|
||||||
ref={setMenu}
|
ref={setMenu}
|
||||||
>
|
>
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger className="w-full">
|
||||||
<div
|
<div
|
||||||
className="flex cursor-pointer items-center space-x-2 px-4 py-2 hover:bg-secondary"
|
className={twMerge(
|
||||||
|
'flex items-center space-x-2 px-4 py-2 hover:bg-secondary',
|
||||||
|
serverEnabled &&
|
||||||
|
activeModel &&
|
||||||
|
activeModel.id !== props.data.id &&
|
||||||
|
'pointer-events-none cursor-not-allowed opacity-40'
|
||||||
|
)}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
onModelActionClick(props.data.id)
|
onModelActionClick(props.data.id)
|
||||||
setMore(false)
|
setMore(false)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{activeModel && activeModel.id === props.data.id ? (
|
{activeModel && activeModel.id === props.data.id ? (
|
||||||
<StopCircleIcon size={16} className="text-muted-foreground" />
|
<StopCircleIcon
|
||||||
|
size={16}
|
||||||
|
className="text-muted-foreground"
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
<PlayIcon size={16} className="text-muted-foreground" />
|
<PlayIcon size={16} className="text-muted-foreground" />
|
||||||
)}
|
)}
|
||||||
@ -130,6 +159,21 @@ export default function RowModel(props: RowModelProps) {
|
|||||||
Model
|
Model
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
</TooltipTrigger>
|
||||||
|
{serverEnabled && (
|
||||||
|
<TooltipPortal>
|
||||||
|
<TooltipContent side="top">
|
||||||
|
<span>
|
||||||
|
{activeModel && activeModel.id === props.data.id
|
||||||
|
? 'The API server is running, change model will stop the server'
|
||||||
|
: 'Threads are disabled while the server is running'}
|
||||||
|
</span>
|
||||||
|
<TooltipArrow />
|
||||||
|
</TooltipContent>
|
||||||
|
</TooltipPortal>
|
||||||
|
)}
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className="flex cursor-pointer items-center space-x-2 px-4 py-2 hover:bg-secondary"
|
className="flex cursor-pointer items-center space-x-2 px-4 py-2 hover:bg-secondary"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|||||||
@ -1,11 +1,22 @@
|
|||||||
import { ScrollArea, Progress, Badge, Button } from '@janhq/uikit'
|
import {
|
||||||
|
ScrollArea,
|
||||||
|
Progress,
|
||||||
|
Badge,
|
||||||
|
Button,
|
||||||
|
Tooltip,
|
||||||
|
TooltipArrow,
|
||||||
|
TooltipContent,
|
||||||
|
TooltipPortal,
|
||||||
|
TooltipTrigger,
|
||||||
|
} from '@janhq/uikit'
|
||||||
|
|
||||||
import { useAtomValue } from 'jotai'
|
import { useAtom, useAtomValue } from 'jotai'
|
||||||
|
|
||||||
import { useActiveModel } from '@/hooks/useActiveModel'
|
import { useActiveModel } from '@/hooks/useActiveModel'
|
||||||
|
|
||||||
import { toGibibytes } from '@/utils/converter'
|
import { toGibibytes } from '@/utils/converter'
|
||||||
|
|
||||||
|
import { serverEnabledAtom } from '@/helpers/atoms/LocalServer.atom'
|
||||||
import {
|
import {
|
||||||
cpuUsageAtom,
|
cpuUsageAtom,
|
||||||
totalRamAtom,
|
totalRamAtom,
|
||||||
@ -19,6 +30,7 @@ export default function SystemMonitorScreen() {
|
|||||||
const usedRam = useAtomValue(usedRamAtom)
|
const usedRam = useAtomValue(usedRamAtom)
|
||||||
const cpuUsage = useAtomValue(cpuUsageAtom)
|
const cpuUsage = useAtomValue(cpuUsageAtom)
|
||||||
const { activeModel, stateModel, stopModel } = useActiveModel()
|
const { activeModel, stateModel, stopModel } = useActiveModel()
|
||||||
|
const [serverEnabled, setServerEnabled] = useAtom(serverEnabledAtom)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full w-full bg-background dark:bg-background">
|
<div className="flex h-full w-full bg-background dark:bg-background">
|
||||||
@ -94,17 +106,38 @@ export default function SystemMonitorScreen() {
|
|||||||
<Badge themes="secondary">v{activeModel.version}</Badge>
|
<Badge themes="secondary">v{activeModel.version}</Badge>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-2 text-center">
|
<td className="px-6 py-2 text-center">
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger className="w-full">
|
||||||
<Button
|
<Button
|
||||||
block
|
block
|
||||||
themes={
|
themes={
|
||||||
stateModel.state === 'stop' ? 'danger' : 'primary'
|
stateModel.state === 'stop'
|
||||||
|
? 'danger'
|
||||||
|
: 'primary'
|
||||||
}
|
}
|
||||||
className="w-16"
|
className="w-16"
|
||||||
loading={stateModel.loading}
|
loading={stateModel.loading}
|
||||||
onClick={() => stopModel()}
|
onClick={() => {
|
||||||
|
stopModel()
|
||||||
|
window.core?.api?.stopServer()
|
||||||
|
setServerEnabled(false)
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
Stop
|
Stop
|
||||||
</Button>
|
</Button>
|
||||||
|
</TooltipTrigger>
|
||||||
|
{serverEnabled && (
|
||||||
|
<TooltipPortal>
|
||||||
|
<TooltipContent side="top">
|
||||||
|
<span>
|
||||||
|
The API server is running, stop the model will
|
||||||
|
also stop the server
|
||||||
|
</span>
|
||||||
|
<TooltipArrow />
|
||||||
|
</TooltipContent>
|
||||||
|
</TooltipPortal>
|
||||||
|
)}
|
||||||
|
</Tooltip>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user