feat: add team selector to dashboard page header

- Dropdown to assign/unassign dashboard to a team
- Updates immediately via PATCH
- createDashboard and updateDashboard API now accept team_id

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Gjermund Høsøien Wiggen
2026-06-09 13:35:40 +02:00
parent 3616046b78
commit 9938c7a7ad
2 changed files with 27 additions and 6 deletions

View File

@@ -16,11 +16,14 @@ import {
deleteWidget,
getWidgetData,
getViews,
getTeams,
updateDashboard,
} from "@/lib/api";
import type {
Dashboard,
DashboardWidget,
SavedView,
Team,
WidgetData,
} from "@/lib/types";
import { Button } from "@/components/ui/button";
@@ -55,6 +58,7 @@ export default function DashboardPage({ params }: { params: Promise<{ id: string
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [autoRefresh, setAutoRefresh] = useState(false);
const [teams, setTeams] = useState<Team[]>([]);
// Add widget dialog
const [addOpen, setAddOpen] = useState(false);
@@ -90,9 +94,8 @@ export default function DashboardPage({ params }: { params: Promise<{ id: string
useEffect(() => {
fetchDashboard();
getViews().then(({ data }) => {
if (data) setViews(data);
});
getViews().then(({ data }) => { if (data) setViews(data); });
getTeams().then(({ data }) => { if (data) setTeams(data); });
}, [fetchDashboard]);
// Auto-refresh: only refresh widget data, not structure
@@ -207,9 +210,25 @@ export default function DashboardPage({ params }: { params: Promise<{ id: string
Dashboard
</div>
<h1 className="mt-1 text-xl font-semibold text-foreground">{dashboard.name}</h1>
{dashboard.description && (
<p className="mt-0.5 text-sm text-muted-foreground">{dashboard.description}</p>
)}
<div className="mt-2 flex items-center gap-2">
<select
value={dashboard.team_id ?? ""}
onChange={async (e) => {
const teamId = e.target.value || null;
await updateDashboard(dashboard.id, { team_id: teamId });
setDashboard((prev) => prev ? { ...prev, team_id: teamId } : prev);
}}
className="h-7 rounded border border-border bg-card px-2 text-xs text-muted-foreground outline-none"
>
<option value="">No team</option>
{teams.map((t) => (
<option key={t.id} value={t.id}>{t.name}</option>
))}
</select>
{dashboard.description && (
<p className="text-sm text-muted-foreground">{dashboard.description}</p>
)}
</div>
</div>
<div className="flex items-center gap-2">
<Button

View File

@@ -297,6 +297,7 @@ export async function getDashboard(id: string): Promise<{ data: Dashboard | null
export async function createDashboard(data: {
name: string;
description?: string;
team_id?: string | null;
is_default?: boolean;
}): Promise<{ data: Dashboard | null; error: string | null }> {
return request<Dashboard>("/dashboards", { method: "POST", body: JSON.stringify(data) });
@@ -305,6 +306,7 @@ export async function createDashboard(data: {
export async function updateDashboard(id: string, data: {
name?: string;
description?: string | null;
team_id?: string | null;
is_default?: boolean;
layout?: unknown[];
}): Promise<{ data: Dashboard | null; error: string | null }> {