"use client"; import { IconRefresh } from "@tabler/icons-react"; import { Button } from "@kandev/ui/button"; import { SettingsPageTemplate } from "@/components/settings/settings-page-template"; import { usePlugins } from "@/hooks/domains/plugins/use-plugins"; import { InstallPluginDialog } from "./install-plugin-dialog"; import { PluginRow } from "./plugin-row"; import { UninstallPluginDialog } from "./uninstall-plugin-dialog"; import { usePluginActions } from "./use-plugin-actions"; /** * Operator UI to install/list/enable/disable/uninstall plugins * (docs/plans/plugins/task-20-mgmt-page.md, reworked for the install-based * flow in docs/plans/plugins/GRPC-CONTRACT.md ยง7). Gated on the `plugins` * feature flag by the page-level default export. */ export function PluginsSettings() { const { items, loaded, loading, error } = usePlugins(); const actions = usePluginActions(); return ( undefined} showSaveButton={false} >
Installed plugins
{actions.syncErrors.length > 0 && (
{actions.syncErrors.map((err) => (
{err.path}: {err.reason}
))}
)}
); } type PluginListProps = { items: ReturnType["items"]; loaded: boolean; loading: boolean; error: string | null; actions: ReturnType; }; function PluginList({ items, loaded, loading, error, actions }: PluginListProps) { if (error) { return (
{error}
); } if (!loaded && loading) { return (
Loading plugins...
); } if (loaded && items.length === 0) { return (
No plugins yet. Install a plugin package to get started.
); } return (
{items.map((plugin) => ( ))}
); }