import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useState, useEffect } from "react"; import { usePluginAction, usePluginData, usePluginToast, } from "@paperclipai/plugin-sdk/ui"; import { DEFAULT_INBOX_CONFIG, PAGE_SLOT_ID, AGENT_TAB_SLOT_ID, } from "../constants.js"; // ----------------------------------------------------------------------------- // Styles // ----------------------------------------------------------------------------- const containerStyle = { display: "grid", gap: "16px", }; const cardStyle = { border: "1px solid var(--border, #e5e7eb)", borderRadius: "12px", padding: "16px", background: "var(--card, white)", }; const sectionHeaderStyle = { display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: "12px", }; const buttonStyle = { appearance: "none", border: "1px solid var(--border, #e5e7eb)", borderRadius: "8px", background: "transparent", color: "inherit", padding: "8px 14px", fontSize: "13px", cursor: "pointer", }; const primaryButtonStyle = { ...buttonStyle, background: "var(--foreground, #1f2937)", color: "var(--background, white)", }; const inputStyle = { width: "100%", border: "1px solid var(--border, #e5e7eb)", borderRadius: "8px", padding: "10px 12px", background: "transparent", color: "inherit", fontSize: "13px", }; const selectStyle = { ...inputStyle, }; const checkboxStyle = { width: "18px", height: "18px", accentColor: "var(--foreground, #1f2937)", }; const rowStyle = { display: "flex", alignItems: "center", gap: "10px", marginBottom: "12px", }; const mutedTextStyle = { fontSize: "12px", opacity: 0.7, lineHeight: 1.5, }; // ----------------------------------------------------------------------------- // Helper functions // ----------------------------------------------------------------------------- function getStatusOptions() { return [ { value: "todo", label: "Todo" }, { value: "in_progress", label: "In Progress" }, { value: "blocked", label: "Blocked" }, { value: "backlog", label: "Backlog" }, { value: "in_review", label: "In Review" }, { value: "done", label: "Done" }, { value: "cancelled", label: "Cancelled" }, ]; } function getStatusLabel(value) { const option = getStatusOptions().find((o) => o.value === value); return option?.label || value; } // ----------------------------------------------------------------------------- // Page Component - Shows all agents and their inbox configs // ----------------------------------------------------------------------------- export function InboxConfigPage({ context }) { const [agents, setAgents] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { async function loadAgents() { if (!context.companyId) return; setLoading(true); try { const response = await fetch(`/api/companies/${context.companyId}/agents`, { credentials: "include", }); if (!response.ok) throw new Error(`Failed to load agents: ${response.status}`); const data = await response.json(); setAgents(Array.isArray(data) ? data : []); setError(null); } catch (err) { setError(err instanceof Error ? err.message : String(err)); } finally { setLoading(false); } } void loadAgents(); }, [context.companyId]); const agentPath = (agentId) => { const prefix = context.companyPrefix || ""; return `${prefix ? "/${prefix}" : "/"}/agents/${agentId}`; }; if (!context.companyId) { return (_jsx("div", { style: { padding: "24px", fontSize: "14px", opacity: 0.7 }, children: "Select a company to configure agent inboxes." })); } if (loading) { return _jsx("div", { style: { padding: "24px", fontSize: "14px" }, children: "Loading agents\u2026" }); } return (_jsxs("div", { style: { padding: "24px", maxWidth: "1000px", margin: "0 auto" }, children: [_jsx("h1", { style: { fontSize: "24px", fontWeight: 700, marginBottom: "8px" }, children: "Agent Inbox Configuration" }), _jsx("p", { style: { ...mutedTextStyle, marginBottom: "24px", fontSize: "14px" }, children: "Configure which issues appear in each agent's inbox via the inbox-lite endpoint." }), error ? (_jsx("div", { style: { ...cardStyle, color: "var(--destructive, #dc2626)" }, children: error })) : (_jsxs("div", { style: { display: "grid", gap: "16px" }, children: [agents.map((agent) => (_jsxs("div", { style: cardStyle, children: [_jsxs("div", { style: sectionHeaderStyle, children: [_jsx("strong", { style: { fontSize: "15px" }, children: agent.name }), _jsx("a", { href: `${agentPath(agent.id)}?tab=plugin:${PAGE_SLOT_ID}:${AGENT_TAB_SLOT_ID}`, style: { fontSize: "12px", textDecoration: "underline", cursor: "pointer" }, children: "Configure \u2192" })] }), _jsx("div", { style: { display: "grid", gap: "8px", fontSize: "13px" }, children: _jsx(AgentInboxSummary, { agentId: agent.id }) })] }, agent.id))), agents.length === 0 && (_jsx("div", { style: { ...cardStyle, padding: "24px", textAlign: "center", opacity: 0.7 }, children: "No agents found in this company." }))] }))] })); } // ----------------------------------------------------------------------------- // Agent Inbox Summary Component (used in page view) // ----------------------------------------------------------------------------- function AgentInboxSummary({ agentId }) { const config = usePluginData("getAgentInboxConfig", { agentId }); if (config.loading) return _jsx("div", { style: { fontSize: "12px", opacity: 0.6 }, children: "Loading\u2026" }); if (config.error) return _jsx("div", { style: { fontSize: "12px", color: "var(--destructive, #dc2626)" }, children: "Error loading config" }); const c = config.data || DEFAULT_INBOX_CONFIG; return (_jsxs("div", { style: { display: "grid", gap: "6px", fontSize: "12px" }, children: [_jsxs("div", { children: [_jsx("strong", { children: "Statuses:" }), " ", c.statuses] }), c.projectId ? (_jsxs("div", { children: [_jsx("strong", { children: "Project:" }), " Filtered"] })) : null, c.goalId ? (_jsxs("div", { children: [_jsx("strong", { children: "Goal:" }), " Filtered"] })) : null, c.labelIds && c.labelIds.length > 0 ? (_jsxs("div", { children: [_jsx("strong", { children: "Labels:" }), " ", c.labelIds.length, " filter(s)"] })) : null, c.query ? (_jsxs("div", { children: [_jsx("strong", { children: "Search:" }), " \"", c.query, "\""] })) : null] })); } // ----------------------------------------------------------------------------- // Agent Detail Tab Component - Configure inbox for a specific agent // ----------------------------------------------------------------------------- export function AgentInboxSettingsTab({ context }) { const { entityId, entityType } = context; if (entityType !== "agent") { return (_jsx("div", { style: { padding: "24px", fontSize: "13px", opacity: 0.7 }, children: "This tab is only available on agent detail pages." })); } const agentId = entityId; const toast = usePluginToast(); // Fetch current config const configData = usePluginData("getAgentInboxConfig", { agentId }); // Fetch projects for dropdown const [projects, setProjects] = useState([]); const [goals, setGoals] = useState([]); const [loadingOptions, setLoadingOptions] = useState(true); // Form state const [formState, setFormState] = useState({ ...DEFAULT_INBOX_CONFIG, statuses: configData.data?.statuses || DEFAULT_INBOX_CONFIG.statuses, includeBacklog: configData.data?.includeBacklog || DEFAULT_INBOX_CONFIG.includeBacklog, projectId: configData.data?.projectId || null, goalId: configData.data?.goalId || null, labelIds: configData.data?.labelIds || [], query: configData.data?.query || null, }); const [saving, setSaving] = useState(false); // Load projects and goals useEffect(() => { async function loadOptions() { if (!context.companyId) return; setLoadingOptions(true); try { const [projectsRes, goalsRes] = await Promise.all([ fetch(`/api/companies/${context.companyId}/projects`, { credentials: "include" }), fetch(`/api/companies/${context.companyId}/goals`, { credentials: "include" }), ]); if (projectsRes.ok) { const data = await projectsRes.json(); setProjects(Array.isArray(data) ? data : []); } if (goalsRes.ok) { const data = await goalsRes.json(); setGoals(Array.isArray(data) ? data : []); } } catch (err) { console.error("Failed to load options:", err); } finally { setLoadingOptions(false); } } void loadOptions(); }, [context.companyId]); // Update form when config data loads useEffect(() => { if (configData.data) { setFormState({ ...DEFAULT_INBOX_CONFIG, ...configData.data }); } }, [configData.data]); const saveConfig = usePluginAction("setAgentInboxConfig"); async function handleSave(e) { e.preventDefault(); if (!agentId) return; setSaving(true); try { await saveConfig({ agentId, config: { statuses: formState.statuses, includeBacklog: formState.includeBacklog, projectId: formState.projectId, goalId: formState.goalId, labelIds: formState.labelIds, query: formState.query, }, }); toast({ title: "Inbox config saved", body: `Configuration updated for this agent.`, tone: "success", }); } catch (err) { const message = err instanceof Error ? err.message : String(err); toast({ title: "Failed to save config", body: message, tone: "error", }); } finally { setSaving(false); } } const statusOptions = getStatusOptions(); const selectedStatuses = formState.statuses.split(","); return (_jsxs("div", { style: { padding: "20px", maxWidth: "700px" }, children: [_jsx("h2", { style: { fontSize: "18px", fontWeight: 600, marginBottom: "8px" }, children: "Inbox Configuration" }), _jsx("p", { style: { ...mutedTextStyle, marginBottom: "20px", fontSize: "13px" }, children: "Configure which issues appear in this agent's inbox via the inbox-lite endpoint." }), _jsxs("form", { onSubmit: handleSave, style: { display: "grid", gap: "20px" }, children: [_jsxs("div", { style: cardStyle, children: [_jsx("div", { style: { fontWeight: 600, marginBottom: "12px", fontSize: "14px" }, children: "Issue Statuses" }), _jsx("p", { style: { ...mutedTextStyle, marginBottom: "12px", fontSize: "12px" }, children: "Select which issue statuses should appear in this agent's inbox." }), _jsx("div", { style: { display: "grid", gap: "8px" }, children: statusOptions.map((option) => (_jsxs("label", { style: { display: "flex", alignItems: "center", gap: "10px", fontSize: "13px" }, children: [_jsx("input", { type: "checkbox", checked: selectedStatuses.includes(option.value), onChange: (e) => { const isChecked = e.target.checked; const current = formState.statuses.split(","); const next = isChecked ? [...current, option.value].filter(Boolean) : current.filter((s) => s !== option.value); setFormState({ ...formState, statuses: next.join(",") }); }, style: checkboxStyle }), _jsx("span", { children: option.label })] }, option.value))) })] }), _jsxs("div", { style: cardStyle, children: [_jsx("div", { style: { fontWeight: 600, marginBottom: "12px", fontSize: "14px" }, children: "Project Filter" }), _jsx("p", { style: { ...mutedTextStyle, marginBottom: "12px", fontSize: "12px" }, children: "Optionally limit inbox to issues from a specific project." }), _jsxs("select", { style: selectStyle, value: formState.projectId || "", onChange: (e) => setFormState({ ...formState, projectId: e.target.value || null }), disabled: loadingOptions, children: [_jsx("option", { value: "", children: "No filter (all projects)" }), projects.map((project) => (_jsx("option", { value: project.id, children: project.name }, project.id)))] })] }), _jsxs("div", { style: cardStyle, children: [_jsx("div", { style: { fontWeight: 600, marginBottom: "12px", fontSize: "14px" }, children: "Goal Filter" }), _jsx("p", { style: { ...mutedTextStyle, marginBottom: "12px", fontSize: "12px" }, children: "Optionally limit inbox to issues linked to a specific goal." }), _jsxs("select", { style: selectStyle, value: formState.goalId || "", onChange: (e) => setFormState({ ...formState, goalId: e.target.value || null }), disabled: loadingOptions, children: [_jsx("option", { value: "", children: "No filter (all goals)" }), goals.map((goal) => (_jsx("option", { value: goal.id, children: goal.title }, goal.id)))] })] }), _jsxs("div", { style: cardStyle, children: [_jsx("div", { style: { fontWeight: 600, marginBottom: "12px", fontSize: "14px" }, children: "Search Query" }), _jsx("p", { style: { ...mutedTextStyle, marginBottom: "12px", fontSize: "12px" }, children: "Optional search query to filter issues by title, description, or comments." }), _jsx("input", { type: "text", style: inputStyle, value: formState.query || "", onChange: (e) => setFormState({ ...formState, query: e.target.value || null }), placeholder: "e.g., docker, deployment, urgent" })] }), _jsxs("div", { style: cardStyle, children: [_jsxs("label", { style: { display: "flex", alignItems: "center", gap: "10px" }, children: [_jsx("input", { type: "checkbox", checked: formState.includeBacklog, onChange: (e) => setFormState({ ...formState, includeBacklog: e.target.checked }), style: checkboxStyle }), _jsx("span", { style: { fontSize: "13px" }, children: "Include backlog issues" })] }), _jsx("p", { style: { ...mutedTextStyle, marginTop: "6px", fontSize: "12px" }, children: "When enabled, issues with status \"backlog\" will be included in the inbox." })] }), _jsxs("div", { style: { display: "flex", gap: "10px", justifyContent: "flex-end" }, children: [_jsx("button", { type: "button", style: buttonStyle, onClick: () => { setFormState({ ...DEFAULT_INBOX_CONFIG }); }, children: "Reset to Defaults" }), _jsx("button", { type: "submit", style: primaryButtonStyle, disabled: saving || configData.loading || loadingOptions, children: saving ? "Saving…" : "Save Configuration" })] })] })] })); } //# sourceMappingURL=index.js.map