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:
@@ -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"
|
||||||
|
|||||||
@@ -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 }> {
|
||||||
|
|||||||
Reference in New Issue
Block a user