fix: fix some displays and features
This commit is contained in:
@ -54,6 +54,50 @@ export function AgentsPanel({ projectId, projectRoot = "" }: AgentsPanelProps) {
|
||||
void templateGw.listTemplates().then(setTemplates).catch(() => {});
|
||||
}
|
||||
|
||||
// Skills available for assignment (global + project), loaded lazily once.
|
||||
const skillGw = gateways.skill ?? null;
|
||||
const [skills, setSkills] = useState<import("@/domain").Skill[]>([]);
|
||||
const [skillsLoaded, setSkillsLoaded] = useState(false);
|
||||
const [skillToAssign, setSkillToAssign] = useState("");
|
||||
|
||||
async function refreshSkills() {
|
||||
if (!skillGw) return;
|
||||
try {
|
||||
const [globals, projects] = await Promise.all([
|
||||
skillGw.listSkills(projectId, "global"),
|
||||
skillGw.listSkills(projectId, "project"),
|
||||
]);
|
||||
setSkills([...projects, ...globals]);
|
||||
} catch {
|
||||
// Skills are optional — leave the list empty on failure.
|
||||
}
|
||||
}
|
||||
|
||||
if (!skillsLoaded && skillGw) {
|
||||
setSkillsLoaded(true);
|
||||
void refreshSkills();
|
||||
}
|
||||
|
||||
async function handleAssignSkill() {
|
||||
if (!skillGw || !vm.selectedAgentId || !skillToAssign) return;
|
||||
const target = skills.find((s) => s.id === skillToAssign);
|
||||
if (!target) return;
|
||||
await skillGw.assignSkill(
|
||||
projectId,
|
||||
vm.selectedAgentId,
|
||||
target.id,
|
||||
target.scope,
|
||||
);
|
||||
setSkillToAssign("");
|
||||
await vm.refresh();
|
||||
}
|
||||
|
||||
async function handleUnassignSkill(skillId: string) {
|
||||
if (!skillGw || !vm.selectedAgentId) return;
|
||||
await skillGw.unassignSkill(projectId, vm.selectedAgentId, skillId);
|
||||
await vm.refresh();
|
||||
}
|
||||
|
||||
// Context editor state — local copy before Save
|
||||
const [editedContext, setEditedContext] = useState(vm.context);
|
||||
|
||||
@ -351,6 +395,79 @@ export function AgentsPanel({ projectId, projectRoot = "" }: AgentsPanelProps) {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* ── Skill assignment ── */}
|
||||
{selectedAgent && skillGw && (
|
||||
<div className="flex flex-col gap-2 border-t border-border p-4">
|
||||
<h4 className="text-sm font-semibold text-content">
|
||||
Skills — {selectedAgent.name}
|
||||
</h4>
|
||||
|
||||
{/* Assigned skills */}
|
||||
{selectedAgent.skills.length === 0 ? (
|
||||
<p className="text-xs text-muted">No skills assigned.</p>
|
||||
) : (
|
||||
<ul className="flex flex-wrap gap-1.5">
|
||||
{selectedAgent.skills.map((ref) => {
|
||||
const name =
|
||||
skills.find((s) => s.id === ref.skillId)?.name ?? ref.skillId;
|
||||
return (
|
||||
<li
|
||||
key={ref.skillId}
|
||||
className="flex items-center gap-1 rounded-full bg-raised px-2 py-0.5 text-xs text-content"
|
||||
>
|
||||
<span>{name}</span>
|
||||
<button
|
||||
type="button"
|
||||
aria-label={`unassign ${name}`}
|
||||
disabled={vm.busy}
|
||||
onClick={() => void handleUnassignSkill(ref.skillId)}
|
||||
className="text-faint hover:text-danger"
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
)}
|
||||
|
||||
{/* Assign selector */}
|
||||
<div className="flex items-end gap-2">
|
||||
<select
|
||||
aria-label="skill to assign"
|
||||
value={skillToAssign}
|
||||
onChange={(e) => setSkillToAssign(e.target.value)}
|
||||
disabled={vm.busy}
|
||||
className={cn(
|
||||
"h-9 min-w-0 flex-1 rounded-md bg-raised px-3 text-sm text-content",
|
||||
"border border-border outline-none transition-colors",
|
||||
"focus:border-primary disabled:cursor-not-allowed disabled:opacity-50",
|
||||
)}
|
||||
>
|
||||
<option value="">— assign a skill —</option>
|
||||
{skills
|
||||
.filter(
|
||||
(s) =>
|
||||
!selectedAgent.skills.some((r) => r.skillId === s.id),
|
||||
)
|
||||
.map((s) => (
|
||||
<option key={s.id} value={s.id}>
|
||||
{s.name} ({s.scope})
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<Button
|
||||
variant="primary"
|
||||
aria-label="assign skill"
|
||||
disabled={vm.busy || !skillToAssign}
|
||||
onClick={() => void handleAssignSkill()}
|
||||
>
|
||||
Assign
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* ── Context editor ── */}
|
||||
{selectedAgent && (
|
||||
<div className="flex flex-col gap-2 border-t border-border p-4">
|
||||
|
||||
Reference in New Issue
Block a user