From c13971d7d6deb5a56bd83bb789664a0b50e59800 Mon Sep 17 00:00:00 2001 From: Junyan Chin Date: Mon, 23 Mar 2026 22:22:31 +0800 Subject: [PATCH] feat(web): merge plugin readme and config into single detail dialog (#2076) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(web): merge plugin readme and config into single detail dialog - Click plugin card directly opens combined dialog (left: readme, right: config) - Remove hover overlay with separate readme/config buttons - Dropdown menu (⋯) still available for update/delete/view source * fix: prettier format for lucide import --- .../PluginInstalledComponent.tsx | 90 ++++++++----------- .../plugin-card/PluginCardComponent.tsx | 67 ++------------ 2 files changed, 44 insertions(+), 113 deletions(-) diff --git a/web/src/app/home/plugins/components/plugin-installed/PluginInstalledComponent.tsx b/web/src/app/home/plugins/components/plugin-installed/PluginInstalledComponent.tsx index baedfee3..d7d8544a 100644 --- a/web/src/app/home/plugins/components/plugin-installed/PluginInstalledComponent.tsx +++ b/web/src/app/home/plugins/components/plugin-installed/PluginInstalledComponent.tsx @@ -38,12 +38,10 @@ const PluginInstalledComponent = forwardRef( (props, ref) => { const { t } = useTranslation(); const [pluginList, setPluginList] = useState([]); - const [modalOpen, setModalOpen] = useState(false); + const [detailModalOpen, setDetailModalOpen] = useState(false); const [selectedPlugin, setSelectedPlugin] = useState( null, ); - const [readmeModalOpen, setReadmeModalOpen] = useState(false); - const [readmePlugin, setReadmePlugin] = useState(null); const [showOperationModal, setShowOperationModal] = useState(false); const [operationType, setOperationType] = useState( PluginOperationType.DELETE, @@ -166,12 +164,7 @@ const PluginInstalledComponent = forwardRef( function handlePluginClick(plugin: PluginCardVO) { setSelectedPlugin(plugin); - setModalOpen(true); - } - - function handleViewReadme(plugin: PluginCardVO) { - setReadmePlugin(plugin); - setReadmeModalOpen(true); + setDetailModalOpen(true); } function handlePluginDelete(plugin: PluginCardVO) { @@ -355,52 +348,46 @@ const PluginInstalledComponent = forwardRef( ) : (
- - - - {t('plugins.pluginConfig')} - -
- {selectedPlugin && ( - { - setModalOpen(false); - if (timeout) { - setTimeout(() => { - getPluginList(); - }, timeout); - } else { - getPluginList(); - } - }} - onFormCancel={() => { - setModalOpen(false); - }} - /> - )} -
-
-
- - - + + - {readmePlugin && - `${readmePlugin.author}/${readmePlugin.name} - ${t( - 'plugins.readme', - )}`} + {selectedPlugin && + `${selectedPlugin.author}/${selectedPlugin.name}`} -
- {readmePlugin && ( - - )} +
+ {/* Left side - Readme */} +
+ {selectedPlugin && ( + + )} +
+ {/* Right side - Config */} +
+ {selectedPlugin && ( + { + setDetailModalOpen(false); + if (timeout) { + setTimeout(() => { + getPluginList(); + }, timeout); + } else { + getPluginList(); + } + }} + onFormCancel={() => { + setDetailModalOpen(false); + }} + /> + )} +
@@ -413,7 +400,6 @@ const PluginInstalledComponent = forwardRef( onCardClick={() => handlePluginClick(vo)} onDeleteClick={() => handlePluginDelete(vo)} onUpgradeClick={() => handlePluginUpdate(vo)} - onViewReadme={() => handleViewReadme(vo)} />
); diff --git a/web/src/app/home/plugins/components/plugin-installed/plugin-card/PluginCardComponent.tsx b/web/src/app/home/plugins/components/plugin-installed/plugin-card/PluginCardComponent.tsx index c15c349d..341493b2 100644 --- a/web/src/app/home/plugins/components/plugin-installed/plugin-card/PluginCardComponent.tsx +++ b/web/src/app/home/plugins/components/plugin-installed/plugin-card/PluginCardComponent.tsx @@ -2,15 +2,7 @@ import { PluginCardVO } from '@/app/home/plugins/components/plugin-installed/Plu import { useState } from 'react'; import { Badge } from '@/components/ui/badge'; import { useTranslation } from 'react-i18next'; -import { - BugIcon, - ExternalLink, - Ellipsis, - Trash, - ArrowUp, - Settings, - FileText, -} from 'lucide-react'; +import { BugIcon, ExternalLink, Ellipsis, Trash, ArrowUp } from 'lucide-react'; import { getCloudServiceClientSync, systemInfo } from '@/app/infra/http'; import { httpClient } from '@/app/infra/http/HttpClient'; import { Button } from '@/components/ui/button'; @@ -27,28 +19,20 @@ export default function PluginCardComponent({ onCardClick, onDeleteClick, onUpgradeClick, - onViewReadme, }: { cardVO: PluginCardVO; onCardClick: () => void; onDeleteClick: (cardVO: PluginCardVO) => void; onUpgradeClick: (cardVO: PluginCardVO) => void; - onViewReadme: (cardVO: PluginCardVO) => void; }) { const { t } = useTranslation(); const [dropdownOpen, setDropdownOpen] = useState(false); - const [isHovered, setIsHovered] = useState(false); return ( <>
setIsHovered(true)} - onMouseLeave={() => { - if (!dropdownOpen) { - setIsHovered(false); - } - }} + onClick={() => onCardClick()} >
{/* Icon - fixed width */} @@ -145,7 +129,10 @@ export default function PluginCardComponent({
{/* Menu button - fixed width and position */} -
+
e.stopPropagation()} + >
@@ -153,9 +140,6 @@ export default function PluginCardComponent({ open={dropdownOpen} onOpenChange={(open) => { setDropdownOpen(open); - if (!open) { - setIsHovered(false); - } }} > @@ -233,45 +217,6 @@ export default function PluginCardComponent({
- - {/* Hover overlay with action buttons */} -
- - -
);