import React, { useEffect, useState, useRef, useMemo, useCallback, } from "react"; import Toggle, { SimpleToggleSwitch } from "@/components/lib/Toggle"; import { Trans, useTranslation } from "react-i18next"; import debounce from "lodash.debounce"; import { MagnifyingGlass, CircleNotch, Warning, CaretDown, CheckCircle, Info, } from "@phosphor-icons/react"; import GMailIcon from "./gmail.png"; import Admin from "@/models/admin"; import System from "@/models/system"; import GmailAgent from "@/models/gmailAgent"; import { getGmailSkills, filterSkillCategories } from "./utils"; import { Tooltip } from "react-tooltip"; import { Link } from "react-router-dom"; import paths from "@/utils/paths"; export default function GMailSkillPanel({ title, skill, toggleSkill, enabled = false, disabled = false, setHasChanges, hasChanges = false, }) { const { t } = useTranslation(); const [disabledSkills, setDisabledSkills] = useState([]); const [loading, setLoading] = useState(true); const [deploymentId, setDeploymentId] = useState(""); const [apiKey, setApiKey] = useState(""); const [isMultiUserMode, setIsMultiUserMode] = useState(false); const [configDefaultExpanded, setConfigDefaultExpanded] = useState(true); const prevHasChanges = useRef(hasChanges); const skillCategories = getGmailSkills(t); useEffect(() => { setLoading(true); Promise.all([ Admin.systemPreferencesByFields(["disabled_gmail_skills"]), System.keys(), GmailAgent.getStatus(), ]) .then(([prefsRes, settingsRes, statusRes]) => { setDisabledSkills(prefsRes?.settings?.disabled_gmail_skills ?? []); setIsMultiUserMode(settingsRes?.MultiUserMode ?? false); if (statusRes?.success && statusRes.config) { const loadedDeploymentId = statusRes.config.deploymentId || ""; const loadedApiKey = statusRes.config.apiKey || ""; setDeploymentId(loadedDeploymentId); setApiKey(loadedApiKey); setConfigDefaultExpanded(!(loadedDeploymentId && loadedApiKey)); } }) .catch(() => { setDisabledSkills([]); setDeploymentId(""); setApiKey(""); }) .finally(() => setLoading(false)); }, []); useEffect(() => { if (prevHasChanges.current === true && hasChanges === false) { Promise.all([ Admin.systemPreferencesByFields(["disabled_gmail_skills"]), GmailAgent.getStatus(), ]) .then(([prefsRes, statusRes]) => { setDisabledSkills(prefsRes?.settings?.disabled_gmail_skills ?? []); if (statusRes?.success && statusRes.config) { setDeploymentId(statusRes.config.deploymentId || ""); setApiKey(statusRes.config.apiKey || ""); } }) .catch(() => {}); } prevHasChanges.current = hasChanges; }, [hasChanges]); function toggleGmailSkill(skillName) { setHasChanges(true); setDisabledSkills((prev) => prev.includes(skillName) ? prev.filter((s) => s !== skillName) : [...prev, skillName] ); } const isConfigured = deploymentId && apiKey; return (
GMail
toggleSkill(skill)} />
{isMultiUserMode && (

{t("agent.skill.gmail.multiUserWarning")}

)}

), }} />

{enabled && !isMultiUserMode && ( <> {loading ? (
) : ( <> {isConfigured && ( )} )} )}
); } function ConfigurationSection({ deploymentId, setDeploymentId, apiKey, setApiKey, setHasChanges, isConfigured, defaultExpanded = true, }) { const { t } = useTranslation(); const [expanded, setExpanded] = useState(defaultExpanded); return (
{expanded && (
{t("agent.skill.gmail.deploymentIdHelp")}
{ setDeploymentId(e.target.value); setHasChanges(true); }} placeholder="AKfycb..." className="w-full px-3 py-2 bg-theme-bg-primary border border-theme-sidebar-border rounded-lg text-theme-text-primary text-sm placeholder:text-theme-text-secondary/50" />
{t("agent.skill.gmail.apiKeyHelp")}
{ setApiKey(e.target.value); setHasChanges(true); }} placeholder="Your API key..." className="w-full px-3 py-2 bg-theme-bg-primary border border-theme-sidebar-border rounded-lg text-theme-text-primary text-sm placeholder:text-theme-text-secondary/50" />
{!isConfigured && (

{t("agent.skill.gmail.configurationRequired")}

)}
)}
); } function SkillSearchInput({ onSearch }) { const { t } = useTranslation(); const inputRef = useRef(null); const debouncedSearch = useMemo( () => debounce((value) => { onSearch(value); }, 300), [onSearch] ); useEffect(() => { return () => { debouncedSearch.cancel(); }; }, [debouncedSearch]); const handleChange = (e) => { debouncedSearch(e.target.value); }; return (
); } function SkillsSection({ skillCategories, disabledSkills, onToggle }) { const { t } = useTranslation(); const [searchTerm, setSearchTerm] = useState(""); const handleSearch = useCallback((value) => { setSearchTerm(value); }, []); const filteredCategories = useMemo( () => filterSkillCategories(skillCategories, searchTerm), [skillCategories, searchTerm] ); const hasResults = Object.keys(filteredCategories).length > 0; return (
{hasResults ? (
{Object.entries(filteredCategories).map(([categoryKey, category]) => ( ))}
) : (

{t("agent.skill.gmail.noSkillsFound")}

)}
); } function CategorySection({ category, disabledSkills, onToggle }) { const Icon = category.icon; return (
{category.title}
{category.skills.map((skill) => ( onToggle(skill.name)} /> ))}
); } function SkillRow({ skill, disabled, onToggle }) { return (
{skill.title} {skill.description}
); } function HiddenFormInputs({ disabledSkills, deploymentId, apiKey }) { const configJson = JSON.stringify({ deploymentId: deploymentId || "", apiKey: apiKey || "", }); return ( <> ); }