"use client";
import { useMemo } from "react";
import { useTranslation } from "react-i18next";
import { IconRefresh } from "@tabler/icons-react";
import { Button } from "@kandev/ui/button";
import { Switch } from "@kandev/ui/switch";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@kandev/ui/tabs";
import { SettingsPageTemplate } from "@/components/settings/settings-page-template";
import { useResponsiveBreakpoint } from "@/hooks/use-responsive-breakpoint";
import { useAutoUpdateSettings } from "@/hooks/domains/plugins/use-auto-update-settings";
import { useIsAdmin } from "@/hooks/domains/auth/use-is-admin";
import { useFeature } from "@/hooks/domains/features/use-feature";
import { usePlugins } from "@/hooks/domains/plugins/use-plugins";
import { usePluginSetupStatus } from "@/hooks/domains/plugins/use-plugin-setup-status";
import { usePluginUpdates } from "@/hooks/domains/plugins/use-plugin-updates";
import { InstallPluginDialog } from "./install-plugin-dialog";
import { MarketplaceBrowser } from "./marketplace-browser";
import { CanvasMarketplace } from "./canvas-marketplace";
import { PluginRow, type PluginRowUpdateState } from "./plugin-row";
import { PluginUpdateStatus } from "./plugin-update-status";
import { usePluginActions } from "./use-plugin-actions";
import { usePluginUpdateAction } from "./use-plugin-update-action";
import { settingsActionClassName } from "@/components/settings/settings-control";
/**
* Operator UI to browse, install, enable, disable, uninstall, and update kandev
* plugins (docs/specs/plugins/requirements/marketplace.md). Gated on the `plugins` feature
* flag by the page-level default export.
*/
export function PluginsSettings() {
const { t } = useTranslation();
const canManage = useIsAdmin();
const canvasesEnabled = useFeature("canvases");
const { isFinePointer } = useResponsiveBreakpoint();
const list = usePlugins();
const actions = usePluginActions();
const autoUpdate = useAutoUpdateSettings();
const updates = usePluginUpdates();
const installedIds = useMemo(() => new Set(list.items.map((p) => p.id)), [list.items]);
const updateAction = usePluginUpdateAction(
actions.marketplaceInstall,
updates.reload,
installedIds,
updates.markUpdated,
);
const handleMarketplaceInstall = async (url: string) => {
const result = await actions.marketplaceInstall(url);
if (result.ok) await updates.reload(result.pluginId);
return result;
};
return (
undefined}
showSaveButton={false}
>
{t("plugins:tabInstalled")}
{t("plugins:tabBrowse")}
{canvasesEnabled && (
{t("plugins:tabCanvases")}
)}
{canvasesEnabled && (
)}
{canManage && (
)}
);
}
type InstalledTabProps = {
list: ReturnType;
actions: ReturnType;
autoUpdate: ReturnType;
canManage: boolean;
updates: ReturnType;
updateAction: ReturnType;
isFinePointer: boolean;
};
/** The Installed tab: auto-update toggle, sync/install toolbar, update status, sync errors, and the plugin list. */
function InstalledTab({
list,
actions,
autoUpdate,
updates,
canManage,
updateAction,
isFinePointer,
}: InstalledTabProps) {
const { t } = useTranslation();
return (
<>
{canManage && }
{t("plugins:installedPlugins")}
{canManage && (
)}
{canManage && actions.syncErrors.length > 0 && (
{actions.syncErrors.map((err) => (
{err.path}: {err.reason}
))}
)}
>
);
}
/**
* The instance-wide "Automatically update plugins" switch. When on, every
* installed plugin without its own per-row override is auto-updated in the
* background. Individual rows can still override this either way.
*/
function GlobalAutoUpdateToggle({
settings,
}: {
settings: ReturnType;
}) {
const { t } = useTranslation();
return (