feat: improvement ux for local api server

This commit is contained in:
Faisal Amir 2024-01-22 18:49:44 +07:00
parent aeab22f5ab
commit 69ff85f66a
4 changed files with 160 additions and 124 deletions

View File

@ -162,7 +162,11 @@ export default function DropdownListSidebar() {
stateModel.loading && 'pointer-events-none bg-blue-200 text-blue-600' stateModel.loading && 'pointer-events-none bg-blue-200 text-blue-600'
)} )}
> >
<Select value={selectedModel?.id} onValueChange={onValueSelected}> <Select
value={selectedModel?.id}
onValueChange={onValueSelected}
disabled={serverEnabled}
>
<SelectTrigger className="relative w-full"> <SelectTrigger className="relative w-full">
<SelectValue placeholder="Choose model to start"> <SelectValue placeholder="Choose model to start">
{stateModel.loading && ( {stateModel.loading && (

View File

@ -49,6 +49,9 @@ const TopBar = () => {
case MainViewState.Thread: case MainViewState.Thread:
return activeThread ? activeThread?.title : 'New Thread' return activeThread ? activeThread?.title : 'New Thread'
case MainViewState.LocalServer:
return 'Local API Server'
default: default:
return MainViewState[viewStateName]?.replace(/([A-Z])/g, ' $1').trim() return MainViewState[viewStateName]?.replace(/([A-Z])/g, ' $1').trim()
} }
@ -78,34 +81,36 @@ const TopBar = () => {
</div> </div>
) : ( ) : (
<div className="relative w-full"> <div className="relative w-full">
<div className="absolute left-16 h-full w-60 border-r border-border"> {mainViewState == MainViewState.Thread && (
<div className="flex h-full w-full items-center justify-between"> <div className="absolute left-16 h-full w-60 border-r border-border">
<div <div className="flex h-full w-full items-center justify-between">
className={twMerge( <div
'unset-drag cursor-pointer', className={twMerge('unset-drag cursor-pointer')}
mainViewState !== MainViewState.Thread && 'invisible' onClick={() => setShowLeftSideBar((show) => !show)}
)} >
onClick={() => setShowLeftSideBar((show) => !show)} <PanelRightCloseIcon
> size={20}
<PanelRightCloseIcon className={twMerge(
size={20} 'ml-4 text-muted-foreground',
className={twMerge( showLeftSideBar && 'rotate-180'
'ml-4 text-muted-foreground', )}
showLeftSideBar && 'rotate-180' />
)} </div>
/> <div
</div> className="unset-drag cursor-pointer pr-4"
<div onClick={onCreateConversationClick}
className="unset-drag cursor-pointer pr-4" >
onClick={onCreateConversationClick} <PenSquareIcon size={20} className="text-muted-foreground" />
> </div>
<PenSquareIcon size={20} className="text-muted-foreground" />
</div> </div>
</div> </div>
</div> )}
<div <div
className={twMerge( className={twMerge(
'absolute left-80 right-10 h-full', 'absolute right-10 h-full',
mainViewState == MainViewState.Thread
? 'left-80'
: 'left-16 pl-6',
showing && 'right-80' showing && 'right-80'
)} )}
> >

View File

@ -2,6 +2,8 @@
import React, { useEffect, useState } from 'react' import React, { useEffect, useState } from 'react'
import ScrollToBottom from 'react-scroll-to-bottom'
import { import {
Button, Button,
Switch, Switch,
@ -99,7 +101,7 @@ const LocalServerScreen = () => {
<div className="space-y-3 px-4"> <div className="space-y-3 px-4">
<Button <Button
block block
themes={serverEnabled ? 'danger' : 'success'} themes={serverEnabled ? 'danger' : 'primary'}
disabled={stateModel.loading} disabled={stateModel.loading}
onClick={() => { onClick={() => {
if (serverEnabled) { if (serverEnabled) {
@ -135,105 +137,124 @@ const LocalServerScreen = () => {
</div> </div>
</div> </div>
<div className="space-y-4 p-4"> <Tooltip>
<div className="flex w-full flex-shrink-0 items-center gap-x-2"> <TooltipTrigger asChild>
<Select <div className="space-y-4 p-4">
value={host} <div>
onValueChange={(e) => setHost(e)} <p className="mb-2 block text-sm font-semibold text-zinc-500 dark:text-gray-300">
disabled={serverEnabled} Server Options
> </p>
<SelectTrigger className="w-full"> <div className="flex w-full flex-shrink-0 items-center gap-x-2">
<SelectValue /> <Select
</SelectTrigger> value={host}
<SelectContent> onValueChange={(e) => setHost(e)}
<SelectItem value="127.0.0.1">127.0.0.1</SelectItem> disabled={serverEnabled}
<SelectItem value="0.0.0.0">0.0.0.0</SelectItem> >
</SelectContent> <SelectTrigger className="w-full">
</Select> <SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="127.0.0.1">127.0.0.1</SelectItem>
<SelectItem value="0.0.0.0">0.0.0.0</SelectItem>
</SelectContent>
</Select>
<Input <Input
className="w-[60px] flex-shrink-0" className="w-[60px] flex-shrink-0"
value={port} value={port}
onChange={(e) => setPort(e.target.value)} onChange={(e) => setPort(e.target.value)}
maxLength={4} maxLength={4}
disabled={serverEnabled} disabled={serverEnabled}
/>
</div>
<div>
<label
id="cors"
className="mb-2 inline-flex items-start gap-x-2 font-bold text-zinc-500 dark:text-gray-300"
>
Cross-Origin-Resource-Sharing (CORS)
<Tooltip>
<TooltipTrigger asChild>
<InfoIcon
size={16}
className="mt-0.5 flex-shrink-0 dark:text-gray-500"
/> />
</TooltipTrigger> </div>
<TooltipPortal> </div>
<TooltipContent side="top" className="max-w-[240px]"> <div>
<span> <label
CORS (Cross-Origin Resource Sharing) manages resource id="cors"
access on this server from external domains. Enable for className="mb-2 inline-flex items-start gap-x-2 font-bold text-zinc-500 dark:text-gray-300"
secure inter-website communication, regulating data >
sharing to bolster overall security. Cross-Origin-Resource-Sharing (CORS)
</span> <Tooltip>
<TooltipArrow /> <TooltipTrigger asChild>
</TooltipContent> <InfoIcon
</TooltipPortal> size={16}
</Tooltip> className="mt-0.5 flex-shrink-0 dark:text-gray-500"
</label> />
<div className="flex items-center justify-between"> </TooltipTrigger>
<Switch <TooltipPortal>
checked={isCorsEnabled} <TooltipContent side="top" className="max-w-[240px]">
onCheckedChange={(e) => setIsCorsEnabled(e)} <span>
name="cors" CORS (Cross-Origin Resource Sharing) manages resource
disabled={serverEnabled} access on this server from external domains. Enable
/> for secure inter-website communication, regulating
</div> data sharing to bolster overall security.
</div> </span>
<div> <TooltipArrow />
<label </TooltipContent>
id="verbose" </TooltipPortal>
className="mb-2 inline-flex items-start gap-x-2 font-bold text-zinc-500 dark:text-gray-300" </Tooltip>
> </label>
Verbose Server Logs <div className="flex items-center justify-between">
<Tooltip> <Switch
<TooltipTrigger asChild> checked={isCorsEnabled}
<InfoIcon onCheckedChange={(e) => setIsCorsEnabled(e)}
size={16} name="cors"
className="mt-0.5 flex-shrink-0 dark:text-gray-500" disabled={serverEnabled}
/> />
</TooltipTrigger> </div>
<TooltipPortal> </div>
<TooltipContent side="top" className="max-w-[240px]"> <div>
<span> <label
Verbose Server Logs provide extensive details about server id="verbose"
activities. Enable to capture thorough records, aiding in className="mb-2 inline-flex items-start gap-x-2 font-bold text-zinc-500 dark:text-gray-300"
troubleshooting and monitoring server performance >
effectively. Verbose Server Logs
</span> <Tooltip>
<TooltipArrow /> <TooltipTrigger asChild>
</TooltipContent> <InfoIcon
</TooltipPortal> size={16}
</Tooltip> className="mt-0.5 flex-shrink-0 dark:text-gray-500"
</label> />
<div className="flex items-center justify-between"> </TooltipTrigger>
<Switch <TooltipPortal>
checked={isVerboseEnabled} <TooltipContent side="top" className="max-w-[240px]">
onCheckedChange={(e) => setIsVerboseEnabled(e)} <span>
name="verbose" Verbose Server Logs provide extensive details about
disabled={serverEnabled} server activities. Enable to capture thorough records,
/> aiding in troubleshooting and monitoring server
performance effectively.
</span>
<TooltipArrow />
</TooltipContent>
</TooltipPortal>
</Tooltip>
</label>
<div className="flex items-center justify-between">
<Switch
checked={isVerboseEnabled}
onCheckedChange={(e) => setIsVerboseEnabled(e)}
name="verbose"
disabled={serverEnabled}
/>
</div>
</div>
</div> </div>
</div> </TooltipTrigger>
</div> <TooltipPortal>
{serverEnabled && (
<TooltipContent side="bottom" className="max-w-[200px]">
<span>
Settings cannot be modified while the server is running
</span>
<TooltipArrow />
</TooltipContent>
)}
</TooltipPortal>
</Tooltip>
</div> </div>
{/* Middle Bar */} {/* Middle Bar */}
<div className="relative flex h-full w-full flex-col overflow-auto bg-background"> <ScrollToBottom className="relative flex h-full w-full flex-col overflow-auto bg-background">
<div className="sticky top-0 flex items-center justify-between bg-zinc-100 px-4 py-2 dark:bg-secondary/30"> <div className="sticky top-0 flex items-center justify-between bg-zinc-100 px-4 py-2 dark:bg-secondary/30">
<h2 className="font-bold">Server Logs</h2> <h2 className="font-bold">Server Logs</h2>
<div className="space-x-2"> <div className="space-x-2">
@ -279,8 +300,8 @@ const LocalServerScreen = () => {
<div> <div>
<h6 className="font-medium text-black"> <h6 className="font-medium text-black">
You cannot chat with your assistant while the server is Once you start the server, you cannot chat with your
running. assistant.
</h6> </h6>
<Button <Button
className="mt-4" className="mt-4"
@ -298,7 +319,7 @@ const LocalServerScreen = () => {
) : ( ) : (
<Logs /> <Logs />
)} )}
</div> </ScrollToBottom>
{/* Right bar */} {/* Right bar */}
<div <div

View File

@ -175,11 +175,17 @@ export default function RowModel(props: RowModelProps) {
</Tooltip> </Tooltip>
<div <div
className="flex cursor-pointer items-center space-x-2 px-4 py-2 hover:bg-secondary" className={twMerge(
'flex cursor-pointer items-center space-x-2 px-4 py-2 hover:bg-secondary',
serverEnabled &&
'pointer-events-none cursor-not-allowed opacity-40'
)}
onClick={() => { onClick={() => {
setTimeout(async () => { setTimeout(async () => {
await stopModel() if (serverEnabled) {
deleteModel(props.data) await stopModel()
deleteModel(props.data)
}
}, 500) }, 500)
setMore(false) setMore(false)
}} }}