- Replace free-text AgentConfig.permissions field with a Select showing the four valid modes (default, accept-edits, auto, bypass-permissions) so users can't enter invalid strings (#186). - Delete the non-functional Notifications bell button from Topbar and DashboardTopbar; remove the now-unused Bell import (#188). Closes #186 Closes #188 Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
9c7866daba
commit
a5d034ae1e
|
|
@ -1,6 +1,6 @@
|
|||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import { useNavigate } from "@tanstack/react-router";
|
||||
import { Bell, Waypoints } from "lucide-react";
|
||||
import { Waypoints } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { findProjectOrchestrator } from "../types/workspace";
|
||||
import { useWorkspaceQuery, workspaceQueryKey } from "../hooks/useWorkspaceQuery";
|
||||
|
|
@ -90,9 +90,6 @@ export function DashboardTopbar({ activeTab, projectId, projectLabel = "agent-or
|
|||
</div>
|
||||
<div className="dashboard-app-header__spacer" />
|
||||
<div className="dashboard-app-header__actions">
|
||||
<button aria-label="Notifications" className="dashboard-app-header__icon-btn" style={noDragStyle} type="button">
|
||||
<Bell className="h-[15px] w-[15px]" aria-hidden="true" />
|
||||
</button>
|
||||
{projectId ? (
|
||||
orchestrator ? (
|
||||
<button
|
||||
|
|
|
|||
|
|
@ -16,6 +16,13 @@ type ProjectConfig = components["schemas"]["ProjectConfig"];
|
|||
// default". Kept short — the spawn modal owns the full list.
|
||||
const AGENT_OPTIONS = ["claude-code", "codex", "opencode", "amp", "goose", "kiro"] as const;
|
||||
|
||||
const PERMISSION_MODE_OPTIONS = [
|
||||
{ value: "default", label: "Default" },
|
||||
{ value: "accept-edits", label: "Accept edits" },
|
||||
{ value: "auto", label: "Auto" },
|
||||
{ value: "bypass-permissions", label: "Bypass permissions" },
|
||||
] as const;
|
||||
|
||||
const projectQueryKey = (id: string) => ["project", id] as const;
|
||||
|
||||
export function ProjectSettingsForm({ projectId }: { projectId: string }) {
|
||||
|
|
@ -67,6 +74,7 @@ function SettingsBody({ project, projectId, onSaved }: { project: Project; proje
|
|||
workerAgent: config.worker?.agent ?? "",
|
||||
orchestratorAgent: config.orchestrator?.agent ?? "",
|
||||
model: config.agentConfig?.model ?? "",
|
||||
permissions: config.agentConfig?.permissions ?? "",
|
||||
});
|
||||
const [savedAt, setSavedAt] = useState<number | null>(null);
|
||||
|
||||
|
|
@ -80,7 +88,11 @@ function SettingsBody({ project, projectId, onSaved }: { project: Project; proje
|
|||
sessionPrefix: form.sessionPrefix || undefined,
|
||||
worker: blankToUndefined({ ...config.worker, agent: form.workerAgent || undefined }),
|
||||
orchestrator: blankToUndefined({ ...config.orchestrator, agent: form.orchestratorAgent || undefined }),
|
||||
agentConfig: blankToUndefined({ ...config.agentConfig, model: form.model || undefined }),
|
||||
agentConfig: blankToUndefined({
|
||||
...config.agentConfig,
|
||||
model: form.model || undefined,
|
||||
permissions: form.permissions || undefined,
|
||||
}),
|
||||
};
|
||||
const { error } = await apiClient.PUT("/api/v1/projects/{id}/config", {
|
||||
params: { path: { id: projectId } },
|
||||
|
|
@ -163,6 +175,12 @@ function SettingsBody({ project, projectId, onSaved }: { project: Project; proje
|
|||
placeholder="(agent default)"
|
||||
/>
|
||||
</Field>
|
||||
<Field label="Permission mode">
|
||||
<PermissionModeSelect
|
||||
value={form.permissions}
|
||||
onChange={(v) => setForm((f) => ({ ...f, permissions: v }))}
|
||||
/>
|
||||
</Field>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
|
|
@ -183,6 +201,24 @@ function SettingsBody({ project, projectId, onSaved }: { project: Project; proje
|
|||
);
|
||||
}
|
||||
|
||||
function PermissionModeSelect({ value, onChange }: { value: string; onChange: (value: string) => void }) {
|
||||
return (
|
||||
<Select value={value || "__default__"} onValueChange={(v) => onChange(v === "__default__" ? "" : v)}>
|
||||
<SelectTrigger className="h-8 w-full text-[13px]">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="__default__">Project default</SelectItem>
|
||||
{PERMISSION_MODE_OPTIONS.map((opt) => (
|
||||
<SelectItem key={opt.value} value={opt.value}>
|
||||
{opt.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
);
|
||||
}
|
||||
|
||||
function AgentSelect({ value, onChange }: { value: string; onChange: (value: string) => void }) {
|
||||
// "" sentinel → daemon default; Select can't hold an empty value, so map it.
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Bell, GitBranch, LayoutGrid, PanelRightClose, PanelRightOpen, Waypoints } from "lucide-react";
|
||||
import { GitBranch, LayoutGrid, PanelRightClose, PanelRightOpen, Waypoints } from "lucide-react";
|
||||
import { type WorkbenchView, useUiStore } from "../stores/ui-store";
|
||||
import type { WorkerDisplayStatus, WorkspaceSession } from "../types/workspace";
|
||||
import { workerDisplayStatus } from "../types/workspace";
|
||||
|
|
@ -68,10 +68,6 @@ export function Topbar({ view, session, projectLabel, onOpenBoard }: TopbarProps
|
|||
<div className="dashboard-app-header__spacer" />
|
||||
|
||||
<div className="dashboard-app-header__actions">
|
||||
{/* Bell leads the actions row, as in AO's SessionDetailHeader. */}
|
||||
<button aria-label="Notifications" className="dashboard-app-header__icon-btn" style={noDragStyle} type="button">
|
||||
<Bell className="h-[15px] w-[15px]" aria-hidden="true" />
|
||||
</button>
|
||||
<button
|
||||
aria-label={view === "orchestrator" ? "Open Kanban" : "Back to board"}
|
||||
className="dashboard-app-header__primary-btn"
|
||||
|
|
|
|||
Loading…
Reference in New Issue