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