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, deleteWidget,
getWidgetData, getWidgetData,
getViews, getViews,
getTeams,
updateDashboard,
} from "@/lib/api"; } from "@/lib/api";
import type { import type {
Dashboard, Dashboard,
DashboardWidget, DashboardWidget,
SavedView, SavedView,
Team,
WidgetData, WidgetData,
} from "@/lib/types"; } from "@/lib/types";
import { Button } from "@/components/ui/button"; 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 [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
const [autoRefresh, setAutoRefresh] = useState(false); const [autoRefresh, setAutoRefresh] = useState(false);
const [teams, setTeams] = useState<Team[]>([]);
// Add widget dialog // Add widget dialog
const [addOpen, setAddOpen] = useState(false); const [addOpen, setAddOpen] = useState(false);
@@ -90,9 +94,8 @@ export default function DashboardPage({ params }: { params: Promise<{ id: string
useEffect(() => { useEffect(() => {
fetchDashboard(); fetchDashboard();
getViews().then(({ data }) => { getViews().then(({ data }) => { if (data) setViews(data); });
if (data) setViews(data); getTeams().then(({ data }) => { if (data) setTeams(data); });
});
}, [fetchDashboard]); }, [fetchDashboard]);
// Auto-refresh: only refresh widget data, not structure // Auto-refresh: only refresh widget data, not structure
@@ -207,10 +210,26 @@ export default function DashboardPage({ params }: { params: Promise<{ id: string
Dashboard Dashboard
</div> </div>
<h1 className="mt-1 text-xl font-semibold text-foreground">{dashboard.name}</h1> <h1 className="mt-1 text-xl font-semibold text-foreground">{dashboard.name}</h1>
<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 && ( {dashboard.description && (
<p className="mt-0.5 text-sm text-muted-foreground">{dashboard.description}</p> <p className="text-sm text-muted-foreground">{dashboard.description}</p>
)} )}
</div> </div>
</div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Button <Button
variant="outline" variant="outline"

View File

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