feat: add board group models and update related interfaces

This commit is contained in:
Abhimanyu Saharan
2026-02-07 20:29:50 +05:30
parent 7b5ee230f5
commit 88a5075684
170 changed files with 12372 additions and 3697 deletions

View File

@@ -10,10 +10,15 @@ import { SignInButton, SignedIn, SignedOut, useAuth } from "@/auth/clerk";
import { ApiError } from "@/api/mutator";
import { useCreateBoardApiV1BoardsPost } from "@/api/generated/boards/boards";
import {
type listBoardGroupsApiV1BoardGroupsGetResponse,
useListBoardGroupsApiV1BoardGroupsGet,
} from "@/api/generated/board-groups/board-groups";
import {
type listGatewaysApiV1GatewaysGetResponse,
useListGatewaysApiV1GatewaysGet,
} from "@/api/generated/gateways/gateways";
import type { BoardGroupRead } from "@/api/generated/model";
import { DashboardSidebar } from "@/components/organisms/DashboardSidebar";
import { DashboardShell } from "@/components/templates/DashboardShell";
import { Button } from "@/components/ui/button";
@@ -33,6 +38,7 @@ export default function NewBoardPage() {
const [name, setName] = useState("");
const [gatewayId, setGatewayId] = useState<string>("");
const [boardGroupId, setBoardGroupId] = useState<string>("none");
const [error, setError] = useState<string | null>(null);
@@ -47,6 +53,17 @@ export default function NewBoardPage() {
},
});
const groupsQuery = useListBoardGroupsApiV1BoardGroupsGet<
listBoardGroupsApiV1BoardGroupsGetResponse,
ApiError
>(undefined, {
query: {
enabled: Boolean(isSignedIn),
refetchOnMount: "always",
retry: false,
},
});
const createBoardMutation = useCreateBoardApiV1BoardsPost<ApiError>({
mutation: {
onSuccess: (result) => {
@@ -60,19 +77,36 @@ export default function NewBoardPage() {
},
});
const gateways =
gatewaysQuery.data?.status === 200
? gatewaysQuery.data.data.items ?? []
: [];
const gateways = useMemo(() => {
if (gatewaysQuery.data?.status !== 200) return [];
return gatewaysQuery.data.data.items ?? [];
}, [gatewaysQuery.data]);
const groups = useMemo<BoardGroupRead[]>(() => {
if (groupsQuery.data?.status !== 200) return [];
return groupsQuery.data.data.items ?? [];
}, [groupsQuery.data]);
const displayGatewayId = gatewayId || gateways[0]?.id || "";
const isLoading = gatewaysQuery.isLoading || createBoardMutation.isPending;
const errorMessage = error ?? gatewaysQuery.error?.message ?? null;
const isLoading =
gatewaysQuery.isLoading ||
groupsQuery.isLoading ||
createBoardMutation.isPending;
const errorMessage =
error ?? gatewaysQuery.error?.message ?? groupsQuery.error?.message ?? null;
const isFormReady = Boolean(name.trim() && displayGatewayId);
const gatewayOptions = useMemo(
() => gateways.map((gateway) => ({ value: gateway.id, label: gateway.name })),
[gateways]
() =>
gateways.map((gateway) => ({ value: gateway.id, label: gateway.name })),
[gateways],
);
const groupOptions = useMemo(
() => [
{ value: "none", label: "No group" },
...groups.map((group) => ({ value: group.id, label: group.name })),
],
[groups],
);
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
@@ -96,6 +130,7 @@ export default function NewBoardPage() {
name: trimmedName,
slug: slugify(trimmedName),
gateway_id: resolvedGatewayId,
board_group_id: boardGroupId === "none" ? null : boardGroupId,
},
});
};
@@ -167,6 +202,29 @@ export default function NewBoardPage() {
</div>
</div>
<div className="grid gap-6 md:grid-cols-2">
<div className="space-y-2">
<label className="text-sm font-medium text-slate-900">
Board group
</label>
<SearchableSelect
ariaLabel="Select board group"
value={boardGroupId}
onValueChange={setBoardGroupId}
options={groupOptions}
placeholder="No group"
searchPlaceholder="Search groups..."
emptyMessage="No groups found."
triggerClassName="w-full h-11 rounded-xl border border-slate-300 bg-white px-3 py-2 text-sm font-medium text-slate-900 shadow-sm focus:border-blue-500 focus:ring-2 focus:ring-blue-200"
contentClassName="rounded-xl border border-slate-200 shadow-lg"
itemClassName="px-4 py-3 text-sm text-slate-700 data-[selected=true]:bg-slate-50 data-[selected=true]:text-slate-900"
disabled={isLoading}
/>
<p className="text-xs text-slate-500">
Optional. Groups increase cross-board visibility.
</p>
</div>
</div>
</div>
{gateways.length === 0 ? (