feat: add is_chat field to board memory and task_id to approvals, update pagination and response models

This commit is contained in:
Abhimanyu Saharan
2026-02-06 19:11:11 +05:30
parent d86fe0a7a6
commit 6c14af0451
76 changed files with 2070 additions and 571 deletions

View File

@@ -18,8 +18,8 @@ import type {
} from "@tanstack/react-query";
import type {
ActivityEventRead,
HTTPValidationError,
LimitOffsetPageTypeVarCustomizedActivityEventRead,
ListActivityApiV1ActivityGetParams,
} from ".././model";
@@ -31,7 +31,7 @@ type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
* @summary List Activity
*/
export type listActivityApiV1ActivityGetResponse200 = {
data: ActivityEventRead[];
data: LimitOffsetPageTypeVarCustomizedActivityEventRead;
status: 200;
};

View File

@@ -34,9 +34,17 @@ import type {
BoardOnboardingRead,
BoardRead,
HTTPValidationError,
LimitOffsetPageTypeVarCustomizedAgentRead,
LimitOffsetPageTypeVarCustomizedApprovalRead,
LimitOffsetPageTypeVarCustomizedBoardMemoryRead,
LimitOffsetPageTypeVarCustomizedBoardRead,
LimitOffsetPageTypeVarCustomizedTaskCommentRead,
LimitOffsetPageTypeVarCustomizedTaskRead,
ListAgentsApiV1AgentAgentsGetParams,
ListApprovalsApiV1AgentBoardsBoardIdApprovalsGetParams,
ListBoardMemoryApiV1AgentBoardsBoardIdMemoryGetParams,
ListBoardsApiV1AgentBoardsGetParams,
ListTaskCommentsApiV1AgentBoardsBoardIdTasksTaskIdCommentsGetParams,
ListTasksApiV1AgentBoardsBoardIdTasksGetParams,
OkResponse,
TaskCommentCreate,
@@ -54,7 +62,7 @@ type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
* @summary List Boards
*/
export type listBoardsApiV1AgentBoardsGetResponse200 = {
data: BoardRead[];
data: LimitOffsetPageTypeVarCustomizedBoardRead;
status: 200;
};
@@ -76,15 +84,30 @@ export type listBoardsApiV1AgentBoardsGetResponse =
| listBoardsApiV1AgentBoardsGetResponseSuccess
| listBoardsApiV1AgentBoardsGetResponseError;
export const getListBoardsApiV1AgentBoardsGetUrl = () => {
return `/api/v1/agent/boards`;
export const getListBoardsApiV1AgentBoardsGetUrl = (
params?: ListBoardsApiV1AgentBoardsGetParams,
) => {
const normalizedParams = new URLSearchParams();
Object.entries(params || {}).forEach(([key, value]) => {
if (value !== undefined) {
normalizedParams.append(key, value === null ? "null" : value.toString());
}
});
const stringifiedParams = normalizedParams.toString();
return stringifiedParams.length > 0
? `/api/v1/agent/boards?${stringifiedParams}`
: `/api/v1/agent/boards`;
};
export const listBoardsApiV1AgentBoardsGet = async (
params?: ListBoardsApiV1AgentBoardsGetParams,
options?: RequestInit,
): Promise<listBoardsApiV1AgentBoardsGetResponse> => {
return customFetch<listBoardsApiV1AgentBoardsGetResponse>(
getListBoardsApiV1AgentBoardsGetUrl(),
getListBoardsApiV1AgentBoardsGetUrl(params),
{
...options,
method: "GET",
@@ -92,32 +115,37 @@ export const listBoardsApiV1AgentBoardsGet = async (
);
};
export const getListBoardsApiV1AgentBoardsGetQueryKey = () => {
return [`/api/v1/agent/boards`] as const;
export const getListBoardsApiV1AgentBoardsGetQueryKey = (
params?: ListBoardsApiV1AgentBoardsGetParams,
) => {
return [`/api/v1/agent/boards`, ...(params ? [params] : [])] as const;
};
export const getListBoardsApiV1AgentBoardsGetQueryOptions = <
TData = Awaited<ReturnType<typeof listBoardsApiV1AgentBoardsGet>>,
TError = HTTPValidationError,
>(options?: {
query?: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof listBoardsApiV1AgentBoardsGet>>,
TError,
TData
>
>;
request?: SecondParameter<typeof customFetch>;
}) => {
>(
params?: ListBoardsApiV1AgentBoardsGetParams,
options?: {
query?: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof listBoardsApiV1AgentBoardsGet>>,
TError,
TData
>
>;
request?: SecondParameter<typeof customFetch>;
},
) => {
const { query: queryOptions, request: requestOptions } = options ?? {};
const queryKey =
queryOptions?.queryKey ?? getListBoardsApiV1AgentBoardsGetQueryKey();
queryOptions?.queryKey ?? getListBoardsApiV1AgentBoardsGetQueryKey(params);
const queryFn: QueryFunction<
Awaited<ReturnType<typeof listBoardsApiV1AgentBoardsGet>>
> = ({ signal }) =>
listBoardsApiV1AgentBoardsGet({ signal, ...requestOptions });
listBoardsApiV1AgentBoardsGet(params, { signal, ...requestOptions });
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
Awaited<ReturnType<typeof listBoardsApiV1AgentBoardsGet>>,
@@ -135,6 +163,7 @@ export function useListBoardsApiV1AgentBoardsGet<
TData = Awaited<ReturnType<typeof listBoardsApiV1AgentBoardsGet>>,
TError = HTTPValidationError,
>(
params: undefined | ListBoardsApiV1AgentBoardsGetParams,
options: {
query: Partial<
UseQueryOptions<
@@ -161,6 +190,7 @@ export function useListBoardsApiV1AgentBoardsGet<
TData = Awaited<ReturnType<typeof listBoardsApiV1AgentBoardsGet>>,
TError = HTTPValidationError,
>(
params?: ListBoardsApiV1AgentBoardsGetParams,
options?: {
query?: Partial<
UseQueryOptions<
@@ -187,6 +217,7 @@ export function useListBoardsApiV1AgentBoardsGet<
TData = Awaited<ReturnType<typeof listBoardsApiV1AgentBoardsGet>>,
TError = HTTPValidationError,
>(
params?: ListBoardsApiV1AgentBoardsGetParams,
options?: {
query?: Partial<
UseQueryOptions<
@@ -209,6 +240,7 @@ export function useListBoardsApiV1AgentBoardsGet<
TData = Awaited<ReturnType<typeof listBoardsApiV1AgentBoardsGet>>,
TError = HTTPValidationError,
>(
params?: ListBoardsApiV1AgentBoardsGetParams,
options?: {
query?: Partial<
UseQueryOptions<
@@ -223,7 +255,10 @@ export function useListBoardsApiV1AgentBoardsGet<
): UseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
} {
const queryOptions = getListBoardsApiV1AgentBoardsGetQueryOptions(options);
const queryOptions = getListBoardsApiV1AgentBoardsGetQueryOptions(
params,
options,
);
const query = useQuery(queryOptions, queryClient) as UseQueryResult<
TData,
@@ -439,7 +474,7 @@ export function useGetBoardApiV1AgentBoardsBoardIdGet<
* @summary List Agents
*/
export type listAgentsApiV1AgentAgentsGetResponse200 = {
data: AgentRead[];
data: LimitOffsetPageTypeVarCustomizedAgentRead;
status: 200;
};
@@ -766,7 +801,7 @@ export const useCreateAgentApiV1AgentAgentsPost = <
* @summary List Tasks
*/
export type listTasksApiV1AgentBoardsBoardIdTasksGetResponse200 = {
data: TaskRead[];
data: LimitOffsetPageTypeVarCustomizedTaskRead;
status: 200;
};
@@ -1265,7 +1300,7 @@ export const useUpdateTaskApiV1AgentBoardsBoardIdTasksTaskIdPatch = <
*/
export type listTaskCommentsApiV1AgentBoardsBoardIdTasksTaskIdCommentsGetResponse200 =
{
data: TaskCommentRead[];
data: LimitOffsetPageTypeVarCustomizedTaskCommentRead;
status: 200;
};
@@ -1290,20 +1325,41 @@ export type listTaskCommentsApiV1AgentBoardsBoardIdTasksTaskIdCommentsGetRespons
| listTaskCommentsApiV1AgentBoardsBoardIdTasksTaskIdCommentsGetResponseError;
export const getListTaskCommentsApiV1AgentBoardsBoardIdTasksTaskIdCommentsGetUrl =
(boardId: string, taskId: string) => {
return `/api/v1/agent/boards/${boardId}/tasks/${taskId}/comments`;
(
boardId: string,
taskId: string,
params?: ListTaskCommentsApiV1AgentBoardsBoardIdTasksTaskIdCommentsGetParams,
) => {
const normalizedParams = new URLSearchParams();
Object.entries(params || {}).forEach(([key, value]) => {
if (value !== undefined) {
normalizedParams.append(
key,
value === null ? "null" : value.toString(),
);
}
});
const stringifiedParams = normalizedParams.toString();
return stringifiedParams.length > 0
? `/api/v1/agent/boards/${boardId}/tasks/${taskId}/comments?${stringifiedParams}`
: `/api/v1/agent/boards/${boardId}/tasks/${taskId}/comments`;
};
export const listTaskCommentsApiV1AgentBoardsBoardIdTasksTaskIdCommentsGet =
async (
boardId: string,
taskId: string,
params?: ListTaskCommentsApiV1AgentBoardsBoardIdTasksTaskIdCommentsGetParams,
options?: RequestInit,
): Promise<listTaskCommentsApiV1AgentBoardsBoardIdTasksTaskIdCommentsGetResponse> => {
return customFetch<listTaskCommentsApiV1AgentBoardsBoardIdTasksTaskIdCommentsGetResponse>(
getListTaskCommentsApiV1AgentBoardsBoardIdTasksTaskIdCommentsGetUrl(
boardId,
taskId,
params,
),
{
...options,
@@ -1313,9 +1369,14 @@ export const listTaskCommentsApiV1AgentBoardsBoardIdTasksTaskIdCommentsGet =
};
export const getListTaskCommentsApiV1AgentBoardsBoardIdTasksTaskIdCommentsGetQueryKey =
(boardId: string, taskId: string) => {
(
boardId: string,
taskId: string,
params?: ListTaskCommentsApiV1AgentBoardsBoardIdTasksTaskIdCommentsGetParams,
) => {
return [
`/api/v1/agent/boards/${boardId}/tasks/${taskId}/comments`,
...(params ? [params] : []),
] as const;
};
@@ -1330,6 +1391,7 @@ export const getListTaskCommentsApiV1AgentBoardsBoardIdTasksTaskIdCommentsGetQue
>(
boardId: string,
taskId: string,
params?: ListTaskCommentsApiV1AgentBoardsBoardIdTasksTaskIdCommentsGetParams,
options?: {
query?: Partial<
UseQueryOptions<
@@ -1352,6 +1414,7 @@ export const getListTaskCommentsApiV1AgentBoardsBoardIdTasksTaskIdCommentsGetQue
getListTaskCommentsApiV1AgentBoardsBoardIdTasksTaskIdCommentsGetQueryKey(
boardId,
taskId,
params,
);
const queryFn: QueryFunction<
@@ -1364,6 +1427,7 @@ export const getListTaskCommentsApiV1AgentBoardsBoardIdTasksTaskIdCommentsGetQue
listTaskCommentsApiV1AgentBoardsBoardIdTasksTaskIdCommentsGet(
boardId,
taskId,
params,
{ signal, ...requestOptions },
);
@@ -1404,6 +1468,9 @@ export function useListTaskCommentsApiV1AgentBoardsBoardIdTasksTaskIdCommentsGet
>(
boardId: string,
taskId: string,
params:
| undefined
| ListTaskCommentsApiV1AgentBoardsBoardIdTasksTaskIdCommentsGetParams,
options: {
query: Partial<
UseQueryOptions<
@@ -1448,6 +1515,7 @@ export function useListTaskCommentsApiV1AgentBoardsBoardIdTasksTaskIdCommentsGet
>(
boardId: string,
taskId: string,
params?: ListTaskCommentsApiV1AgentBoardsBoardIdTasksTaskIdCommentsGetParams,
options?: {
query?: Partial<
UseQueryOptions<
@@ -1492,6 +1560,7 @@ export function useListTaskCommentsApiV1AgentBoardsBoardIdTasksTaskIdCommentsGet
>(
boardId: string,
taskId: string,
params?: ListTaskCommentsApiV1AgentBoardsBoardIdTasksTaskIdCommentsGetParams,
options?: {
query?: Partial<
UseQueryOptions<
@@ -1524,6 +1593,7 @@ export function useListTaskCommentsApiV1AgentBoardsBoardIdTasksTaskIdCommentsGet
>(
boardId: string,
taskId: string,
params?: ListTaskCommentsApiV1AgentBoardsBoardIdTasksTaskIdCommentsGetParams,
options?: {
query?: Partial<
UseQueryOptions<
@@ -1546,6 +1616,7 @@ export function useListTaskCommentsApiV1AgentBoardsBoardIdTasksTaskIdCommentsGet
getListTaskCommentsApiV1AgentBoardsBoardIdTasksTaskIdCommentsGetQueryOptions(
boardId,
taskId,
params,
options,
);
@@ -1720,7 +1791,7 @@ export const useCreateTaskCommentApiV1AgentBoardsBoardIdTasksTaskIdCommentsPost
* @summary List Board Memory
*/
export type listBoardMemoryApiV1AgentBoardsBoardIdMemoryGetResponse200 = {
data: BoardMemoryRead[];
data: LimitOffsetPageTypeVarCustomizedBoardMemoryRead;
status: 200;
};
@@ -2121,7 +2192,7 @@ export const useCreateBoardMemoryApiV1AgentBoardsBoardIdMemoryPost = <
* @summary List Approvals
*/
export type listApprovalsApiV1AgentBoardsBoardIdApprovalsGetResponse200 = {
data: ApprovalRead[];
data: LimitOffsetPageTypeVarCustomizedApprovalRead;
status: 200;
};

View File

@@ -27,6 +27,8 @@ import type {
AgentRead,
AgentUpdate,
HTTPValidationError,
LimitOffsetPageTypeVarCustomizedAgentRead,
ListAgentsApiV1AgentsGetParams,
OkResponse,
StreamAgentsApiV1AgentsStreamGetParams,
UpdateAgentApiV1AgentsAgentIdPatchParams,
@@ -40,26 +42,52 @@ type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
* @summary List Agents
*/
export type listAgentsApiV1AgentsGetResponse200 = {
data: AgentRead[];
data: LimitOffsetPageTypeVarCustomizedAgentRead;
status: 200;
};
export type listAgentsApiV1AgentsGetResponse422 = {
data: HTTPValidationError;
status: 422;
};
export type listAgentsApiV1AgentsGetResponseSuccess =
listAgentsApiV1AgentsGetResponse200 & {
headers: Headers;
};
export type listAgentsApiV1AgentsGetResponse =
listAgentsApiV1AgentsGetResponseSuccess;
export type listAgentsApiV1AgentsGetResponseError =
listAgentsApiV1AgentsGetResponse422 & {
headers: Headers;
};
export const getListAgentsApiV1AgentsGetUrl = () => {
return `/api/v1/agents`;
export type listAgentsApiV1AgentsGetResponse =
| listAgentsApiV1AgentsGetResponseSuccess
| listAgentsApiV1AgentsGetResponseError;
export const getListAgentsApiV1AgentsGetUrl = (
params?: ListAgentsApiV1AgentsGetParams,
) => {
const normalizedParams = new URLSearchParams();
Object.entries(params || {}).forEach(([key, value]) => {
if (value !== undefined) {
normalizedParams.append(key, value === null ? "null" : value.toString());
}
});
const stringifiedParams = normalizedParams.toString();
return stringifiedParams.length > 0
? `/api/v1/agents?${stringifiedParams}`
: `/api/v1/agents`;
};
export const listAgentsApiV1AgentsGet = async (
params?: ListAgentsApiV1AgentsGetParams,
options?: RequestInit,
): Promise<listAgentsApiV1AgentsGetResponse> => {
return customFetch<listAgentsApiV1AgentsGetResponse>(
getListAgentsApiV1AgentsGetUrl(),
getListAgentsApiV1AgentsGetUrl(params),
{
...options,
method: "GET",
@@ -67,31 +95,37 @@ export const listAgentsApiV1AgentsGet = async (
);
};
export const getListAgentsApiV1AgentsGetQueryKey = () => {
return [`/api/v1/agents`] as const;
export const getListAgentsApiV1AgentsGetQueryKey = (
params?: ListAgentsApiV1AgentsGetParams,
) => {
return [`/api/v1/agents`, ...(params ? [params] : [])] as const;
};
export const getListAgentsApiV1AgentsGetQueryOptions = <
TData = Awaited<ReturnType<typeof listAgentsApiV1AgentsGet>>,
TError = unknown,
>(options?: {
query?: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof listAgentsApiV1AgentsGet>>,
TError,
TData
>
>;
request?: SecondParameter<typeof customFetch>;
}) => {
TError = HTTPValidationError,
>(
params?: ListAgentsApiV1AgentsGetParams,
options?: {
query?: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof listAgentsApiV1AgentsGet>>,
TError,
TData
>
>;
request?: SecondParameter<typeof customFetch>;
},
) => {
const { query: queryOptions, request: requestOptions } = options ?? {};
const queryKey =
queryOptions?.queryKey ?? getListAgentsApiV1AgentsGetQueryKey();
queryOptions?.queryKey ?? getListAgentsApiV1AgentsGetQueryKey(params);
const queryFn: QueryFunction<
Awaited<ReturnType<typeof listAgentsApiV1AgentsGet>>
> = ({ signal }) => listAgentsApiV1AgentsGet({ signal, ...requestOptions });
> = ({ signal }) =>
listAgentsApiV1AgentsGet(params, { signal, ...requestOptions });
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
Awaited<ReturnType<typeof listAgentsApiV1AgentsGet>>,
@@ -103,12 +137,13 @@ export const getListAgentsApiV1AgentsGetQueryOptions = <
export type ListAgentsApiV1AgentsGetQueryResult = NonNullable<
Awaited<ReturnType<typeof listAgentsApiV1AgentsGet>>
>;
export type ListAgentsApiV1AgentsGetQueryError = unknown;
export type ListAgentsApiV1AgentsGetQueryError = HTTPValidationError;
export function useListAgentsApiV1AgentsGet<
TData = Awaited<ReturnType<typeof listAgentsApiV1AgentsGet>>,
TError = unknown,
TError = HTTPValidationError,
>(
params: undefined | ListAgentsApiV1AgentsGetParams,
options: {
query: Partial<
UseQueryOptions<
@@ -133,8 +168,9 @@ export function useListAgentsApiV1AgentsGet<
};
export function useListAgentsApiV1AgentsGet<
TData = Awaited<ReturnType<typeof listAgentsApiV1AgentsGet>>,
TError = unknown,
TError = HTTPValidationError,
>(
params?: ListAgentsApiV1AgentsGetParams,
options?: {
query?: Partial<
UseQueryOptions<
@@ -159,8 +195,9 @@ export function useListAgentsApiV1AgentsGet<
};
export function useListAgentsApiV1AgentsGet<
TData = Awaited<ReturnType<typeof listAgentsApiV1AgentsGet>>,
TError = unknown,
TError = HTTPValidationError,
>(
params?: ListAgentsApiV1AgentsGetParams,
options?: {
query?: Partial<
UseQueryOptions<
@@ -181,8 +218,9 @@ export function useListAgentsApiV1AgentsGet<
export function useListAgentsApiV1AgentsGet<
TData = Awaited<ReturnType<typeof listAgentsApiV1AgentsGet>>,
TError = unknown,
TError = HTTPValidationError,
>(
params?: ListAgentsApiV1AgentsGetParams,
options?: {
query?: Partial<
UseQueryOptions<
@@ -197,7 +235,7 @@ export function useListAgentsApiV1AgentsGet<
): UseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
} {
const queryOptions = getListAgentsApiV1AgentsGetQueryOptions(options);
const queryOptions = getListAgentsApiV1AgentsGetQueryOptions(params, options);
const query = useQuery(queryOptions, queryClient) as UseQueryResult<
TData,

View File

@@ -25,6 +25,7 @@ import type {
ApprovalRead,
ApprovalUpdate,
HTTPValidationError,
LimitOffsetPageTypeVarCustomizedApprovalRead,
ListApprovalsApiV1BoardsBoardIdApprovalsGetParams,
StreamApprovalsApiV1BoardsBoardIdApprovalsStreamGetParams,
} from ".././model";
@@ -37,7 +38,7 @@ type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
* @summary List Approvals
*/
export type listApprovalsApiV1BoardsBoardIdApprovalsGetResponse200 = {
data: ApprovalRead[];
data: LimitOffsetPageTypeVarCustomizedApprovalRead;
status: 200;
};

View File

@@ -24,6 +24,7 @@ import type {
BoardMemoryCreate,
BoardMemoryRead,
HTTPValidationError,
LimitOffsetPageTypeVarCustomizedBoardMemoryRead,
ListBoardMemoryApiV1BoardsBoardIdMemoryGetParams,
StreamBoardMemoryApiV1BoardsBoardIdMemoryStreamGetParams,
} from ".././model";
@@ -36,7 +37,7 @@ type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
* @summary List Board Memory
*/
export type listBoardMemoryApiV1BoardsBoardIdMemoryGetResponse200 = {
data: BoardMemoryRead[];
data: LimitOffsetPageTypeVarCustomizedBoardMemoryRead;
status: 200;
};

View File

@@ -23,8 +23,11 @@ import type {
import type {
BoardCreate,
BoardRead,
BoardSnapshot,
BoardUpdate,
HTTPValidationError,
LimitOffsetPageTypeVarCustomizedBoardRead,
ListBoardsApiV1BoardsGetParams,
OkResponse,
} from ".././model";
@@ -36,7 +39,7 @@ type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
* @summary List Boards
*/
export type listBoardsApiV1BoardsGetResponse200 = {
data: BoardRead[];
data: LimitOffsetPageTypeVarCustomizedBoardRead;
status: 200;
};
@@ -58,15 +61,30 @@ export type listBoardsApiV1BoardsGetResponse =
| listBoardsApiV1BoardsGetResponseSuccess
| listBoardsApiV1BoardsGetResponseError;
export const getListBoardsApiV1BoardsGetUrl = () => {
return `/api/v1/boards`;
export const getListBoardsApiV1BoardsGetUrl = (
params?: ListBoardsApiV1BoardsGetParams,
) => {
const normalizedParams = new URLSearchParams();
Object.entries(params || {}).forEach(([key, value]) => {
if (value !== undefined) {
normalizedParams.append(key, value === null ? "null" : value.toString());
}
});
const stringifiedParams = normalizedParams.toString();
return stringifiedParams.length > 0
? `/api/v1/boards?${stringifiedParams}`
: `/api/v1/boards`;
};
export const listBoardsApiV1BoardsGet = async (
params?: ListBoardsApiV1BoardsGetParams,
options?: RequestInit,
): Promise<listBoardsApiV1BoardsGetResponse> => {
return customFetch<listBoardsApiV1BoardsGetResponse>(
getListBoardsApiV1BoardsGetUrl(),
getListBoardsApiV1BoardsGetUrl(params),
{
...options,
method: "GET",
@@ -74,31 +92,37 @@ export const listBoardsApiV1BoardsGet = async (
);
};
export const getListBoardsApiV1BoardsGetQueryKey = () => {
return [`/api/v1/boards`] as const;
export const getListBoardsApiV1BoardsGetQueryKey = (
params?: ListBoardsApiV1BoardsGetParams,
) => {
return [`/api/v1/boards`, ...(params ? [params] : [])] as const;
};
export const getListBoardsApiV1BoardsGetQueryOptions = <
TData = Awaited<ReturnType<typeof listBoardsApiV1BoardsGet>>,
TError = HTTPValidationError,
>(options?: {
query?: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof listBoardsApiV1BoardsGet>>,
TError,
TData
>
>;
request?: SecondParameter<typeof customFetch>;
}) => {
>(
params?: ListBoardsApiV1BoardsGetParams,
options?: {
query?: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof listBoardsApiV1BoardsGet>>,
TError,
TData
>
>;
request?: SecondParameter<typeof customFetch>;
},
) => {
const { query: queryOptions, request: requestOptions } = options ?? {};
const queryKey =
queryOptions?.queryKey ?? getListBoardsApiV1BoardsGetQueryKey();
queryOptions?.queryKey ?? getListBoardsApiV1BoardsGetQueryKey(params);
const queryFn: QueryFunction<
Awaited<ReturnType<typeof listBoardsApiV1BoardsGet>>
> = ({ signal }) => listBoardsApiV1BoardsGet({ signal, ...requestOptions });
> = ({ signal }) =>
listBoardsApiV1BoardsGet(params, { signal, ...requestOptions });
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
Awaited<ReturnType<typeof listBoardsApiV1BoardsGet>>,
@@ -116,6 +140,7 @@ export function useListBoardsApiV1BoardsGet<
TData = Awaited<ReturnType<typeof listBoardsApiV1BoardsGet>>,
TError = HTTPValidationError,
>(
params: undefined | ListBoardsApiV1BoardsGetParams,
options: {
query: Partial<
UseQueryOptions<
@@ -142,6 +167,7 @@ export function useListBoardsApiV1BoardsGet<
TData = Awaited<ReturnType<typeof listBoardsApiV1BoardsGet>>,
TError = HTTPValidationError,
>(
params?: ListBoardsApiV1BoardsGetParams,
options?: {
query?: Partial<
UseQueryOptions<
@@ -168,6 +194,7 @@ export function useListBoardsApiV1BoardsGet<
TData = Awaited<ReturnType<typeof listBoardsApiV1BoardsGet>>,
TError = HTTPValidationError,
>(
params?: ListBoardsApiV1BoardsGetParams,
options?: {
query?: Partial<
UseQueryOptions<
@@ -190,6 +217,7 @@ export function useListBoardsApiV1BoardsGet<
TData = Awaited<ReturnType<typeof listBoardsApiV1BoardsGet>>,
TError = HTTPValidationError,
>(
params?: ListBoardsApiV1BoardsGetParams,
options?: {
query?: Partial<
UseQueryOptions<
@@ -204,7 +232,7 @@ export function useListBoardsApiV1BoardsGet<
): UseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
} {
const queryOptions = getListBoardsApiV1BoardsGetQueryOptions(options);
const queryOptions = getListBoardsApiV1BoardsGetQueryOptions(params, options);
const query = useQuery(queryOptions, queryClient) as UseQueryResult<
TData,
@@ -765,3 +793,240 @@ export const useDeleteBoardApiV1BoardsBoardIdDelete = <
queryClient,
);
};
/**
* @summary Get Board Snapshot
*/
export type getBoardSnapshotApiV1BoardsBoardIdSnapshotGetResponse200 = {
data: BoardSnapshot;
status: 200;
};
export type getBoardSnapshotApiV1BoardsBoardIdSnapshotGetResponse422 = {
data: HTTPValidationError;
status: 422;
};
export type getBoardSnapshotApiV1BoardsBoardIdSnapshotGetResponseSuccess =
getBoardSnapshotApiV1BoardsBoardIdSnapshotGetResponse200 & {
headers: Headers;
};
export type getBoardSnapshotApiV1BoardsBoardIdSnapshotGetResponseError =
getBoardSnapshotApiV1BoardsBoardIdSnapshotGetResponse422 & {
headers: Headers;
};
export type getBoardSnapshotApiV1BoardsBoardIdSnapshotGetResponse =
| getBoardSnapshotApiV1BoardsBoardIdSnapshotGetResponseSuccess
| getBoardSnapshotApiV1BoardsBoardIdSnapshotGetResponseError;
export const getGetBoardSnapshotApiV1BoardsBoardIdSnapshotGetUrl = (
boardId: string,
) => {
return `/api/v1/boards/${boardId}/snapshot`;
};
export const getBoardSnapshotApiV1BoardsBoardIdSnapshotGet = async (
boardId: string,
options?: RequestInit,
): Promise<getBoardSnapshotApiV1BoardsBoardIdSnapshotGetResponse> => {
return customFetch<getBoardSnapshotApiV1BoardsBoardIdSnapshotGetResponse>(
getGetBoardSnapshotApiV1BoardsBoardIdSnapshotGetUrl(boardId),
{
...options,
method: "GET",
},
);
};
export const getGetBoardSnapshotApiV1BoardsBoardIdSnapshotGetQueryKey = (
boardId: string,
) => {
return [`/api/v1/boards/${boardId}/snapshot`] as const;
};
export const getGetBoardSnapshotApiV1BoardsBoardIdSnapshotGetQueryOptions = <
TData = Awaited<
ReturnType<typeof getBoardSnapshotApiV1BoardsBoardIdSnapshotGet>
>,
TError = HTTPValidationError,
>(
boardId: string,
options?: {
query?: Partial<
UseQueryOptions<
Awaited<
ReturnType<typeof getBoardSnapshotApiV1BoardsBoardIdSnapshotGet>
>,
TError,
TData
>
>;
request?: SecondParameter<typeof customFetch>;
},
) => {
const { query: queryOptions, request: requestOptions } = options ?? {};
const queryKey =
queryOptions?.queryKey ??
getGetBoardSnapshotApiV1BoardsBoardIdSnapshotGetQueryKey(boardId);
const queryFn: QueryFunction<
Awaited<ReturnType<typeof getBoardSnapshotApiV1BoardsBoardIdSnapshotGet>>
> = ({ signal }) =>
getBoardSnapshotApiV1BoardsBoardIdSnapshotGet(boardId, {
signal,
...requestOptions,
});
return {
queryKey,
queryFn,
enabled: !!boardId,
...queryOptions,
} as UseQueryOptions<
Awaited<ReturnType<typeof getBoardSnapshotApiV1BoardsBoardIdSnapshotGet>>,
TError,
TData
> & { queryKey: DataTag<QueryKey, TData, TError> };
};
export type GetBoardSnapshotApiV1BoardsBoardIdSnapshotGetQueryResult =
NonNullable<
Awaited<ReturnType<typeof getBoardSnapshotApiV1BoardsBoardIdSnapshotGet>>
>;
export type GetBoardSnapshotApiV1BoardsBoardIdSnapshotGetQueryError =
HTTPValidationError;
export function useGetBoardSnapshotApiV1BoardsBoardIdSnapshotGet<
TData = Awaited<
ReturnType<typeof getBoardSnapshotApiV1BoardsBoardIdSnapshotGet>
>,
TError = HTTPValidationError,
>(
boardId: string,
options: {
query: Partial<
UseQueryOptions<
Awaited<
ReturnType<typeof getBoardSnapshotApiV1BoardsBoardIdSnapshotGet>
>,
TError,
TData
>
> &
Pick<
DefinedInitialDataOptions<
Awaited<
ReturnType<typeof getBoardSnapshotApiV1BoardsBoardIdSnapshotGet>
>,
TError,
Awaited<
ReturnType<typeof getBoardSnapshotApiV1BoardsBoardIdSnapshotGet>
>
>,
"initialData"
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): DefinedUseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
};
export function useGetBoardSnapshotApiV1BoardsBoardIdSnapshotGet<
TData = Awaited<
ReturnType<typeof getBoardSnapshotApiV1BoardsBoardIdSnapshotGet>
>,
TError = HTTPValidationError,
>(
boardId: string,
options?: {
query?: Partial<
UseQueryOptions<
Awaited<
ReturnType<typeof getBoardSnapshotApiV1BoardsBoardIdSnapshotGet>
>,
TError,
TData
>
> &
Pick<
UndefinedInitialDataOptions<
Awaited<
ReturnType<typeof getBoardSnapshotApiV1BoardsBoardIdSnapshotGet>
>,
TError,
Awaited<
ReturnType<typeof getBoardSnapshotApiV1BoardsBoardIdSnapshotGet>
>
>,
"initialData"
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
};
export function useGetBoardSnapshotApiV1BoardsBoardIdSnapshotGet<
TData = Awaited<
ReturnType<typeof getBoardSnapshotApiV1BoardsBoardIdSnapshotGet>
>,
TError = HTTPValidationError,
>(
boardId: string,
options?: {
query?: Partial<
UseQueryOptions<
Awaited<
ReturnType<typeof getBoardSnapshotApiV1BoardsBoardIdSnapshotGet>
>,
TError,
TData
>
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
};
/**
* @summary Get Board Snapshot
*/
export function useGetBoardSnapshotApiV1BoardsBoardIdSnapshotGet<
TData = Awaited<
ReturnType<typeof getBoardSnapshotApiV1BoardsBoardIdSnapshotGet>
>,
TError = HTTPValidationError,
>(
boardId: string,
options?: {
query?: Partial<
UseQueryOptions<
Awaited<
ReturnType<typeof getBoardSnapshotApiV1BoardsBoardIdSnapshotGet>
>,
TError,
TData
>
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
} {
const queryOptions =
getGetBoardSnapshotApiV1BoardsBoardIdSnapshotGetQueryOptions(
boardId,
options,
);
const query = useQuery(queryOptions, queryClient) as UseQueryResult<
TData,
TError
> & { queryKey: DataTag<QueryKey, TData, TError> };
return { ...query, queryKey: queryOptions.queryKey };
}

View File

@@ -34,7 +34,9 @@ import type {
GetGatewaySessionApiV1GatewaysSessionsSessionIdGetParams,
GetSessionHistoryApiV1GatewaysSessionsSessionIdHistoryGetParams,
HTTPValidationError,
LimitOffsetPageTypeVarCustomizedGatewayRead,
ListGatewaySessionsApiV1GatewaysSessionsGetParams,
ListGatewaysApiV1GatewaysGetParams,
OkResponse,
SendGatewaySessionMessageApiV1GatewaysSessionsSessionIdMessagePostParams,
} from ".././model";
@@ -1451,26 +1453,52 @@ export function useGatewayCommandsApiV1GatewaysCommandsGet<
* @summary List Gateways
*/
export type listGatewaysApiV1GatewaysGetResponse200 = {
data: GatewayRead[];
data: LimitOffsetPageTypeVarCustomizedGatewayRead;
status: 200;
};
export type listGatewaysApiV1GatewaysGetResponse422 = {
data: HTTPValidationError;
status: 422;
};
export type listGatewaysApiV1GatewaysGetResponseSuccess =
listGatewaysApiV1GatewaysGetResponse200 & {
headers: Headers;
};
export type listGatewaysApiV1GatewaysGetResponse =
listGatewaysApiV1GatewaysGetResponseSuccess;
export type listGatewaysApiV1GatewaysGetResponseError =
listGatewaysApiV1GatewaysGetResponse422 & {
headers: Headers;
};
export const getListGatewaysApiV1GatewaysGetUrl = () => {
return `/api/v1/gateways`;
export type listGatewaysApiV1GatewaysGetResponse =
| listGatewaysApiV1GatewaysGetResponseSuccess
| listGatewaysApiV1GatewaysGetResponseError;
export const getListGatewaysApiV1GatewaysGetUrl = (
params?: ListGatewaysApiV1GatewaysGetParams,
) => {
const normalizedParams = new URLSearchParams();
Object.entries(params || {}).forEach(([key, value]) => {
if (value !== undefined) {
normalizedParams.append(key, value === null ? "null" : value.toString());
}
});
const stringifiedParams = normalizedParams.toString();
return stringifiedParams.length > 0
? `/api/v1/gateways?${stringifiedParams}`
: `/api/v1/gateways`;
};
export const listGatewaysApiV1GatewaysGet = async (
params?: ListGatewaysApiV1GatewaysGetParams,
options?: RequestInit,
): Promise<listGatewaysApiV1GatewaysGetResponse> => {
return customFetch<listGatewaysApiV1GatewaysGetResponse>(
getListGatewaysApiV1GatewaysGetUrl(),
getListGatewaysApiV1GatewaysGetUrl(params),
{
...options,
method: "GET",
@@ -1478,32 +1506,37 @@ export const listGatewaysApiV1GatewaysGet = async (
);
};
export const getListGatewaysApiV1GatewaysGetQueryKey = () => {
return [`/api/v1/gateways`] as const;
export const getListGatewaysApiV1GatewaysGetQueryKey = (
params?: ListGatewaysApiV1GatewaysGetParams,
) => {
return [`/api/v1/gateways`, ...(params ? [params] : [])] as const;
};
export const getListGatewaysApiV1GatewaysGetQueryOptions = <
TData = Awaited<ReturnType<typeof listGatewaysApiV1GatewaysGet>>,
TError = unknown,
>(options?: {
query?: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof listGatewaysApiV1GatewaysGet>>,
TError,
TData
>
>;
request?: SecondParameter<typeof customFetch>;
}) => {
TError = HTTPValidationError,
>(
params?: ListGatewaysApiV1GatewaysGetParams,
options?: {
query?: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof listGatewaysApiV1GatewaysGet>>,
TError,
TData
>
>;
request?: SecondParameter<typeof customFetch>;
},
) => {
const { query: queryOptions, request: requestOptions } = options ?? {};
const queryKey =
queryOptions?.queryKey ?? getListGatewaysApiV1GatewaysGetQueryKey();
queryOptions?.queryKey ?? getListGatewaysApiV1GatewaysGetQueryKey(params);
const queryFn: QueryFunction<
Awaited<ReturnType<typeof listGatewaysApiV1GatewaysGet>>
> = ({ signal }) =>
listGatewaysApiV1GatewaysGet({ signal, ...requestOptions });
listGatewaysApiV1GatewaysGet(params, { signal, ...requestOptions });
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
Awaited<ReturnType<typeof listGatewaysApiV1GatewaysGet>>,
@@ -1515,12 +1548,13 @@ export const getListGatewaysApiV1GatewaysGetQueryOptions = <
export type ListGatewaysApiV1GatewaysGetQueryResult = NonNullable<
Awaited<ReturnType<typeof listGatewaysApiV1GatewaysGet>>
>;
export type ListGatewaysApiV1GatewaysGetQueryError = unknown;
export type ListGatewaysApiV1GatewaysGetQueryError = HTTPValidationError;
export function useListGatewaysApiV1GatewaysGet<
TData = Awaited<ReturnType<typeof listGatewaysApiV1GatewaysGet>>,
TError = unknown,
TError = HTTPValidationError,
>(
params: undefined | ListGatewaysApiV1GatewaysGetParams,
options: {
query: Partial<
UseQueryOptions<
@@ -1545,8 +1579,9 @@ export function useListGatewaysApiV1GatewaysGet<
};
export function useListGatewaysApiV1GatewaysGet<
TData = Awaited<ReturnType<typeof listGatewaysApiV1GatewaysGet>>,
TError = unknown,
TError = HTTPValidationError,
>(
params?: ListGatewaysApiV1GatewaysGetParams,
options?: {
query?: Partial<
UseQueryOptions<
@@ -1571,8 +1606,9 @@ export function useListGatewaysApiV1GatewaysGet<
};
export function useListGatewaysApiV1GatewaysGet<
TData = Awaited<ReturnType<typeof listGatewaysApiV1GatewaysGet>>,
TError = unknown,
TError = HTTPValidationError,
>(
params?: ListGatewaysApiV1GatewaysGetParams,
options?: {
query?: Partial<
UseQueryOptions<
@@ -1593,8 +1629,9 @@ export function useListGatewaysApiV1GatewaysGet<
export function useListGatewaysApiV1GatewaysGet<
TData = Awaited<ReturnType<typeof listGatewaysApiV1GatewaysGet>>,
TError = unknown,
TError = HTTPValidationError,
>(
params?: ListGatewaysApiV1GatewaysGetParams,
options?: {
query?: Partial<
UseQueryOptions<
@@ -1609,7 +1646,10 @@ export function useListGatewaysApiV1GatewaysGet<
): UseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
} {
const queryOptions = getListGatewaysApiV1GatewaysGetQueryOptions(options);
const queryOptions = getListGatewaysApiV1GatewaysGetQueryOptions(
params,
options,
);
const query = useQuery(queryOptions, queryClient) as UseQueryResult<
TData,

View File

@@ -10,6 +10,7 @@ import type { ApprovalCreateStatus } from "./approvalCreateStatus";
export interface ApprovalCreate {
action_type: string;
task_id?: string | null;
payload?: ApprovalCreatePayload;
confidence: number;
rubric_scores?: ApprovalCreateRubricScores;

View File

@@ -10,6 +10,7 @@ import type { ApprovalReadStatus } from "./approvalReadStatus";
export interface ApprovalRead {
action_type: string;
task_id?: string | null;
payload?: ApprovalReadPayload;
confidence: number;
rubric_scores?: ApprovalReadRubricScores;

View File

@@ -12,5 +12,6 @@ export interface BoardMemoryRead {
source?: string | null;
id: string;
board_id: string;
is_chat?: boolean;
created_at: string;
}

View File

@@ -0,0 +1,20 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
import type { AgentRead } from "./agentRead";
import type { ApprovalRead } from "./approvalRead";
import type { BoardMemoryRead } from "./boardMemoryRead";
import type { BoardRead } from "./boardRead";
import type { TaskCardRead } from "./taskCardRead";
export interface BoardSnapshot {
board: BoardRead;
tasks: TaskCardRead[];
agents: AgentRead[];
approvals: ApprovalRead[];
chat_messages: BoardMemoryRead[];
pending_approvals_count?: number;
}

View File

@@ -46,6 +46,7 @@ export * from "./boardOnboardingReadMessages";
export * from "./boardOnboardingStart";
export * from "./boardRead";
export * from "./boardReadSuccessMetrics";
export * from "./boardSnapshot";
export * from "./boardUpdate";
export * from "./boardUpdateSuccessMetrics";
export * from "./confirmDeleteAgentApiV1AgentsAgentIdDeleteConfirmPost200";
@@ -90,15 +91,29 @@ export * from "./getSessionHistoryApiV1GatewaysSessionsSessionIdHistoryGetParams
export * from "./healthHealthGet200";
export * from "./healthzHealthzGet200";
export * from "./hTTPValidationError";
export * from "./limitOffsetPageTypeVarCustomizedActivityEventRead";
export * from "./limitOffsetPageTypeVarCustomizedAgentRead";
export * from "./limitOffsetPageTypeVarCustomizedApprovalRead";
export * from "./limitOffsetPageTypeVarCustomizedBoardMemoryRead";
export * from "./limitOffsetPageTypeVarCustomizedBoardRead";
export * from "./limitOffsetPageTypeVarCustomizedGatewayRead";
export * from "./limitOffsetPageTypeVarCustomizedTaskCommentRead";
export * from "./limitOffsetPageTypeVarCustomizedTaskRead";
export * from "./listActivityApiV1ActivityGetParams";
export * from "./listAgentsApiV1AgentAgentsGetParams";
export * from "./listAgentsApiV1AgentsGetParams";
export * from "./listApprovalsApiV1AgentBoardsBoardIdApprovalsGetParams";
export * from "./listApprovalsApiV1BoardsBoardIdApprovalsGetParams";
export * from "./listBoardMemoryApiV1AgentBoardsBoardIdMemoryGetParams";
export * from "./listBoardMemoryApiV1BoardsBoardIdMemoryGetParams";
export * from "./listBoardsApiV1AgentBoardsGetParams";
export * from "./listBoardsApiV1BoardsGetParams";
export * from "./listGatewaysApiV1GatewaysGetParams";
export * from "./listGatewaySessionsApiV1GatewaysSessionsGetParams";
export * from "./listSessionsApiV1GatewaySessionsGet200";
export * from "./listSessionsApiV1GatewaySessionsGetParams";
export * from "./listTaskCommentsApiV1AgentBoardsBoardIdTasksTaskIdCommentsGetParams";
export * from "./listTaskCommentsApiV1BoardsBoardIdTasksTaskIdCommentsGetParams";
export * from "./listTasksApiV1AgentBoardsBoardIdTasksGetParams";
export * from "./listTasksApiV1BoardsBoardIdTasksGetParams";
export * from "./okResponse";
@@ -111,6 +126,8 @@ export * from "./streamAgentsApiV1AgentsStreamGetParams";
export * from "./streamApprovalsApiV1BoardsBoardIdApprovalsStreamGetParams";
export * from "./streamBoardMemoryApiV1BoardsBoardIdMemoryStreamGetParams";
export * from "./streamTasksApiV1BoardsBoardIdTasksStreamGetParams";
export * from "./taskCardRead";
export * from "./taskCardReadStatus";
export * from "./taskCommentCreate";
export * from "./taskCommentRead";
export * from "./taskCreate";

View File

@@ -0,0 +1,17 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
import type { ActivityEventRead } from "./activityEventRead";
export interface LimitOffsetPageTypeVarCustomizedActivityEventRead {
items: ActivityEventRead[];
/** @minimum 0 */
total: number;
/** @minimum 1 */
limit: number;
/** @minimum 0 */
offset: number;
}

View File

@@ -0,0 +1,17 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
import type { AgentRead } from "./agentRead";
export interface LimitOffsetPageTypeVarCustomizedAgentRead {
items: AgentRead[];
/** @minimum 0 */
total: number;
/** @minimum 1 */
limit: number;
/** @minimum 0 */
offset: number;
}

View File

@@ -0,0 +1,17 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
import type { ApprovalRead } from "./approvalRead";
export interface LimitOffsetPageTypeVarCustomizedApprovalRead {
items: ApprovalRead[];
/** @minimum 0 */
total: number;
/** @minimum 1 */
limit: number;
/** @minimum 0 */
offset: number;
}

View File

@@ -0,0 +1,17 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
import type { BoardMemoryRead } from "./boardMemoryRead";
export interface LimitOffsetPageTypeVarCustomizedBoardMemoryRead {
items: BoardMemoryRead[];
/** @minimum 0 */
total: number;
/** @minimum 1 */
limit: number;
/** @minimum 0 */
offset: number;
}

View File

@@ -0,0 +1,17 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
import type { BoardRead } from "./boardRead";
export interface LimitOffsetPageTypeVarCustomizedBoardRead {
items: BoardRead[];
/** @minimum 0 */
total: number;
/** @minimum 1 */
limit: number;
/** @minimum 0 */
offset: number;
}

View File

@@ -0,0 +1,17 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
import type { GatewayRead } from "./gatewayRead";
export interface LimitOffsetPageTypeVarCustomizedGatewayRead {
items: GatewayRead[];
/** @minimum 0 */
total: number;
/** @minimum 1 */
limit: number;
/** @minimum 0 */
offset: number;
}

View File

@@ -0,0 +1,17 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
import type { TaskCommentRead } from "./taskCommentRead";
export interface LimitOffsetPageTypeVarCustomizedTaskCommentRead {
items: TaskCommentRead[];
/** @minimum 0 */
total: number;
/** @minimum 1 */
limit: number;
/** @minimum 0 */
offset: number;
}

View File

@@ -0,0 +1,17 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
import type { TaskRead } from "./taskRead";
export interface LimitOffsetPageTypeVarCustomizedTaskRead {
items: TaskRead[];
/** @minimum 0 */
total: number;
/** @minimum 1 */
limit: number;
/** @minimum 0 */
offset: number;
}

View File

@@ -7,5 +7,13 @@
export type ListAgentsApiV1AgentAgentsGetParams = {
board_id?: string | null;
limit?: number | null;
/**
* @minimum 1
* @maximum 200
*/
limit?: number;
/**
* @minimum 0
*/
offset?: number;
};

View File

@@ -0,0 +1,20 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export type ListAgentsApiV1AgentsGetParams = {
board_id?: string | null;
gateway_id?: string | null;
/**
* @minimum 1
* @maximum 200
*/
limit?: number;
/**
* @minimum 0
*/
offset?: number;
};

View File

@@ -7,4 +7,13 @@
export type ListApprovalsApiV1AgentBoardsBoardIdApprovalsGetParams = {
status?: "pending" | "approved" | "rejected" | null;
/**
* @minimum 1
* @maximum 200
*/
limit?: number;
/**
* @minimum 0
*/
offset?: number;
};

View File

@@ -7,4 +7,13 @@
export type ListApprovalsApiV1BoardsBoardIdApprovalsGetParams = {
status?: "pending" | "approved" | "rejected" | null;
/**
* @minimum 1
* @maximum 200
*/
limit?: number;
/**
* @minimum 0
*/
offset?: number;
};

View File

@@ -6,6 +6,7 @@
*/
export type ListBoardMemoryApiV1BoardsBoardIdMemoryGetParams = {
is_chat?: boolean | null;
/**
* @minimum 1
* @maximum 200

View File

@@ -0,0 +1,18 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export type ListBoardsApiV1AgentBoardsGetParams = {
/**
* @minimum 1
* @maximum 200
*/
limit?: number;
/**
* @minimum 0
*/
offset?: number;
};

View File

@@ -0,0 +1,19 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export type ListBoardsApiV1BoardsGetParams = {
gateway_id?: string | null;
/**
* @minimum 1
* @maximum 200
*/
limit?: number;
/**
* @minimum 0
*/
offset?: number;
};

View File

@@ -0,0 +1,18 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export type ListGatewaysApiV1GatewaysGetParams = {
/**
* @minimum 1
* @maximum 200
*/
limit?: number;
/**
* @minimum 0
*/
offset?: number;
};

View File

@@ -0,0 +1,19 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export type ListTaskCommentsApiV1AgentBoardsBoardIdTasksTaskIdCommentsGetParams =
{
/**
* @minimum 1
* @maximum 200
*/
limit?: number;
/**
* @minimum 0
*/
offset?: number;
};

View File

@@ -0,0 +1,18 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export type ListTaskCommentsApiV1BoardsBoardIdTasksTaskIdCommentsGetParams = {
/**
* @minimum 1
* @maximum 200
*/
limit?: number;
/**
* @minimum 0
*/
offset?: number;
};

View File

@@ -9,5 +9,13 @@ export type ListTasksApiV1AgentBoardsBoardIdTasksGetParams = {
status?: string | null;
assigned_agent_id?: string | null;
unassigned?: boolean | null;
limit?: number | null;
/**
* @minimum 1
* @maximum 200
*/
limit?: number;
/**
* @minimum 0
*/
offset?: number;
};

View File

@@ -9,5 +9,13 @@ export type ListTasksApiV1BoardsBoardIdTasksGetParams = {
status?: string | null;
assigned_agent_id?: string | null;
unassigned?: boolean | null;
limit?: number | null;
/**
* @minimum 1
* @maximum 200
*/
limit?: number;
/**
* @minimum 0
*/
offset?: number;
};

View File

@@ -7,4 +7,5 @@
export type StreamBoardMemoryApiV1BoardsBoardIdMemoryStreamGetParams = {
since?: string | null;
is_chat?: boolean | null;
};

View File

@@ -0,0 +1,25 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
import type { TaskCardReadStatus } from "./taskCardReadStatus";
export interface TaskCardRead {
title: string;
description?: string | null;
status?: TaskCardReadStatus;
priority?: string;
due_at?: string | null;
assigned_agent_id?: string | null;
id: string;
board_id: string | null;
created_by_user_id: string | null;
in_progress_at: string | null;
created_at: string;
updated_at: string;
assignee?: string | null;
approvals_count?: number;
approvals_pending_count?: number;
}

View File

@@ -0,0 +1,16 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export type TaskCardReadStatus =
(typeof TaskCardReadStatus)[keyof typeof TaskCardReadStatus];
export const TaskCardReadStatus = {
inbox: "inbox",
in_progress: "in_progress",
review: "review",
done: "done",
} as const;

View File

@@ -22,6 +22,9 @@ import type {
import type {
HTTPValidationError,
LimitOffsetPageTypeVarCustomizedTaskCommentRead,
LimitOffsetPageTypeVarCustomizedTaskRead,
ListTaskCommentsApiV1BoardsBoardIdTasksTaskIdCommentsGetParams,
ListTasksApiV1BoardsBoardIdTasksGetParams,
OkResponse,
StreamTasksApiV1BoardsBoardIdTasksStreamGetParams,
@@ -292,7 +295,7 @@ export function useStreamTasksApiV1BoardsBoardIdTasksStreamGet<
* @summary List Tasks
*/
export type listTasksApiV1BoardsBoardIdTasksGetResponse200 = {
data: TaskRead[];
data: LimitOffsetPageTypeVarCustomizedTaskRead;
status: 200;
};
@@ -900,7 +903,7 @@ export const useDeleteTaskApiV1BoardsBoardIdTasksTaskIdDelete = <
*/
export type listTaskCommentsApiV1BoardsBoardIdTasksTaskIdCommentsGetResponse200 =
{
data: TaskCommentRead[];
data: LimitOffsetPageTypeVarCustomizedTaskCommentRead;
status: 200;
};
@@ -926,19 +929,34 @@ export type listTaskCommentsApiV1BoardsBoardIdTasksTaskIdCommentsGetResponse =
export const getListTaskCommentsApiV1BoardsBoardIdTasksTaskIdCommentsGetUrl = (
boardId: string,
taskId: string,
params?: ListTaskCommentsApiV1BoardsBoardIdTasksTaskIdCommentsGetParams,
) => {
return `/api/v1/boards/${boardId}/tasks/${taskId}/comments`;
const normalizedParams = new URLSearchParams();
Object.entries(params || {}).forEach(([key, value]) => {
if (value !== undefined) {
normalizedParams.append(key, value === null ? "null" : value.toString());
}
});
const stringifiedParams = normalizedParams.toString();
return stringifiedParams.length > 0
? `/api/v1/boards/${boardId}/tasks/${taskId}/comments?${stringifiedParams}`
: `/api/v1/boards/${boardId}/tasks/${taskId}/comments`;
};
export const listTaskCommentsApiV1BoardsBoardIdTasksTaskIdCommentsGet = async (
boardId: string,
taskId: string,
params?: ListTaskCommentsApiV1BoardsBoardIdTasksTaskIdCommentsGetParams,
options?: RequestInit,
): Promise<listTaskCommentsApiV1BoardsBoardIdTasksTaskIdCommentsGetResponse> => {
return customFetch<listTaskCommentsApiV1BoardsBoardIdTasksTaskIdCommentsGetResponse>(
getListTaskCommentsApiV1BoardsBoardIdTasksTaskIdCommentsGetUrl(
boardId,
taskId,
params,
),
{
...options,
@@ -948,8 +966,15 @@ export const listTaskCommentsApiV1BoardsBoardIdTasksTaskIdCommentsGet = async (
};
export const getListTaskCommentsApiV1BoardsBoardIdTasksTaskIdCommentsGetQueryKey =
(boardId: string, taskId: string) => {
return [`/api/v1/boards/${boardId}/tasks/${taskId}/comments`] as const;
(
boardId: string,
taskId: string,
params?: ListTaskCommentsApiV1BoardsBoardIdTasksTaskIdCommentsGetParams,
) => {
return [
`/api/v1/boards/${boardId}/tasks/${taskId}/comments`,
...(params ? [params] : []),
] as const;
};
export const getListTaskCommentsApiV1BoardsBoardIdTasksTaskIdCommentsGetQueryOptions =
@@ -963,6 +988,7 @@ export const getListTaskCommentsApiV1BoardsBoardIdTasksTaskIdCommentsGetQueryOpt
>(
boardId: string,
taskId: string,
params?: ListTaskCommentsApiV1BoardsBoardIdTasksTaskIdCommentsGetParams,
options?: {
query?: Partial<
UseQueryOptions<
@@ -985,6 +1011,7 @@ export const getListTaskCommentsApiV1BoardsBoardIdTasksTaskIdCommentsGetQueryOpt
getListTaskCommentsApiV1BoardsBoardIdTasksTaskIdCommentsGetQueryKey(
boardId,
taskId,
params,
);
const queryFn: QueryFunction<
@@ -997,6 +1024,7 @@ export const getListTaskCommentsApiV1BoardsBoardIdTasksTaskIdCommentsGetQueryOpt
listTaskCommentsApiV1BoardsBoardIdTasksTaskIdCommentsGet(
boardId,
taskId,
params,
{ signal, ...requestOptions },
);
@@ -1035,6 +1063,9 @@ export function useListTaskCommentsApiV1BoardsBoardIdTasksTaskIdCommentsGet<
>(
boardId: string,
taskId: string,
params:
| undefined
| ListTaskCommentsApiV1BoardsBoardIdTasksTaskIdCommentsGetParams,
options: {
query: Partial<
UseQueryOptions<
@@ -1077,6 +1108,7 @@ export function useListTaskCommentsApiV1BoardsBoardIdTasksTaskIdCommentsGet<
>(
boardId: string,
taskId: string,
params?: ListTaskCommentsApiV1BoardsBoardIdTasksTaskIdCommentsGetParams,
options?: {
query?: Partial<
UseQueryOptions<
@@ -1119,6 +1151,7 @@ export function useListTaskCommentsApiV1BoardsBoardIdTasksTaskIdCommentsGet<
>(
boardId: string,
taskId: string,
params?: ListTaskCommentsApiV1BoardsBoardIdTasksTaskIdCommentsGetParams,
options?: {
query?: Partial<
UseQueryOptions<
@@ -1149,6 +1182,7 @@ export function useListTaskCommentsApiV1BoardsBoardIdTasksTaskIdCommentsGet<
>(
boardId: string,
taskId: string,
params?: ListTaskCommentsApiV1BoardsBoardIdTasksTaskIdCommentsGetParams,
options?: {
query?: Partial<
UseQueryOptions<
@@ -1171,6 +1205,7 @@ export function useListTaskCommentsApiV1BoardsBoardIdTasksTaskIdCommentsGet<
getListTaskCommentsApiV1BoardsBoardIdTasksTaskIdCommentsGetQueryOptions(
boardId,
taskId,
params,
options,
);

View File

@@ -116,7 +116,7 @@ export default function EditAgentPage() {
const boardsQuery = useListBoardsApiV1BoardsGet<
listBoardsApiV1BoardsGetResponse,
ApiError
>({
>(undefined, {
query: {
enabled: Boolean(isSignedIn),
refetchOnMount: "always",
@@ -148,7 +148,8 @@ export default function EditAgentPage() {
},
});
const boards = boardsQuery.data?.status === 200 ? boardsQuery.data.data : [];
const boards =
boardsQuery.data?.status === 200 ? boardsQuery.data.data.items ?? [] : [];
const loadedAgent: AgentRead | null =
agentQuery.data?.status === 200 ? agentQuery.data.data : null;

View File

@@ -106,7 +106,7 @@ export default function AgentDetailPage() {
const boardsQuery = useListBoardsApiV1BoardsGet<
listBoardsApiV1BoardsGetResponse,
ApiError
>({
>(undefined, {
query: {
enabled: Boolean(isSignedIn),
refetchInterval: 60_000,
@@ -118,9 +118,11 @@ export default function AgentDetailPage() {
const agent: AgentRead | null =
agentQuery.data?.status === 200 ? agentQuery.data.data : null;
const events: ActivityEventRead[] =
activityQuery.data?.status === 200 ? activityQuery.data.data : [];
activityQuery.data?.status === 200
? activityQuery.data.data.items ?? []
: [];
const boards: BoardRead[] =
boardsQuery.data?.status === 200 ? boardsQuery.data.data : [];
boardsQuery.data?.status === 200 ? boardsQuery.data.data.items ?? [] : [];
const agentEvents = useMemo(() => {
if (!agent) return [];

View File

@@ -91,7 +91,7 @@ export default function NewAgentPage() {
const boardsQuery = useListBoardsApiV1BoardsGet<
listBoardsApiV1BoardsGetResponse,
ApiError
>({
>(undefined, {
query: {
enabled: Boolean(isSignedIn),
refetchOnMount: "always",
@@ -111,7 +111,8 @@ export default function NewAgentPage() {
},
});
const boards = boardsQuery.data?.status === 200 ? boardsQuery.data.data : [];
const boards =
boardsQuery.data?.status === 200 ? boardsQuery.data.data.items ?? [] : [];
const displayBoardId = boardId || boards[0]?.id || "";
const isLoading = boardsQuery.isLoading || createAgentMutation.isPending;
const errorMessage = error ?? boardsQuery.error?.message ?? null;

View File

@@ -98,7 +98,7 @@ export default function AgentsPage() {
const boardsQuery = useListBoardsApiV1BoardsGet<
listBoardsApiV1BoardsGetResponse,
ApiError
>({
>(undefined, {
query: {
enabled: Boolean(isSignedIn),
refetchInterval: 30_000,
@@ -109,7 +109,7 @@ export default function AgentsPage() {
const agentsQuery = useListAgentsApiV1AgentsGet<
listAgentsApiV1AgentsGetResponse,
ApiError
>({
>(undefined, {
query: {
enabled: Boolean(isSignedIn),
refetchInterval: 15_000,
@@ -118,10 +118,15 @@ export default function AgentsPage() {
});
const boards = useMemo(
() => (boardsQuery.data?.status === 200 ? boardsQuery.data.data : []),
() =>
boardsQuery.data?.status === 200 ? boardsQuery.data.data.items ?? [] : [],
[boardsQuery.data]
);
const agents = useMemo(() => agentsQuery.data?.data ?? [], [agentsQuery.data]);
const agents = useMemo(
() =>
agentsQuery.data?.status === 200 ? agentsQuery.data.data.items ?? [] : [],
[agentsQuery.data]
);
const deleteMutation = useDeleteAgentApiV1AgentsAgentIdDelete<
ApiError,
@@ -133,10 +138,18 @@ export default function AgentsPage() {
await queryClient.cancelQueries({ queryKey: agentsKey });
const previous =
queryClient.getQueryData<listAgentsApiV1AgentsGetResponse>(agentsKey);
if (previous) {
if (previous && previous.status === 200) {
const nextItems = previous.data.items.filter(
(agent) => agent.id !== agentId
);
const removedCount = previous.data.items.length - nextItems.length;
queryClient.setQueryData<listAgentsApiV1AgentsGetResponse>(agentsKey, {
...previous,
data: previous.data.filter((agent) => agent.id !== agentId),
data: {
...previous.data,
items: nextItems,
total: Math.max(0, previous.data.total - removedCount),
},
});
}
return { previous };

View File

@@ -16,8 +16,6 @@ import {
useListGatewaysApiV1GatewaysGet,
} from "@/api/generated/gateways/gateways";
import type { BoardRead, BoardUpdate } from "@/api/generated/model";
import { BoardApprovalsPanel } from "@/components/BoardApprovalsPanel";
import { BoardGoalPanel } from "@/components/BoardGoalPanel";
import { BoardOnboardingChat } from "@/components/BoardOnboardingChat";
import { DashboardSidebar } from "@/components/organisms/DashboardSidebar";
import { DashboardShell } from "@/components/templates/DashboardShell";
@@ -72,7 +70,7 @@ export default function EditBoardPage() {
const gatewaysQuery = useListGatewaysApiV1GatewaysGet<
listGatewaysApiV1GatewaysGetResponse,
ApiError
>({
>(undefined, {
query: {
enabled: Boolean(isSignedIn),
refetchOnMount: "always",
@@ -105,7 +103,9 @@ export default function EditBoardPage() {
});
const gateways =
gatewaysQuery.data?.status === 200 ? gatewaysQuery.data.data : [];
gatewaysQuery.data?.status === 200
? gatewaysQuery.data.data.items ?? []
: [];
const loadedBoard: BoardRead | null =
boardQuery.data?.status === 200 ? boardQuery.data.data : null;
const baseBoard = board ?? loadedBoard;
@@ -224,135 +224,149 @@ export default function EditBoardPage() {
</div>
<div className="p-8">
<div className="grid gap-6 xl:grid-cols-[minmax(0,1fr)_360px]">
<div className="space-y-6">
<BoardGoalPanel
board={baseBoard}
onStartOnboarding={() => setIsOnboardingOpen(true)}
/>
<form
onSubmit={handleSubmit}
className="space-y-6 rounded-xl border border-slate-200 bg-white p-6 shadow-sm"
>
<div className="grid gap-6 md:grid-cols-2">
<div className="space-y-2">
<label className="text-sm font-medium text-slate-900">
Board name <span className="text-red-500">*</span>
</label>
<Input
value={resolvedName}
onChange={(event) => setName(event.target.value)}
placeholder="Board name"
disabled={isLoading || !baseBoard}
/>
<div className="space-y-6">
<form
onSubmit={handleSubmit}
className="space-y-6 rounded-xl border border-slate-200 bg-white p-6 shadow-sm"
>
{resolvedBoardType !== "general" &&
baseBoard &&
!(baseBoard.goal_confirmed ?? false) ? (
<div className="flex flex-wrap items-center justify-between gap-3 rounded-xl border border-amber-200 bg-amber-50 px-4 py-3">
<div className="min-w-0">
<p className="text-sm font-semibold text-amber-900">
Goal needs confirmation
</p>
<p className="mt-1 text-xs text-amber-800/80">
Start onboarding to draft an objective and success
metrics.
</p>
</div>
<div className="space-y-2">
<label className="text-sm font-medium text-slate-900">
Gateway <span className="text-red-500">*</span>
</label>
<SearchableSelect
ariaLabel="Select gateway"
value={displayGatewayId}
onValueChange={setGatewayId}
options={gatewayOptions}
placeholder="Select gateway"
searchPlaceholder="Search gateways..."
emptyMessage="No gateways 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"
/>
</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 type
</label>
<Select value={resolvedBoardType} onValueChange={setBoardType}>
<SelectTrigger>
<SelectValue placeholder="Select board type" />
</SelectTrigger>
<SelectContent>
<SelectItem value="goal">Goal</SelectItem>
<SelectItem value="general">General</SelectItem>
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<label className="text-sm font-medium text-slate-900">
Target date
</label>
<Input
type="date"
value={resolvedTargetDate}
onChange={(event) => setTargetDate(event.target.value)}
disabled={isLoading}
/>
</div>
</div>
<div className="space-y-2">
<label className="text-sm font-medium text-slate-900">
Objective
</label>
<Textarea
value={resolvedObjective}
onChange={(event) => setObjective(event.target.value)}
placeholder="What should this board achieve?"
className="min-h-[120px]"
disabled={isLoading}
/>
</div>
<div className="space-y-2">
<label className="text-sm font-medium text-slate-900">
Success metrics (JSON)
</label>
<Textarea
value={resolvedSuccessMetrics}
onChange={(event) => setSuccessMetrics(event.target.value)}
placeholder='e.g. { "target": "Launch by week 2" }'
className="min-h-[140px] font-mono text-xs"
disabled={isLoading}
/>
<p className="text-xs text-slate-500">
Add key outcomes so the lead agent can measure progress.
</p>
{metricsError ? (
<p className="text-xs text-red-500">{metricsError}</p>
) : null}
</div>
{gateways.length === 0 ? (
<div className="rounded-lg border border-slate-200 bg-slate-50 px-4 py-3 text-sm text-slate-600">
<p>No gateways available. Create one in Gateways to continue.</p>
</div>
) : null}
{errorMessage ? (
<p className="text-sm text-red-500">{errorMessage}</p>
) : null}
<div className="flex justify-end gap-3">
<Button
type="button"
variant="ghost"
onClick={() => router.push(`/boards/${boardId}`)}
disabled={isLoading}
variant="secondary"
onClick={() => setIsOnboardingOpen(true)}
disabled={isLoading || !baseBoard}
>
Cancel
</Button>
<Button type="submit" disabled={isLoading || !baseBoard || !isFormReady}>
{isLoading ? "Saving…" : "Save changes"}
Start onboarding
</Button>
</div>
</form>
</div>
<div className="space-y-6">
{boardId ? <BoardApprovalsPanel boardId={boardId} /> : null}
</div>
) : null}
<div className="grid gap-6 md:grid-cols-2">
<div className="space-y-2">
<label className="text-sm font-medium text-slate-900">
Board name <span className="text-red-500">*</span>
</label>
<Input
value={resolvedName}
onChange={(event) => setName(event.target.value)}
placeholder="Board name"
disabled={isLoading || !baseBoard}
/>
</div>
<div className="space-y-2">
<label className="text-sm font-medium text-slate-900">
Gateway <span className="text-red-500">*</span>
</label>
<SearchableSelect
ariaLabel="Select gateway"
value={displayGatewayId}
onValueChange={setGatewayId}
options={gatewayOptions}
placeholder="Select gateway"
searchPlaceholder="Search gateways..."
emptyMessage="No gateways 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"
/>
</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 type
</label>
<Select value={resolvedBoardType} onValueChange={setBoardType}>
<SelectTrigger>
<SelectValue placeholder="Select board type" />
</SelectTrigger>
<SelectContent>
<SelectItem value="goal">Goal</SelectItem>
<SelectItem value="general">General</SelectItem>
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<label className="text-sm font-medium text-slate-900">
Target date
</label>
<Input
type="date"
value={resolvedTargetDate}
onChange={(event) => setTargetDate(event.target.value)}
disabled={isLoading}
/>
</div>
</div>
<div className="space-y-2">
<label className="text-sm font-medium text-slate-900">
Objective
</label>
<Textarea
value={resolvedObjective}
onChange={(event) => setObjective(event.target.value)}
placeholder="What should this board achieve?"
className="min-h-[120px]"
disabled={isLoading}
/>
</div>
<div className="space-y-2">
<label className="text-sm font-medium text-slate-900">
Success metrics (JSON)
</label>
<Textarea
value={resolvedSuccessMetrics}
onChange={(event) => setSuccessMetrics(event.target.value)}
placeholder='e.g. { "target": "Launch by week 2" }'
className="min-h-[140px] font-mono text-xs"
disabled={isLoading}
/>
<p className="text-xs text-slate-500">
Add key outcomes so the lead agent can measure progress.
</p>
{metricsError ? (
<p className="text-xs text-red-500">{metricsError}</p>
) : null}
</div>
{gateways.length === 0 ? (
<div className="rounded-lg border border-slate-200 bg-slate-50 px-4 py-3 text-sm text-slate-600">
<p>No gateways available. Create one in Gateways to continue.</p>
</div>
) : null}
{errorMessage ? (
<p className="text-sm text-red-500">{errorMessage}</p>
) : null}
<div className="flex justify-end gap-3">
<Button
type="button"
variant="ghost"
onClick={() => router.push(`/boards/${boardId}`)}
disabled={isLoading}
>
Cancel
</Button>
<Button type="submit" disabled={isLoading || !baseBoard || !isFormReady}>
{isLoading ? "Saving…" : "Save changes"}
</Button>
</div>
</form>
</div>
</div>
</main>

View File

@@ -28,16 +28,14 @@ import {
SelectValue,
} from "@/components/ui/select";
import { Textarea } from "@/components/ui/textarea";
import { listAgentsApiV1AgentsGet, streamAgentsApiV1AgentsStreamGet } from "@/api/generated/agents/agents";
import { streamAgentsApiV1AgentsStreamGet } from "@/api/generated/agents/agents";
import {
listApprovalsApiV1BoardsBoardIdApprovalsGet,
streamApprovalsApiV1BoardsBoardIdApprovalsStreamGet,
updateApprovalApiV1BoardsBoardIdApprovalsApprovalIdPatch,
} from "@/api/generated/approvals/approvals";
import { getBoardApiV1BoardsBoardIdGet } from "@/api/generated/boards/boards";
import { getBoardSnapshotApiV1BoardsBoardIdSnapshotGet } from "@/api/generated/boards/boards";
import {
createBoardMemoryApiV1BoardsBoardIdMemoryPost,
listBoardMemoryApiV1BoardsBoardIdMemoryGet,
streamBoardMemoryApiV1BoardsBoardIdMemoryStreamGet,
} from "@/api/generated/board-memory/board-memory";
import {
@@ -45,7 +43,6 @@ import {
createTaskCommentApiV1BoardsBoardIdTasksTaskIdCommentsPost,
deleteTaskApiV1BoardsBoardIdTasksTaskIdDelete,
listTaskCommentsApiV1BoardsBoardIdTasksTaskIdCommentsGet,
listTasksApiV1BoardsBoardIdTasksGet,
streamTasksApiV1BoardsBoardIdTasksStreamGet,
updateTaskApiV1BoardsBoardIdTasksTaskIdPatch,
} from "@/api/generated/tasks/tasks";
@@ -54,6 +51,7 @@ import type {
ApprovalRead,
BoardMemoryRead,
BoardRead,
TaskCardRead,
TaskCommentRead,
TaskRead,
} from "@/api/generated/model";
@@ -61,13 +59,16 @@ import { cn } from "@/lib/utils";
type Board = BoardRead;
type TaskStatus = Exclude<TaskRead["status"], undefined>;
type TaskStatus = Exclude<TaskCardRead["status"], undefined>;
type Task = TaskRead & {
type Task = Omit<
TaskCardRead,
"status" | "priority" | "approvals_count" | "approvals_pending_count"
> & {
status: TaskStatus;
priority: string;
approvalsCount?: number;
approvalsPendingCount?: number;
approvals_count: number;
approvals_pending_count: number;
};
type Agent = AgentRead & { status: string };
@@ -78,10 +79,12 @@ type Approval = ApprovalRead & { status: string };
type BoardChatMessage = BoardMemoryRead;
const normalizeTask = (task: TaskRead): Task => ({
const normalizeTask = (task: TaskCardRead): Task => ({
...task,
status: task.status ?? "inbox",
priority: task.priority ?? "medium",
approvals_count: task.approvals_count ?? 0,
approvals_pending_count: task.approvals_pending_count ?? 0,
});
const normalizeAgent = (agent: AgentRead): Agent => ({
@@ -94,15 +97,6 @@ const normalizeApproval = (approval: ApprovalRead): Approval => ({
status: approval.status ?? "pending",
});
const approvalTaskId = (approval: Approval) => {
const payload = approval.payload ?? {};
return (
(payload as Record<string, unknown>).task_id ??
(payload as Record<string, unknown>).taskId ??
(payload as Record<string, unknown>).taskID
);
};
const priorities = [
{ value: "low", label: "Low" },
{ value: "medium", label: "Medium" },
@@ -244,31 +238,38 @@ export default function BoardDetailPage() {
const loadBoard = async () => {
if (!isSignedIn || !boardId) return;
setIsLoading(true);
setIsApprovalsLoading(true);
setError(null);
setApprovalsError(null);
setChatError(null);
try {
const [boardResult, tasksResult, agentsResult] = await Promise.all([
getBoardApiV1BoardsBoardIdGet(boardId),
listTasksApiV1BoardsBoardIdTasksGet(boardId),
listAgentsApiV1AgentsGet(),
]);
if (boardResult.status !== 200) throw new Error("Unable to load board.");
if (tasksResult.status !== 200) throw new Error("Unable to load tasks.");
setBoard(boardResult.data);
setTasks(tasksResult.data.map(normalizeTask));
setAgents(agentsResult.data.map(normalizeAgent));
const snapshotResult = await getBoardSnapshotApiV1BoardsBoardIdSnapshotGet(
boardId,
);
if (snapshotResult.status !== 200) {
throw new Error("Unable to load board snapshot.");
}
const snapshot = snapshotResult.data;
setBoard(snapshot.board);
setTasks((snapshot.tasks ?? []).map(normalizeTask));
setAgents((snapshot.agents ?? []).map(normalizeAgent));
setApprovals((snapshot.approvals ?? []).map(normalizeApproval));
setChatMessages(snapshot.chat_messages ?? []);
} catch (err) {
setError(err instanceof Error ? err.message : "Something went wrong.");
const message = err instanceof Error ? err.message : "Something went wrong.";
setError(message);
setApprovalsError(message);
setChatError(message);
} finally {
setIsLoading(false);
setIsApprovalsLoading(false);
}
};
useEffect(() => {
loadBoard();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [boardId, isSignedIn]);
}, [board, boardId, isSignedIn]);
useEffect(() => {
tasksRef.current = tasks;
@@ -294,54 +295,6 @@ export default function BoardDetailPage() {
return () => window.clearTimeout(timeout);
}, [chatMessages, isChatOpen]);
const loadApprovals = useCallback(async () => {
if (!isSignedIn || !boardId) return;
setIsApprovalsLoading(true);
setApprovalsError(null);
try {
const result = await listApprovalsApiV1BoardsBoardIdApprovalsGet(boardId);
if (result.status !== 200) throw new Error("Unable to load approvals.");
setApprovals(result.data.map(normalizeApproval));
} catch (err) {
setApprovalsError(
err instanceof Error ? err.message : "Unable to load approvals.",
);
} finally {
setIsApprovalsLoading(false);
}
}, [boardId, isSignedIn]);
useEffect(() => {
loadApprovals();
}, [boardId, isSignedIn, loadApprovals]);
const loadBoardChat = useCallback(async () => {
if (!isSignedIn || !boardId) return;
setChatError(null);
try {
const result = await listBoardMemoryApiV1BoardsBoardIdMemoryGet(boardId, {
limit: 200,
});
if (result.status !== 200) throw new Error("Unable to load board chat.");
const data = result.data;
const chatOnly = data.filter((item) => item.tags?.includes("chat"));
const ordered = chatOnly.sort((a, b) => {
const aTime = new Date(a.created_at).getTime();
const bTime = new Date(b.created_at).getTime();
return aTime - bTime;
});
setChatMessages(ordered);
} catch (err) {
setChatError(
err instanceof Error ? err.message : "Unable to load board chat.",
);
}
}, [boardId, isSignedIn]);
useEffect(() => {
loadBoardChat();
}, [boardId, isSignedIn, loadBoardChat]);
const latestChatTimestamp = (items: BoardChatMessage[]) => {
if (!items.length) return undefined;
const latest = items.reduce((max, item) => {
@@ -353,17 +306,18 @@ export default function BoardDetailPage() {
};
useEffect(() => {
if (!isSignedIn || !boardId) return;
if (!isSignedIn || !boardId || !board) return;
let isCancelled = false;
const abortController = new AbortController();
const connect = async () => {
try {
const since = latestChatTimestamp(chatMessagesRef.current);
const params = { is_chat: true, ...(since ? { since } : {}) };
const streamResult =
await streamBoardMemoryApiV1BoardsBoardIdMemoryStreamGet(
boardId,
since ? { since } : undefined,
params,
{
headers: { Accept: "text/event-stream" },
signal: abortController.signal,
@@ -439,7 +393,7 @@ export default function BoardDetailPage() {
}, [boardId, isSignedIn]);
useEffect(() => {
if (!isSignedIn || !boardId) return;
if (!isSignedIn || !boardId || !board) return;
let isCancelled = false;
const abortController = new AbortController();
@@ -487,7 +441,15 @@ export default function BoardDetailPage() {
}
if (eventType === "approval" && data) {
try {
const payload = JSON.parse(data) as { approval?: ApprovalRead };
const payload = JSON.parse(data) as {
approval?: ApprovalRead;
task_counts?: {
task_id?: string;
approvals_count?: number;
approvals_pending_count?: number;
};
pending_approvals_count?: number;
};
if (payload.approval) {
const normalized = normalizeApproval(payload.approval);
setApprovals((prev) => {
@@ -505,6 +467,25 @@ export default function BoardDetailPage() {
return next;
});
}
if (payload.task_counts?.task_id) {
const taskId = payload.task_counts.task_id;
setTasks((prev) => {
const index = prev.findIndex((task) => task.id === taskId);
if (index === -1) return prev;
const next = [...prev];
const current = next[index];
next[index] = {
...current,
approvals_count:
payload.task_counts?.approvals_count ??
current.approvals_count,
approvals_pending_count:
payload.task_counts?.approvals_pending_count ??
current.approvals_pending_count,
};
return next;
});
}
} catch {
// Ignore malformed payloads.
}
@@ -524,7 +505,7 @@ export default function BoardDetailPage() {
isCancelled = true;
abortController.abort();
};
}, [boardId, isSignedIn]);
}, [board, boardId, isSignedIn]);
useEffect(() => {
if (!selectedTask) {
@@ -610,14 +591,37 @@ export default function BoardDetailPage() {
return [...prev, payload.comment as TaskComment];
});
} else if (payload.task) {
const normalizedTask = normalizeTask(payload.task);
setTasks((prev) => {
const index = prev.findIndex((item) => item.id === normalizedTask.id);
const index = prev.findIndex((item) => item.id === payload.task?.id);
if (index === -1) {
return [normalizedTask, ...prev];
const assignee = payload.task?.assigned_agent_id
? agentsRef.current.find(
(agent) => agent.id === payload.task?.assigned_agent_id,
)?.name ?? null
: null;
const created = normalizeTask({
...payload.task,
assignee,
approvals_count: 0,
approvals_pending_count: 0,
} as TaskCardRead);
return [created, ...prev];
}
const next = [...prev];
next[index] = { ...next[index], ...normalizedTask };
const existing = next[index];
const assignee = payload.task?.assigned_agent_id
? agentsRef.current.find(
(agent) => agent.id === payload.task?.assigned_agent_id,
)?.name ?? null
: null;
const updated = normalizeTask({
...existing,
...payload.task,
assignee,
approvals_count: existing.approvals_count,
approvals_pending_count: existing.approvals_pending_count,
} as TaskCardRead);
next[index] = { ...existing, ...updated };
return next;
});
}
@@ -727,7 +731,7 @@ export default function BoardDetailPage() {
isCancelled = true;
abortController.abort();
};
}, [boardId, isSignedIn]);
}, [board, boardId, isSignedIn]);
const resetForm = () => {
setTitle("");
@@ -754,7 +758,14 @@ export default function BoardDetailPage() {
});
if (result.status !== 200) throw new Error("Unable to create task.");
const created = normalizeTask(result.data);
const created = normalizeTask({
...result.data,
assignee: result.data.assigned_agent_id
? assigneeById.get(result.data.assigned_agent_id) ?? null
: null,
approvals_count: 0,
approvals_pending_count: 0,
} as TaskCardRead);
setTasks((prev) => [created, ...prev]);
setIsDialogOpen(false);
resetForm();
@@ -829,49 +840,9 @@ export default function BoardDetailPage() {
});
}, [liveFeed]);
const pendingApprovalsByTaskId = useMemo(() => {
const map = new Map<string, number>();
approvals
.filter((approval) => approval.status === "pending")
.forEach((approval) => {
const taskId = approvalTaskId(approval);
if (!taskId || typeof taskId !== "string") return;
map.set(taskId, (map.get(taskId) ?? 0) + 1);
});
return map;
}, [approvals]);
const totalApprovalsByTaskId = useMemo(() => {
const map = new Map<string, number>();
approvals.forEach((approval) => {
const taskId = approvalTaskId(approval);
if (!taskId || typeof taskId !== "string") return;
map.set(taskId, (map.get(taskId) ?? 0) + 1);
});
return map;
}, [approvals]);
const displayTasks = useMemo(
() =>
tasks.map((task) => ({
...task,
assignee: task.assigned_agent_id
? assigneeById.get(task.assigned_agent_id)
: undefined,
approvalsCount: totalApprovalsByTaskId.get(task.id) ?? 0,
approvalsPendingCount: pendingApprovalsByTaskId.get(task.id) ?? 0,
})),
[tasks, assigneeById, pendingApprovalsByTaskId, totalApprovalsByTaskId],
);
const boardAgents = useMemo(
() => agents.filter((agent) => !boardId || agent.board_id === boardId),
[agents, boardId],
);
const assignableAgents = useMemo(
() => boardAgents.filter((agent) => !agent.is_board_lead),
[boardAgents],
() => agents.filter((agent) => !agent.is_board_lead),
[agents],
);
const hasTaskChanges = useMemo(() => {
@@ -912,10 +883,7 @@ export default function BoardDetailPage() {
const taskApprovals = useMemo(() => {
if (!selectedTask) return [];
const taskId = selectedTask.id;
return approvals.filter((approval) => {
const payloadTaskId = approvalTaskId(approval);
return payloadTaskId === taskId;
});
return approvals.filter((approval) => approval.task_id === taskId);
}, [approvals, selectedTask]);
const workingAgentIds = useMemo(() => {
@@ -935,12 +903,12 @@ export default function BoardDetailPage() {
if (agent.status === "provisioning") return 2;
return 3;
};
return [...boardAgents].sort((a, b) => {
return [...agents].sort((a, b) => {
const diff = rank(a) - rank(b);
if (diff !== 0) return diff;
return a.name.localeCompare(b.name);
});
}, [boardAgents, workingAgentIds]);
}, [agents, workingAgentIds]);
const loadComments = async (taskId: string) => {
if (!isSignedIn || !boardId) return;
@@ -953,7 +921,7 @@ export default function BoardDetailPage() {
taskId,
);
if (result.status !== 200) throw new Error("Unable to load comments.");
setComments(result.data);
setComments(result.data.items ?? []);
} catch (err) {
setCommentsError(err instanceof Error ? err.message : "Something went wrong.");
} finally {
@@ -1059,9 +1027,20 @@ export default function BoardDetailPage() {
},
);
if (result.status !== 200) throw new Error("Unable to update task.");
const updated = normalizeTask(result.data);
const previous =
tasksRef.current.find((task) => task.id === selectedTask.id) ??
selectedTask;
const updated = normalizeTask({
...previous,
...result.data,
assignee: result.data.assigned_agent_id
? assigneeById.get(result.data.assigned_agent_id) ?? null
: null,
approvals_count: previous.approvals_count,
approvals_pending_count: previous.approvals_pending_count,
} as TaskCardRead);
setTasks((prev) =>
prev.map((task) => (task.id === updated.id ? updated : task)),
prev.map((task) => (task.id === updated.id ? { ...task, ...updated } : task)),
);
setSelectedTask(updated);
if (closeOnSuccess) {
@@ -1119,6 +1098,7 @@ export default function BoardDetailPage() {
status,
assigned_agent_id:
status === "inbox" ? null : task.assigned_agent_id,
assignee: status === "inbox" ? null : task.assignee,
}
: task,
),
@@ -1130,9 +1110,17 @@ export default function BoardDetailPage() {
{ status },
);
if (result.status !== 200) throw new Error("Unable to move task.");
const updated = normalizeTask(result.data);
const updated = normalizeTask({
...currentTask,
...result.data,
assignee: result.data.assigned_agent_id
? assigneeById.get(result.data.assigned_agent_id) ?? null
: null,
approvals_count: currentTask.approvals_count,
approvals_pending_count: currentTask.approvals_pending_count,
} as TaskCardRead);
setTasks((prev) =>
prev.map((task) => (task.id === updated.id ? updated : task)),
prev.map((task) => (task.id === updated.id ? { ...task, ...updated } : task)),
);
} catch (err) {
setTasks(previousTasks);
@@ -1262,6 +1250,7 @@ export default function BoardDetailPage() {
const approvalRows = (approval: Approval) => {
const payload = approval.payload ?? {};
const taskId =
approval.task_id ??
approvalPayloadValue(payload, "task_id") ??
approvalPayloadValue(payload, "taskId") ??
approvalPayloadValue(payload, "taskID");
@@ -1499,7 +1488,7 @@ export default function BoardDetailPage() {
<>
{viewMode === "board" ? (
<TaskBoard
tasks={displayTasks}
tasks={tasks}
onTaskSelect={openComments}
onTaskMove={handleTaskMove}
/>
@@ -1512,7 +1501,7 @@ export default function BoardDetailPage() {
All tasks
</p>
<p className="text-xs text-slate-500">
{displayTasks.length} tasks in this board
{tasks.length} tasks in this board
</p>
</div>
<Button
@@ -1526,12 +1515,12 @@ export default function BoardDetailPage() {
</div>
</div>
<div className="divide-y divide-slate-100">
{displayTasks.length === 0 ? (
{tasks.length === 0 ? (
<div className="px-5 py-8 text-sm text-slate-500">
No tasks yet. Create your first task to get started.
</div>
) : (
displayTasks.map((task) => (
tasks.map((task) => (
<button
key={task.id}
type="button"
@@ -1553,10 +1542,10 @@ export default function BoardDetailPage() {
</p>
</div>
<div className="flex flex-wrap items-center gap-3 text-xs text-slate-500">
{task.approvalsPendingCount ? (
{task.approvals_pending_count ? (
<span className="inline-flex items-center gap-2 text-[10px] font-semibold uppercase tracking-wide text-amber-700">
<span className="h-1.5 w-1.5 rounded-full bg-amber-500" />
Approval needed · {task.approvalsPendingCount}
Approval needed · {task.approvals_pending_count}
</span>
) : null}
<span

View File

@@ -37,7 +37,7 @@ export default function NewBoardPage() {
const gatewaysQuery = useListGatewaysApiV1GatewaysGet<
listGatewaysApiV1GatewaysGetResponse,
ApiError
>({
>(undefined, {
query: {
enabled: Boolean(isSignedIn),
refetchOnMount: "always",
@@ -59,7 +59,9 @@ export default function NewBoardPage() {
});
const gateways =
gatewaysQuery.data?.status === 200 ? gatewaysQuery.data.data : [];
gatewaysQuery.data?.status === 200
? gatewaysQuery.data.data.items ?? []
: [];
const displayGatewayId = gatewayId || gateways[0]?.id || "";
const isLoading = gatewaysQuery.isLoading || createBoardMutation.isPending;
const errorMessage = error ?? gatewaysQuery.error?.message ?? null;

View File

@@ -53,7 +53,7 @@ export default function BoardsPage() {
const boardsQuery = useListBoardsApiV1BoardsGet<
listBoardsApiV1BoardsGetResponse,
ApiError
>({
>(undefined, {
query: {
enabled: Boolean(isSignedIn),
refetchInterval: 30_000,
@@ -62,15 +62,11 @@ export default function BoardsPage() {
});
const boards = useMemo(
() => (boardsQuery.data?.status === 200 ? boardsQuery.data.data : []),
() =>
boardsQuery.data?.status === 200 ? boardsQuery.data.data.items ?? [] : [],
[boardsQuery.data]
);
const sortedBoards = useMemo(
() => [...boards].sort((a, b) => a.name.localeCompare(b.name)),
[boards]
);
const deleteMutation = useDeleteBoardApiV1BoardsBoardIdDelete<
ApiError,
{ previous?: listBoardsApiV1BoardsGetResponse }
@@ -82,9 +78,17 @@ export default function BoardsPage() {
const previous =
queryClient.getQueryData<listBoardsApiV1BoardsGetResponse>(boardsKey);
if (previous && previous.status === 200) {
const nextItems = previous.data.items.filter(
(board) => board.id !== boardId
);
const removedCount = previous.data.items.length - nextItems.length;
queryClient.setQueryData<listBoardsApiV1BoardsGetResponse>(boardsKey, {
...previous,
data: previous.data.filter((board) => board.id !== boardId),
data: {
...previous.data,
items: nextItems,
total: Math.max(0, previous.data.total - removedCount),
},
});
}
return { previous };
@@ -159,7 +163,7 @@ export default function BoardsPage() {
// eslint-disable-next-line react-hooks/incompatible-library
const table = useReactTable({
data: sortedBoards,
data: boards,
columns,
getCoreRowModel: getCoreRowModel(),
});
@@ -191,11 +195,11 @@ export default function BoardsPage() {
Boards
</h1>
<p className="mt-1 text-sm text-slate-500">
Manage boards and task workflows. {sortedBoards.length} board
{sortedBoards.length === 1 ? "" : "s"} total.
Manage boards and task workflows. {boards.length} board
{boards.length === 1 ? "" : "s"} total.
</p>
</div>
{sortedBoards.length > 0 ? (
{boards.length > 0 ? (
<Link
href="/boards/new"
className={buttonVariants({ size: "md", variant: "primary" })}

View File

@@ -16,11 +16,6 @@ import {
type listAgentsApiV1AgentsGetResponse,
useListAgentsApiV1AgentsGet,
} from "@/api/generated/agents/agents";
import {
type listBoardsApiV1BoardsGetResponse,
useListBoardsApiV1BoardsGet,
} from "@/api/generated/boards/boards";
import type { AgentRead } from "@/api/generated/model";
import { DashboardSidebar } from "@/components/organisms/DashboardSidebar";
import { DashboardShell } from "@/components/templates/DashboardShell";
import { Button } from "@/components/ui/button";
@@ -65,22 +60,12 @@ export default function GatewayDetailPage() {
const gateway =
gatewayQuery.data?.status === 200 ? gatewayQuery.data.data : null;
const boardsQuery = useListBoardsApiV1BoardsGet<
listBoardsApiV1BoardsGetResponse,
ApiError
>({
query: {
enabled: Boolean(isSignedIn),
refetchInterval: 30_000,
},
});
const agentsQuery = useListAgentsApiV1AgentsGet<
listAgentsApiV1AgentsGetResponse,
ApiError
>({
>(gatewayId ? { gateway_id: gatewayId } : undefined, {
query: {
enabled: Boolean(isSignedIn),
enabled: Boolean(isSignedIn && gatewayId),
refetchInterval: 15_000,
},
});
@@ -103,22 +88,11 @@ export default function GatewayDetailPage() {
},
});
const agents = useMemo(() => {
const allAgents = agentsQuery.data?.data ?? [];
const boards = boardsQuery.data?.status === 200 ? boardsQuery.data.data : [];
if (!gatewayId) {
return allAgents;
}
const boardIds = new Set(
boards.filter((board) => board.gateway_id === gatewayId).map((board) => board.id),
);
if (boardIds.size === 0) {
return [];
}
return allAgents.filter(
(agent): agent is AgentRead => Boolean(agent.board_id && boardIds.has(agent.board_id)),
);
}, [agentsQuery.data, boardsQuery.data, gatewayId]);
const agents = useMemo(
() =>
agentsQuery.data?.status === 200 ? agentsQuery.data.data.items ?? [] : [],
[agentsQuery.data],
);
const status =
statusQuery.data?.status === 200 ? statusQuery.data.data : null;

View File

@@ -65,7 +65,7 @@ export default function GatewaysPage() {
const gatewaysQuery = useListGatewaysApiV1GatewaysGet<
listGatewaysApiV1GatewaysGetResponse,
ApiError
>({
>(undefined, {
query: {
enabled: Boolean(isSignedIn),
refetchInterval: 30_000,
@@ -73,7 +73,13 @@ export default function GatewaysPage() {
},
});
const gateways = useMemo(() => gatewaysQuery.data?.data ?? [], [gatewaysQuery.data]);
const gateways = useMemo(
() =>
gatewaysQuery.data?.status === 200
? gatewaysQuery.data.data.items ?? []
: [],
[gatewaysQuery.data]
);
const sortedGateways = useMemo(() => [...gateways], [gateways]);
const deleteMutation = useDeleteGatewayApiV1GatewaysGatewayIdDelete<
@@ -86,10 +92,18 @@ export default function GatewaysPage() {
await queryClient.cancelQueries({ queryKey: gatewaysKey });
const previous =
queryClient.getQueryData<listGatewaysApiV1GatewaysGetResponse>(gatewaysKey);
if (previous) {
if (previous && previous.status === 200) {
const nextItems = previous.data.items.filter(
(gateway) => gateway.id !== gatewayId
);
const removedCount = previous.data.items.length - nextItems.length;
queryClient.setQueryData<listGatewaysApiV1GatewaysGetResponse>(gatewaysKey, {
...previous,
data: previous.data.filter((gateway) => gateway.id !== gatewayId),
data: {
...previous.data,
items: nextItems,
total: Math.max(0, previous.data.total - removedCount),
},
});
}
return { previous };

View File

@@ -161,6 +161,7 @@ const payloadValue = (payload: Approval["payload"], key: string) => {
const approvalSummary = (approval: Approval) => {
const payload = approval.payload ?? {};
const taskId =
approval.task_id ??
payloadValue(payload, "task_id") ??
payloadValue(payload, "taskId") ??
payloadValue(payload, "taskID");
@@ -223,7 +224,7 @@ export function BoardApprovalsPanel({
const raw = usingExternal
? externalApprovals ?? []
: approvalsQuery.data?.status === 200
? approvalsQuery.data.data
? approvalsQuery.data.data.items ?? []
: [];
return raw.map(normalizeApproval);
}, [approvalsQuery.data, externalApprovals, usingExternal]);
@@ -266,9 +267,12 @@ export function BoardApprovalsPanel({
if (!previous || previous.status !== 200) return previous;
return {
...previous,
data: previous.data.map((item) =>
item.id === approvalId ? result.data : item,
),
data: {
...previous.data,
items: previous.data.items.map((item) =>
item.id === approvalId ? result.data : item,
),
},
};
},
);

View File

@@ -15,8 +15,8 @@ type Task = {
description?: string | null;
due_at?: string | null;
assigned_agent_id?: string | null;
assignee?: string;
approvalsPendingCount?: number;
assignee?: string | null;
approvals_pending_count?: number;
};
type TaskBoardProps = {
@@ -187,9 +187,9 @@ export function TaskBoard({
key={task.id}
title={task.title}
priority={task.priority}
assignee={task.assignee}
assignee={task.assignee ?? undefined}
due={formatDueDate(task.due_at)}
approvalsPendingCount={task.approvalsPendingCount}
approvalsPendingCount={task.approvals_pending_count}
onClick={() => onTaskSelect?.(task)}
draggable
isDragging={draggingId === task.id}