new plugin
This commit is contained in:
4
plugin-agent-inbox-config/dist/ui/index.d.ts
vendored
Normal file
4
plugin-agent-inbox-config/dist/ui/index.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { type PluginPageProps, type PluginDetailTabProps } from "@paperclipai/plugin-sdk/ui";
|
||||
export declare function InboxConfigPage({ context }: PluginPageProps): import("react/jsx-runtime").JSX.Element;
|
||||
export declare function AgentInboxSettingsTab({ context }: PluginDetailTabProps): import("react/jsx-runtime").JSX.Element;
|
||||
//# sourceMappingURL=index.d.ts.map
|
||||
1
plugin-agent-inbox-config/dist/ui/index.d.ts.map
vendored
Normal file
1
plugin-agent-inbox-config/dist/ui/index.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ui/index.tsx"],"names":[],"mappings":"AACA,OAAO,EAKL,KAAK,eAAe,EACpB,KAAK,oBAAoB,EAC1B,MAAM,4BAA4B,CAAC;AAuHpC,wBAAgB,eAAe,CAAC,EAAE,OAAO,EAAE,EAAE,eAAe,2CA+E3D;AA+CD,wBAAgB,qBAAqB,CAAC,EAAE,OAAO,EAAE,EAAE,oBAAoB,2CA4OtE"}
|
||||
251
plugin-agent-inbox-config/dist/ui/index.js
vendored
Normal file
251
plugin-agent-inbox-config/dist/ui/index.js
vendored
Normal file
@@ -0,0 +1,251 @@
|
||||
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
|
||||
1
plugin-agent-inbox-config/dist/ui/index.js.map
vendored
Normal file
1
plugin-agent-inbox-config/dist/ui/index.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user