mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-19 14:41:24 +08:00
refactor: update PluginSettings and ToolingSettings for improved layout and functionality
This commit is contained in:
parent
fcb0020787
commit
6ae5f69163
@ -1,3 +1,4 @@
|
||||
import Scrollbar from '@renderer/components/Scrollbar'
|
||||
import { useAvailablePlugins, useInstalledPlugins, usePluginActions } from '@renderer/hooks/usePlugins'
|
||||
import type { GetAgentResponse, GetAgentSessionResponse, UpdateAgentFunctionUnion } from '@renderer/types/agent'
|
||||
import { Card, Segmented } from 'antd'
|
||||
@ -8,7 +9,6 @@ import { useTranslation } from 'react-i18next'
|
||||
|
||||
import { InstalledPluginsList } from './components/InstalledPluginsList'
|
||||
import { PluginBrowser } from './components/PluginBrowser'
|
||||
import { SettingsContainer } from './shared'
|
||||
|
||||
interface PluginSettingsProps {
|
||||
agentBase: GetAgentResponse | GetAgentSessionResponse
|
||||
@ -131,14 +131,14 @@ const PluginSettings: FC<PluginSettingsProps> = ({ agentBase }) => {
|
||||
])
|
||||
|
||||
return (
|
||||
<SettingsContainer className="pt-0">
|
||||
<Scrollbar>
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex justify-center">
|
||||
<Segmented options={segmentOptions} value={activeTab} onChange={(value) => setActiveTab(value as string)} />
|
||||
</div>
|
||||
{renderContent}
|
||||
</div>
|
||||
</SettingsContainer>
|
||||
</Scrollbar>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -14,7 +14,7 @@ import type {
|
||||
import { AgentConfigurationSchema } from '@renderer/types'
|
||||
import { Modal, Tag } from 'antd'
|
||||
import { Alert, Card, Input, Switch } from 'antd'
|
||||
import { ShieldAlert, ShieldCheck, Wrench } from 'lucide-react'
|
||||
import { ShieldAlert, Wrench } from 'lucide-react'
|
||||
import type { FC } from 'react'
|
||||
import { useCallback, useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
@ -274,15 +274,15 @@ export const ToolingSettings: FC<AgentToolingSettingsProps> = ({ agentBase, upda
|
||||
return (
|
||||
<div
|
||||
key={card.mode}
|
||||
className={`flex overflow-hidden rounded-lg border ${
|
||||
isSelected ? 'border-primary' : 'border-default-200'
|
||||
} ${disabled ? 'opacity-60' : ''}`}
|
||||
onClick={() => handleSelectPermissionMode(card.mode)}>
|
||||
<Card
|
||||
variant={'borderless'}
|
||||
title={
|
||||
<div className="flex flex-row items-center justify-between gap-2 py-2">
|
||||
<div className="flex flex-col">
|
||||
className={`flex flex-col gap-3 overflow-hidden rounded-lg border p-4 transition-colors ${
|
||||
isSelected
|
||||
? 'border-primary bg-primary-50/30 dark:bg-primary-950/20'
|
||||
: 'border-default-200 hover:bg-default-50 dark:hover:bg-default-900/20'
|
||||
} ${disabled ? 'cursor-not-allowed opacity-60' : 'cursor-pointer'}`}
|
||||
onClick={() => !disabled && handleSelectPermissionMode(card.mode)}>
|
||||
{/* Header */}
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div className="flex min-w-0 flex-1 flex-col gap-1">
|
||||
<span className="whitespace-normal break-words text-left font-semibold text-sm">
|
||||
{t(card.titleKey, card.titleFallback)}
|
||||
</span>
|
||||
@ -290,44 +290,31 @@ export const ToolingSettings: FC<AgentToolingSettingsProps> = ({ agentBase, upda
|
||||
{t(card.descriptionKey, card.descriptionFallback)}
|
||||
</span>
|
||||
</div>
|
||||
{disabled ? (
|
||||
<Tag color="warning">{t('common.coming_soon', 'Coming soon')}</Tag>
|
||||
) : isSelected ? (
|
||||
{disabled && <Tag color="warning">{t('common.coming_soon', 'Coming soon')}</Tag>}
|
||||
{isSelected && !disabled && (
|
||||
<Tag color="success">
|
||||
<div className="flex flex-col items-center py-2">
|
||||
<ShieldCheck size={14} />
|
||||
<div className="flex items-center gap-1">
|
||||
<span>{t('common.selected', 'Selected')}</span>
|
||||
</div>
|
||||
</Tag>
|
||||
) : null}
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
styles={{
|
||||
header: {
|
||||
paddingLeft: '12px',
|
||||
paddingRight: '12px',
|
||||
borderBottom: 'none'
|
||||
},
|
||||
body: {
|
||||
paddingLeft: '12px',
|
||||
paddingRight: '12px'
|
||||
}
|
||||
}}>
|
||||
<div className="gap-2 text-left text-xs">
|
||||
<span className="text-foreground-600">{t(card.behaviorKey, card.behaviorFallback)}</span>
|
||||
{showCaution ? (
|
||||
<div className="flex items-center gap-1">
|
||||
<ShieldAlert className="text-danger-600" size={24} />
|
||||
<span className="text-danger-600">
|
||||
|
||||
{/* Body */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<span className="text-foreground-600 text-xs">{t(card.behaviorKey, card.behaviorFallback)}</span>
|
||||
{showCaution && (
|
||||
<div className="flex items-start gap-2 rounded-md bg-danger-50 p-2 dark:bg-danger-950/30">
|
||||
<ShieldAlert className="mt-0.5 flex-shrink-0 text-danger-600" size={16} />
|
||||
<span className="text-danger-600 text-xs">
|
||||
{t(
|
||||
'agent.settings.tooling.permissionMode.bypassPermissions.warning',
|
||||
'Use with caution — all tools will run without asking for approval.'
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
) : null}
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
@ -414,7 +401,7 @@ export const ToolingSettings: FC<AgentToolingSettingsProps> = ({ agentBase, upda
|
||||
})}
|
||||
checked={isApproved}
|
||||
disabled={isAuto || isUpdatingTools}
|
||||
size="default"
|
||||
size="small"
|
||||
onChange={(checked) => handleToggleTool(tool.id, checked)}
|
||||
/>
|
||||
</div>
|
||||
@ -485,7 +472,7 @@ export const ToolingSettings: FC<AgentToolingSettingsProps> = ({ agentBase, upda
|
||||
name: server.name
|
||||
})}
|
||||
checked={isSelected}
|
||||
size="default"
|
||||
size="small"
|
||||
disabled={!server.isActive || isUpdatingMcp}
|
||||
onChange={(checked) => handleToggleMcp(server.id, checked)}
|
||||
/>
|
||||
|
||||
@ -230,57 +230,27 @@ export const PluginBrowser: FC<PluginBrowserProps> = ({
|
||||
setSelectedPlugin(null)
|
||||
}
|
||||
|
||||
const handleOpenFilterDropdown = () => {
|
||||
setFilterDropdownOpen(!filterDropdownOpen)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
{/* Search and Filter */}
|
||||
<div className="relative flex gap-0">
|
||||
<div className="flex gap-2">
|
||||
<AntInput
|
||||
placeholder={t('plugins.search_placeholder')}
|
||||
value={searchQuery}
|
||||
onChange={(e) => handleSearchChange(e.target.value)}
|
||||
prefix={<Search className="h-4 w-4 text-default-400" />}
|
||||
suffix={
|
||||
<AntButton
|
||||
variant={selectedCategories.length > 0 ? 'filled' : 'text'}
|
||||
color={selectedCategories.length > 0 ? 'primary' : 'default'}
|
||||
size="small"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: '50%',
|
||||
right: '8px',
|
||||
transform: 'translateY(-50%)',
|
||||
padding: '4px',
|
||||
minWidth: '32px',
|
||||
borderRadius: '4px'
|
||||
}}
|
||||
icon={<Filter className="h-4 w-4" />}
|
||||
onClick={handleOpenFilterDropdown}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<AntDropdown
|
||||
menu={{ items: pluginCategoryMenuItems }}
|
||||
trigger={['click']}
|
||||
open={filterDropdownOpen}
|
||||
placement="bottomRight"
|
||||
onOpenChange={setFilterDropdownOpen}>
|
||||
<AntButton
|
||||
variant={selectedCategories.length > 0 ? 'filled' : 'text'}
|
||||
variant={selectedCategories.length > 0 ? 'filled' : 'outlined'}
|
||||
color={selectedCategories.length > 0 ? 'primary' : 'default'}
|
||||
size="small"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: '50%',
|
||||
right: '8px',
|
||||
transform: 'translateY(-50%)',
|
||||
padding: '4px',
|
||||
minWidth: '32px',
|
||||
borderRadius: '4px'
|
||||
}}
|
||||
icon={<Filter className="h-4 w-4" />}
|
||||
size="middle"
|
||||
icon={<Filter className="h-4 w-4" color="var(--color-text-2)" />}
|
||||
/>
|
||||
</AntDropdown>
|
||||
</div>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user