"use client" import Link from "next/link" import { ChevronDown, Settings2 } from "lucide-react" import { useState } from "react" import { AutomationTabMasonry } from "@/components/gmail/settings/automation/automation-tab-masonry" import { OrgSettingsSection } from "@/components/admin/settings/org-settings-form" import { SettingsCard, SettingsField, SettingsGrid, SettingsToggleRow, } from "@/components/settings/settings-kit" import { DeployLockedHint, useDeployFieldLocked } from "@/components/admin/settings/deploy-locked-hint" import { useOrgSettingsStore } from "@/lib/admin-settings/org-settings-store" import { isPluginDeployLocked } from "@/lib/admin/deploy-runtime" import { Switch } from "@/components/ui/switch" import { Badge } from "@/components/ui/badge" import { TechBrandSelectLabel } from "@/components/admin/settings/tech-brand-select-label" import { Input } from "@/components/ui/input" import { Button } from "@/components/ui/button" import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from "@/components/ui/collapsible" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select" import { ULTICAL_APP_NAME } from "@/lib/suite/page-metadata" import { cn } from "@/lib/utils" const SIMPLE_PLUGIN_IDS = new Set(["mail-automation", "contact-discovery", "public-share"]) const CONFIG_PLUGIN_IDS = new Set(["office-editor", "richtext-editor", "ai-assistant"]) export function PluginsSection() { const plugins = useOrgSettingsStore((s) => s.plugins) const togglePlugin = useOrgSettingsStore((s) => s.togglePlugin) const deployLocked = useOrgSettingsStore((s) => s.meta?.deployLocked) const simplePlugins = plugins.filter((p) => SIMPLE_PLUGIN_IDS.has(p.id)) const configPlugins = plugins.filter((p) => CONFIG_PLUGIN_IDS.has(p.id)) return ( {simplePlugins.map((plugin) => { const locked = isPluginDeployLocked(deployLocked, plugin.id) return ( togglePlugin(plugin.id, enabled)} /> ) })} {configPlugins.map((plugin) => { const locked = isPluginDeployLocked(deployLocked, plugin.id) if (plugin.id === "office-editor") { return ( togglePlugin(plugin.id, enabled)} /> ) } if (plugin.id === "richtext-editor") { return ( togglePlugin(plugin.id, enabled)} /> ) } return ( togglePlugin(plugin.id, enabled)} /> ) })} ) } function PluginToggleCard({ name, description, version, enabled, locked, lockSection, lockField, onToggle, hint, action, children, defaultOpen = false, }: { name: string description: string version?: string enabled: boolean locked?: boolean lockSection?: string lockField?: string onToggle: (enabled: boolean) => void hint?: React.ReactNode action?: React.ReactNode children?: React.ReactNode defaultOpen?: boolean }) { const [open, setOpen] = useState(defaultOpen) const hasConfig = Boolean(children) const body = action ? ( action ) : hasConfig ? ( {children} ) : null return ( {name} {version ? v{version} : null} } description={description} action={} hint={ hint || (locked && lockSection && lockField) ? ( <> {hint} {locked && lockSection && lockField ? ( ) : null} ) : null } divider={false} contentClassName="space-y-0 !mt-3 !pt-0" > {body} ) } function NextcloudPluginCard() { const nextcloud = useOrgSettingsStore((s) => s.nextcloud) const setNextcloud = useOrgSettingsStore((s) => s.setNextcloud) const effective = useOrgSettingsStore((s) => s.meta?.effective.nextcloud) const enabledLocked = useDeployFieldLocked("nextcloud", "enabled") const urlLocked = useDeployFieldLocked("nextcloud", "base_url") const userLocked = useDeployFieldLocked("nextcloud", "admin_user") const passLocked = useDeployFieldLocked("nextcloud", "admin_password") const enabled = enabledLocked ? (effective?.enabled ?? nextcloud.enabled) : nextcloud.enabled const baseURL = urlLocked ? (effective?.base_url ?? nextcloud.base_url) : nextcloud.base_url const adminUser = userLocked ? (effective?.admin_user ?? nextcloud.admin_user) : nextcloud.admin_user return ( setNextcloud({ enabled: v })} defaultOpen={enabled} > : undefined} > setNextcloud({ base_url: e.target.value })} placeholder="https://cloud.example.com" /> : undefined} > setNextcloud({ admin_user: e.target.value })} /> : undefined} > setNextcloud({ admin_password: e.target.value })} placeholder={passLocked ? "Défini via NC_ADMIN_PASSWORD" : undefined} />

Modules exposés

Active ou masque chaque application Nextcloud dans la suite.

setNextcloud({ drive_enabled })} /> setNextcloud({ calendar_enabled })} /> setNextcloud({ contacts_enabled })} /> setNextcloud({ talk_enabled })} />
) } function OnlyOfficePluginCard({ plugin, locked, onToggle, }: { plugin: { name: string; description: string; version: string; enabled: boolean } locked: boolean onToggle: (enabled: boolean) => void }) { const onlyoffice = useOrgSettingsStore((s) => s.onlyoffice) const setOnlyoffice = useOrgSettingsStore((s) => s.setOnlyoffice) const effective = useOrgSettingsStore((s) => s.meta?.effective.onlyoffice) const enabledLocked = useDeployFieldLocked("onlyoffice", "enabled") const urlLocked = useDeployFieldLocked("onlyoffice", "document_server_url") const jwtLocked = useDeployFieldLocked("onlyoffice", "jwt_secret") const headerLocked = useDeployFieldLocked("onlyoffice", "jwt_header") const enabled = enabledLocked ? (effective?.enabled ?? plugin.enabled) : plugin.enabled const docURL = urlLocked ? (effective?.document_server_url ?? onlyoffice.document_server_url) : onlyoffice.document_server_url return (
{enabledLocked ? : null} : undefined } > setOnlyoffice({ document_server_url: e.target.value })} placeholder="https://office.example.com" /> : undefined} > setOnlyoffice({ jwt_secret: e.target.value })} placeholder={jwtLocked ? "Défini via ONLYOFFICE_JWT_SECRET" : undefined} /> : undefined} > setOnlyoffice({ jwt_header: e.target.value })} />
) } function RichtextPluginCard({ plugin, locked, onToggle, }: { plugin: { name: string; description: string; version: string; enabled: boolean } locked: boolean onToggle: (enabled: boolean) => void }) { const richtext = useOrgSettingsStore((s) => s.richtext) const setRichtext = useOrgSettingsStore((s) => s.setRichtext) return ( setRichtext({ hocuspocus_url: e.target.value })} placeholder="ws://localhost:1234" /> ) } function AiAssistantPluginCard({ plugin, locked, onToggle, }: { plugin: { name: string; description: string; version: string; enabled: boolean } locked: boolean onToggle: (enabled: boolean) => void }) { return ( OpenWebUI doit être déployé ( AI_ASSISTANT_ENABLED=true ).

) : null } action={ } /> ) } function ServiceToggle({ label, checked, onChange, }: { label: string checked: boolean onChange: (v: boolean) => void }) { return }