feat: add custom-fields

This commit is contained in:
Abhimanyu Saharan
2026-02-13 21:24:36 +05:30
parent b032e94ca1
commit 277bfcb33a
127 changed files with 11305 additions and 6643 deletions

View File

@@ -287,13 +287,16 @@ async def create_task(
"""Create a task as the board lead.
Lead-only endpoint. Supports dependency-aware creation via
`depends_on_task_ids` and optional `tag_ids`.
`depends_on_task_ids`, optional `tag_ids`, and `custom_field_values`.
"""
_guard_board_access(agent_ctx, board)
_require_board_lead(agent_ctx)
data = payload.model_dump(exclude={"depends_on_task_ids", "tag_ids"})
data = payload.model_dump(
exclude={"depends_on_task_ids", "tag_ids", "custom_field_values"},
)
depends_on_task_ids = list(payload.depends_on_task_ids)
tag_ids = list(payload.tag_ids)
custom_field_values = dict(payload.custom_field_values)
task = Task.model_validate(data)
task.board_id = board.id
@@ -343,6 +346,12 @@ async def create_task(
session.add(task)
# Ensure the task exists in the DB before inserting dependency rows.
await session.flush()
await tasks_api._set_task_custom_field_values_for_create(
session,
board_id=board.id,
task_id=task.id,
custom_field_values=custom_field_values,
)
for dep_id in normalized_deps:
session.add(
TaskDependency(

View File

@@ -0,0 +1,343 @@
"""Organization-level task custom field definition management."""
from __future__ import annotations
from typing import TYPE_CHECKING
from uuid import UUID
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy import func
from sqlalchemy.exc import IntegrityError
from sqlmodel import col, select
from app.api.deps import require_org_admin, require_org_member
from app.core.time import utcnow
from app.db.session import get_session
from app.models.boards import Board
from app.models.task_custom_fields import (
BoardTaskCustomField,
TaskCustomFieldDefinition,
TaskCustomFieldValue,
)
from app.schemas.common import OkResponse
from app.schemas.task_custom_fields import (
TaskCustomFieldDefinitionCreate,
TaskCustomFieldDefinitionRead,
TaskCustomFieldDefinitionUpdate,
validate_custom_field_definition,
)
from app.services.organizations import OrganizationContext
if TYPE_CHECKING:
from sqlmodel.ext.asyncio.session import AsyncSession
router = APIRouter(prefix="/organizations/me/custom-fields", tags=["org-custom-fields"])
SESSION_DEP = Depends(get_session)
ORG_MEMBER_DEP = Depends(require_org_member)
ORG_ADMIN_DEP = Depends(require_org_admin)
def _to_definition_read_payload(
*,
definition: TaskCustomFieldDefinition,
board_ids: list[UUID],
) -> TaskCustomFieldDefinitionRead:
payload = TaskCustomFieldDefinitionRead.model_validate(definition, from_attributes=True)
payload.board_ids = board_ids
return payload
async def _board_ids_by_definition_id(
*,
session: AsyncSession,
definition_ids: list[UUID],
) -> dict[UUID, list[UUID]]:
if not definition_ids:
return {}
rows = (
await session.exec(
select(
col(BoardTaskCustomField.task_custom_field_definition_id),
col(BoardTaskCustomField.board_id),
).where(
col(BoardTaskCustomField.task_custom_field_definition_id).in_(definition_ids),
),
)
).all()
board_ids_by_definition_id: dict[UUID, list[UUID]] = {
definition_id: [] for definition_id in definition_ids
}
for definition_id, board_id in rows:
board_ids_by_definition_id.setdefault(definition_id, []).append(board_id)
for definition_id in board_ids_by_definition_id:
board_ids_by_definition_id[definition_id].sort(key=str)
return board_ids_by_definition_id
async def _validated_board_ids_for_org(
*,
session: AsyncSession,
ctx: OrganizationContext,
board_ids: list[UUID],
) -> list[UUID]:
normalized_board_ids = list(dict.fromkeys(board_ids))
if not normalized_board_ids:
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail="At least one board must be selected.",
)
valid_board_ids = set(
(
await session.exec(
select(col(Board.id)).where(
col(Board.organization_id) == ctx.organization.id,
col(Board.id).in_(normalized_board_ids),
),
)
).all(),
)
missing_board_ids = sorted(
{board_id for board_id in normalized_board_ids if board_id not in valid_board_ids},
key=str,
)
if missing_board_ids:
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail={
"message": "Some selected boards are invalid for this organization.",
"invalid_board_ids": [str(value) for value in missing_board_ids],
},
)
return normalized_board_ids
async def _get_org_definition(
*,
session: AsyncSession,
ctx: OrganizationContext,
definition_id: UUID,
) -> TaskCustomFieldDefinition:
definition = (
await session.exec(
select(TaskCustomFieldDefinition).where(
col(TaskCustomFieldDefinition.id) == definition_id,
col(TaskCustomFieldDefinition.organization_id) == ctx.organization.id,
),
)
).first()
if definition is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)
return definition
@router.get("", response_model=list[TaskCustomFieldDefinitionRead])
async def list_org_custom_fields(
ctx: OrganizationContext = ORG_MEMBER_DEP,
session: AsyncSession = SESSION_DEP,
) -> list[TaskCustomFieldDefinitionRead]:
"""List task custom field definitions for the authenticated organization."""
definitions = list(
await session.exec(
select(TaskCustomFieldDefinition)
.where(col(TaskCustomFieldDefinition.organization_id) == ctx.organization.id)
.order_by(func.lower(col(TaskCustomFieldDefinition.label)).asc()),
),
)
board_ids_by_definition_id = await _board_ids_by_definition_id(
session=session,
definition_ids=[definition.id for definition in definitions],
)
return [
_to_definition_read_payload(
definition=definition,
board_ids=board_ids_by_definition_id.get(definition.id, []),
)
for definition in definitions
]
@router.post("", response_model=TaskCustomFieldDefinitionRead)
async def create_org_custom_field(
payload: TaskCustomFieldDefinitionCreate,
ctx: OrganizationContext = ORG_ADMIN_DEP,
session: AsyncSession = SESSION_DEP,
) -> TaskCustomFieldDefinitionRead:
"""Create an organization-level task custom field definition."""
board_ids = await _validated_board_ids_for_org(
session=session,
ctx=ctx,
board_ids=payload.board_ids,
)
try:
validate_custom_field_definition(
field_type=payload.field_type,
validation_regex=payload.validation_regex,
default_value=payload.default_value,
)
except ValueError as err:
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail=str(err),
) from err
definition = TaskCustomFieldDefinition(
organization_id=ctx.organization.id,
field_key=payload.field_key,
label=payload.label or payload.field_key,
field_type=payload.field_type,
ui_visibility=payload.ui_visibility,
validation_regex=payload.validation_regex,
description=payload.description,
required=payload.required,
default_value=payload.default_value,
)
session.add(definition)
await session.flush()
for board_id in board_ids:
session.add(
BoardTaskCustomField(
board_id=board_id,
task_custom_field_definition_id=definition.id,
),
)
try:
await session.commit()
except IntegrityError as err:
await session.rollback()
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail="Field key already exists in this organization.",
) from err
await session.refresh(definition)
return _to_definition_read_payload(definition=definition, board_ids=board_ids)
@router.patch("/{task_custom_field_definition_id}", response_model=TaskCustomFieldDefinitionRead)
async def update_org_custom_field(
task_custom_field_definition_id: UUID,
payload: TaskCustomFieldDefinitionUpdate,
ctx: OrganizationContext = ORG_ADMIN_DEP,
session: AsyncSession = SESSION_DEP,
) -> TaskCustomFieldDefinitionRead:
"""Update an organization-level task custom field definition."""
definition = await _get_org_definition(
session=session,
ctx=ctx,
definition_id=task_custom_field_definition_id,
)
updates = payload.model_dump(exclude_unset=True)
board_ids = updates.pop("board_ids", None)
validated_board_ids: list[UUID] | None = None
if board_ids is not None:
validated_board_ids = await _validated_board_ids_for_org(
session=session,
ctx=ctx,
board_ids=board_ids,
)
next_field_type = updates.get("field_type", definition.field_type)
next_validation_regex = (
updates["validation_regex"]
if "validation_regex" in updates
else definition.validation_regex
)
next_default_value = (
updates["default_value"] if "default_value" in updates else definition.default_value
)
try:
validate_custom_field_definition(
field_type=next_field_type,
validation_regex=next_validation_regex,
default_value=next_default_value,
)
except ValueError as err:
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail=str(err),
) from err
for key, value in updates.items():
setattr(definition, key, value)
if validated_board_ids is not None:
bindings = list(
await session.exec(
select(BoardTaskCustomField).where(
col(BoardTaskCustomField.task_custom_field_definition_id) == definition.id,
),
),
)
current_board_ids = {binding.board_id for binding in bindings}
target_board_ids = set(validated_board_ids)
for binding in bindings:
if binding.board_id not in target_board_ids:
await session.delete(binding)
for board_id in validated_board_ids:
if board_id in current_board_ids:
continue
session.add(
BoardTaskCustomField(
board_id=board_id,
task_custom_field_definition_id=definition.id,
),
)
definition.updated_at = utcnow()
session.add(definition)
try:
await session.commit()
except IntegrityError as err:
await session.rollback()
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail="Field key already exists in this organization.",
) from err
await session.refresh(definition)
if validated_board_ids is None:
board_ids = (
await _board_ids_by_definition_id(
session=session,
definition_ids=[definition.id],
)
).get(definition.id, [])
else:
board_ids = validated_board_ids
return _to_definition_read_payload(definition=definition, board_ids=board_ids)
@router.delete("/{task_custom_field_definition_id}", response_model=OkResponse)
async def delete_org_custom_field(
task_custom_field_definition_id: UUID,
ctx: OrganizationContext = ORG_ADMIN_DEP,
session: AsyncSession = SESSION_DEP,
) -> OkResponse:
"""Delete an org-level definition when it has no persisted task values."""
definition = await _get_org_definition(
session=session,
ctx=ctx,
definition_id=task_custom_field_definition_id,
)
value_ids = (
await session.exec(
select(col(TaskCustomFieldValue.id)).where(
col(TaskCustomFieldValue.task_custom_field_definition_id) == definition.id,
),
)
).all()
if value_ids:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail="Cannot delete a custom field definition while task values exist.",
)
bindings = list(
await session.exec(
select(BoardTaskCustomField).where(
col(BoardTaskCustomField.task_custom_field_definition_id) == definition.id,
),
),
)
for binding in bindings:
await session.delete(binding)
await session.delete(definition)
await session.commit()
return OkResponse()

View File

@@ -7,7 +7,7 @@ import json
from collections import deque
from dataclasses import dataclass
from datetime import UTC, datetime
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, cast
from uuid import UUID
from fastapi import APIRouter, Depends, HTTPException, Query, Request, status
@@ -33,6 +33,11 @@ from app.models.approval_task_links import ApprovalTaskLink
from app.models.approvals import Approval
from app.models.boards import Board
from app.models.tag_assignments import TagAssignment
from app.models.task_custom_fields import (
BoardTaskCustomField,
TaskCustomFieldDefinition,
TaskCustomFieldValue,
)
from app.models.task_dependencies import TaskDependency
from app.models.task_fingerprints import TaskFingerprint
from app.models.tasks import Task
@@ -40,6 +45,11 @@ from app.schemas.activity_events import ActivityEventRead
from app.schemas.common import OkResponse
from app.schemas.errors import BlockedTaskError
from app.schemas.pagination import DefaultLimitOffsetPage
from app.schemas.task_custom_fields import (
TaskCustomFieldType,
TaskCustomFieldValues,
validate_custom_field_value,
)
from app.schemas.tasks import TaskCommentCreate, TaskCommentRead, TaskCreate, TaskRead, TaskUpdate
from app.services.activity_log import record_activity
from app.services.approval_task_links import (
@@ -99,6 +109,16 @@ ADMIN_AUTH_DEP = Depends(require_admin_auth)
TASK_DEP = Depends(get_task_or_404)
@dataclass(frozen=True, slots=True)
class _BoardCustomFieldDefinition:
id: UUID
field_key: str
field_type: TaskCustomFieldType
validation_regex: str | None
required: bool
default_value: object | None
def _comment_validation_error() -> HTTPException:
return HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
@@ -697,6 +717,281 @@ def _status_values(status_filter: str | None) -> list[str]:
return values
async def _organization_custom_field_definitions_for_board(
session: AsyncSession,
*,
board_id: UUID,
) -> dict[str, _BoardCustomFieldDefinition]:
organization_id = (
await session.exec(
select(Board.organization_id).where(col(Board.id) == board_id),
)
).first()
if organization_id is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)
definitions = list(
await session.exec(
select(TaskCustomFieldDefinition)
.join(
BoardTaskCustomField,
col(BoardTaskCustomField.task_custom_field_definition_id)
== col(TaskCustomFieldDefinition.id),
)
.where(
col(BoardTaskCustomField.board_id) == board_id,
col(TaskCustomFieldDefinition.organization_id) == organization_id,
),
),
)
return {
definition.field_key: _BoardCustomFieldDefinition(
id=definition.id,
field_key=definition.field_key,
field_type=cast(TaskCustomFieldType, definition.field_type),
validation_regex=definition.validation_regex,
required=definition.required,
default_value=definition.default_value,
)
for definition in definitions
}
def _reject_unknown_custom_field_keys(
*,
custom_field_values: TaskCustomFieldValues,
definitions_by_key: dict[str, _BoardCustomFieldDefinition],
) -> None:
unknown_field_keys = sorted(set(custom_field_values) - set(definitions_by_key))
if not unknown_field_keys:
return
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail={
"message": "Unknown custom field keys for this board.",
"unknown_field_keys": unknown_field_keys,
},
)
def _reject_missing_required_custom_field_keys(
*,
effective_values: TaskCustomFieldValues,
definitions_by_key: dict[str, _BoardCustomFieldDefinition],
) -> None:
missing_field_keys = [
definition.field_key
for definition in definitions_by_key.values()
if definition.required and effective_values.get(definition.field_key) is None
]
if not missing_field_keys:
return
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail={
"message": "Required custom fields must have values.",
"missing_field_keys": sorted(missing_field_keys),
},
)
def _reject_invalid_custom_field_values(
*,
custom_field_values: TaskCustomFieldValues,
definitions_by_key: dict[str, _BoardCustomFieldDefinition],
) -> None:
for field_key, value in custom_field_values.items():
definition = definitions_by_key[field_key]
try:
validate_custom_field_value(
field_type=definition.field_type,
value=value,
validation_regex=definition.validation_regex,
)
except ValueError as err:
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail={
"message": "Invalid custom field value.",
"field_key": field_key,
"field_type": definition.field_type,
"reason": str(err),
},
) from err
async def _task_custom_field_rows_by_definition_id(
session: AsyncSession,
*,
task_id: UUID,
definition_ids: list[UUID],
) -> dict[UUID, TaskCustomFieldValue]:
if not definition_ids:
return {}
rows = list(
await session.exec(
select(TaskCustomFieldValue).where(
col(TaskCustomFieldValue.task_id) == task_id,
col(TaskCustomFieldValue.task_custom_field_definition_id).in_(definition_ids),
),
),
)
return {row.task_custom_field_definition_id: row for row in rows}
async def _set_task_custom_field_values_for_create(
session: AsyncSession,
*,
board_id: UUID,
task_id: UUID,
custom_field_values: TaskCustomFieldValues,
) -> None:
definitions_by_key = await _organization_custom_field_definitions_for_board(
session,
board_id=board_id,
)
_reject_unknown_custom_field_keys(
custom_field_values=custom_field_values,
definitions_by_key=definitions_by_key,
)
_reject_invalid_custom_field_values(
custom_field_values=custom_field_values,
definitions_by_key=definitions_by_key,
)
effective_values: TaskCustomFieldValues = {}
for field_key, definition in definitions_by_key.items():
if field_key in custom_field_values:
effective_values[field_key] = custom_field_values[field_key]
else:
effective_values[field_key] = definition.default_value
_reject_missing_required_custom_field_keys(
effective_values=effective_values,
definitions_by_key=definitions_by_key,
)
for field_key, definition in definitions_by_key.items():
value = effective_values.get(field_key)
if value is None:
continue
session.add(
TaskCustomFieldValue(
task_id=task_id,
task_custom_field_definition_id=definition.id,
value=value,
),
)
async def _set_task_custom_field_values_for_update(
session: AsyncSession,
*,
board_id: UUID,
task_id: UUID,
custom_field_values: TaskCustomFieldValues,
) -> None:
definitions_by_key = await _organization_custom_field_definitions_for_board(
session,
board_id=board_id,
)
_reject_unknown_custom_field_keys(
custom_field_values=custom_field_values,
definitions_by_key=definitions_by_key,
)
_reject_invalid_custom_field_values(
custom_field_values=custom_field_values,
definitions_by_key=definitions_by_key,
)
definitions_by_id = {definition.id: definition for definition in definitions_by_key.values()}
rows_by_definition_id = await _task_custom_field_rows_by_definition_id(
session,
task_id=task_id,
definition_ids=list(definitions_by_id),
)
effective_values: TaskCustomFieldValues = {}
for field_key, definition in definitions_by_key.items():
current_row = rows_by_definition_id.get(definition.id)
if field_key in custom_field_values:
effective_values[field_key] = custom_field_values[field_key]
elif current_row is not None:
effective_values[field_key] = current_row.value
else:
effective_values[field_key] = definition.default_value
_reject_missing_required_custom_field_keys(
effective_values=effective_values,
definitions_by_key=definitions_by_key,
)
for field_key, value in custom_field_values.items():
definition = definitions_by_key[field_key]
row = rows_by_definition_id.get(definition.id)
if value is None:
if row is not None:
await session.delete(row)
continue
if row is None:
session.add(
TaskCustomFieldValue(
task_id=task_id,
task_custom_field_definition_id=definition.id,
value=value,
),
)
continue
row.value = value
row.updated_at = utcnow()
session.add(row)
async def _task_custom_field_values_by_task_id(
session: AsyncSession,
*,
board_id: UUID,
task_ids: Sequence[UUID],
) -> dict[UUID, TaskCustomFieldValues]:
unique_task_ids = list({*task_ids})
if not unique_task_ids:
return {}
definitions_by_key = await _organization_custom_field_definitions_for_board(
session,
board_id=board_id,
)
if not definitions_by_key:
return {task_id: {} for task_id in unique_task_ids}
definitions_by_id = {definition.id: definition for definition in definitions_by_key.values()}
default_values = {
field_key: definition.default_value for field_key, definition in definitions_by_key.items()
}
values_by_task_id: dict[UUID, TaskCustomFieldValues] = {
task_id: dict(default_values) for task_id in unique_task_ids
}
rows = (
await session.exec(
select(
col(TaskCustomFieldValue.task_id),
col(TaskCustomFieldValue.task_custom_field_definition_id),
col(TaskCustomFieldValue.value),
).where(
col(TaskCustomFieldValue.task_id).in_(unique_task_ids),
col(TaskCustomFieldValue.task_custom_field_definition_id).in_(
list(definitions_by_id),
),
),
)
).all()
for task_id, definition_id, value in rows:
definition = definitions_by_id.get(definition_id)
if definition is None:
continue
values_by_task_id[task_id][definition.field_key] = value
return values_by_task_id
def _task_list_statement(
*,
board_id: UUID,
@@ -742,6 +1037,11 @@ async def _task_read_page(
board_id=board_id,
dependency_ids=list({*dep_ids}),
)
custom_field_values_by_task_id = await _task_custom_field_values_by_task_id(
session,
board_id=board_id,
task_ids=task_ids,
)
output: list[TaskRead] = []
for task in tasks:
@@ -761,6 +1061,7 @@ async def _task_read_page(
"tags": tag_state.tags,
"blocked_by_task_ids": blocked_by,
"is_blocked": bool(blocked_by),
"custom_field_values": custom_field_values_by_task_id.get(task.id, {}),
},
),
)
@@ -772,12 +1073,17 @@ async def _stream_task_state(
*,
board_id: UUID,
rows: list[tuple[ActivityEvent, Task | None]],
) -> tuple[dict[UUID, list[UUID]], dict[UUID, str], dict[UUID, TagState]]:
) -> tuple[
dict[UUID, list[UUID]],
dict[UUID, str],
dict[UUID, TagState],
dict[UUID, TaskCustomFieldValues],
]:
task_ids = [
task.id for event, task in rows if task is not None and event.event_type != "task.comment"
]
if not task_ids:
return {}, {}, {}
return {}, {}, {}, {}
tag_state_by_task_id = await load_tag_state(
session,
@@ -791,15 +1097,20 @@ async def _stream_task_state(
dep_ids: list[UUID] = []
for value in deps_map.values():
dep_ids.extend(value)
custom_field_values_by_task_id = await _task_custom_field_values_by_task_id(
session,
board_id=board_id,
task_ids=list({*task_ids}),
)
if not dep_ids:
return deps_map, {}, tag_state_by_task_id
return deps_map, {}, tag_state_by_task_id, custom_field_values_by_task_id
dep_status = await dependency_status_by_id(
session,
board_id=board_id,
dependency_ids=list({*dep_ids}),
)
return deps_map, dep_status, tag_state_by_task_id
return deps_map, dep_status, tag_state_by_task_id, custom_field_values_by_task_id
def _task_event_payload(
@@ -809,7 +1120,9 @@ def _task_event_payload(
deps_map: dict[UUID, list[UUID]],
dep_status: dict[UUID, str],
tag_state_by_task_id: dict[UUID, TagState],
custom_field_values_by_task_id: dict[UUID, TaskCustomFieldValues] | None = None,
) -> dict[str, object]:
resolved_custom_field_values_by_task_id = custom_field_values_by_task_id or {}
payload: dict[str, object] = {
"type": event.event_type,
"activity": ActivityEventRead.model_validate(event).model_dump(mode="json"),
@@ -838,6 +1151,10 @@ def _task_event_payload(
"tags": tag_state.tags,
"blocked_by_task_ids": blocked_by,
"is_blocked": bool(blocked_by),
"custom_field_values": resolved_custom_field_values_by_task_id.get(
task.id,
{},
),
},
)
.model_dump(mode="json")
@@ -861,11 +1178,13 @@ async def _task_event_generator(
async with async_session_maker() as session:
rows = await _fetch_task_events(session, board_id, last_seen)
deps_map, dep_status, tag_state_by_task_id = await _stream_task_state(
deps_map, dep_status, tag_state_by_task_id, custom_field_values_by_task_id = (
await _stream_task_state(
session,
board_id=board_id,
rows=rows,
)
)
for event, task in rows:
if event.id in seen_ids:
@@ -883,6 +1202,7 @@ async def _task_event_generator(
deps_map=deps_map,
dep_status=dep_status,
tag_state_by_task_id=tag_state_by_task_id,
custom_field_values_by_task_id=custom_field_values_by_task_id,
)
yield {"event": "task", "data": json.dumps(payload)}
await asyncio.sleep(2)
@@ -943,9 +1263,10 @@ async def create_task(
auth: AuthContext = ADMIN_AUTH_DEP,
) -> TaskRead:
"""Create a task and initialize dependency rows."""
data = payload.model_dump(exclude={"depends_on_task_ids", "tag_ids"})
data = payload.model_dump(exclude={"depends_on_task_ids", "tag_ids", "custom_field_values"})
depends_on_task_ids = list(payload.depends_on_task_ids)
tag_ids = list(payload.tag_ids)
custom_field_values = dict(payload.custom_field_values)
task = Task.model_validate(data)
task.board_id = board.id
@@ -977,6 +1298,12 @@ async def create_task(
session.add(task)
# Ensure the task exists in the DB before inserting dependency rows.
await session.flush()
await _set_task_custom_field_values_for_create(
session,
board_id=board.id,
task_id=task.id,
custom_field_values=custom_field_values,
)
for dep_id in normalized_deps:
session.add(
TaskDependency(
@@ -1051,9 +1378,14 @@ async def update_task(
payload.depends_on_task_ids if "depends_on_task_ids" in payload.model_fields_set else None
)
tag_ids = payload.tag_ids if "tag_ids" in payload.model_fields_set else None
custom_field_values = (
payload.custom_field_values if "custom_field_values" in payload.model_fields_set else None
)
custom_field_values_set = "custom_field_values" in payload.model_fields_set
updates.pop("comment", None)
updates.pop("depends_on_task_ids", None)
updates.pop("tag_ids", None)
updates.pop("custom_field_values", None)
requested_status = payload.status if "status" in payload.model_fields_set else None
update = _TaskUpdateInput(
task=task,
@@ -1066,6 +1398,8 @@ async def update_task(
comment=comment,
depends_on_task_ids=depends_on_task_ids,
tag_ids=tag_ids,
custom_field_values=custom_field_values or {},
custom_field_values_set=custom_field_values_set,
)
if actor.actor_type == "agent" and actor.agent and actor.agent.is_board_lead:
return await _apply_lead_task_update(session, update=update)
@@ -1142,6 +1476,12 @@ async def delete_task(
col(TagAssignment.task_id) == task.id,
commit=False,
)
await crud.delete_where(
session,
TaskCustomFieldValue,
col(TaskCustomFieldValue.task_id) == task.id,
commit=False,
)
await session.delete(task)
await session.commit()
return OkResponse()
@@ -1306,6 +1646,8 @@ class _TaskUpdateInput:
comment: str | None
depends_on_task_ids: list[UUID] | None
tag_ids: list[UUID] | None
custom_field_values: TaskCustomFieldValues
custom_field_values_set: bool
normalized_tag_ids: list[UUID] | None = None
@@ -1385,6 +1727,11 @@ async def _task_read_response(
board_id=board_id,
dep_ids=dep_ids,
)
custom_field_values_by_task_id = await _task_custom_field_values_by_task_id(
session,
board_id=board_id,
task_ids=[task.id],
)
if task.status == "done":
blocked_ids = []
return TaskRead.model_validate(task, from_attributes=True).model_copy(
@@ -1394,6 +1741,7 @@ async def _task_read_response(
"tags": tag_state.tags,
"blocked_by_task_ids": blocked_ids,
"is_blocked": bool(blocked_ids),
"custom_field_values": custom_field_values_by_task_id.get(task.id, {}),
},
)
@@ -1420,18 +1768,26 @@ def _lead_requested_fields(update: _TaskUpdateInput) -> set[str]:
requested_fields.add("depends_on_task_ids")
if update.tag_ids is not None:
requested_fields.add("tag_ids")
if update.custom_field_values_set:
requested_fields.add("custom_field_values")
return requested_fields
def _validate_lead_update_request(update: _TaskUpdateInput) -> None:
allowed_fields = {"assigned_agent_id", "status", "depends_on_task_ids", "tag_ids"}
allowed_fields = {
"assigned_agent_id",
"status",
"depends_on_task_ids",
"tag_ids",
"custom_field_values",
}
requested_fields = _lead_requested_fields(update)
if update.comment is not None or not requested_fields.issubset(allowed_fields):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail=(
"Board leads can only assign/unassign tasks, update "
"dependencies, or resolve review tasks."
"dependencies/custom fields, or resolve review tasks."
),
)
@@ -1622,6 +1978,13 @@ async def _apply_lead_task_update(
task_id=update.task.id,
tag_ids=normalized_tag_ids,
)
if update.custom_field_values_set:
await _set_task_custom_field_values_for_update(
session,
board_id=update.board_id,
task_id=update.task.id,
custom_field_values=update.custom_field_values,
)
update.task.updated_at = utcnow()
session.add(update.task)
@@ -1666,7 +2029,7 @@ async def _apply_non_lead_agent_task_rules(
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN)
# Agents are limited to status/comment updates, and non-inbox status moves
# must pass dependency checks before they can proceed.
allowed_fields = {"status", "comment"}
allowed_fields = {"status", "comment", "custom_field_values"}
if (
update.depends_on_task_ids is not None
or update.tag_ids is not None
@@ -1938,6 +2301,14 @@ async def _finalize_updated_task(
tag_ids=normalized or [],
)
if update.custom_field_values_set:
await _set_task_custom_field_values_for_update(
session,
board_id=update.board_id,
task_id=update.task.id,
custom_field_values=update.custom_field_values,
)
session.add(update.task)
await session.commit()
await session.refresh(update.task)

View File

@@ -26,6 +26,7 @@ from app.api.metrics import router as metrics_router
from app.api.organizations import router as organizations_router
from app.api.souls_directory import router as souls_directory_router
from app.api.tags import router as tags_router
from app.api.task_custom_fields import router as task_custom_fields_router
from app.api.tasks import router as tasks_router
from app.api.users import router as users_router
from app.core.config import settings
@@ -145,6 +146,7 @@ api_v1.include_router(board_webhooks_router)
api_v1.include_router(board_onboarding_router)
api_v1.include_router(approvals_router)
api_v1.include_router(tasks_router)
api_v1.include_router(task_custom_fields_router)
api_v1.include_router(tags_router)
api_v1.include_router(users_router)
app.include_router(api_v1)

View File

@@ -19,6 +19,11 @@ from app.models.organization_members import OrganizationMember
from app.models.organizations import Organization
from app.models.tag_assignments import TagAssignment
from app.models.tags import Tag
from app.models.task_custom_fields import (
BoardTaskCustomField,
TaskCustomFieldDefinition,
TaskCustomFieldValue,
)
from app.models.task_dependencies import TaskDependency
from app.models.task_fingerprints import TaskFingerprint
from app.models.tasks import Task
@@ -38,6 +43,9 @@ __all__ = [
"Board",
"Gateway",
"Organization",
"BoardTaskCustomField",
"TaskCustomFieldDefinition",
"TaskCustomFieldValue",
"OrganizationMember",
"OrganizationBoardAccess",
"OrganizationInvite",

View File

@@ -0,0 +1,92 @@
"""Task custom field models and board binding helpers."""
from __future__ import annotations
from datetime import datetime
from uuid import UUID, uuid4
from sqlalchemy import JSON, CheckConstraint, Column, UniqueConstraint
from sqlmodel import Field
from app.core.time import utcnow
from app.models.tenancy import TenantScoped
RUNTIME_ANNOTATION_TYPES = (datetime,)
class TaskCustomFieldDefinition(TenantScoped, table=True):
"""Reusable custom field definition for task metadata."""
__tablename__ = "task_custom_field_definitions" # pyright: ignore[reportAssignmentType]
__table_args__ = (
UniqueConstraint(
"organization_id",
"field_key",
name="uq_task_custom_field_definitions_org_id_field_key",
),
CheckConstraint(
"field_type IN ('text','text_long','integer','decimal','boolean','date','date_time','url','json')",
name="ck_tcf_def_field_type",
),
CheckConstraint(
"ui_visibility IN ('always','if_set','hidden')",
name="ck_tcf_def_ui_visibility",
),
)
id: UUID = Field(default_factory=uuid4, primary_key=True)
organization_id: UUID = Field(foreign_key="organizations.id", index=True)
field_key: str = Field(index=True)
label: str
field_type: str = Field(default="text")
ui_visibility: str = Field(default="always")
validation_regex: str | None = None
description: str | None = None
required: bool = Field(default=False)
default_value: object | None = Field(default=None, sa_column=Column(JSON))
created_at: datetime = Field(default_factory=utcnow)
updated_at: datetime = Field(default_factory=utcnow)
class BoardTaskCustomField(TenantScoped, table=True):
"""Board-level binding of a custom field definition."""
__tablename__ = "board_task_custom_fields" # pyright: ignore[reportAssignmentType]
__table_args__ = (
UniqueConstraint(
"board_id",
"task_custom_field_definition_id",
name="uq_board_task_custom_fields_board_id_task_custom_field_definition_id",
),
)
id: UUID = Field(default_factory=uuid4, primary_key=True)
board_id: UUID = Field(foreign_key="boards.id", index=True)
task_custom_field_definition_id: UUID = Field(
foreign_key="task_custom_field_definitions.id",
index=True,
)
created_at: datetime = Field(default_factory=utcnow)
class TaskCustomFieldValue(TenantScoped, table=True):
"""Stored task-level values for bound custom fields."""
__tablename__ = "task_custom_field_values" # pyright: ignore[reportAssignmentType]
__table_args__ = (
UniqueConstraint(
"task_id",
"task_custom_field_definition_id",
name="uq_task_custom_field_values_task_id_task_custom_field_definition_id",
),
)
id: UUID = Field(default_factory=uuid4, primary_key=True)
task_id: UUID = Field(foreign_key="tasks.id", index=True)
task_custom_field_definition_id: UUID = Field(
foreign_key="task_custom_field_definitions.id",
index=True,
)
value: object | None = Field(default=None, sa_column=Column(JSON))
created_at: datetime = Field(default_factory=utcnow)
updated_at: datetime = Field(default_factory=utcnow)

View File

@@ -0,0 +1,366 @@
"""Schemas for task custom field metadata, board bindings, and payloads."""
from __future__ import annotations
import re
from datetime import date, datetime
from typing import Literal, Self
from urllib.parse import urlparse
from uuid import UUID
from pydantic import Field, field_validator, model_validator
from sqlmodel import SQLModel
from app.schemas.common import NonEmptyStr
RUNTIME_ANNOTATION_TYPES = (datetime, UUID, date)
TaskCustomFieldType = Literal[
"text",
"text_long",
"integer",
"decimal",
"boolean",
"date",
"date_time",
"url",
"json",
]
TaskCustomFieldUiVisibility = Literal["always", "if_set", "hidden"]
STRING_FIELD_TYPES: set[str] = {"text", "text_long", "date", "date_time", "url"}
TASK_CUSTOM_FIELD_TYPE_ALIASES: dict[str, TaskCustomFieldType] = {
"text": "text",
"text_long": "text_long",
"text (long)": "text_long",
"long_text": "text_long",
"integer": "integer",
"decimal": "decimal",
"boolean": "boolean",
"true/false": "boolean",
"date": "date",
"date_time": "date_time",
"date & time": "date_time",
"datetime": "date_time",
"url": "url",
"json": "json",
}
TASK_CUSTOM_FIELD_UI_VISIBILITY_ALIASES: dict[str, TaskCustomFieldUiVisibility] = {
"always": "always",
"if_set": "if_set",
"if set": "if_set",
"hidden": "hidden",
}
# Reusable alias for task payload payloads containing custom-field values.
TaskCustomFieldValues = dict[str, object | None]
class TaskCustomFieldDefinitionBase(SQLModel):
"""Shared custom field definition properties."""
field_key: str
label: str | None = None
field_type: TaskCustomFieldType = "text"
ui_visibility: TaskCustomFieldUiVisibility = "always"
validation_regex: str | None = None
description: str | None = None
required: bool = False
default_value: object | None = None
@field_validator("field_key", mode="before")
@classmethod
def normalize_field_key(cls, value: object) -> object:
"""Normalize field keys to a stable lowercase representation."""
if not isinstance(value, str):
raise ValueError("field_key must be a string")
normalized = value.strip()
if not normalized:
raise ValueError("field_key is required")
return normalized
@field_validator("label", mode="before")
@classmethod
def normalize_label(cls, value: object) -> object:
"""Normalize labels to a trimmed representation when provided."""
if value is None:
return None
if not isinstance(value, str):
raise ValueError("label must be a string")
normalized = value.strip()
if not normalized:
raise ValueError("label is required")
return normalized
@field_validator("field_type", mode="before")
@classmethod
def normalize_field_type(cls, value: object) -> object:
"""Normalize field type aliases."""
if not isinstance(value, str):
raise ValueError("field_type must be a string")
normalized = value.strip().lower()
resolved = TASK_CUSTOM_FIELD_TYPE_ALIASES.get(normalized)
if resolved is None:
raise ValueError(
"field_type must be one of: text, text_long, integer, decimal, "
"boolean, date, date_time, url, json",
)
return resolved
@field_validator("validation_regex", mode="before")
@classmethod
def normalize_validation_regex(cls, value: object) -> object:
"""Normalize and validate regex pattern syntax."""
if value is None:
return None
if not isinstance(value, str):
raise ValueError("validation_regex must be a string")
normalized = value.strip()
if not normalized:
return None
try:
re.compile(normalized)
except re.error as exc:
raise ValueError(f"validation_regex is invalid: {exc}") from exc
return normalized
@field_validator("ui_visibility", mode="before")
@classmethod
def normalize_ui_visibility(cls, value: object) -> object:
"""Normalize UI visibility aliases."""
if not isinstance(value, str):
raise ValueError("ui_visibility must be a string")
normalized = value.strip().lower()
resolved = TASK_CUSTOM_FIELD_UI_VISIBILITY_ALIASES.get(normalized)
if resolved is None:
raise ValueError("ui_visibility must be one of: always, if_set, hidden")
return resolved
class TaskCustomFieldDefinitionCreate(TaskCustomFieldDefinitionBase):
"""Payload for creating a task custom field definition."""
field_key: NonEmptyStr
label: NonEmptyStr | None = None
board_ids: list[UUID] = Field(min_length=1)
@field_validator("board_ids")
@classmethod
def normalize_board_ids(cls, value: list[UUID]) -> list[UUID]:
"""Remove duplicates while preserving user-supplied order."""
deduped = list(dict.fromkeys(value))
if not deduped:
raise ValueError("board_ids must include at least one board")
return deduped
@model_validator(mode="after")
def default_label_to_field_key(self) -> Self:
"""Default labels to field_key when omitted by older clients."""
if self.label is None:
self.label = self.field_key
return self
@model_validator(mode="after")
def validate_regex_field_type_combo(self) -> Self:
"""Restrict regex validation to string-compatible field types."""
if self.validation_regex is not None and self.field_type not in STRING_FIELD_TYPES:
raise ValueError(
"validation_regex is only supported for string field types.",
)
return self
class TaskCustomFieldDefinitionUpdate(SQLModel):
"""Payload for editing an existing task custom field definition."""
label: NonEmptyStr | None = None
field_type: TaskCustomFieldType | None = None
ui_visibility: TaskCustomFieldUiVisibility | None = None
validation_regex: str | None = None
description: str | None = None
required: bool | None = None
default_value: object | None = None
board_ids: list[UUID] | None = None
@field_validator("board_ids")
@classmethod
def normalize_board_ids(cls, value: list[UUID] | None) -> list[UUID] | None:
"""Normalize board bindings when provided in updates."""
if value is None:
return None
deduped = list(dict.fromkeys(value))
if not deduped:
raise ValueError("board_ids must include at least one board")
return deduped
@field_validator("field_type", mode="before")
@classmethod
def normalize_optional_field_type(cls, value: object) -> object:
"""Normalize optional field type aliases."""
if value is None:
return None
return TaskCustomFieldDefinitionBase.normalize_field_type(value)
@field_validator("validation_regex", mode="before")
@classmethod
def normalize_optional_validation_regex(cls, value: object) -> object:
"""Normalize and validate optional regex pattern syntax."""
if value is None:
return None
return TaskCustomFieldDefinitionBase.normalize_validation_regex(value)
@field_validator("ui_visibility", mode="before")
@classmethod
def normalize_optional_ui_visibility(cls, value: object) -> object:
"""Normalize optional UI visibility aliases."""
if value is None:
return None
return TaskCustomFieldDefinitionBase.normalize_ui_visibility(value)
@model_validator(mode="before")
@classmethod
def reject_field_key_update(cls, value: object) -> object:
"""Disallow field_key updates after definition creation."""
if isinstance(value, dict) and "field_key" in value:
raise ValueError("field_key cannot be changed after creation.")
return value
@model_validator(mode="after")
def reject_null_for_non_nullable_fields(self) -> Self:
"""Reject explicit null for non-nullable update fields."""
non_nullable_fields = ("label", "field_type", "ui_visibility", "required")
invalid = [
field_name
for field_name in non_nullable_fields
if field_name in self.model_fields_set and getattr(self, field_name) is None
]
if invalid:
raise ValueError(
f"{', '.join(invalid)} cannot be null; omit the field to leave it unchanged",
)
return self
@model_validator(mode="after")
def require_some_update(self) -> Self:
"""Reject empty updates to avoid no-op requests."""
if not self.model_fields_set:
raise ValueError("At least one field is required")
return self
class TaskCustomFieldDefinitionRead(TaskCustomFieldDefinitionBase):
"""Payload returned for custom field definitions."""
id: UUID
organization_id: UUID
label: str
field_type: TaskCustomFieldType
ui_visibility: TaskCustomFieldUiVisibility
validation_regex: str | None = None
board_ids: list[UUID] = Field(default_factory=list)
created_at: datetime
updated_at: datetime
class BoardTaskCustomFieldCreate(SQLModel):
"""Payload for binding a definition to a board."""
task_custom_field_definition_id: UUID
class BoardTaskCustomFieldRead(SQLModel):
"""Payload returned when listing board-bound custom fields."""
id: UUID
board_id: UUID
task_custom_field_definition_id: UUID
field_key: str
label: str
field_type: TaskCustomFieldType
ui_visibility: TaskCustomFieldUiVisibility
validation_regex: str | None
description: str | None
required: bool
default_value: object | None
created_at: datetime
class TaskCustomFieldValuesPayload(SQLModel):
"""Payload for setting all custom-field values at once."""
custom_field_values: TaskCustomFieldValues = Field(default_factory=dict)
def _parse_iso_datetime(value: str) -> datetime:
normalized = value.strip()
if normalized.endswith("Z"):
normalized = f"{normalized[:-1]}+00:00"
return datetime.fromisoformat(normalized)
def validate_custom_field_value(
*,
field_type: TaskCustomFieldType,
value: object | None,
validation_regex: str | None = None,
) -> None:
"""Validate a custom field value against field type and optional regex."""
if value is None:
return
if field_type in {"text", "text_long"}:
if not isinstance(value, str):
raise ValueError("must be a string")
elif field_type == "integer":
if not isinstance(value, int) or isinstance(value, bool):
raise ValueError("must be an integer")
elif field_type == "decimal":
if (not isinstance(value, (int, float))) or isinstance(value, bool):
raise ValueError("must be a decimal number")
elif field_type == "boolean":
if not isinstance(value, bool):
raise ValueError("must be true or false")
elif field_type == "date":
if not isinstance(value, str):
raise ValueError("must be an ISO date string (YYYY-MM-DD)")
try:
date.fromisoformat(value)
except ValueError as exc:
raise ValueError("must be an ISO date string (YYYY-MM-DD)") from exc
elif field_type == "date_time":
if not isinstance(value, str):
raise ValueError("must be an ISO datetime string")
try:
_parse_iso_datetime(value)
except ValueError as exc:
raise ValueError("must be an ISO datetime string") from exc
elif field_type == "url":
if not isinstance(value, str):
raise ValueError("must be a URL string")
parsed = urlparse(value)
if parsed.scheme not in {"http", "https"} or not parsed.netloc:
raise ValueError("must be a valid http/https URL")
elif field_type == "json":
if not isinstance(value, (dict, list)):
raise ValueError("must be a JSON object or array")
if validation_regex is not None and field_type in STRING_FIELD_TYPES:
if not isinstance(value, str):
raise ValueError("must be a string for regex validation")
if re.fullmatch(validation_regex, value) is None:
raise ValueError("does not match validation_regex")
def validate_custom_field_definition(
*,
field_type: TaskCustomFieldType,
validation_regex: str | None,
default_value: object | None,
) -> None:
"""Validate field definition constraints and default-value compatibility."""
if validation_regex is not None and field_type not in STRING_FIELD_TYPES:
raise ValueError("validation_regex is only supported for string field types.")
validate_custom_field_value(
field_type=field_type,
value=default_value,
validation_regex=validation_regex,
)

View File

@@ -11,6 +11,7 @@ from sqlmodel import Field, SQLModel
from app.schemas.common import NonEmptyStr
from app.schemas.tags import TagRef
from app.schemas.task_custom_fields import TaskCustomFieldValues
TaskStatus = Literal["inbox", "in_progress", "review", "done"]
STATUS_REQUIRED_ERROR = "status is required"
@@ -36,6 +37,7 @@ class TaskCreate(TaskBase):
"""Payload for creating a task."""
created_by_user_id: UUID | None = None
custom_field_values: TaskCustomFieldValues = Field(default_factory=dict)
class TaskUpdate(SQLModel):
@@ -49,6 +51,7 @@ class TaskUpdate(SQLModel):
assigned_agent_id: UUID | None = None
depends_on_task_ids: list[UUID] | None = None
tag_ids: list[UUID] | None = None
custom_field_values: TaskCustomFieldValues | None = None
comment: NonEmptyStr | None = None
@field_validator("comment", mode="before")
@@ -81,6 +84,7 @@ class TaskRead(TaskBase):
blocked_by_task_ids: list[UUID] = Field(default_factory=list)
is_blocked: bool = False
tags: list[TagRef] = Field(default_factory=list)
custom_field_values: TaskCustomFieldValues | None = None
class TaskCommentCreate(SQLModel):

View File

@@ -0,0 +1,141 @@
"""Add task custom field tables.
Revision ID: b6f4c7d9e1a2
Revises: 1a7b2c3d4e5f
Create Date: 2026-02-13 00:20:00.000000
"""
from __future__ import annotations
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = "b6f4c7d9e1a2"
down_revision = "1a7b2c3d4e5f"
branch_labels = None
depends_on = None
def upgrade() -> None:
"""Create task custom-field definition, binding, and value tables."""
op.create_table(
"task_custom_field_definitions",
sa.Column("id", sa.Uuid(), nullable=False),
sa.Column("organization_id", sa.Uuid(), nullable=False),
sa.Column("field_key", sa.String(), nullable=False),
sa.Column("label", sa.String(), nullable=False),
sa.Column(
"field_type",
sa.String(),
nullable=False,
server_default=sa.text("'text'"),
),
sa.Column(
"ui_visibility",
sa.String(),
nullable=False,
server_default=sa.text("'always'"),
),
sa.Column("validation_regex", sa.String(), nullable=True),
sa.Column("description", sa.String(), nullable=True),
sa.Column("required", sa.Boolean(), nullable=False),
sa.Column("default_value", sa.JSON(), nullable=True),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.Column("updated_at", sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(["organization_id"], ["organizations.id"]),
sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint(
"organization_id",
"field_key",
name="uq_tcf_def_org_key",
),
sa.CheckConstraint(
"field_type IN "
"('text','text_long','integer','decimal','boolean','date','date_time','url','json')",
name="ck_tcf_def_field_type",
),
sa.CheckConstraint(
"ui_visibility IN ('always','if_set','hidden')",
name="ck_tcf_def_ui_visibility",
),
)
op.create_index(
"ix_task_custom_field_definitions_organization_id",
"task_custom_field_definitions",
["organization_id"],
)
op.create_index(
"ix_task_custom_field_definitions_field_key",
"task_custom_field_definitions",
["field_key"],
)
op.create_table(
"board_task_custom_fields",
sa.Column("id", sa.Uuid(), nullable=False),
sa.Column("board_id", sa.Uuid(), nullable=False),
sa.Column("task_custom_field_definition_id", sa.Uuid(), nullable=False),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(["board_id"], ["boards.id"]),
sa.ForeignKeyConstraint(
["task_custom_field_definition_id"],
["task_custom_field_definitions.id"],
),
sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint(
"board_id",
"task_custom_field_definition_id",
name="uq_board_tcf_binding",
),
)
op.create_index(
"ix_board_task_custom_fields_board_id",
"board_task_custom_fields",
["board_id"],
)
op.create_index(
"ix_board_task_custom_fields_task_custom_field_definition_id",
"board_task_custom_fields",
["task_custom_field_definition_id"],
)
op.create_table(
"task_custom_field_values",
sa.Column("id", sa.Uuid(), nullable=False),
sa.Column("task_id", sa.Uuid(), nullable=False),
sa.Column("task_custom_field_definition_id", sa.Uuid(), nullable=False),
sa.Column("value", sa.JSON(), nullable=True),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.Column("updated_at", sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(["task_id"], ["tasks.id"]),
sa.ForeignKeyConstraint(
["task_custom_field_definition_id"],
["task_custom_field_definitions.id"],
),
sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint(
"task_id",
"task_custom_field_definition_id",
name="uq_tcf_values_task_def",
),
)
op.create_index(
"ix_task_custom_field_values_task_id",
"task_custom_field_values",
["task_id"],
)
op.create_index(
"ix_task_custom_field_values_task_custom_field_definition_id",
"task_custom_field_values",
["task_custom_field_definition_id"],
)
def downgrade() -> None:
"""Drop task custom field tables."""
op.drop_table("task_custom_field_values")
op.drop_table("board_task_custom_fields")
op.drop_table("task_custom_field_definitions")

View File

@@ -43,7 +43,9 @@ def main() -> int:
return 1
if len(heads) > 1 and not allow_multiple_heads:
print("ERROR: multiple Alembic heads detected (set ALLOW_MULTIPLE_HEADS=true only for intentional merge windows)")
print(
"ERROR: multiple Alembic heads detected (set ALLOW_MULTIPLE_HEADS=true only for intentional merge windows)"
)
for h in heads:
print(f" - {h}")
return 1

File diff suppressed because it is too large Load Diff

View File

@@ -364,6 +364,134 @@ export const useCreateAgentApiV1AgentsPost = <
queryClient,
);
};
/**
* Heartbeat an existing agent or create/provision one if needed.
* @summary Heartbeat Or Create Agent
*/
export type heartbeatOrCreateAgentApiV1AgentsHeartbeatPostResponse200 = {
data: AgentRead;
status: 200;
};
export type heartbeatOrCreateAgentApiV1AgentsHeartbeatPostResponse422 = {
data: HTTPValidationError;
status: 422;
};
export type heartbeatOrCreateAgentApiV1AgentsHeartbeatPostResponseSuccess =
heartbeatOrCreateAgentApiV1AgentsHeartbeatPostResponse200 & {
headers: Headers;
};
export type heartbeatOrCreateAgentApiV1AgentsHeartbeatPostResponseError =
heartbeatOrCreateAgentApiV1AgentsHeartbeatPostResponse422 & {
headers: Headers;
};
export type heartbeatOrCreateAgentApiV1AgentsHeartbeatPostResponse =
| heartbeatOrCreateAgentApiV1AgentsHeartbeatPostResponseSuccess
| heartbeatOrCreateAgentApiV1AgentsHeartbeatPostResponseError;
export const getHeartbeatOrCreateAgentApiV1AgentsHeartbeatPostUrl = () => {
return `/api/v1/agents/heartbeat`;
};
export const heartbeatOrCreateAgentApiV1AgentsHeartbeatPost = async (
agentHeartbeatCreate: AgentHeartbeatCreate,
options?: RequestInit,
): Promise<heartbeatOrCreateAgentApiV1AgentsHeartbeatPostResponse> => {
return customFetch<heartbeatOrCreateAgentApiV1AgentsHeartbeatPostResponse>(
getHeartbeatOrCreateAgentApiV1AgentsHeartbeatPostUrl(),
{
...options,
method: "POST",
headers: { "Content-Type": "application/json", ...options?.headers },
body: JSON.stringify(agentHeartbeatCreate),
},
);
};
export const getHeartbeatOrCreateAgentApiV1AgentsHeartbeatPostMutationOptions =
<TError = HTTPValidationError, TContext = unknown>(options?: {
mutation?: UseMutationOptions<
Awaited<
ReturnType<typeof heartbeatOrCreateAgentApiV1AgentsHeartbeatPost>
>,
TError,
{ data: AgentHeartbeatCreate },
TContext
>;
request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
Awaited<ReturnType<typeof heartbeatOrCreateAgentApiV1AgentsHeartbeatPost>>,
TError,
{ data: AgentHeartbeatCreate },
TContext
> => {
const mutationKey = ["heartbeatOrCreateAgentApiV1AgentsHeartbeatPost"];
const { mutation: mutationOptions, request: requestOptions } = options
? options.mutation &&
"mutationKey" in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey }, request: undefined };
const mutationFn: MutationFunction<
Awaited<
ReturnType<typeof heartbeatOrCreateAgentApiV1AgentsHeartbeatPost>
>,
{ data: AgentHeartbeatCreate }
> = (props) => {
const { data } = props ?? {};
return heartbeatOrCreateAgentApiV1AgentsHeartbeatPost(
data,
requestOptions,
);
};
return { mutationFn, ...mutationOptions };
};
export type HeartbeatOrCreateAgentApiV1AgentsHeartbeatPostMutationResult =
NonNullable<
Awaited<ReturnType<typeof heartbeatOrCreateAgentApiV1AgentsHeartbeatPost>>
>;
export type HeartbeatOrCreateAgentApiV1AgentsHeartbeatPostMutationBody =
AgentHeartbeatCreate;
export type HeartbeatOrCreateAgentApiV1AgentsHeartbeatPostMutationError =
HTTPValidationError;
/**
* @summary Heartbeat Or Create Agent
*/
export const useHeartbeatOrCreateAgentApiV1AgentsHeartbeatPost = <
TError = HTTPValidationError,
TContext = unknown,
>(
options?: {
mutation?: UseMutationOptions<
Awaited<
ReturnType<typeof heartbeatOrCreateAgentApiV1AgentsHeartbeatPost>
>,
TError,
{ data: AgentHeartbeatCreate },
TContext
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseMutationResult<
Awaited<ReturnType<typeof heartbeatOrCreateAgentApiV1AgentsHeartbeatPost>>,
TError,
{ data: AgentHeartbeatCreate },
TContext
> => {
return useMutation(
getHeartbeatOrCreateAgentApiV1AgentsHeartbeatPostMutationOptions(options),
queryClient,
);
};
/**
* Stream agent updates as SSE events.
* @summary Stream Agents
@@ -576,6 +704,123 @@ export function useStreamAgentsApiV1AgentsStreamGet<
return { ...query, queryKey: queryOptions.queryKey };
}
/**
* Delete an agent and clean related task state.
* @summary Delete Agent
*/
export type deleteAgentApiV1AgentsAgentIdDeleteResponse200 = {
data: OkResponse;
status: 200;
};
export type deleteAgentApiV1AgentsAgentIdDeleteResponse422 = {
data: HTTPValidationError;
status: 422;
};
export type deleteAgentApiV1AgentsAgentIdDeleteResponseSuccess =
deleteAgentApiV1AgentsAgentIdDeleteResponse200 & {
headers: Headers;
};
export type deleteAgentApiV1AgentsAgentIdDeleteResponseError =
deleteAgentApiV1AgentsAgentIdDeleteResponse422 & {
headers: Headers;
};
export type deleteAgentApiV1AgentsAgentIdDeleteResponse =
| deleteAgentApiV1AgentsAgentIdDeleteResponseSuccess
| deleteAgentApiV1AgentsAgentIdDeleteResponseError;
export const getDeleteAgentApiV1AgentsAgentIdDeleteUrl = (agentId: string) => {
return `/api/v1/agents/${agentId}`;
};
export const deleteAgentApiV1AgentsAgentIdDelete = async (
agentId: string,
options?: RequestInit,
): Promise<deleteAgentApiV1AgentsAgentIdDeleteResponse> => {
return customFetch<deleteAgentApiV1AgentsAgentIdDeleteResponse>(
getDeleteAgentApiV1AgentsAgentIdDeleteUrl(agentId),
{
...options,
method: "DELETE",
},
);
};
export const getDeleteAgentApiV1AgentsAgentIdDeleteMutationOptions = <
TError = HTTPValidationError,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof deleteAgentApiV1AgentsAgentIdDelete>>,
TError,
{ agentId: string },
TContext
>;
request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
Awaited<ReturnType<typeof deleteAgentApiV1AgentsAgentIdDelete>>,
TError,
{ agentId: string },
TContext
> => {
const mutationKey = ["deleteAgentApiV1AgentsAgentIdDelete"];
const { mutation: mutationOptions, request: requestOptions } = options
? options.mutation &&
"mutationKey" in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey }, request: undefined };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof deleteAgentApiV1AgentsAgentIdDelete>>,
{ agentId: string }
> = (props) => {
const { agentId } = props ?? {};
return deleteAgentApiV1AgentsAgentIdDelete(agentId, requestOptions);
};
return { mutationFn, ...mutationOptions };
};
export type DeleteAgentApiV1AgentsAgentIdDeleteMutationResult = NonNullable<
Awaited<ReturnType<typeof deleteAgentApiV1AgentsAgentIdDelete>>
>;
export type DeleteAgentApiV1AgentsAgentIdDeleteMutationError =
HTTPValidationError;
/**
* @summary Delete Agent
*/
export const useDeleteAgentApiV1AgentsAgentIdDelete = <
TError = HTTPValidationError,
TContext = unknown,
>(
options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof deleteAgentApiV1AgentsAgentIdDelete>>,
TError,
{ agentId: string },
TContext
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseMutationResult<
Awaited<ReturnType<typeof deleteAgentApiV1AgentsAgentIdDelete>>,
TError,
{ agentId: string },
TContext
> => {
return useMutation(
getDeleteAgentApiV1AgentsAgentIdDeleteMutationOptions(options),
queryClient,
);
};
/**
* Get a single agent by id.
* @summary Get Agent
@@ -937,123 +1182,6 @@ export const useUpdateAgentApiV1AgentsAgentIdPatch = <
queryClient,
);
};
/**
* Delete an agent and clean related task state.
* @summary Delete Agent
*/
export type deleteAgentApiV1AgentsAgentIdDeleteResponse200 = {
data: OkResponse;
status: 200;
};
export type deleteAgentApiV1AgentsAgentIdDeleteResponse422 = {
data: HTTPValidationError;
status: 422;
};
export type deleteAgentApiV1AgentsAgentIdDeleteResponseSuccess =
deleteAgentApiV1AgentsAgentIdDeleteResponse200 & {
headers: Headers;
};
export type deleteAgentApiV1AgentsAgentIdDeleteResponseError =
deleteAgentApiV1AgentsAgentIdDeleteResponse422 & {
headers: Headers;
};
export type deleteAgentApiV1AgentsAgentIdDeleteResponse =
| deleteAgentApiV1AgentsAgentIdDeleteResponseSuccess
| deleteAgentApiV1AgentsAgentIdDeleteResponseError;
export const getDeleteAgentApiV1AgentsAgentIdDeleteUrl = (agentId: string) => {
return `/api/v1/agents/${agentId}`;
};
export const deleteAgentApiV1AgentsAgentIdDelete = async (
agentId: string,
options?: RequestInit,
): Promise<deleteAgentApiV1AgentsAgentIdDeleteResponse> => {
return customFetch<deleteAgentApiV1AgentsAgentIdDeleteResponse>(
getDeleteAgentApiV1AgentsAgentIdDeleteUrl(agentId),
{
...options,
method: "DELETE",
},
);
};
export const getDeleteAgentApiV1AgentsAgentIdDeleteMutationOptions = <
TError = HTTPValidationError,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof deleteAgentApiV1AgentsAgentIdDelete>>,
TError,
{ agentId: string },
TContext
>;
request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
Awaited<ReturnType<typeof deleteAgentApiV1AgentsAgentIdDelete>>,
TError,
{ agentId: string },
TContext
> => {
const mutationKey = ["deleteAgentApiV1AgentsAgentIdDelete"];
const { mutation: mutationOptions, request: requestOptions } = options
? options.mutation &&
"mutationKey" in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey }, request: undefined };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof deleteAgentApiV1AgentsAgentIdDelete>>,
{ agentId: string }
> = (props) => {
const { agentId } = props ?? {};
return deleteAgentApiV1AgentsAgentIdDelete(agentId, requestOptions);
};
return { mutationFn, ...mutationOptions };
};
export type DeleteAgentApiV1AgentsAgentIdDeleteMutationResult = NonNullable<
Awaited<ReturnType<typeof deleteAgentApiV1AgentsAgentIdDelete>>
>;
export type DeleteAgentApiV1AgentsAgentIdDeleteMutationError =
HTTPValidationError;
/**
* @summary Delete Agent
*/
export const useDeleteAgentApiV1AgentsAgentIdDelete = <
TError = HTTPValidationError,
TContext = unknown,
>(
options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof deleteAgentApiV1AgentsAgentIdDelete>>,
TError,
{ agentId: string },
TContext
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseMutationResult<
Awaited<ReturnType<typeof deleteAgentApiV1AgentsAgentIdDelete>>,
TError,
{ agentId: string },
TContext
> => {
return useMutation(
getDeleteAgentApiV1AgentsAgentIdDeleteMutationOptions(options),
queryClient,
);
};
/**
* Record a heartbeat for a specific agent.
* @summary Heartbeat Agent
@@ -1182,131 +1310,3 @@ export const useHeartbeatAgentApiV1AgentsAgentIdHeartbeatPost = <
queryClient,
);
};
/**
* Heartbeat an existing agent or create/provision one if needed.
* @summary Heartbeat Or Create Agent
*/
export type heartbeatOrCreateAgentApiV1AgentsHeartbeatPostResponse200 = {
data: AgentRead;
status: 200;
};
export type heartbeatOrCreateAgentApiV1AgentsHeartbeatPostResponse422 = {
data: HTTPValidationError;
status: 422;
};
export type heartbeatOrCreateAgentApiV1AgentsHeartbeatPostResponseSuccess =
heartbeatOrCreateAgentApiV1AgentsHeartbeatPostResponse200 & {
headers: Headers;
};
export type heartbeatOrCreateAgentApiV1AgentsHeartbeatPostResponseError =
heartbeatOrCreateAgentApiV1AgentsHeartbeatPostResponse422 & {
headers: Headers;
};
export type heartbeatOrCreateAgentApiV1AgentsHeartbeatPostResponse =
| heartbeatOrCreateAgentApiV1AgentsHeartbeatPostResponseSuccess
| heartbeatOrCreateAgentApiV1AgentsHeartbeatPostResponseError;
export const getHeartbeatOrCreateAgentApiV1AgentsHeartbeatPostUrl = () => {
return `/api/v1/agents/heartbeat`;
};
export const heartbeatOrCreateAgentApiV1AgentsHeartbeatPost = async (
agentHeartbeatCreate: AgentHeartbeatCreate,
options?: RequestInit,
): Promise<heartbeatOrCreateAgentApiV1AgentsHeartbeatPostResponse> => {
return customFetch<heartbeatOrCreateAgentApiV1AgentsHeartbeatPostResponse>(
getHeartbeatOrCreateAgentApiV1AgentsHeartbeatPostUrl(),
{
...options,
method: "POST",
headers: { "Content-Type": "application/json", ...options?.headers },
body: JSON.stringify(agentHeartbeatCreate),
},
);
};
export const getHeartbeatOrCreateAgentApiV1AgentsHeartbeatPostMutationOptions =
<TError = HTTPValidationError, TContext = unknown>(options?: {
mutation?: UseMutationOptions<
Awaited<
ReturnType<typeof heartbeatOrCreateAgentApiV1AgentsHeartbeatPost>
>,
TError,
{ data: AgentHeartbeatCreate },
TContext
>;
request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
Awaited<ReturnType<typeof heartbeatOrCreateAgentApiV1AgentsHeartbeatPost>>,
TError,
{ data: AgentHeartbeatCreate },
TContext
> => {
const mutationKey = ["heartbeatOrCreateAgentApiV1AgentsHeartbeatPost"];
const { mutation: mutationOptions, request: requestOptions } = options
? options.mutation &&
"mutationKey" in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey }, request: undefined };
const mutationFn: MutationFunction<
Awaited<
ReturnType<typeof heartbeatOrCreateAgentApiV1AgentsHeartbeatPost>
>,
{ data: AgentHeartbeatCreate }
> = (props) => {
const { data } = props ?? {};
return heartbeatOrCreateAgentApiV1AgentsHeartbeatPost(
data,
requestOptions,
);
};
return { mutationFn, ...mutationOptions };
};
export type HeartbeatOrCreateAgentApiV1AgentsHeartbeatPostMutationResult =
NonNullable<
Awaited<ReturnType<typeof heartbeatOrCreateAgentApiV1AgentsHeartbeatPost>>
>;
export type HeartbeatOrCreateAgentApiV1AgentsHeartbeatPostMutationBody =
AgentHeartbeatCreate;
export type HeartbeatOrCreateAgentApiV1AgentsHeartbeatPostMutationError =
HTTPValidationError;
/**
* @summary Heartbeat Or Create Agent
*/
export const useHeartbeatOrCreateAgentApiV1AgentsHeartbeatPost = <
TError = HTTPValidationError,
TContext = unknown,
>(
options?: {
mutation?: UseMutationOptions<
Awaited<
ReturnType<typeof heartbeatOrCreateAgentApiV1AgentsHeartbeatPost>
>,
TError,
{ data: AgentHeartbeatCreate },
TContext
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseMutationResult<
Awaited<ReturnType<typeof heartbeatOrCreateAgentApiV1AgentsHeartbeatPost>>,
TError,
{ data: AgentHeartbeatCreate },
TContext
> => {
return useMutation(
getHeartbeatOrCreateAgentApiV1AgentsHeartbeatPostMutationOptions(options),
queryClient,
);
};

View File

@@ -801,7 +801,9 @@ export function useStreamBoardGroupMemoryApiV1BoardGroupsGroupIdMemoryStreamGet<
}
/**
* List memory entries for the board's linked group.
* List shared memory for the board's linked group.
Use this for cross-board context and coordination signals.
* @summary List Board Group Memory For Board
*/
export type listBoardGroupMemoryForBoardApiV1BoardsBoardIdGroupMemoryGetResponse200 =
@@ -1123,7 +1125,10 @@ export function useListBoardGroupMemoryForBoardApiV1BoardsBoardIdGroupMemoryGet<
}
/**
* Create a group memory entry from a board context and notify recipients.
* Create shared group memory from a board context.
When tags/mentions indicate chat or broadcast intent, eligible agents in the
linked group are notified.
* @summary Create Board Group Memory For Board
*/
export type createBoardGroupMemoryForBoardApiV1BoardsBoardIdGroupMemoryPostResponse200 =
@@ -1280,7 +1285,7 @@ export const useCreateBoardGroupMemoryForBoardApiV1BoardsBoardIdGroupMemoryPost
);
};
/**
* Stream memory entries for the board's linked group.
* Stream linked-group memory via SSE for near-real-time coordination.
* @summary Stream Board Group Memory For Board
*/
export type streamBoardGroupMemoryForBoardApiV1BoardsBoardIdGroupMemoryStreamGetResponse200 =

View File

@@ -369,6 +369,129 @@ export const useCreateBoardGroupApiV1BoardGroupsPost = <
queryClient,
);
};
/**
* Delete a board group.
* @summary Delete Board Group
*/
export type deleteBoardGroupApiV1BoardGroupsGroupIdDeleteResponse200 = {
data: OkResponse;
status: 200;
};
export type deleteBoardGroupApiV1BoardGroupsGroupIdDeleteResponse422 = {
data: HTTPValidationError;
status: 422;
};
export type deleteBoardGroupApiV1BoardGroupsGroupIdDeleteResponseSuccess =
deleteBoardGroupApiV1BoardGroupsGroupIdDeleteResponse200 & {
headers: Headers;
};
export type deleteBoardGroupApiV1BoardGroupsGroupIdDeleteResponseError =
deleteBoardGroupApiV1BoardGroupsGroupIdDeleteResponse422 & {
headers: Headers;
};
export type deleteBoardGroupApiV1BoardGroupsGroupIdDeleteResponse =
| deleteBoardGroupApiV1BoardGroupsGroupIdDeleteResponseSuccess
| deleteBoardGroupApiV1BoardGroupsGroupIdDeleteResponseError;
export const getDeleteBoardGroupApiV1BoardGroupsGroupIdDeleteUrl = (
groupId: string,
) => {
return `/api/v1/board-groups/${groupId}`;
};
export const deleteBoardGroupApiV1BoardGroupsGroupIdDelete = async (
groupId: string,
options?: RequestInit,
): Promise<deleteBoardGroupApiV1BoardGroupsGroupIdDeleteResponse> => {
return customFetch<deleteBoardGroupApiV1BoardGroupsGroupIdDeleteResponse>(
getDeleteBoardGroupApiV1BoardGroupsGroupIdDeleteUrl(groupId),
{
...options,
method: "DELETE",
},
);
};
export const getDeleteBoardGroupApiV1BoardGroupsGroupIdDeleteMutationOptions = <
TError = HTTPValidationError,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof deleteBoardGroupApiV1BoardGroupsGroupIdDelete>>,
TError,
{ groupId: string },
TContext
>;
request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
Awaited<ReturnType<typeof deleteBoardGroupApiV1BoardGroupsGroupIdDelete>>,
TError,
{ groupId: string },
TContext
> => {
const mutationKey = ["deleteBoardGroupApiV1BoardGroupsGroupIdDelete"];
const { mutation: mutationOptions, request: requestOptions } = options
? options.mutation &&
"mutationKey" in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey }, request: undefined };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof deleteBoardGroupApiV1BoardGroupsGroupIdDelete>>,
{ groupId: string }
> = (props) => {
const { groupId } = props ?? {};
return deleteBoardGroupApiV1BoardGroupsGroupIdDelete(
groupId,
requestOptions,
);
};
return { mutationFn, ...mutationOptions };
};
export type DeleteBoardGroupApiV1BoardGroupsGroupIdDeleteMutationResult =
NonNullable<
Awaited<ReturnType<typeof deleteBoardGroupApiV1BoardGroupsGroupIdDelete>>
>;
export type DeleteBoardGroupApiV1BoardGroupsGroupIdDeleteMutationError =
HTTPValidationError;
/**
* @summary Delete Board Group
*/
export const useDeleteBoardGroupApiV1BoardGroupsGroupIdDelete = <
TError = HTTPValidationError,
TContext = unknown,
>(
options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof deleteBoardGroupApiV1BoardGroupsGroupIdDelete>>,
TError,
{ groupId: string },
TContext
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseMutationResult<
Awaited<ReturnType<typeof deleteBoardGroupApiV1BoardGroupsGroupIdDelete>>,
TError,
{ groupId: string },
TContext
> => {
return useMutation(
getDeleteBoardGroupApiV1BoardGroupsGroupIdDeleteMutationOptions(options),
queryClient,
);
};
/**
* Get a board group by id.
* @summary Get Board Group
@@ -707,69 +830,85 @@ export const useUpdateBoardGroupApiV1BoardGroupsGroupIdPatch = <
);
};
/**
* Delete a board group.
* @summary Delete Board Group
* Apply heartbeat settings to agents in a board group.
* @summary Apply Board Group Heartbeat
*/
export type deleteBoardGroupApiV1BoardGroupsGroupIdDeleteResponse200 = {
data: OkResponse;
export type applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostResponse200 =
{
data: BoardGroupHeartbeatApplyResult;
status: 200;
};
};
export type deleteBoardGroupApiV1BoardGroupsGroupIdDeleteResponse422 = {
export type applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostResponse422 =
{
data: HTTPValidationError;
status: 422;
};
};
export type deleteBoardGroupApiV1BoardGroupsGroupIdDeleteResponseSuccess =
deleteBoardGroupApiV1BoardGroupsGroupIdDeleteResponse200 & {
export type applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostResponseSuccess =
applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostResponse200 & {
headers: Headers;
};
export type deleteBoardGroupApiV1BoardGroupsGroupIdDeleteResponseError =
deleteBoardGroupApiV1BoardGroupsGroupIdDeleteResponse422 & {
export type applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostResponseError =
applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostResponse422 & {
headers: Headers;
};
export type deleteBoardGroupApiV1BoardGroupsGroupIdDeleteResponse =
| deleteBoardGroupApiV1BoardGroupsGroupIdDeleteResponseSuccess
| deleteBoardGroupApiV1BoardGroupsGroupIdDeleteResponseError;
export type applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostResponse =
export const getDeleteBoardGroupApiV1BoardGroupsGroupIdDeleteUrl = (
groupId: string,
) => {
return `/api/v1/board-groups/${groupId}`;
};
| applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostResponseSuccess
| applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostResponseError;
export const deleteBoardGroupApiV1BoardGroupsGroupIdDelete = async (
export const getApplyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostUrl =
(groupId: string) => {
return `/api/v1/board-groups/${groupId}/heartbeat`;
};
export const applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPost =
async (
groupId: string,
boardGroupHeartbeatApply: BoardGroupHeartbeatApply,
options?: RequestInit,
): Promise<deleteBoardGroupApiV1BoardGroupsGroupIdDeleteResponse> => {
return customFetch<deleteBoardGroupApiV1BoardGroupsGroupIdDeleteResponse>(
getDeleteBoardGroupApiV1BoardGroupsGroupIdDeleteUrl(groupId),
): Promise<applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostResponse> => {
return customFetch<applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostResponse>(
getApplyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostUrl(
groupId,
),
{
...options,
method: "DELETE",
method: "POST",
headers: { "Content-Type": "application/json", ...options?.headers },
body: JSON.stringify(boardGroupHeartbeatApply),
},
);
};
};
export const getDeleteBoardGroupApiV1BoardGroupsGroupIdDeleteMutationOptions = <
TError = HTTPValidationError,
TContext = unknown,
>(options?: {
export const getApplyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostMutationOptions =
<TError = HTTPValidationError, TContext = unknown>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof deleteBoardGroupApiV1BoardGroupsGroupIdDelete>>,
Awaited<
ReturnType<
typeof applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPost
>
>,
TError,
{ groupId: string },
{ groupId: string; data: BoardGroupHeartbeatApply },
TContext
>;
request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
Awaited<ReturnType<typeof deleteBoardGroupApiV1BoardGroupsGroupIdDelete>>,
}): UseMutationOptions<
Awaited<
ReturnType<
typeof applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPost
>
>,
TError,
{ groupId: string },
{ groupId: string; data: BoardGroupHeartbeatApply },
TContext
> => {
const mutationKey = ["deleteBoardGroupApiV1BoardGroupsGroupIdDelete"];
> => {
const mutationKey = [
"applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPost",
];
const { mutation: mutationOptions, request: requestOptions } = options
? options.mutation &&
"mutationKey" in options.mutation &&
@@ -779,53 +918,73 @@ export const getDeleteBoardGroupApiV1BoardGroupsGroupIdDeleteMutationOptions = <
: { mutation: { mutationKey }, request: undefined };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof deleteBoardGroupApiV1BoardGroupsGroupIdDelete>>,
{ groupId: string }
Awaited<
ReturnType<
typeof applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPost
>
>,
{ groupId: string; data: BoardGroupHeartbeatApply }
> = (props) => {
const { groupId } = props ?? {};
const { groupId, data } = props ?? {};
return deleteBoardGroupApiV1BoardGroupsGroupIdDelete(
return applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPost(
groupId,
data,
requestOptions,
);
};
return { mutationFn, ...mutationOptions };
};
};
export type DeleteBoardGroupApiV1BoardGroupsGroupIdDeleteMutationResult =
export type ApplyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostMutationResult =
NonNullable<
Awaited<ReturnType<typeof deleteBoardGroupApiV1BoardGroupsGroupIdDelete>>
Awaited<
ReturnType<
typeof applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPost
>
>
>;
export type DeleteBoardGroupApiV1BoardGroupsGroupIdDeleteMutationError =
export type ApplyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostMutationBody =
BoardGroupHeartbeatApply;
export type ApplyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostMutationError =
HTTPValidationError;
/**
* @summary Delete Board Group
* @summary Apply Board Group Heartbeat
*/
export const useDeleteBoardGroupApiV1BoardGroupsGroupIdDelete = <
export const useApplyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPost = <
TError = HTTPValidationError,
TContext = unknown,
>(
options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof deleteBoardGroupApiV1BoardGroupsGroupIdDelete>>,
Awaited<
ReturnType<
typeof applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPost
>
>,
TError,
{ groupId: string },
{ groupId: string; data: BoardGroupHeartbeatApply },
TContext
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseMutationResult<
Awaited<ReturnType<typeof deleteBoardGroupApiV1BoardGroupsGroupIdDelete>>,
Awaited<
ReturnType<
typeof applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPost
>
>,
TError,
{ groupId: string },
{ groupId: string; data: BoardGroupHeartbeatApply },
TContext
> => {
return useMutation(
getDeleteBoardGroupApiV1BoardGroupsGroupIdDeleteMutationOptions(options),
getApplyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostMutationOptions(
options,
),
queryClient,
);
};
@@ -1131,163 +1290,3 @@ export function useGetBoardGroupSnapshotApiV1BoardGroupsGroupIdSnapshotGet<
return { ...query, queryKey: queryOptions.queryKey };
}
/**
* Apply heartbeat settings to agents in a board group.
* @summary Apply Board Group Heartbeat
*/
export type applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostResponse200 =
{
data: BoardGroupHeartbeatApplyResult;
status: 200;
};
export type applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostResponse422 =
{
data: HTTPValidationError;
status: 422;
};
export type applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostResponseSuccess =
applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostResponse200 & {
headers: Headers;
};
export type applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostResponseError =
applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostResponse422 & {
headers: Headers;
};
export type applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostResponse =
| applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostResponseSuccess
| applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostResponseError;
export const getApplyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostUrl =
(groupId: string) => {
return `/api/v1/board-groups/${groupId}/heartbeat`;
};
export const applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPost =
async (
groupId: string,
boardGroupHeartbeatApply: BoardGroupHeartbeatApply,
options?: RequestInit,
): Promise<applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostResponse> => {
return customFetch<applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostResponse>(
getApplyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostUrl(
groupId,
),
{
...options,
method: "POST",
headers: { "Content-Type": "application/json", ...options?.headers },
body: JSON.stringify(boardGroupHeartbeatApply),
},
);
};
export const getApplyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostMutationOptions =
<TError = HTTPValidationError, TContext = unknown>(options?: {
mutation?: UseMutationOptions<
Awaited<
ReturnType<
typeof applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPost
>
>,
TError,
{ groupId: string; data: BoardGroupHeartbeatApply },
TContext
>;
request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
Awaited<
ReturnType<
typeof applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPost
>
>,
TError,
{ groupId: string; data: BoardGroupHeartbeatApply },
TContext
> => {
const mutationKey = [
"applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPost",
];
const { mutation: mutationOptions, request: requestOptions } = options
? options.mutation &&
"mutationKey" in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey }, request: undefined };
const mutationFn: MutationFunction<
Awaited<
ReturnType<
typeof applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPost
>
>,
{ groupId: string; data: BoardGroupHeartbeatApply }
> = (props) => {
const { groupId, data } = props ?? {};
return applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPost(
groupId,
data,
requestOptions,
);
};
return { mutationFn, ...mutationOptions };
};
export type ApplyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostMutationResult =
NonNullable<
Awaited<
ReturnType<
typeof applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPost
>
>
>;
export type ApplyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostMutationBody =
BoardGroupHeartbeatApply;
export type ApplyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostMutationError =
HTTPValidationError;
/**
* @summary Apply Board Group Heartbeat
*/
export const useApplyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPost = <
TError = HTTPValidationError,
TContext = unknown,
>(
options?: {
mutation?: UseMutationOptions<
Awaited<
ReturnType<
typeof applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPost
>
>,
TError,
{ groupId: string; data: BoardGroupHeartbeatApply },
TContext
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseMutationResult<
Awaited<
ReturnType<
typeof applyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPost
>
>,
TError,
{ groupId: string; data: BoardGroupHeartbeatApply },
TContext
> => {
return useMutation(
getApplyBoardGroupHeartbeatApiV1BoardGroupsGroupIdHeartbeatPostMutationOptions(
options,
),
queryClient,
);
};

View File

@@ -274,298 +274,6 @@ export function useGetOnboardingApiV1BoardsBoardIdOnboardingGet<
return { ...query, queryKey: queryOptions.queryKey };
}
/**
* Start onboarding and send instructions to the gateway agent.
* @summary Start Onboarding
*/
export type startOnboardingApiV1BoardsBoardIdOnboardingStartPostResponse200 = {
data: BoardOnboardingRead;
status: 200;
};
export type startOnboardingApiV1BoardsBoardIdOnboardingStartPostResponse422 = {
data: HTTPValidationError;
status: 422;
};
export type startOnboardingApiV1BoardsBoardIdOnboardingStartPostResponseSuccess =
startOnboardingApiV1BoardsBoardIdOnboardingStartPostResponse200 & {
headers: Headers;
};
export type startOnboardingApiV1BoardsBoardIdOnboardingStartPostResponseError =
startOnboardingApiV1BoardsBoardIdOnboardingStartPostResponse422 & {
headers: Headers;
};
export type startOnboardingApiV1BoardsBoardIdOnboardingStartPostResponse =
| startOnboardingApiV1BoardsBoardIdOnboardingStartPostResponseSuccess
| startOnboardingApiV1BoardsBoardIdOnboardingStartPostResponseError;
export const getStartOnboardingApiV1BoardsBoardIdOnboardingStartPostUrl = (
boardId: string,
) => {
return `/api/v1/boards/${boardId}/onboarding/start`;
};
export const startOnboardingApiV1BoardsBoardIdOnboardingStartPost = async (
boardId: string,
boardOnboardingStart: BoardOnboardingStart,
options?: RequestInit,
): Promise<startOnboardingApiV1BoardsBoardIdOnboardingStartPostResponse> => {
return customFetch<startOnboardingApiV1BoardsBoardIdOnboardingStartPostResponse>(
getStartOnboardingApiV1BoardsBoardIdOnboardingStartPostUrl(boardId),
{
...options,
method: "POST",
headers: { "Content-Type": "application/json", ...options?.headers },
body: JSON.stringify(boardOnboardingStart),
},
);
};
export const getStartOnboardingApiV1BoardsBoardIdOnboardingStartPostMutationOptions =
<TError = HTTPValidationError, TContext = unknown>(options?: {
mutation?: UseMutationOptions<
Awaited<
ReturnType<typeof startOnboardingApiV1BoardsBoardIdOnboardingStartPost>
>,
TError,
{ boardId: string; data: BoardOnboardingStart },
TContext
>;
request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
Awaited<
ReturnType<typeof startOnboardingApiV1BoardsBoardIdOnboardingStartPost>
>,
TError,
{ boardId: string; data: BoardOnboardingStart },
TContext
> => {
const mutationKey = [
"startOnboardingApiV1BoardsBoardIdOnboardingStartPost",
];
const { mutation: mutationOptions, request: requestOptions } = options
? options.mutation &&
"mutationKey" in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey }, request: undefined };
const mutationFn: MutationFunction<
Awaited<
ReturnType<typeof startOnboardingApiV1BoardsBoardIdOnboardingStartPost>
>,
{ boardId: string; data: BoardOnboardingStart }
> = (props) => {
const { boardId, data } = props ?? {};
return startOnboardingApiV1BoardsBoardIdOnboardingStartPost(
boardId,
data,
requestOptions,
);
};
return { mutationFn, ...mutationOptions };
};
export type StartOnboardingApiV1BoardsBoardIdOnboardingStartPostMutationResult =
NonNullable<
Awaited<
ReturnType<typeof startOnboardingApiV1BoardsBoardIdOnboardingStartPost>
>
>;
export type StartOnboardingApiV1BoardsBoardIdOnboardingStartPostMutationBody =
BoardOnboardingStart;
export type StartOnboardingApiV1BoardsBoardIdOnboardingStartPostMutationError =
HTTPValidationError;
/**
* @summary Start Onboarding
*/
export const useStartOnboardingApiV1BoardsBoardIdOnboardingStartPost = <
TError = HTTPValidationError,
TContext = unknown,
>(
options?: {
mutation?: UseMutationOptions<
Awaited<
ReturnType<typeof startOnboardingApiV1BoardsBoardIdOnboardingStartPost>
>,
TError,
{ boardId: string; data: BoardOnboardingStart },
TContext
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseMutationResult<
Awaited<
ReturnType<typeof startOnboardingApiV1BoardsBoardIdOnboardingStartPost>
>,
TError,
{ boardId: string; data: BoardOnboardingStart },
TContext
> => {
return useMutation(
getStartOnboardingApiV1BoardsBoardIdOnboardingStartPostMutationOptions(
options,
),
queryClient,
);
};
/**
* Send a user onboarding answer to the gateway agent.
* @summary Answer Onboarding
*/
export type answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostResponse200 =
{
data: BoardOnboardingRead;
status: 200;
};
export type answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostResponse422 =
{
data: HTTPValidationError;
status: 422;
};
export type answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostResponseSuccess =
answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostResponse200 & {
headers: Headers;
};
export type answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostResponseError =
answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostResponse422 & {
headers: Headers;
};
export type answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostResponse =
| answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostResponseSuccess
| answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostResponseError;
export const getAnswerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostUrl = (
boardId: string,
) => {
return `/api/v1/boards/${boardId}/onboarding/answer`;
};
export const answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPost = async (
boardId: string,
boardOnboardingAnswer: BoardOnboardingAnswer,
options?: RequestInit,
): Promise<answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostResponse> => {
return customFetch<answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostResponse>(
getAnswerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostUrl(boardId),
{
...options,
method: "POST",
headers: { "Content-Type": "application/json", ...options?.headers },
body: JSON.stringify(boardOnboardingAnswer),
},
);
};
export const getAnswerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostMutationOptions =
<TError = HTTPValidationError, TContext = unknown>(options?: {
mutation?: UseMutationOptions<
Awaited<
ReturnType<
typeof answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPost
>
>,
TError,
{ boardId: string; data: BoardOnboardingAnswer },
TContext
>;
request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
Awaited<
ReturnType<typeof answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPost>
>,
TError,
{ boardId: string; data: BoardOnboardingAnswer },
TContext
> => {
const mutationKey = [
"answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPost",
];
const { mutation: mutationOptions, request: requestOptions } = options
? options.mutation &&
"mutationKey" in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey }, request: undefined };
const mutationFn: MutationFunction<
Awaited<
ReturnType<
typeof answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPost
>
>,
{ boardId: string; data: BoardOnboardingAnswer }
> = (props) => {
const { boardId, data } = props ?? {};
return answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPost(
boardId,
data,
requestOptions,
);
};
return { mutationFn, ...mutationOptions };
};
export type AnswerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostMutationResult =
NonNullable<
Awaited<
ReturnType<typeof answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPost>
>
>;
export type AnswerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostMutationBody =
BoardOnboardingAnswer;
export type AnswerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostMutationError =
HTTPValidationError;
/**
* @summary Answer Onboarding
*/
export const useAnswerOnboardingApiV1BoardsBoardIdOnboardingAnswerPost = <
TError = HTTPValidationError,
TContext = unknown,
>(
options?: {
mutation?: UseMutationOptions<
Awaited<
ReturnType<
typeof answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPost
>
>,
TError,
{ boardId: string; data: BoardOnboardingAnswer },
TContext
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseMutationResult<
Awaited<
ReturnType<typeof answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPost>
>,
TError,
{ boardId: string; data: BoardOnboardingAnswer },
TContext
> => {
return useMutation(
getAnswerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostMutationOptions(
options,
),
queryClient,
);
};
/**
* Store onboarding updates submitted by the gateway agent.
* @summary Agent Onboarding Update
@@ -741,6 +449,156 @@ export const useAgentOnboardingUpdateApiV1BoardsBoardIdOnboardingAgentPost = <
queryClient,
);
};
/**
* Send a user onboarding answer to the gateway agent.
* @summary Answer Onboarding
*/
export type answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostResponse200 =
{
data: BoardOnboardingRead;
status: 200;
};
export type answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostResponse422 =
{
data: HTTPValidationError;
status: 422;
};
export type answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostResponseSuccess =
answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostResponse200 & {
headers: Headers;
};
export type answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostResponseError =
answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostResponse422 & {
headers: Headers;
};
export type answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostResponse =
| answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostResponseSuccess
| answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostResponseError;
export const getAnswerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostUrl = (
boardId: string,
) => {
return `/api/v1/boards/${boardId}/onboarding/answer`;
};
export const answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPost = async (
boardId: string,
boardOnboardingAnswer: BoardOnboardingAnswer,
options?: RequestInit,
): Promise<answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostResponse> => {
return customFetch<answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostResponse>(
getAnswerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostUrl(boardId),
{
...options,
method: "POST",
headers: { "Content-Type": "application/json", ...options?.headers },
body: JSON.stringify(boardOnboardingAnswer),
},
);
};
export const getAnswerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostMutationOptions =
<TError = HTTPValidationError, TContext = unknown>(options?: {
mutation?: UseMutationOptions<
Awaited<
ReturnType<
typeof answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPost
>
>,
TError,
{ boardId: string; data: BoardOnboardingAnswer },
TContext
>;
request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
Awaited<
ReturnType<typeof answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPost>
>,
TError,
{ boardId: string; data: BoardOnboardingAnswer },
TContext
> => {
const mutationKey = [
"answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPost",
];
const { mutation: mutationOptions, request: requestOptions } = options
? options.mutation &&
"mutationKey" in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey }, request: undefined };
const mutationFn: MutationFunction<
Awaited<
ReturnType<
typeof answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPost
>
>,
{ boardId: string; data: BoardOnboardingAnswer }
> = (props) => {
const { boardId, data } = props ?? {};
return answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPost(
boardId,
data,
requestOptions,
);
};
return { mutationFn, ...mutationOptions };
};
export type AnswerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostMutationResult =
NonNullable<
Awaited<
ReturnType<typeof answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPost>
>
>;
export type AnswerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostMutationBody =
BoardOnboardingAnswer;
export type AnswerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostMutationError =
HTTPValidationError;
/**
* @summary Answer Onboarding
*/
export const useAnswerOnboardingApiV1BoardsBoardIdOnboardingAnswerPost = <
TError = HTTPValidationError,
TContext = unknown,
>(
options?: {
mutation?: UseMutationOptions<
Awaited<
ReturnType<
typeof answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPost
>
>,
TError,
{ boardId: string; data: BoardOnboardingAnswer },
TContext
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseMutationResult<
Awaited<
ReturnType<typeof answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPost>
>,
TError,
{ boardId: string; data: BoardOnboardingAnswer },
TContext
> => {
return useMutation(
getAnswerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostMutationOptions(
options,
),
queryClient,
);
};
/**
* Confirm onboarding results and provision the board lead agent.
* @summary Confirm Onboarding
@@ -895,3 +753,145 @@ export const useConfirmOnboardingApiV1BoardsBoardIdOnboardingConfirmPost = <
queryClient,
);
};
/**
* Start onboarding and send instructions to the gateway agent.
* @summary Start Onboarding
*/
export type startOnboardingApiV1BoardsBoardIdOnboardingStartPostResponse200 = {
data: BoardOnboardingRead;
status: 200;
};
export type startOnboardingApiV1BoardsBoardIdOnboardingStartPostResponse422 = {
data: HTTPValidationError;
status: 422;
};
export type startOnboardingApiV1BoardsBoardIdOnboardingStartPostResponseSuccess =
startOnboardingApiV1BoardsBoardIdOnboardingStartPostResponse200 & {
headers: Headers;
};
export type startOnboardingApiV1BoardsBoardIdOnboardingStartPostResponseError =
startOnboardingApiV1BoardsBoardIdOnboardingStartPostResponse422 & {
headers: Headers;
};
export type startOnboardingApiV1BoardsBoardIdOnboardingStartPostResponse =
| startOnboardingApiV1BoardsBoardIdOnboardingStartPostResponseSuccess
| startOnboardingApiV1BoardsBoardIdOnboardingStartPostResponseError;
export const getStartOnboardingApiV1BoardsBoardIdOnboardingStartPostUrl = (
boardId: string,
) => {
return `/api/v1/boards/${boardId}/onboarding/start`;
};
export const startOnboardingApiV1BoardsBoardIdOnboardingStartPost = async (
boardId: string,
boardOnboardingStart: BoardOnboardingStart,
options?: RequestInit,
): Promise<startOnboardingApiV1BoardsBoardIdOnboardingStartPostResponse> => {
return customFetch<startOnboardingApiV1BoardsBoardIdOnboardingStartPostResponse>(
getStartOnboardingApiV1BoardsBoardIdOnboardingStartPostUrl(boardId),
{
...options,
method: "POST",
headers: { "Content-Type": "application/json", ...options?.headers },
body: JSON.stringify(boardOnboardingStart),
},
);
};
export const getStartOnboardingApiV1BoardsBoardIdOnboardingStartPostMutationOptions =
<TError = HTTPValidationError, TContext = unknown>(options?: {
mutation?: UseMutationOptions<
Awaited<
ReturnType<typeof startOnboardingApiV1BoardsBoardIdOnboardingStartPost>
>,
TError,
{ boardId: string; data: BoardOnboardingStart },
TContext
>;
request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
Awaited<
ReturnType<typeof startOnboardingApiV1BoardsBoardIdOnboardingStartPost>
>,
TError,
{ boardId: string; data: BoardOnboardingStart },
TContext
> => {
const mutationKey = [
"startOnboardingApiV1BoardsBoardIdOnboardingStartPost",
];
const { mutation: mutationOptions, request: requestOptions } = options
? options.mutation &&
"mutationKey" in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey }, request: undefined };
const mutationFn: MutationFunction<
Awaited<
ReturnType<typeof startOnboardingApiV1BoardsBoardIdOnboardingStartPost>
>,
{ boardId: string; data: BoardOnboardingStart }
> = (props) => {
const { boardId, data } = props ?? {};
return startOnboardingApiV1BoardsBoardIdOnboardingStartPost(
boardId,
data,
requestOptions,
);
};
return { mutationFn, ...mutationOptions };
};
export type StartOnboardingApiV1BoardsBoardIdOnboardingStartPostMutationResult =
NonNullable<
Awaited<
ReturnType<typeof startOnboardingApiV1BoardsBoardIdOnboardingStartPost>
>
>;
export type StartOnboardingApiV1BoardsBoardIdOnboardingStartPostMutationBody =
BoardOnboardingStart;
export type StartOnboardingApiV1BoardsBoardIdOnboardingStartPostMutationError =
HTTPValidationError;
/**
* @summary Start Onboarding
*/
export const useStartOnboardingApiV1BoardsBoardIdOnboardingStartPost = <
TError = HTTPValidationError,
TContext = unknown,
>(
options?: {
mutation?: UseMutationOptions<
Awaited<
ReturnType<typeof startOnboardingApiV1BoardsBoardIdOnboardingStartPost>
>,
TError,
{ boardId: string; data: BoardOnboardingStart },
TContext
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseMutationResult<
Awaited<
ReturnType<typeof startOnboardingApiV1BoardsBoardIdOnboardingStartPost>
>,
TError,
{ boardId: string; data: BoardOnboardingStart },
TContext
> => {
return useMutation(
getStartOnboardingApiV1BoardsBoardIdOnboardingStartPostMutationOptions(
options,
),
queryClient,
);
};

View File

@@ -363,6 +363,123 @@ export const useCreateBoardApiV1BoardsPost = <
queryClient,
);
};
/**
* Delete a board and all dependent records.
* @summary Delete Board
*/
export type deleteBoardApiV1BoardsBoardIdDeleteResponse200 = {
data: OkResponse;
status: 200;
};
export type deleteBoardApiV1BoardsBoardIdDeleteResponse422 = {
data: HTTPValidationError;
status: 422;
};
export type deleteBoardApiV1BoardsBoardIdDeleteResponseSuccess =
deleteBoardApiV1BoardsBoardIdDeleteResponse200 & {
headers: Headers;
};
export type deleteBoardApiV1BoardsBoardIdDeleteResponseError =
deleteBoardApiV1BoardsBoardIdDeleteResponse422 & {
headers: Headers;
};
export type deleteBoardApiV1BoardsBoardIdDeleteResponse =
| deleteBoardApiV1BoardsBoardIdDeleteResponseSuccess
| deleteBoardApiV1BoardsBoardIdDeleteResponseError;
export const getDeleteBoardApiV1BoardsBoardIdDeleteUrl = (boardId: string) => {
return `/api/v1/boards/${boardId}`;
};
export const deleteBoardApiV1BoardsBoardIdDelete = async (
boardId: string,
options?: RequestInit,
): Promise<deleteBoardApiV1BoardsBoardIdDeleteResponse> => {
return customFetch<deleteBoardApiV1BoardsBoardIdDeleteResponse>(
getDeleteBoardApiV1BoardsBoardIdDeleteUrl(boardId),
{
...options,
method: "DELETE",
},
);
};
export const getDeleteBoardApiV1BoardsBoardIdDeleteMutationOptions = <
TError = HTTPValidationError,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof deleteBoardApiV1BoardsBoardIdDelete>>,
TError,
{ boardId: string },
TContext
>;
request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
Awaited<ReturnType<typeof deleteBoardApiV1BoardsBoardIdDelete>>,
TError,
{ boardId: string },
TContext
> => {
const mutationKey = ["deleteBoardApiV1BoardsBoardIdDelete"];
const { mutation: mutationOptions, request: requestOptions } = options
? options.mutation &&
"mutationKey" in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey }, request: undefined };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof deleteBoardApiV1BoardsBoardIdDelete>>,
{ boardId: string }
> = (props) => {
const { boardId } = props ?? {};
return deleteBoardApiV1BoardsBoardIdDelete(boardId, requestOptions);
};
return { mutationFn, ...mutationOptions };
};
export type DeleteBoardApiV1BoardsBoardIdDeleteMutationResult = NonNullable<
Awaited<ReturnType<typeof deleteBoardApiV1BoardsBoardIdDelete>>
>;
export type DeleteBoardApiV1BoardsBoardIdDeleteMutationError =
HTTPValidationError;
/**
* @summary Delete Board
*/
export const useDeleteBoardApiV1BoardsBoardIdDelete = <
TError = HTTPValidationError,
TContext = unknown,
>(
options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof deleteBoardApiV1BoardsBoardIdDelete>>,
TError,
{ boardId: string },
TContext
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseMutationResult<
Awaited<ReturnType<typeof deleteBoardApiV1BoardsBoardIdDelete>>,
TError,
{ boardId: string },
TContext
> => {
return useMutation(
getDeleteBoardApiV1BoardsBoardIdDeleteMutationOptions(options),
queryClient,
);
};
/**
* Get a board by id.
* @summary Get Board
@@ -683,364 +800,10 @@ export const useUpdateBoardApiV1BoardsBoardIdPatch = <
queryClient,
);
};
/**
* Delete a board and all dependent records.
* @summary Delete Board
*/
export type deleteBoardApiV1BoardsBoardIdDeleteResponse200 = {
data: OkResponse;
status: 200;
};
export type deleteBoardApiV1BoardsBoardIdDeleteResponse422 = {
data: HTTPValidationError;
status: 422;
};
export type deleteBoardApiV1BoardsBoardIdDeleteResponseSuccess =
deleteBoardApiV1BoardsBoardIdDeleteResponse200 & {
headers: Headers;
};
export type deleteBoardApiV1BoardsBoardIdDeleteResponseError =
deleteBoardApiV1BoardsBoardIdDeleteResponse422 & {
headers: Headers;
};
export type deleteBoardApiV1BoardsBoardIdDeleteResponse =
| deleteBoardApiV1BoardsBoardIdDeleteResponseSuccess
| deleteBoardApiV1BoardsBoardIdDeleteResponseError;
export const getDeleteBoardApiV1BoardsBoardIdDeleteUrl = (boardId: string) => {
return `/api/v1/boards/${boardId}`;
};
export const deleteBoardApiV1BoardsBoardIdDelete = async (
boardId: string,
options?: RequestInit,
): Promise<deleteBoardApiV1BoardsBoardIdDeleteResponse> => {
return customFetch<deleteBoardApiV1BoardsBoardIdDeleteResponse>(
getDeleteBoardApiV1BoardsBoardIdDeleteUrl(boardId),
{
...options,
method: "DELETE",
},
);
};
export const getDeleteBoardApiV1BoardsBoardIdDeleteMutationOptions = <
TError = HTTPValidationError,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof deleteBoardApiV1BoardsBoardIdDelete>>,
TError,
{ boardId: string },
TContext
>;
request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
Awaited<ReturnType<typeof deleteBoardApiV1BoardsBoardIdDelete>>,
TError,
{ boardId: string },
TContext
> => {
const mutationKey = ["deleteBoardApiV1BoardsBoardIdDelete"];
const { mutation: mutationOptions, request: requestOptions } = options
? options.mutation &&
"mutationKey" in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey }, request: undefined };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof deleteBoardApiV1BoardsBoardIdDelete>>,
{ boardId: string }
> = (props) => {
const { boardId } = props ?? {};
return deleteBoardApiV1BoardsBoardIdDelete(boardId, requestOptions);
};
return { mutationFn, ...mutationOptions };
};
export type DeleteBoardApiV1BoardsBoardIdDeleteMutationResult = NonNullable<
Awaited<ReturnType<typeof deleteBoardApiV1BoardsBoardIdDelete>>
>;
export type DeleteBoardApiV1BoardsBoardIdDeleteMutationError =
HTTPValidationError;
/**
* @summary Delete Board
*/
export const useDeleteBoardApiV1BoardsBoardIdDelete = <
TError = HTTPValidationError,
TContext = unknown,
>(
options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof deleteBoardApiV1BoardsBoardIdDelete>>,
TError,
{ boardId: string },
TContext
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseMutationResult<
Awaited<ReturnType<typeof deleteBoardApiV1BoardsBoardIdDelete>>,
TError,
{ boardId: string },
TContext
> => {
return useMutation(
getDeleteBoardApiV1BoardsBoardIdDeleteMutationOptions(options),
queryClient,
);
};
/**
* Get a board snapshot view model.
* @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 };
}
/**
* Get a grouped snapshot across related boards.
Returns high-signal cross-board status for dependency and overlap checks.
* @summary Get Board Group Snapshot
*/
export type getBoardGroupSnapshotApiV1BoardsBoardIdGroupSnapshotGetResponse200 =
@@ -1341,3 +1104,242 @@ export function useGetBoardGroupSnapshotApiV1BoardsBoardIdGroupSnapshotGet<
return { ...query, queryKey: queryOptions.queryKey };
}
/**
* Get a board snapshot view model.
* @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 };
}

File diff suppressed because it is too large Load Diff

View File

@@ -9,10 +9,10 @@
* Serialized activity event payload returned by activity endpoints.
*/
export interface ActivityEventRead {
id: string;
event_type: string;
message: string | null;
agent_id: string | null;
task_id: string | null;
created_at: string;
event_type: string;
id: string;
message: string | null;
task_id: string | null;
}

View File

@@ -9,14 +9,14 @@
* Denormalized task-comment feed item enriched with task and board fields.
*/
export interface ActivityTaskCommentFeedItemRead {
id: string;
created_at: string;
message: string | null;
agent_id: string | null;
agent_name?: string | null;
agent_role?: string | null;
task_id: string;
task_title: string;
board_id: string;
board_name: string;
created_at: string;
id: string;
message: string | null;
task_id: string;
task_title: string;
}

View File

@@ -12,11 +12,11 @@ import type { AgentCreateIdentityProfile } from "./agentCreateIdentityProfile";
*/
export interface AgentCreate {
board_id?: string | null;
/** @minLength 1 */
name: string;
status?: string;
heartbeat_config?: AgentCreateHeartbeatConfig;
identity_profile?: AgentCreateIdentityProfile;
identity_template?: string | null;
/** @minLength 1 */
name: string;
soul_template?: string | null;
status?: string;
}

View File

@@ -9,8 +9,8 @@
* Heartbeat payload used to create an agent lazily.
*/
export interface AgentHeartbeatCreate {
status?: string | null;
board_id?: string | null;
/** @minLength 1 */
name: string;
board_id?: string | null;
status?: string | null;
}

View File

@@ -12,19 +12,19 @@ import type { AgentReadIdentityProfile } from "./agentReadIdentityProfile";
*/
export interface AgentRead {
board_id?: string | null;
/** @minLength 1 */
name: string;
status?: string;
created_at: string;
gateway_id: string;
heartbeat_config?: AgentReadHeartbeatConfig;
id: string;
identity_profile?: AgentReadIdentityProfile;
identity_template?: string | null;
soul_template?: string | null;
id: string;
gateway_id: string;
is_board_lead?: boolean;
is_gateway_main?: boolean;
openclaw_session_id?: string | null;
last_seen_at: string | null;
created_at: string;
/** @minLength 1 */
name: string;
openclaw_session_id?: string | null;
soul_template?: string | null;
status?: string;
updated_at: string;
}

View File

@@ -12,11 +12,11 @@ import type { AgentUpdateIdentityProfile } from "./agentUpdateIdentityProfile";
*/
export interface AgentUpdate {
board_id?: string | null;
is_gateway_main?: boolean | null;
name?: string | null;
status?: string | null;
heartbeat_config?: AgentUpdateHeartbeatConfig;
identity_profile?: AgentUpdateIdentityProfile;
identity_template?: string | null;
is_gateway_main?: boolean | null;
name?: string | null;
soul_template?: string | null;
status?: string | null;
}

View File

@@ -13,15 +13,15 @@ import type { ApprovalCreateStatus } from "./approvalCreateStatus";
*/
export interface ApprovalCreate {
action_type: string;
task_id?: string | null;
task_ids?: string[];
payload?: ApprovalCreatePayload;
agent_id?: string | null;
/**
* @minimum 0
* @maximum 100
*/
confidence: number;
payload?: ApprovalCreatePayload;
rubric_scores?: ApprovalCreateRubricScores;
status?: ApprovalCreateStatus;
agent_id?: string | null;
task_id?: string | null;
task_ids?: string[];
}

View File

@@ -13,20 +13,20 @@ import type { ApprovalReadStatus } from "./approvalReadStatus";
*/
export interface ApprovalRead {
action_type: string;
task_id?: string | null;
task_ids?: string[];
payload?: ApprovalReadPayload;
agent_id?: string | null;
board_id: string;
/**
* @minimum 0
* @maximum 100
*/
confidence: number;
created_at: string;
id: string;
payload?: ApprovalReadPayload;
resolved_at?: string | null;
rubric_scores?: ApprovalReadRubricScores;
status?: ApprovalReadStatus;
id: string;
board_id: string;
task_id?: string | null;
task_ids?: string[];
task_titles?: string[];
agent_id?: string | null;
created_at: string;
resolved_at?: string | null;
}

View File

@@ -9,6 +9,6 @@
* Error detail payload listing blocking dependency task identifiers.
*/
export interface BlockedTaskDetail {
message: string;
blocked_by_task_ids?: string[];
message: string;
}

View File

@@ -10,18 +10,19 @@ import type { BoardCreateSuccessMetrics } from "./boardCreateSuccessMetrics";
* Payload for creating a board.
*/
export interface BoardCreate {
name: string;
slug: string;
description: string;
gateway_id?: string | null;
block_status_changes_with_pending_approval?: boolean;
board_group_id?: string | null;
board_type?: string;
objective?: string | null;
success_metrics?: BoardCreateSuccessMetrics;
target_date?: string | null;
description: string;
gateway_id?: string | null;
goal_confirmed?: boolean;
goal_source?: string | null;
name: string;
objective?: string | null;
only_lead_can_change_status?: boolean;
require_approval_for_done?: boolean;
require_review_before_done?: boolean;
block_status_changes_with_pending_approval?: boolean;
slug: string;
success_metrics?: BoardCreateSuccessMetrics;
target_date?: string | null;
}

View File

@@ -9,7 +9,7 @@
* Payload for creating a board group.
*/
export interface BoardGroupCreate {
description?: string | null;
name: string;
slug: string;
description?: string | null;
}

View File

@@ -10,6 +10,6 @@
*/
export interface BoardGroupHeartbeatApply {
every: string;
target?: string | null;
include_board_leads?: boolean;
target?: string | null;
}

View File

@@ -11,7 +11,7 @@ import type { BoardGroupHeartbeatApplyResultRequested } from "./boardGroupHeartb
*/
export interface BoardGroupHeartbeatApplyResult {
board_group_id: string;
failed_agent_ids: string[];
requested: BoardGroupHeartbeatApplyResultRequested;
updated_agent_ids: string[];
failed_agent_ids: string[];
}

View File

@@ -11,6 +11,6 @@
export interface BoardGroupMemoryCreate {
/** @minLength 1 */
content: string;
tags?: string[] | null;
source?: string | null;
tags?: string[] | null;
}

View File

@@ -9,11 +9,11 @@
* Serialized board-group memory entry returned from read endpoints.
*/
export interface BoardGroupMemoryRead {
id: string;
board_group_id: string;
content: string;
tags?: string[] | null;
source?: string | null;
is_chat?: boolean;
created_at: string;
id: string;
is_chat?: boolean;
source?: string | null;
tags?: string[] | null;
}

View File

@@ -9,11 +9,11 @@
* Board-group payload returned from read endpoints.
*/
export interface BoardGroupRead {
name: string;
slug: string;
created_at: string;
description?: string | null;
id: string;
name: string;
organization_id: string;
created_at: string;
slug: string;
updated_at: string;
}

View File

@@ -11,6 +11,6 @@ import type { BoardGroupRead } from "./boardGroupRead";
* Top-level board-group snapshot response payload.
*/
export interface BoardGroupSnapshot {
group?: BoardGroupRead | null;
boards?: BoardGroupBoardSnapshot[];
group?: BoardGroupRead | null;
}

View File

@@ -10,17 +10,17 @@ import type { TagRef } from "./tagRef";
* Task summary row used inside board-group snapshot responses.
*/
export interface BoardGroupTaskSummary {
id: string;
board_id: string;
board_name: string;
title: string;
status: string;
priority: string;
assigned_agent_id?: string | null;
assignee?: string | null;
due_at?: string | null;
in_progress_at?: string | null;
tags?: TagRef[];
board_id: string;
board_name: string;
created_at: string;
due_at?: string | null;
id: string;
in_progress_at?: string | null;
priority: string;
status: string;
tags?: TagRef[];
title: string;
updated_at: string;
}

View File

@@ -9,7 +9,7 @@
* Payload for partial board-group updates.
*/
export interface BoardGroupUpdate {
description?: string | null;
name?: string | null;
slug?: string | null;
description?: string | null;
}

View File

@@ -11,6 +11,6 @@
export interface BoardMemoryCreate {
/** @minLength 1 */
content: string;
tags?: string[] | null;
source?: string | null;
tags?: string[] | null;
}

View File

@@ -9,11 +9,11 @@
* Serialized board memory entry returned from read endpoints.
*/
export interface BoardMemoryRead {
id: string;
board_id: string;
content: string;
tags?: string[] | null;
source?: string | null;
is_chat?: boolean;
created_at: string;
id: string;
is_chat?: boolean;
source?: string | null;
tags?: string[] | null;
}

View File

@@ -13,10 +13,10 @@ import type { BoardOnboardingUserProfile } from "./boardOnboardingUserProfile";
*/
export interface BoardOnboardingAgentComplete {
board_type: string;
lead_agent?: BoardOnboardingLeadAgentDraft | null;
objective?: string | null;
status: "complete";
success_metrics?: BoardOnboardingAgentCompleteSuccessMetrics;
target_date?: string | null;
status: "complete";
user_profile?: BoardOnboardingUserProfile | null;
lead_agent?: BoardOnboardingLeadAgentDraft | null;
}

View File

@@ -10,8 +10,8 @@ import type { BoardOnboardingQuestionOption } from "./boardOnboardingQuestionOpt
* Question payload emitted by the onboarding assistant.
*/
export interface BoardOnboardingAgentQuestion {
/** @minLength 1 */
question: string;
/** @minItems 1 */
options: BoardOnboardingQuestionOption[];
/** @minLength 1 */
question: string;
}

View File

@@ -10,11 +10,11 @@ import type { BoardOnboardingLeadAgentDraftIdentityProfile } from "./boardOnboar
* Editable lead-agent draft configuration.
*/
export interface BoardOnboardingLeadAgentDraft {
name?: string | null;
identity_profile?: BoardOnboardingLeadAgentDraftIdentityProfile;
autonomy_level?: "ask_first" | "balanced" | "autonomous" | null;
verbosity?: "concise" | "balanced" | "detailed" | null;
custom_instructions?: string | null;
identity_profile?: BoardOnboardingLeadAgentDraftIdentityProfile;
name?: string | null;
output_format?: "bullets" | "mixed" | "narrative" | null;
update_cadence?: "asap" | "hourly" | "daily" | "weekly" | null;
custom_instructions?: string | null;
verbosity?: "concise" | "balanced" | "detailed" | null;
}

View File

@@ -11,12 +11,12 @@ import type { BoardOnboardingReadMessages } from "./boardOnboardingReadMessages"
* Stored onboarding session state returned by API endpoints.
*/
export interface BoardOnboardingRead {
id: string;
board_id: string;
created_at: string;
draft_goal?: BoardOnboardingAgentComplete | null;
id: string;
messages?: BoardOnboardingReadMessages;
session_key: string;
status: string;
messages?: BoardOnboardingReadMessages;
draft_goal?: BoardOnboardingAgentComplete | null;
created_at: string;
updated_at: string;
}

View File

@@ -9,9 +9,9 @@
* User-profile preferences gathered during onboarding.
*/
export interface BoardOnboardingUserProfile {
context?: string | null;
notes?: string | null;
preferred_name?: string | null;
pronouns?: string | null;
timezone?: string | null;
notes?: string | null;
context?: string | null;
}

View File

@@ -10,23 +10,23 @@ import type { BoardReadSuccessMetrics } from "./boardReadSuccessMetrics";
* Board payload returned from read endpoints.
*/
export interface BoardRead {
name: string;
slug: string;
description: string;
gateway_id?: string | null;
block_status_changes_with_pending_approval?: boolean;
board_group_id?: string | null;
board_type?: string;
objective?: string | null;
success_metrics?: BoardReadSuccessMetrics;
target_date?: string | null;
created_at: string;
description: string;
gateway_id?: string | null;
goal_confirmed?: boolean;
goal_source?: string | null;
id: string;
name: string;
objective?: string | null;
only_lead_can_change_status?: boolean;
organization_id: string;
require_approval_for_done?: boolean;
require_review_before_done?: boolean;
block_status_changes_with_pending_approval?: boolean;
only_lead_can_change_status?: boolean;
id: string;
organization_id: string;
created_at: string;
slug: string;
success_metrics?: BoardReadSuccessMetrics;
target_date?: string | null;
updated_at: string;
}

View File

@@ -14,10 +14,10 @@ import type { TaskCardRead } from "./taskCardRead";
* Aggregated board payload used by board snapshot endpoints.
*/
export interface BoardSnapshot {
board: BoardRead;
tasks: TaskCardRead[];
agents: AgentRead[];
approvals: ApprovalRead[];
board: BoardRead;
chat_messages: BoardMemoryRead[];
pending_approvals_count?: number;
tasks: TaskCardRead[];
}

View File

@@ -10,19 +10,19 @@ import type { BoardUpdateSuccessMetrics } from "./boardUpdateSuccessMetrics";
* Payload for partial board updates.
*/
export interface BoardUpdate {
name?: string | null;
slug?: string | null;
description?: string | null;
gateway_id?: string | null;
block_status_changes_with_pending_approval?: boolean | null;
board_group_id?: string | null;
board_type?: string | null;
objective?: string | null;
success_metrics?: BoardUpdateSuccessMetrics;
target_date?: string | null;
description?: string | null;
gateway_id?: string | null;
goal_confirmed?: boolean | null;
goal_source?: string | null;
name?: string | null;
objective?: string | null;
only_lead_can_change_status?: boolean | null;
require_approval_for_done?: boolean | null;
require_review_before_done?: boolean | null;
block_status_changes_with_pending_approval?: boolean | null;
only_lead_can_change_status?: boolean | null;
slug?: string | null;
success_metrics?: BoardUpdateSuccessMetrics;
target_date?: string | null;
}

View File

@@ -10,7 +10,7 @@
*/
export interface DashboardKpis {
active_agents: number;
tasks_in_progress: number;
error_rate_pct: number;
median_cycle_time_hours_7d: number | null;
tasks_in_progress: number;
}

View File

@@ -13,11 +13,11 @@ import type { DashboardWipSeriesSet } from "./dashboardWipSeriesSet";
* Complete dashboard metrics response payload.
*/
export interface DashboardMetrics {
range: DashboardMetricsRange;
generated_at: string;
kpis: DashboardKpis;
throughput: DashboardSeriesSet;
cycle_time: DashboardSeriesSet;
error_rate: DashboardSeriesSet;
generated_at: string;
kpis: DashboardKpis;
range: DashboardMetricsRange;
throughput: DashboardSeriesSet;
wip: DashboardWipSeriesSet;
}

View File

@@ -12,7 +12,7 @@ import type { DashboardSeriesPoint } from "./dashboardSeriesPoint";
* Series payload for a single range/bucket combination.
*/
export interface DashboardRangeSeries {
range: DashboardRangeSeriesRange;
bucket: DashboardRangeSeriesBucket;
points: DashboardSeriesPoint[];
range: DashboardRangeSeriesRange;
}

View File

@@ -10,6 +10,6 @@ import type { DashboardRangeSeries } from "./dashboardRangeSeries";
* Primary vs comparison pair for generic series metrics.
*/
export interface DashboardSeriesSet {
primary: DashboardRangeSeries;
comparison: DashboardRangeSeries;
primary: DashboardRangeSeries;
}

View File

@@ -9,9 +9,9 @@
* Work-in-progress point split by task status buckets.
*/
export interface DashboardWipPoint {
period: string;
inbox: number;
in_progress: number;
review: number;
done: number;
in_progress: number;
inbox: number;
period: string;
review: number;
}

View File

@@ -12,7 +12,7 @@ import type { DashboardWipRangeSeriesRange } from "./dashboardWipRangeSeriesRang
* WIP series payload for a single range/bucket combination.
*/
export interface DashboardWipRangeSeries {
range: DashboardWipRangeSeriesRange;
bucket: DashboardWipRangeSeriesBucket;
points: DashboardWipPoint[];
range: DashboardWipRangeSeriesRange;
}

View File

@@ -10,6 +10,6 @@ import type { DashboardWipRangeSeries } from "./dashboardWipRangeSeries";
* Primary vs comparison pair for WIP status series metrics.
*/
export interface DashboardWipSeriesSet {
primary: DashboardWipRangeSeries;
comparison: DashboardWipRangeSeries;
primary: DashboardWipRangeSeries;
}

View File

@@ -9,7 +9,7 @@
* Gateway command catalog and protocol metadata.
*/
export interface GatewayCommandsResponse {
protocol_version: number;
methods: string[];
events: string[];
methods: string[];
protocol_version: number;
}

View File

@@ -10,7 +10,7 @@
*/
export interface GatewayCreate {
name: string;
token?: string | null;
url: string;
workspace_root: string;
token?: string | null;
}

View File

@@ -10,8 +10,8 @@
*/
export interface GatewayLeadBroadcastBoardResult {
board_id: string;
error?: string | null;
lead_agent_id?: string | null;
lead_agent_name?: string | null;
ok?: boolean;
error?: string | null;
}

View File

@@ -10,11 +10,11 @@ import type { GatewayLeadBroadcastRequestKind } from "./gatewayLeadBroadcastRequ
* Request payload for broadcasting a message to multiple board leads.
*/
export interface GatewayLeadBroadcastRequest {
kind?: GatewayLeadBroadcastRequestKind;
correlation_id?: string | null;
board_ids?: string[] | null;
/** @minLength 1 */
content: string;
board_ids?: string[] | null;
reply_tags?: string[];
correlation_id?: string | null;
kind?: GatewayLeadBroadcastRequestKind;
reply_source?: string | null;
reply_tags?: string[];
}

View File

@@ -10,8 +10,8 @@ import type { GatewayLeadBroadcastBoardResult } from "./gatewayLeadBroadcastBoar
* Aggregate response for a lead broadcast operation.
*/
export interface GatewayLeadBroadcastResponse {
ok?: boolean;
sent?: number;
failed?: number;
ok?: boolean;
results?: GatewayLeadBroadcastBoardResult[];
sent?: number;
}

View File

@@ -10,10 +10,10 @@ import type { GatewayLeadMessageRequestKind } from "./gatewayLeadMessageRequestK
* Request payload for sending a message to a board lead agent.
*/
export interface GatewayLeadMessageRequest {
kind?: GatewayLeadMessageRequestKind;
correlation_id?: string | null;
/** @minLength 1 */
content: string;
reply_tags?: string[];
correlation_id?: string | null;
kind?: GatewayLeadMessageRequestKind;
reply_source?: string | null;
reply_tags?: string[];
}

View File

@@ -9,9 +9,9 @@
* Response payload for a lead-message dispatch attempt.
*/
export interface GatewayLeadMessageResponse {
ok?: boolean;
board_id: string;
lead_agent_id?: string | null;
lead_agent_name?: string | null;
lead_created?: boolean;
ok?: boolean;
}

View File

@@ -9,10 +9,10 @@
* Request payload for asking the end user via a main gateway agent.
*/
export interface GatewayMainAskUserRequest {
correlation_id?: string | null;
/** @minLength 1 */
content: string;
correlation_id?: string | null;
preferred_channel?: string | null;
reply_tags?: string[];
reply_source?: string | null;
reply_tags?: string[];
}

View File

@@ -9,8 +9,8 @@
* Response payload for user-question dispatch via gateway main agent.
*/
export interface GatewayMainAskUserResponse {
ok?: boolean;
board_id: string;
main_agent_id?: string | null;
main_agent_name?: string | null;
ok?: boolean;
}

View File

@@ -9,12 +9,12 @@
* Gateway payload returned from read endpoints.
*/
export interface GatewayRead {
name: string;
url: string;
workspace_root: string;
created_at: string;
id: string;
name: string;
organization_id: string;
token?: string | null;
created_at: string;
updated_at: string;
url: string;
workspace_root: string;
}

View File

@@ -9,6 +9,6 @@
* Gateway sessions list response payload.
*/
export interface GatewaySessionsResponse {
sessions: unknown[];
main_session?: unknown | null;
sessions: unknown[];
}

View File

@@ -10,11 +10,11 @@ import type { GatewayTemplatesSyncError } from "./gatewayTemplatesSyncError";
* Summary payload returned by gateway template sync endpoints.
*/
export interface GatewayTemplatesSyncResult {
agents_skipped: number;
agents_updated: number;
errors?: GatewayTemplatesSyncError[];
gateway_id: string;
include_main: boolean;
reset_sessions: boolean;
agents_updated: number;
agents_skipped: number;
main_updated: boolean;
errors?: GatewayTemplatesSyncError[];
reset_sessions: boolean;
}

View File

@@ -10,7 +10,7 @@
*/
export interface GatewayUpdate {
name?: string | null;
url?: string | null;
token?: string | null;
url?: string | null;
workspace_root?: string | null;
}

View File

@@ -10,10 +10,10 @@
*/
export interface GatewaysStatusResponse {
connected: boolean;
error?: string | null;
gateway_url: string;
sessions_count?: number | null;
sessions?: unknown[] | null;
main_session?: unknown | null;
main_session_error?: string | null;
error?: string | null;
sessions?: unknown[] | null;
sessions_count?: number | null;
}

View File

@@ -188,14 +188,25 @@ export * from "./tagRead";
export * from "./tagRef";
export * from "./tagUpdate";
export * from "./taskCardRead";
export * from "./taskCardReadCustomFieldValues";
export * from "./taskCardReadStatus";
export * from "./taskCommentCreate";
export * from "./taskCommentRead";
export * from "./taskCreate";
export * from "./taskCreateCustomFieldValues";
export * from "./taskCreateStatus";
export * from "./taskCustomFieldDefinitionCreate";
export * from "./taskCustomFieldDefinitionCreateFieldType";
export * from "./taskCustomFieldDefinitionCreateUiVisibility";
export * from "./taskCustomFieldDefinitionRead";
export * from "./taskCustomFieldDefinitionReadFieldType";
export * from "./taskCustomFieldDefinitionReadUiVisibility";
export * from "./taskCustomFieldDefinitionUpdate";
export * from "./taskRead";
export * from "./taskReadCustomFieldValues";
export * from "./taskReadStatus";
export * from "./taskUpdate";
export * from "./taskUpdateCustomFieldValues";
export * from "./updateAgentApiV1AgentsAgentIdPatchParams";
export * from "./userRead";
export * from "./userUpdate";

View File

@@ -8,10 +8,10 @@ import type { ActivityEventRead } from "./activityEventRead";
export interface LimitOffsetPageTypeVarCustomizedActivityEventRead {
items: ActivityEventRead[];
/** @minimum 0 */
total: number;
/** @minimum 1 */
limit: number;
/** @minimum 0 */
offset: number;
/** @minimum 0 */
total: number;
}

View File

@@ -8,10 +8,10 @@ import type { ActivityTaskCommentFeedItemRead } from "./activityTaskCommentFeedI
export interface LimitOffsetPageTypeVarCustomizedActivityTaskCommentFeedItemRead {
items: ActivityTaskCommentFeedItemRead[];
/** @minimum 0 */
total: number;
/** @minimum 1 */
limit: number;
/** @minimum 0 */
offset: number;
/** @minimum 0 */
total: number;
}

View File

@@ -8,10 +8,10 @@ import type { AgentRead } from "./agentRead";
export interface LimitOffsetPageTypeVarCustomizedAgentRead {
items: AgentRead[];
/** @minimum 0 */
total: number;
/** @minimum 1 */
limit: number;
/** @minimum 0 */
offset: number;
/** @minimum 0 */
total: number;
}

View File

@@ -8,10 +8,10 @@ import type { ApprovalRead } from "./approvalRead";
export interface LimitOffsetPageTypeVarCustomizedApprovalRead {
items: ApprovalRead[];
/** @minimum 0 */
total: number;
/** @minimum 1 */
limit: number;
/** @minimum 0 */
offset: number;
/** @minimum 0 */
total: number;
}

View File

@@ -8,10 +8,10 @@ import type { BoardGroupMemoryRead } from "./boardGroupMemoryRead";
export interface LimitOffsetPageTypeVarCustomizedBoardGroupMemoryRead {
items: BoardGroupMemoryRead[];
/** @minimum 0 */
total: number;
/** @minimum 1 */
limit: number;
/** @minimum 0 */
offset: number;
/** @minimum 0 */
total: number;
}

View File

@@ -8,10 +8,10 @@ import type { BoardGroupRead } from "./boardGroupRead";
export interface LimitOffsetPageTypeVarCustomizedBoardGroupRead {
items: BoardGroupRead[];
/** @minimum 0 */
total: number;
/** @minimum 1 */
limit: number;
/** @minimum 0 */
offset: number;
/** @minimum 0 */
total: number;
}

View File

@@ -8,10 +8,10 @@ import type { BoardMemoryRead } from "./boardMemoryRead";
export interface LimitOffsetPageTypeVarCustomizedBoardMemoryRead {
items: BoardMemoryRead[];
/** @minimum 0 */
total: number;
/** @minimum 1 */
limit: number;
/** @minimum 0 */
offset: number;
/** @minimum 0 */
total: number;
}

View File

@@ -8,10 +8,10 @@ import type { BoardRead } from "./boardRead";
export interface LimitOffsetPageTypeVarCustomizedBoardRead {
items: BoardRead[];
/** @minimum 0 */
total: number;
/** @minimum 1 */
limit: number;
/** @minimum 0 */
offset: number;
/** @minimum 0 */
total: number;
}

View File

@@ -8,10 +8,10 @@ import type { GatewayRead } from "./gatewayRead";
export interface LimitOffsetPageTypeVarCustomizedGatewayRead {
items: GatewayRead[];
/** @minimum 0 */
total: number;
/** @minimum 1 */
limit: number;
/** @minimum 0 */
offset: number;
/** @minimum 0 */
total: number;
}

View File

@@ -8,10 +8,10 @@ import type { OrganizationInviteRead } from "./organizationInviteRead";
export interface LimitOffsetPageTypeVarCustomizedOrganizationInviteRead {
items: OrganizationInviteRead[];
/** @minimum 0 */
total: number;
/** @minimum 1 */
limit: number;
/** @minimum 0 */
offset: number;
/** @minimum 0 */
total: number;
}

View File

@@ -8,10 +8,10 @@ import type { OrganizationMemberRead } from "./organizationMemberRead";
export interface LimitOffsetPageTypeVarCustomizedOrganizationMemberRead {
items: OrganizationMemberRead[];
/** @minimum 0 */
total: number;
/** @minimum 1 */
limit: number;
/** @minimum 0 */
offset: number;
/** @minimum 0 */
total: number;
}

View File

@@ -8,10 +8,10 @@ import type { TagRead } from "./tagRead";
export interface LimitOffsetPageTypeVarCustomizedTagRead {
items: TagRead[];
/** @minimum 0 */
total: number;
/** @minimum 1 */
limit: number;
/** @minimum 0 */
offset: number;
/** @minimum 0 */
total: number;
}

View File

@@ -8,10 +8,10 @@ import type { TaskCommentRead } from "./taskCommentRead";
export interface LimitOffsetPageTypeVarCustomizedTaskCommentRead {
items: TaskCommentRead[];
/** @minimum 0 */
total: number;
/** @minimum 1 */
limit: number;
/** @minimum 0 */
offset: number;
/** @minimum 0 */
total: number;
}

View File

@@ -8,10 +8,10 @@ import type { TaskRead } from "./taskRead";
export interface LimitOffsetPageTypeVarCustomizedTaskRead {
items: TaskRead[];
/** @minimum 0 */
total: number;
/** @minimum 1 */
limit: number;
/** @minimum 0 */
offset: number;
/** @minimum 0 */
total: number;
}

View File

@@ -9,10 +9,10 @@
* Board access payload returned from read endpoints.
*/
export interface OrganizationBoardAccessRead {
id: string;
board_id: string;
can_read: boolean;
can_write: boolean;
created_at: string;
id: string;
updated_at: string;
}

View File

@@ -10,9 +10,9 @@ import type { OrganizationBoardAccessSpec } from "./organizationBoardAccessSpec"
* Payload for creating an organization invite.
*/
export interface OrganizationInviteCreate {
invited_email: string;
role?: string;
all_boards_read?: boolean;
all_boards_write?: boolean;
board_access?: OrganizationBoardAccessSpec[];
invited_email: string;
role?: string;
}

View File

@@ -9,16 +9,16 @@
* Organization invite payload returned from read endpoints.
*/
export interface OrganizationInviteRead {
id: string;
organization_id: string;
invited_email: string;
role: string;
accepted_at?: string | null;
accepted_by_user_id?: string | null;
all_boards_read: boolean;
all_boards_write: boolean;
token: string;
created_by_user_id?: string | null;
accepted_by_user_id?: string | null;
accepted_at?: string | null;
created_at: string;
created_by_user_id?: string | null;
id: string;
invited_email: string;
organization_id: string;
role: string;
token: string;
updated_at: string;
}

View File

@@ -10,7 +10,7 @@
*/
export interface OrganizationListItem {
id: string;
is_active: boolean;
name: string;
role: string;
is_active: boolean;
}

View File

@@ -11,14 +11,14 @@ import type { OrganizationUserRead } from "./organizationUserRead";
* Organization member payload including board-level access overrides.
*/
export interface OrganizationMemberRead {
id: string;
organization_id: string;
user_id: string;
role: string;
all_boards_read: boolean;
all_boards_write: boolean;
board_access?: OrganizationBoardAccessRead[];
created_at: string;
id: string;
organization_id: string;
role: string;
updated_at: string;
user?: OrganizationUserRead | null;
board_access?: OrganizationBoardAccessRead[];
user_id: string;
}

View File

@@ -9,8 +9,8 @@
* Organization payload returned by read endpoints.
*/
export interface OrganizationRead {
created_at: string;
id: string;
name: string;
created_at: string;
updated_at: string;
}

View File

@@ -9,8 +9,8 @@
* Embedded user fields included in organization member payloads.
*/
export interface OrganizationUserRead {
id: string;
email?: string | null;
id: string;
name?: string | null;
preferred_name?: string | null;
}

View File

@@ -10,6 +10,6 @@
*/
export interface SoulUpdateRequest {
content: string;
source_url?: string | null;
reason?: string | null;
source_url?: string | null;
}

View File

@@ -9,7 +9,7 @@
* Response payload containing rendered markdown for a soul.
*/
export interface SoulsDirectoryMarkdownResponse {
content: string;
handle: string;
slug: string;
content: string;
}

View File

@@ -10,7 +10,7 @@
*/
export interface SoulsDirectorySoulRef {
handle: string;
slug: string;
page_url: string;
raw_md_url: string;
slug: string;
}

View File

@@ -9,9 +9,9 @@
* Payload for creating a tag.
*/
export interface TagCreate {
color?: string;
description?: string | null;
/** @minLength 1 */
name: string;
slug?: string | null;
color?: string;
description?: string | null;
}

View File

@@ -9,13 +9,13 @@
* Tag payload returned from API endpoints.
*/
export interface TagRead {
name: string;
slug: string;
color?: string;
created_at: string;
description?: string | null;
id: string;
name: string;
organization_id: string;
slug: string;
task_count?: number;
created_at: string;
updated_at: string;
}

View File

@@ -9,8 +9,8 @@
* Compact tag representation embedded in task payloads.
*/
export interface TagRef {
color: string;
id: string;
name: string;
slug: string;
color: string;
}

View File

@@ -9,8 +9,8 @@
* Payload for partial tag updates.
*/
export interface TagUpdate {
name?: string | null;
slug?: string | null;
color?: string | null;
description?: string | null;
name?: string | null;
slug?: string | null;
}

View File

@@ -5,30 +5,32 @@
* OpenAPI spec version: 0.1.0
*/
import type { TagRef } from "./tagRef";
import type { TaskCardReadCustomFieldValues } from "./taskCardReadCustomFieldValues";
import type { TaskCardReadStatus } from "./taskCardReadStatus";
/**
* Task read model enriched with assignee and approval counters.
*/
export interface TaskCardRead {
title: string;
description?: string | null;
status?: TaskCardReadStatus;
priority?: string;
due_at?: string | null;
assigned_agent_id?: string | null;
depends_on_task_ids?: string[];
tag_ids?: string[];
id: string;
board_id: string | null;
created_by_user_id: string | null;
in_progress_at: string | null;
created_at: string;
updated_at: string;
blocked_by_task_ids?: string[];
is_blocked?: boolean;
tags?: TagRef[];
assignee?: string | null;
approvals_count?: number;
approvals_pending_count?: number;
assigned_agent_id?: string | null;
assignee?: string | null;
blocked_by_task_ids?: string[];
board_id: string | null;
created_at: string;
created_by_user_id: string | null;
custom_field_values?: TaskCardReadCustomFieldValues;
depends_on_task_ids?: string[];
description?: string | null;
due_at?: string | null;
id: string;
in_progress_at: string | null;
is_blocked?: boolean;
priority?: string;
status?: TaskCardReadStatus;
tag_ids?: string[];
tags?: TagRef[];
title: string;
updated_at: string;
}

View File

@@ -0,0 +1,10 @@
/**
* Generated by orval v8.3.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export type TaskCardReadCustomFieldValues = {
[key: string]: unknown | null;
} | null;

View File

@@ -9,9 +9,9 @@
* Task comment payload returned from read endpoints.
*/
export interface TaskCommentRead {
agent_id: string | null;
created_at: string;
id: string;
message: string | null;
agent_id: string | null;
task_id: string | null;
created_at: string;
}

View File

@@ -4,19 +4,21 @@
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
import type { TaskCreateCustomFieldValues } from "./taskCreateCustomFieldValues";
import type { TaskCreateStatus } from "./taskCreateStatus";
/**
* Payload for creating a task.
*/
export interface TaskCreate {
title: string;
description?: string | null;
status?: TaskCreateStatus;
priority?: string;
due_at?: string | null;
assigned_agent_id?: string | null;
depends_on_task_ids?: string[];
tag_ids?: string[];
created_by_user_id?: string | null;
custom_field_values?: TaskCreateCustomFieldValues;
depends_on_task_ids?: string[];
description?: string | null;
due_at?: string | null;
priority?: string;
status?: TaskCreateStatus;
tag_ids?: string[];
title: string;
}

Some files were not shown because too many files have changed in this diff Show More