feat: add description field to boards and update related components for onboarding
This commit is contained in:
@@ -12,6 +12,7 @@ import type { BoardCreateSuccessMetrics } from "./boardCreateSuccessMetrics";
|
||||
export interface BoardCreate {
|
||||
name: string;
|
||||
slug: string;
|
||||
description: string;
|
||||
gateway_id?: string | null;
|
||||
board_group_id?: string | null;
|
||||
board_type?: string;
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
import type { BoardOnboardingAgentCompleteSuccessMetrics } from "./boardOnboardingAgentCompleteSuccessMetrics";
|
||||
import type { BoardOnboardingLeadAgentDraft } from "./boardOnboardingLeadAgentDraft";
|
||||
import type { BoardOnboardingUserProfile } from "./boardOnboardingUserProfile";
|
||||
import { BoardOnboardingAgentCompleteStatus } from "./boardOnboardingAgentCompleteStatus";
|
||||
|
||||
/**
|
||||
* Complete onboarding draft produced by the onboarding assistant.
|
||||
@@ -17,7 +16,7 @@ export interface BoardOnboardingAgentComplete {
|
||||
objective?: string | null;
|
||||
success_metrics?: BoardOnboardingAgentCompleteSuccessMetrics;
|
||||
target_date?: string | null;
|
||||
status: BoardOnboardingAgentCompleteStatus;
|
||||
status: "complete";
|
||||
user_profile?: BoardOnboardingUserProfile | null;
|
||||
lead_agent?: BoardOnboardingLeadAgentDraft | null;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import type { BoardReadSuccessMetrics } from "./boardReadSuccessMetrics";
|
||||
export interface BoardRead {
|
||||
name: string;
|
||||
slug: string;
|
||||
description: string;
|
||||
gateway_id?: string | null;
|
||||
board_group_id?: string | null;
|
||||
board_type?: string;
|
||||
|
||||
@@ -12,6 +12,7 @@ import type { BoardUpdateSuccessMetrics } from "./boardUpdateSuccessMetrics";
|
||||
export interface BoardUpdate {
|
||||
name?: string | null;
|
||||
slug?: string | null;
|
||||
description?: string | null;
|
||||
gateway_id?: string | null;
|
||||
board_group_id?: string | null;
|
||||
board_type?: string | null;
|
||||
|
||||
@@ -206,3 +206,4 @@ export * from "./updateAgentApiV1AgentsAgentIdPatchParams";
|
||||
export * from "./userRead";
|
||||
export * from "./userUpdate";
|
||||
export * from "./validationError";
|
||||
export * from "./validationErrorCtx";
|
||||
|
||||
@@ -4,9 +4,12 @@
|
||||
* Mission Control API
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
import type { ValidationErrorCtx } from "./validationErrorCtx";
|
||||
|
||||
export interface ValidationError {
|
||||
loc: (string | number)[];
|
||||
msg: string;
|
||||
type: string;
|
||||
input?: unknown;
|
||||
ctx?: ValidationErrorCtx;
|
||||
}
|
||||
|
||||
8
frontend/src/api/generated/model/validationErrorCtx.ts
Normal file
8
frontend/src/api/generated/model/validationErrorCtx.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Generated by orval v8.2.0 🍺
|
||||
* Do not edit manually.
|
||||
* Mission Control API
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
export type ValidationErrorCtx = { [key: string]: unknown };
|
||||
@@ -65,6 +65,7 @@ export default function EditBoardPage() {
|
||||
|
||||
const [board, setBoard] = useState<BoardRead | null>(null);
|
||||
const [name, setName] = useState<string | undefined>(undefined);
|
||||
const [description, setDescription] = useState<string | undefined>(undefined);
|
||||
const [gatewayId, setGatewayId] = useState<string | undefined>(undefined);
|
||||
const [boardGroupId, setBoardGroupId] = useState<string | undefined>(
|
||||
undefined,
|
||||
@@ -182,6 +183,7 @@ export default function EditBoardPage() {
|
||||
const baseBoard = board ?? loadedBoard;
|
||||
|
||||
const resolvedName = name ?? baseBoard?.name ?? "";
|
||||
const resolvedDescription = description ?? baseBoard?.description ?? "";
|
||||
const resolvedGatewayId = gatewayId ?? baseBoard?.gateway_id ?? "";
|
||||
const resolvedBoardGroupId =
|
||||
boardGroupId ?? baseBoard?.board_group_id ?? "none";
|
||||
@@ -209,7 +211,9 @@ export default function EditBoardPage() {
|
||||
boardQuery.error?.message ??
|
||||
null;
|
||||
|
||||
const isFormReady = Boolean(resolvedName.trim() && displayGatewayId);
|
||||
const isFormReady = Boolean(
|
||||
resolvedName.trim() && resolvedDescription.trim() && displayGatewayId,
|
||||
);
|
||||
|
||||
const gatewayOptions = useMemo(
|
||||
() =>
|
||||
@@ -231,6 +235,7 @@ export default function EditBoardPage() {
|
||||
|
||||
const handleOnboardingConfirmed = (updated: BoardRead) => {
|
||||
setBoard(updated);
|
||||
setDescription(updated.description ?? "");
|
||||
setBoardType(updated.board_type ?? "goal");
|
||||
setObjective(updated.objective ?? "");
|
||||
setSuccessMetrics(
|
||||
@@ -256,6 +261,11 @@ export default function EditBoardPage() {
|
||||
setError("Select a gateway before saving.");
|
||||
return;
|
||||
}
|
||||
const trimmedDescription = resolvedDescription.trim();
|
||||
if (!trimmedDescription) {
|
||||
setError("Board description is required.");
|
||||
return;
|
||||
}
|
||||
|
||||
setError(null);
|
||||
setMetricsError(null);
|
||||
@@ -276,6 +286,7 @@ export default function EditBoardPage() {
|
||||
const payload: BoardUpdate = {
|
||||
name: trimmedName,
|
||||
slug: slugify(trimmedName),
|
||||
description: trimmedDescription,
|
||||
gateway_id: resolvedGatewayId || null,
|
||||
board_group_id:
|
||||
resolvedBoardGroupId === "none" ? null : resolvedBoardGroupId,
|
||||
@@ -410,6 +421,19 @@ export default function EditBoardPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium text-slate-900">
|
||||
Description <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<Textarea
|
||||
value={resolvedDescription}
|
||||
onChange={(event) => setDescription(event.target.value)}
|
||||
placeholder="What context should the lead agent know?"
|
||||
className="min-h-[120px]"
|
||||
disabled={isLoading}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium text-slate-900">
|
||||
Objective
|
||||
|
||||
@@ -24,6 +24,7 @@ import { DashboardPageLayout } from "@/components/templates/DashboardPageLayout"
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import SearchableSelect from "@/components/ui/searchable-select";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
|
||||
const slugify = (value: string) =>
|
||||
value
|
||||
@@ -39,6 +40,7 @@ export default function NewBoardPage() {
|
||||
const { isAdmin } = useOrganizationMembership(isSignedIn);
|
||||
|
||||
const [name, setName] = useState("");
|
||||
const [description, setDescription] = useState("");
|
||||
const [gatewayId, setGatewayId] = useState<string>("");
|
||||
const [boardGroupId, setBoardGroupId] = useState<string>("none");
|
||||
|
||||
@@ -95,7 +97,9 @@ export default function NewBoardPage() {
|
||||
const errorMessage =
|
||||
error ?? gatewaysQuery.error?.message ?? groupsQuery.error?.message ?? null;
|
||||
|
||||
const isFormReady = Boolean(name.trim() && displayGatewayId);
|
||||
const isFormReady = Boolean(
|
||||
name.trim() && description.trim() && displayGatewayId,
|
||||
);
|
||||
|
||||
const gatewayOptions = useMemo(
|
||||
() =>
|
||||
@@ -124,6 +128,11 @@ export default function NewBoardPage() {
|
||||
setError("Select a gateway before creating a board.");
|
||||
return;
|
||||
}
|
||||
const trimmedDescription = description.trim();
|
||||
if (!trimmedDescription) {
|
||||
setError("Board description is required.");
|
||||
return;
|
||||
}
|
||||
|
||||
setError(null);
|
||||
|
||||
@@ -131,6 +140,7 @@ export default function NewBoardPage() {
|
||||
data: {
|
||||
name: trimmedName,
|
||||
slug: slugify(trimmedName),
|
||||
description: trimmedDescription,
|
||||
gateway_id: resolvedGatewayId,
|
||||
board_group_id: boardGroupId === "none" ? null : boardGroupId,
|
||||
},
|
||||
@@ -208,6 +218,19 @@ export default function NewBoardPage() {
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium text-slate-900">
|
||||
Description <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<Textarea
|
||||
value={description}
|
||||
onChange={(event) => setDescription(event.target.value)}
|
||||
placeholder="What context should the lead agent know before onboarding?"
|
||||
className="min-h-[120px]"
|
||||
disabled={isLoading}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{gateways.length === 0 ? (
|
||||
|
||||
@@ -37,6 +37,7 @@ const buildBoard = (overrides: Partial<BoardRead> = {}): BoardRead => ({
|
||||
id: "board-1",
|
||||
name: "Ops Board",
|
||||
slug: "ops-board",
|
||||
description: "Operations board context.",
|
||||
organization_id: "org-1",
|
||||
created_at: "2026-01-01T00:00:00Z",
|
||||
updated_at: "2026-01-01T00:00:00Z",
|
||||
|
||||
Reference in New Issue
Block a user