feat(agents): Add identity and soul template fields to board creation

This commit is contained in:
Abhimanyu Saharan
2026-02-04 20:21:33 +05:30
parent 1c972edb46
commit c3357f92d9
117 changed files with 7899 additions and 1339 deletions

View File

@@ -1,27 +0,0 @@
"""add agent heartbeat config column
Revision ID: 2b4c2f7b3eda
Revises: 69858cb75533
Create Date: 2026-02-04 16:36:55.587762
"""
from __future__ import annotations
from alembic import op
# revision identifiers, used by Alembic.
revision = '2b4c2f7b3eda'
down_revision = '69858cb75533'
branch_labels = None
depends_on = None
def upgrade() -> None:
op.execute(
"ALTER TABLE agents ADD COLUMN IF NOT EXISTS heartbeat_config JSON"
)
def downgrade() -> None:
op.execute("ALTER TABLE agents DROP COLUMN IF EXISTS heartbeat_config")

View File

@@ -1,574 +0,0 @@
"""init
Revision ID: 5630abfa60f8
Revises:
Create Date: 2026-02-03 17:52:47.887105
"""
from __future__ import annotations
from alembic import op
import sqlalchemy as sa
import sqlmodel
# revision identifiers, used by Alembic.
revision = "5630abfa60f8"
down_revision = None
branch_labels = None
depends_on = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.create_table(
"orgs",
sa.Column("id", sa.Uuid(), nullable=False),
sa.Column("name", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("slug", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(op.f("ix_orgs_slug"), "orgs", ["slug"], unique=True)
op.create_table(
"users",
sa.Column("id", sa.Uuid(), nullable=False),
sa.Column("clerk_user_id", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("email", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("name", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("is_super_admin", sa.Boolean(), nullable=False),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(op.f("ix_users_clerk_user_id"), "users", ["clerk_user_id"], unique=True)
op.create_index(op.f("ix_users_email"), "users", ["email"], unique=False)
op.create_table(
"workspaces",
sa.Column("id", sa.Uuid(), nullable=False),
sa.Column("org_id", sa.Uuid(), nullable=False),
sa.Column("name", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("slug", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.ForeignKeyConstraint(
["org_id"],
["orgs.id"],
),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(op.f("ix_workspaces_org_id"), "workspaces", ["org_id"], unique=False)
op.create_index(op.f("ix_workspaces_slug"), "workspaces", ["slug"], unique=False)
op.create_table(
"agents",
sa.Column("org_id", sa.Uuid(), nullable=False),
sa.Column("workspace_id", sa.Uuid(), nullable=False),
sa.Column("id", sa.Uuid(), nullable=False),
sa.Column("name", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("role", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("status", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("openclaw_session_id", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("api_token_hash", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("api_token_last_used_at", sa.DateTime(), nullable=True),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.Column("updated_at", sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(
["org_id"],
["orgs.id"],
),
sa.ForeignKeyConstraint(
["workspace_id"],
["workspaces.id"],
),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(
op.f("ix_agents_openclaw_session_id"), "agents", ["openclaw_session_id"], unique=False
)
op.create_index(op.f("ix_agents_org_id"), "agents", ["org_id"], unique=False)
op.create_index(op.f("ix_agents_workspace_id"), "agents", ["workspace_id"], unique=False)
op.create_table(
"gateway_configs",
sa.Column("id", sa.Uuid(), nullable=False),
sa.Column("org_id", sa.Uuid(), nullable=False),
sa.Column("workspace_id", sa.Uuid(), nullable=True),
sa.Column("name", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("base_url", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("token", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(
["org_id"],
["orgs.id"],
),
sa.ForeignKeyConstraint(
["workspace_id"],
["workspaces.id"],
),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(op.f("ix_gateway_configs_org_id"), "gateway_configs", ["org_id"], unique=False)
op.create_index(
op.f("ix_gateway_configs_workspace_id"), "gateway_configs", ["workspace_id"], unique=False
)
op.create_table(
"memberships",
sa.Column("org_id", sa.Uuid(), nullable=False),
sa.Column("workspace_id", sa.Uuid(), nullable=False),
sa.Column("id", sa.Uuid(), nullable=False),
sa.Column("user_id", sa.Uuid(), nullable=False),
sa.Column("role", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(
["org_id"],
["orgs.id"],
),
sa.ForeignKeyConstraint(
["user_id"],
["users.id"],
),
sa.ForeignKeyConstraint(
["workspace_id"],
["workspaces.id"],
),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(op.f("ix_memberships_org_id"), "memberships", ["org_id"], unique=False)
op.create_index(op.f("ix_memberships_user_id"), "memberships", ["user_id"], unique=False)
op.create_index(
op.f("ix_memberships_workspace_id"), "memberships", ["workspace_id"], unique=False
)
op.create_table(
"orchestration_templates",
sa.Column("org_id", sa.Uuid(), nullable=False),
sa.Column("workspace_id", sa.Uuid(), nullable=False),
sa.Column("id", sa.Uuid(), nullable=False),
sa.Column("kind", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("title", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("template_markdown", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.Column("updated_at", sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(
["org_id"],
["orgs.id"],
),
sa.ForeignKeyConstraint(
["workspace_id"],
["workspaces.id"],
),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(
op.f("ix_orchestration_templates_kind"), "orchestration_templates", ["kind"], unique=False
)
op.create_index(
op.f("ix_orchestration_templates_org_id"),
"orchestration_templates",
["org_id"],
unique=False,
)
op.create_index(
op.f("ix_orchestration_templates_workspace_id"),
"orchestration_templates",
["workspace_id"],
unique=False,
)
op.create_table(
"projects",
sa.Column("org_id", sa.Uuid(), nullable=False),
sa.Column("workspace_id", sa.Uuid(), nullable=False),
sa.Column("id", sa.Uuid(), nullable=False),
sa.Column("name", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("description", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("status", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.Column("updated_at", sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(
["org_id"],
["orgs.id"],
),
sa.ForeignKeyConstraint(
["workspace_id"],
["workspaces.id"],
),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(op.f("ix_projects_org_id"), "projects", ["org_id"], unique=False)
op.create_index(op.f("ix_projects_status"), "projects", ["status"], unique=False)
op.create_index(op.f("ix_projects_workspace_id"), "projects", ["workspace_id"], unique=False)
op.create_table(
"workspace_api_tokens",
sa.Column("org_id", sa.Uuid(), nullable=False),
sa.Column("workspace_id", sa.Uuid(), nullable=False),
sa.Column("id", sa.Uuid(), nullable=False),
sa.Column("token_hash", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("label", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("last_used_at", sa.DateTime(), nullable=True),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(
["org_id"],
["orgs.id"],
),
sa.ForeignKeyConstraint(
["workspace_id"],
["workspaces.id"],
),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(
op.f("ix_workspace_api_tokens_org_id"), "workspace_api_tokens", ["org_id"], unique=False
)
op.create_index(
op.f("ix_workspace_api_tokens_token_hash"),
"workspace_api_tokens",
["token_hash"],
unique=True,
)
op.create_index(
op.f("ix_workspace_api_tokens_workspace_id"),
"workspace_api_tokens",
["workspace_id"],
unique=False,
)
op.create_table(
"openclaw_sessions",
sa.Column("org_id", sa.Uuid(), nullable=False),
sa.Column("workspace_id", sa.Uuid(), nullable=False),
sa.Column("id", sa.Uuid(), nullable=False),
sa.Column("session_id", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("agent_id", sa.Uuid(), nullable=True),
sa.Column("status", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("last_seen_at", sa.DateTime(), nullable=True),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(
["agent_id"],
["agents.id"],
),
sa.ForeignKeyConstraint(
["org_id"],
["orgs.id"],
),
sa.ForeignKeyConstraint(
["workspace_id"],
["workspaces.id"],
),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(
op.f("ix_openclaw_sessions_org_id"), "openclaw_sessions", ["org_id"], unique=False
)
op.create_index(
op.f("ix_openclaw_sessions_session_id"), "openclaw_sessions", ["session_id"], unique=True
)
op.create_index(
op.f("ix_openclaw_sessions_status"), "openclaw_sessions", ["status"], unique=False
)
op.create_index(
op.f("ix_openclaw_sessions_workspace_id"),
"openclaw_sessions",
["workspace_id"],
unique=False,
)
op.create_table(
"tasks",
sa.Column("org_id", sa.Uuid(), nullable=False),
sa.Column("workspace_id", sa.Uuid(), nullable=False),
sa.Column("id", sa.Uuid(), nullable=False),
sa.Column("project_id", sa.Uuid(), nullable=False),
sa.Column("title", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("description", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("status", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("priority", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("due_at", sa.DateTime(), nullable=True),
sa.Column("assigned_agent_id", sa.Uuid(), nullable=True),
sa.Column("created_by_user_id", sa.Uuid(), nullable=True),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.Column("updated_at", sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(
["assigned_agent_id"],
["agents.id"],
),
sa.ForeignKeyConstraint(
["created_by_user_id"],
["users.id"],
),
sa.ForeignKeyConstraint(
["org_id"],
["orgs.id"],
),
sa.ForeignKeyConstraint(
["project_id"],
["projects.id"],
),
sa.ForeignKeyConstraint(
["workspace_id"],
["workspaces.id"],
),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(
op.f("ix_tasks_assigned_agent_id"), "tasks", ["assigned_agent_id"], unique=False
)
op.create_index(
op.f("ix_tasks_created_by_user_id"), "tasks", ["created_by_user_id"], unique=False
)
op.create_index(op.f("ix_tasks_org_id"), "tasks", ["org_id"], unique=False)
op.create_index(op.f("ix_tasks_priority"), "tasks", ["priority"], unique=False)
op.create_index(op.f("ix_tasks_project_id"), "tasks", ["project_id"], unique=False)
op.create_index(op.f("ix_tasks_status"), "tasks", ["status"], unique=False)
op.create_index(op.f("ix_tasks_workspace_id"), "tasks", ["workspace_id"], unique=False)
op.create_table(
"task_activities",
sa.Column("org_id", sa.Uuid(), nullable=False),
sa.Column("workspace_id", sa.Uuid(), nullable=False),
sa.Column("id", sa.Uuid(), nullable=False),
sa.Column("task_id", sa.Uuid(), nullable=False),
sa.Column("activity_type", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("message", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("actor_user_id", sa.Uuid(), nullable=True),
sa.Column("actor_agent_id", sa.Uuid(), nullable=True),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(
["actor_agent_id"],
["agents.id"],
),
sa.ForeignKeyConstraint(
["actor_user_id"],
["users.id"],
),
sa.ForeignKeyConstraint(
["org_id"],
["orgs.id"],
),
sa.ForeignKeyConstraint(
["task_id"],
["tasks.id"],
),
sa.ForeignKeyConstraint(
["workspace_id"],
["workspaces.id"],
),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(op.f("ix_task_activities_org_id"), "task_activities", ["org_id"], unique=False)
op.create_index(
op.f("ix_task_activities_task_id"), "task_activities", ["task_id"], unique=False
)
op.create_index(
op.f("ix_task_activities_workspace_id"), "task_activities", ["workspace_id"], unique=False
)
op.create_table(
"task_deliverables",
sa.Column("org_id", sa.Uuid(), nullable=False),
sa.Column("workspace_id", sa.Uuid(), nullable=False),
sa.Column("id", sa.Uuid(), nullable=False),
sa.Column("task_id", sa.Uuid(), nullable=False),
sa.Column("title", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("markdown_content", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("created_by_user_id", sa.Uuid(), nullable=True),
sa.Column("created_by_agent_id", sa.Uuid(), nullable=True),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(
["created_by_agent_id"],
["agents.id"],
),
sa.ForeignKeyConstraint(
["created_by_user_id"],
["users.id"],
),
sa.ForeignKeyConstraint(
["org_id"],
["orgs.id"],
),
sa.ForeignKeyConstraint(
["task_id"],
["tasks.id"],
),
sa.ForeignKeyConstraint(
["workspace_id"],
["workspaces.id"],
),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(
op.f("ix_task_deliverables_org_id"), "task_deliverables", ["org_id"], unique=False
)
op.create_index(
op.f("ix_task_deliverables_task_id"), "task_deliverables", ["task_id"], unique=False
)
op.create_index(
op.f("ix_task_deliverables_workspace_id"),
"task_deliverables",
["workspace_id"],
unique=False,
)
op.create_table(
"task_status_history",
sa.Column("org_id", sa.Uuid(), nullable=False),
sa.Column("workspace_id", sa.Uuid(), nullable=False),
sa.Column("id", sa.Uuid(), nullable=False),
sa.Column("task_id", sa.Uuid(), nullable=False),
sa.Column("from_status", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("to_status", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("actor_user_id", sa.Uuid(), nullable=True),
sa.Column("actor_agent_id", sa.Uuid(), nullable=True),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(
["actor_agent_id"],
["agents.id"],
),
sa.ForeignKeyConstraint(
["actor_user_id"],
["users.id"],
),
sa.ForeignKeyConstraint(
["org_id"],
["orgs.id"],
),
sa.ForeignKeyConstraint(
["task_id"],
["tasks.id"],
),
sa.ForeignKeyConstraint(
["workspace_id"],
["workspaces.id"],
),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(
op.f("ix_task_status_history_org_id"), "task_status_history", ["org_id"], unique=False
)
op.create_index(
op.f("ix_task_status_history_task_id"), "task_status_history", ["task_id"], unique=False
)
op.create_index(
op.f("ix_task_status_history_workspace_id"),
"task_status_history",
["workspace_id"],
unique=False,
)
op.create_table(
"task_subagents",
sa.Column("org_id", sa.Uuid(), nullable=False),
sa.Column("workspace_id", sa.Uuid(), nullable=False),
sa.Column("id", sa.Uuid(), nullable=False),
sa.Column("task_id", sa.Uuid(), nullable=False),
sa.Column("agent_name", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("openclaw_session_id", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(
["org_id"],
["orgs.id"],
),
sa.ForeignKeyConstraint(
["task_id"],
["tasks.id"],
),
sa.ForeignKeyConstraint(
["workspace_id"],
["workspaces.id"],
),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(op.f("ix_task_subagents_org_id"), "task_subagents", ["org_id"], unique=False)
op.create_index(op.f("ix_task_subagents_task_id"), "task_subagents", ["task_id"], unique=False)
op.create_index(
op.f("ix_task_subagents_workspace_id"), "task_subagents", ["workspace_id"], unique=False
)
op.create_table(
"transcripts",
sa.Column("org_id", sa.Uuid(), nullable=False),
sa.Column("workspace_id", sa.Uuid(), nullable=False),
sa.Column("id", sa.Uuid(), nullable=False),
sa.Column("task_id", sa.Uuid(), nullable=True),
sa.Column("session_id", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("full_text", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(
["org_id"],
["orgs.id"],
),
sa.ForeignKeyConstraint(
["task_id"],
["tasks.id"],
),
sa.ForeignKeyConstraint(
["workspace_id"],
["workspaces.id"],
),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(op.f("ix_transcripts_org_id"), "transcripts", ["org_id"], unique=False)
op.create_index(op.f("ix_transcripts_session_id"), "transcripts", ["session_id"], unique=False)
op.create_index(op.f("ix_transcripts_task_id"), "transcripts", ["task_id"], unique=False)
op.create_index(
op.f("ix_transcripts_workspace_id"), "transcripts", ["workspace_id"], unique=False
)
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_index(op.f("ix_transcripts_workspace_id"), table_name="transcripts")
op.drop_index(op.f("ix_transcripts_task_id"), table_name="transcripts")
op.drop_index(op.f("ix_transcripts_session_id"), table_name="transcripts")
op.drop_index(op.f("ix_transcripts_org_id"), table_name="transcripts")
op.drop_table("transcripts")
op.drop_index(op.f("ix_task_subagents_workspace_id"), table_name="task_subagents")
op.drop_index(op.f("ix_task_subagents_task_id"), table_name="task_subagents")
op.drop_index(op.f("ix_task_subagents_org_id"), table_name="task_subagents")
op.drop_table("task_subagents")
op.drop_index(op.f("ix_task_status_history_workspace_id"), table_name="task_status_history")
op.drop_index(op.f("ix_task_status_history_task_id"), table_name="task_status_history")
op.drop_index(op.f("ix_task_status_history_org_id"), table_name="task_status_history")
op.drop_table("task_status_history")
op.drop_index(op.f("ix_task_deliverables_workspace_id"), table_name="task_deliverables")
op.drop_index(op.f("ix_task_deliverables_task_id"), table_name="task_deliverables")
op.drop_index(op.f("ix_task_deliverables_org_id"), table_name="task_deliverables")
op.drop_table("task_deliverables")
op.drop_index(op.f("ix_task_activities_workspace_id"), table_name="task_activities")
op.drop_index(op.f("ix_task_activities_task_id"), table_name="task_activities")
op.drop_index(op.f("ix_task_activities_org_id"), table_name="task_activities")
op.drop_table("task_activities")
op.drop_index(op.f("ix_tasks_workspace_id"), table_name="tasks")
op.drop_index(op.f("ix_tasks_status"), table_name="tasks")
op.drop_index(op.f("ix_tasks_project_id"), table_name="tasks")
op.drop_index(op.f("ix_tasks_priority"), table_name="tasks")
op.drop_index(op.f("ix_tasks_org_id"), table_name="tasks")
op.drop_index(op.f("ix_tasks_created_by_user_id"), table_name="tasks")
op.drop_index(op.f("ix_tasks_assigned_agent_id"), table_name="tasks")
op.drop_table("tasks")
op.drop_index(op.f("ix_openclaw_sessions_workspace_id"), table_name="openclaw_sessions")
op.drop_index(op.f("ix_openclaw_sessions_status"), table_name="openclaw_sessions")
op.drop_index(op.f("ix_openclaw_sessions_session_id"), table_name="openclaw_sessions")
op.drop_index(op.f("ix_openclaw_sessions_org_id"), table_name="openclaw_sessions")
op.drop_table("openclaw_sessions")
op.drop_index(op.f("ix_workspace_api_tokens_workspace_id"), table_name="workspace_api_tokens")
op.drop_index(op.f("ix_workspace_api_tokens_token_hash"), table_name="workspace_api_tokens")
op.drop_index(op.f("ix_workspace_api_tokens_org_id"), table_name="workspace_api_tokens")
op.drop_table("workspace_api_tokens")
op.drop_index(op.f("ix_projects_workspace_id"), table_name="projects")
op.drop_index(op.f("ix_projects_status"), table_name="projects")
op.drop_index(op.f("ix_projects_org_id"), table_name="projects")
op.drop_table("projects")
op.drop_index(
op.f("ix_orchestration_templates_workspace_id"), table_name="orchestration_templates"
)
op.drop_index(op.f("ix_orchestration_templates_org_id"), table_name="orchestration_templates")
op.drop_index(op.f("ix_orchestration_templates_kind"), table_name="orchestration_templates")
op.drop_table("orchestration_templates")
op.drop_index(op.f("ix_memberships_workspace_id"), table_name="memberships")
op.drop_index(op.f("ix_memberships_user_id"), table_name="memberships")
op.drop_index(op.f("ix_memberships_org_id"), table_name="memberships")
op.drop_table("memberships")
op.drop_index(op.f("ix_gateway_configs_workspace_id"), table_name="gateway_configs")
op.drop_index(op.f("ix_gateway_configs_org_id"), table_name="gateway_configs")
op.drop_table("gateway_configs")
op.drop_index(op.f("ix_agents_workspace_id"), table_name="agents")
op.drop_index(op.f("ix_agents_org_id"), table_name="agents")
op.drop_index(op.f("ix_agents_openclaw_session_id"), table_name="agents")
op.drop_table("agents")
op.drop_index(op.f("ix_workspaces_slug"), table_name="workspaces")
op.drop_index(op.f("ix_workspaces_org_id"), table_name="workspaces")
op.drop_table("workspaces")
op.drop_index(op.f("ix_users_email"), table_name="users")
op.drop_index(op.f("ix_users_clerk_user_id"), table_name="users")
op.drop_table("users")
op.drop_index(op.f("ix_orgs_slug"), table_name="orgs")
op.drop_table("orgs")
# ### end Alembic commands ###

View File

@@ -1,29 +0,0 @@
"""add agent heartbeat config
Revision ID: 69858cb75533
Revises: f1a2b3c4d5e6
Create Date: 2026-02-04 16:32:42.028772
"""
from __future__ import annotations
from alembic import op
# revision identifiers, used by Alembic.
revision = '69858cb75533'
down_revision = 'f1a2b3c4d5e6'
branch_labels = None
depends_on = None
def upgrade() -> None:
op.execute(
"ALTER TABLE agents ADD COLUMN IF NOT EXISTS heartbeat_config JSON"
)
def downgrade() -> None:
op.execute(
"ALTER TABLE agents DROP COLUMN IF EXISTS heartbeat_config"
)

View File

@@ -1,41 +0,0 @@
"""add agent provision confirmation
Revision ID: 6df47d330227
Revises: e0f28e965fa5
Create Date: 2026-02-04 17:16:44.472239
"""
from __future__ import annotations
from alembic import op
# revision identifiers, used by Alembic.
revision = '6df47d330227'
down_revision = 'e0f28e965fa5'
branch_labels = None
depends_on = None
def upgrade() -> None:
op.execute(
"ALTER TABLE agents ADD COLUMN IF NOT EXISTS provision_requested_at TIMESTAMP"
)
op.execute(
"ALTER TABLE agents ADD COLUMN IF NOT EXISTS provision_confirm_token_hash VARCHAR"
)
op.execute(
"ALTER TABLE agents ADD COLUMN IF NOT EXISTS provision_action VARCHAR"
)
def downgrade() -> None:
op.execute(
"ALTER TABLE agents DROP COLUMN IF EXISTS provision_action"
)
op.execute(
"ALTER TABLE agents DROP COLUMN IF EXISTS provision_confirm_token_hash"
)
op.execute(
"ALTER TABLE agents DROP COLUMN IF EXISTS provision_requested_at"
)

View File

@@ -1,64 +0,0 @@
"""add boards and task board id
Revision ID: 7e3d9b8c1f4a
Revises: 5630abfa60f8
Create Date: 2026-02-03 20:12:00.000000
"""
from __future__ import annotations
from alembic import op
import sqlalchemy as sa
import sqlmodel
# revision identifiers, used by Alembic.
revision = "7e3d9b8c1f4a"
down_revision = "5630abfa60f8"
branch_labels = None
depends_on = None
def upgrade() -> None:
op.create_table(
"boards",
sa.Column("org_id", sa.Uuid(), nullable=False),
sa.Column("workspace_id", sa.Uuid(), nullable=False),
sa.Column("id", sa.Uuid(), nullable=False),
sa.Column("name", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("slug", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.Column("updated_at", sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(
["org_id"],
["orgs.id"],
),
sa.ForeignKeyConstraint(
["workspace_id"],
["workspaces.id"],
),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(op.f("ix_boards_org_id"), "boards", ["org_id"], unique=False)
op.create_index(
op.f("ix_boards_workspace_id"), "boards", ["workspace_id"], unique=False
)
op.create_index(op.f("ix_boards_slug"), "boards", ["slug"], unique=False)
op.add_column("tasks", sa.Column("board_id", sa.Uuid(), nullable=True))
op.create_index(op.f("ix_tasks_board_id"), "tasks", ["board_id"], unique=False)
op.create_foreign_key(
"fk_tasks_board_id_boards", "tasks", "boards", ["board_id"], ["id"]
)
def downgrade() -> None:
op.drop_constraint("fk_tasks_board_id_boards", "tasks", type_="foreignkey")
op.drop_index(op.f("ix_tasks_board_id"), table_name="tasks")
op.drop_column("tasks", "board_id")
op.drop_index(op.f("ix_boards_slug"), table_name="boards")
op.drop_index(op.f("ix_boards_workspace_id"), table_name="boards")
op.drop_index(op.f("ix_boards_org_id"), table_name="boards")
op.drop_table("boards")

View File

@@ -1,36 +0,0 @@
"""add task assigned agent
Revision ID: 8045fbfb157f
Revises: 6df47d330227
Create Date: 2026-02-04 17:28:57.465934
"""
from __future__ import annotations
from alembic import op
# revision identifiers, used by Alembic.
revision = '8045fbfb157f'
down_revision = '6df47d330227'
branch_labels = None
depends_on = None
def upgrade() -> None:
op.execute(
"ALTER TABLE tasks ADD COLUMN IF NOT EXISTS assigned_agent_id UUID"
)
op.execute(
"ALTER TABLE tasks ADD CONSTRAINT IF NOT EXISTS tasks_assigned_agent_id_fkey "
"FOREIGN KEY (assigned_agent_id) REFERENCES agents(id)"
)
def downgrade() -> None:
op.execute(
"ALTER TABLE tasks DROP CONSTRAINT IF EXISTS tasks_assigned_agent_id_fkey"
)
op.execute(
"ALTER TABLE tasks DROP COLUMN IF EXISTS assigned_agent_id"
)

View File

@@ -1,63 +0,0 @@
"""drop projects and task project_id
Revision ID: 8b6d1b8f4b21
Revises: 7e3d9b8c1f4a
Create Date: 2026-02-03 23:05:00.000000
"""
from __future__ import annotations
from alembic import op
import sqlalchemy as sa
import sqlmodel
# revision identifiers, used by Alembic.
revision = "8b6d1b8f4b21"
down_revision = "7e3d9b8c1f4a"
branch_labels = None
depends_on = None
def upgrade() -> None:
op.drop_constraint("tasks_project_id_fkey", "tasks", type_="foreignkey")
op.drop_index(op.f("ix_tasks_project_id"), table_name="tasks")
op.drop_column("tasks", "project_id")
op.drop_index(op.f("ix_projects_workspace_id"), table_name="projects")
op.drop_index(op.f("ix_projects_status"), table_name="projects")
op.drop_index(op.f("ix_projects_org_id"), table_name="projects")
op.drop_table("projects")
def downgrade() -> None:
op.create_table(
"projects",
sa.Column("org_id", sa.Uuid(), nullable=False),
sa.Column("workspace_id", sa.Uuid(), nullable=False),
sa.Column("id", sa.Uuid(), nullable=False),
sa.Column("name", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("description", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("status", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.Column("updated_at", sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(
["org_id"],
["orgs.id"],
),
sa.ForeignKeyConstraint(
["workspace_id"],
["workspaces.id"],
),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(op.f("ix_projects_org_id"), "projects", ["org_id"], unique=False)
op.create_index(op.f("ix_projects_status"), "projects", ["status"], unique=False)
op.create_index(op.f("ix_projects_workspace_id"), "projects", ["workspace_id"], unique=False)
op.add_column("tasks", sa.Column("project_id", sa.Uuid(), nullable=True))
op.create_index(op.f("ix_tasks_project_id"), "tasks", ["project_id"], unique=False)
op.create_foreign_key(
"tasks_project_id_fkey", "tasks", "projects", ["project_id"], ["id"]
)

View File

@@ -0,0 +1,147 @@
"""init
Revision ID: 939a1d2dc607
Revises:
Create Date: 2026-02-04 19:34:33.600751
"""
from __future__ import annotations
from alembic import op
import sqlalchemy as sa
import sqlmodel
# revision identifiers, used by Alembic.
revision = '939a1d2dc607'
down_revision = None
branch_labels = None
depends_on = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('boards',
sa.Column('id', sa.Uuid(), nullable=False),
sa.Column('name', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column('slug', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column('gateway_url', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column('gateway_token', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column('gateway_main_session_key', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column('gateway_workspace_root', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column('identity_template', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column('soul_template', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column('created_at', sa.DateTime(), nullable=False),
sa.Column('updated_at', sa.DateTime(), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_boards_slug'), 'boards', ['slug'], unique=False)
op.create_table('users',
sa.Column('id', sa.Uuid(), nullable=False),
sa.Column('clerk_user_id', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column('email', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column('name', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column('preferred_name', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column('pronouns', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column('timezone', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column('notes', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column('context', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column('is_super_admin', sa.Boolean(), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_users_clerk_user_id'), 'users', ['clerk_user_id'], unique=True)
op.create_index(op.f('ix_users_email'), 'users', ['email'], unique=False)
op.create_table('agents',
sa.Column('id', sa.Uuid(), nullable=False),
sa.Column('board_id', sa.Uuid(), nullable=True),
sa.Column('name', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column('status', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column('openclaw_session_id', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column('agent_token_hash', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column('heartbeat_config', sa.JSON(), nullable=True),
sa.Column('provision_requested_at', sa.DateTime(), nullable=True),
sa.Column('provision_confirm_token_hash', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column('provision_action', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column('delete_requested_at', sa.DateTime(), nullable=True),
sa.Column('delete_confirm_token_hash', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column('last_seen_at', sa.DateTime(), nullable=True),
sa.Column('created_at', sa.DateTime(), nullable=False),
sa.Column('updated_at', sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(['board_id'], ['boards.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_agents_agent_token_hash'), 'agents', ['agent_token_hash'], unique=False)
op.create_index(op.f('ix_agents_board_id'), 'agents', ['board_id'], unique=False)
op.create_index(op.f('ix_agents_delete_confirm_token_hash'), 'agents', ['delete_confirm_token_hash'], unique=False)
op.create_index(op.f('ix_agents_name'), 'agents', ['name'], unique=False)
op.create_index(op.f('ix_agents_openclaw_session_id'), 'agents', ['openclaw_session_id'], unique=False)
op.create_index(op.f('ix_agents_provision_action'), 'agents', ['provision_action'], unique=False)
op.create_index(op.f('ix_agents_provision_confirm_token_hash'), 'agents', ['provision_confirm_token_hash'], unique=False)
op.create_index(op.f('ix_agents_status'), 'agents', ['status'], unique=False)
op.create_table('tasks',
sa.Column('id', sa.Uuid(), nullable=False),
sa.Column('board_id', sa.Uuid(), nullable=True),
sa.Column('title', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column('description', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column('status', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column('priority', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column('due_at', sa.DateTime(), nullable=True),
sa.Column('in_progress_at', sa.DateTime(), nullable=True),
sa.Column('created_by_user_id', sa.Uuid(), nullable=True),
sa.Column('assigned_agent_id', sa.Uuid(), nullable=True),
sa.Column('created_at', sa.DateTime(), nullable=False),
sa.Column('updated_at', sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(['assigned_agent_id'], ['agents.id'], ),
sa.ForeignKeyConstraint(['board_id'], ['boards.id'], ),
sa.ForeignKeyConstraint(['created_by_user_id'], ['users.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_tasks_assigned_agent_id'), 'tasks', ['assigned_agent_id'], unique=False)
op.create_index(op.f('ix_tasks_board_id'), 'tasks', ['board_id'], unique=False)
op.create_index(op.f('ix_tasks_created_by_user_id'), 'tasks', ['created_by_user_id'], unique=False)
op.create_index(op.f('ix_tasks_priority'), 'tasks', ['priority'], unique=False)
op.create_index(op.f('ix_tasks_status'), 'tasks', ['status'], unique=False)
op.create_table('activity_events',
sa.Column('id', sa.Uuid(), nullable=False),
sa.Column('event_type', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column('message', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column('agent_id', sa.Uuid(), nullable=True),
sa.Column('task_id', sa.Uuid(), nullable=True),
sa.Column('created_at', sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(['agent_id'], ['agents.id'], ),
sa.ForeignKeyConstraint(['task_id'], ['tasks.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_activity_events_agent_id'), 'activity_events', ['agent_id'], unique=False)
op.create_index(op.f('ix_activity_events_event_type'), 'activity_events', ['event_type'], unique=False)
op.create_index(op.f('ix_activity_events_task_id'), 'activity_events', ['task_id'], unique=False)
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_index(op.f('ix_activity_events_task_id'), table_name='activity_events')
op.drop_index(op.f('ix_activity_events_event_type'), table_name='activity_events')
op.drop_index(op.f('ix_activity_events_agent_id'), table_name='activity_events')
op.drop_table('activity_events')
op.drop_index(op.f('ix_tasks_status'), table_name='tasks')
op.drop_index(op.f('ix_tasks_priority'), table_name='tasks')
op.drop_index(op.f('ix_tasks_created_by_user_id'), table_name='tasks')
op.drop_index(op.f('ix_tasks_board_id'), table_name='tasks')
op.drop_index(op.f('ix_tasks_assigned_agent_id'), table_name='tasks')
op.drop_table('tasks')
op.drop_index(op.f('ix_agents_status'), table_name='agents')
op.drop_index(op.f('ix_agents_provision_confirm_token_hash'), table_name='agents')
op.drop_index(op.f('ix_agents_provision_action'), table_name='agents')
op.drop_index(op.f('ix_agents_openclaw_session_id'), table_name='agents')
op.drop_index(op.f('ix_agents_name'), table_name='agents')
op.drop_index(op.f('ix_agents_delete_confirm_token_hash'), table_name='agents')
op.drop_index(op.f('ix_agents_board_id'), table_name='agents')
op.drop_index(op.f('ix_agents_agent_token_hash'), table_name='agents')
op.drop_table('agents')
op.drop_index(op.f('ix_users_email'), table_name='users')
op.drop_index(op.f('ix_users_clerk_user_id'), table_name='users')
op.drop_table('users')
op.drop_index(op.f('ix_boards_slug'), table_name='boards')
op.drop_table('boards')
# ### end Alembic commands ###

View File

@@ -1,56 +0,0 @@
"""drop tenancy tables and columns
Revision ID: 9c4f1a2b3d4e
Revises: 8b6d1b8f4b21
Create Date: 2026-02-03 23:35:00.000000
"""
from __future__ import annotations
from alembic import op
# revision identifiers, used by Alembic.
revision = "9c4f1a2b3d4e"
down_revision = "8b6d1b8f4b21"
branch_labels = None
depends_on = None
def upgrade() -> None:
op.drop_table("task_subagents")
op.drop_table("task_status_history")
op.drop_table("task_deliverables")
op.drop_table("task_activities")
op.drop_table("transcripts")
op.drop_table("openclaw_sessions")
op.drop_table("workspace_api_tokens")
op.drop_table("orchestration_templates")
op.drop_table("memberships")
op.drop_table("gateway_configs")
op.drop_constraint("tasks_assigned_agent_id_fkey", "tasks", type_="foreignkey")
op.drop_constraint("tasks_org_id_fkey", "tasks", type_="foreignkey")
op.drop_constraint("tasks_workspace_id_fkey", "tasks", type_="foreignkey")
op.drop_index(op.f("ix_tasks_assigned_agent_id"), table_name="tasks")
op.drop_index(op.f("ix_tasks_org_id"), table_name="tasks")
op.drop_index(op.f("ix_tasks_workspace_id"), table_name="tasks")
op.drop_column("tasks", "assigned_agent_id")
op.drop_column("tasks", "org_id")
op.drop_column("tasks", "workspace_id")
op.drop_constraint("boards_org_id_fkey", "boards", type_="foreignkey")
op.drop_constraint("boards_workspace_id_fkey", "boards", type_="foreignkey")
op.drop_index(op.f("ix_boards_org_id"), table_name="boards")
op.drop_index(op.f("ix_boards_workspace_id"), table_name="boards")
op.drop_column("boards", "org_id")
op.drop_column("boards", "workspace_id")
op.drop_table("agents")
op.drop_table("workspaces")
op.drop_table("orgs")
def downgrade() -> None:
raise NotImplementedError("Downgrade not supported for simplified tenancy removal.")

View File

@@ -1,70 +0,0 @@
"""add agents and activity events
Revision ID: a1b2c3d4e5f6
Revises: 9c4f1a2b3d4e
Create Date: 2026-02-03 23:50:00.000000
"""
from __future__ import annotations
from alembic import op
import sqlalchemy as sa
import sqlmodel
# revision identifiers, used by Alembic.
revision = "a1b2c3d4e5f6"
down_revision = "9c4f1a2b3d4e"
branch_labels = None
depends_on = None
def upgrade() -> None:
op.create_table(
"agents",
sa.Column("id", sa.Uuid(), nullable=False),
sa.Column("name", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("status", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("last_seen_at", sa.DateTime(), nullable=False),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.Column("updated_at", sa.DateTime(), nullable=False),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(op.f("ix_agents_name"), "agents", ["name"], unique=False)
op.create_index(op.f("ix_agents_status"), "agents", ["status"], unique=False)
op.create_table(
"activity_events",
sa.Column("id", sa.Uuid(), nullable=False),
sa.Column("event_type", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("message", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("agent_id", sa.Uuid(), nullable=True),
sa.Column("task_id", sa.Uuid(), nullable=True),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(["agent_id"], ["agents.id"]),
sa.ForeignKeyConstraint(["task_id"], ["tasks.id"]),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(
op.f("ix_activity_events_agent_id"), "activity_events", ["agent_id"], unique=False
)
op.create_index(
op.f("ix_activity_events_event_type"),
"activity_events",
["event_type"],
unique=False,
)
op.create_index(
op.f("ix_activity_events_task_id"), "activity_events", ["task_id"], unique=False
)
def downgrade() -> None:
op.drop_index(op.f("ix_activity_events_task_id"), table_name="activity_events")
op.drop_index(op.f("ix_activity_events_event_type"), table_name="activity_events")
op.drop_index(op.f("ix_activity_events_agent_id"), table_name="activity_events")
op.drop_table("activity_events")
op.drop_index(op.f("ix_agents_status"), table_name="agents")
op.drop_index(op.f("ix_agents_name"), table_name="agents")
op.drop_table("agents")

View File

@@ -1,29 +0,0 @@
"""add task comments index
Revision ID: b9d22e2a4d50
Revises: 8045fbfb157f
Create Date: 2026-02-04 17:32:06.204331
"""
from __future__ import annotations
from alembic import op
# revision identifiers, used by Alembic.
revision = 'b9d22e2a4d50'
down_revision = '8045fbfb157f'
branch_labels = None
depends_on = None
def upgrade() -> None:
op.execute(
"CREATE INDEX IF NOT EXISTS ix_activity_events_task_comment "
"ON activity_events (task_id, created_at) "
"WHERE event_type = 'task.comment'"
)
def downgrade() -> None:
op.execute("DROP INDEX IF EXISTS ix_activity_events_task_comment")

View File

@@ -1,31 +0,0 @@
"""add task in_progress_at
Revision ID: c1a2b3c4d5e7
Revises: b9d22e2a4d50
Create Date: 2026-02-04 13:34:25.000000
"""
from __future__ import annotations
from alembic import op
# revision identifiers, used by Alembic.
revision = "c1a2b3c4d5e7"
down_revision = "b9d22e2a4d50"
branch_labels = None
depends_on = None
def upgrade() -> None:
op.execute(
"ALTER TABLE tasks ADD COLUMN IF NOT EXISTS in_progress_at TIMESTAMP WITHOUT TIME ZONE"
)
op.execute(
"CREATE INDEX IF NOT EXISTS ix_tasks_in_progress_at ON tasks (in_progress_at)"
)
def downgrade() -> None:
op.execute("DROP INDEX IF EXISTS ix_tasks_in_progress_at")
op.execute("ALTER TABLE tasks DROP COLUMN IF EXISTS in_progress_at")

View File

@@ -1,38 +0,0 @@
"""add agent openclaw session id
Revision ID: c7f0a2b1d4e3
Revises: a1b2c3d4e5f6
Create Date: 2026-02-04 02:20:00.000000
"""
from __future__ import annotations
from alembic import op
import sqlalchemy as sa
import sqlmodel
# revision identifiers, used by Alembic.
revision = "c7f0a2b1d4e3"
down_revision = "a1b2c3d4e5f6"
branch_labels = None
depends_on = None
def upgrade() -> None:
op.add_column(
"agents",
sa.Column("openclaw_session_id", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
)
op.create_index(
op.f("ix_agents_openclaw_session_id"),
"agents",
["openclaw_session_id"],
unique=False,
)
def downgrade() -> None:
op.drop_index(op.f("ix_agents_openclaw_session_id"), table_name="agents")
op.drop_column("agents", "openclaw_session_id")

View File

@@ -1,29 +0,0 @@
"""ensure heartbeat config column
Revision ID: cefef25d4634
Revises: 2b4c2f7b3eda
Create Date: 2026-02-04 16:38:25.234627
"""
from __future__ import annotations
from alembic import op
# revision identifiers, used by Alembic.
revision = 'cefef25d4634'
down_revision = '2b4c2f7b3eda'
branch_labels = None
depends_on = None
def upgrade() -> None:
op.execute(
"ALTER TABLE agents ADD COLUMN IF NOT EXISTS heartbeat_config JSON"
)
def downgrade() -> None:
op.execute(
"ALTER TABLE agents DROP COLUMN IF EXISTS heartbeat_config"
)

View File

@@ -1,38 +0,0 @@
"""add agent token hash
Revision ID: d3e4f5a6b7c8
Revises: c7f0a2b1d4e3
Create Date: 2026-02-04 06:50:00.000000
"""
from __future__ import annotations
from alembic import op
import sqlalchemy as sa
import sqlmodel
# revision identifiers, used by Alembic.
revision = "d3e4f5a6b7c8"
down_revision = "c7f0a2b1d4e3"
branch_labels = None
depends_on = None
def upgrade() -> None:
op.add_column(
"agents",
sa.Column("agent_token_hash", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
)
op.create_index(
op.f("ix_agents_agent_token_hash"),
"agents",
["agent_token_hash"],
unique=False,
)
def downgrade() -> None:
op.drop_index(op.f("ix_agents_agent_token_hash"), table_name="agents")
op.drop_column("agents", "agent_token_hash")

View File

@@ -1,35 +0,0 @@
"""add agent delete confirmation
Revision ID: e0f28e965fa5
Revises: cefef25d4634
Create Date: 2026-02-04 16:55:33.389505
"""
from __future__ import annotations
from alembic import op
# revision identifiers, used by Alembic.
revision = 'e0f28e965fa5'
down_revision = 'cefef25d4634'
branch_labels = None
depends_on = None
def upgrade() -> None:
op.execute(
"ALTER TABLE agents ADD COLUMN IF NOT EXISTS delete_requested_at TIMESTAMP"
)
op.execute(
"ALTER TABLE agents ADD COLUMN IF NOT EXISTS delete_confirm_token_hash VARCHAR"
)
def downgrade() -> None:
op.execute(
"ALTER TABLE agents DROP COLUMN IF EXISTS delete_confirm_token_hash"
)
op.execute(
"ALTER TABLE agents DROP COLUMN IF EXISTS delete_requested_at"
)

View File

@@ -1,27 +0,0 @@
"""make agent last_seen_at nullable
Revision ID: e4f5a6b7c8d9
Revises: d3e4f5a6b7c8
Create Date: 2026-02-04 07:10:00.000000
"""
from __future__ import annotations
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = "e4f5a6b7c8d9"
down_revision = "d3e4f5a6b7c8"
branch_labels = None
depends_on = None
def upgrade() -> None:
op.alter_column("agents", "last_seen_at", existing_type=sa.DateTime(), nullable=True)
def downgrade() -> None:
op.alter_column("agents", "last_seen_at", existing_type=sa.DateTime(), nullable=False)

View File

@@ -1,47 +0,0 @@
"""add board gateway config
Revision ID: f1a2b3c4d5e6
Revises: e4f5a6b7c8d9
Create Date: 2026-02-04 00:00:00.000000
"""
from __future__ import annotations
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = "f1a2b3c4d5e6"
down_revision = "e4f5a6b7c8d9"
branch_labels = None
depends_on = None
def upgrade() -> None:
op.add_column("boards", sa.Column("gateway_url", sa.String(), nullable=True))
op.add_column("boards", sa.Column("gateway_token", sa.String(), nullable=True))
op.add_column(
"boards", sa.Column("gateway_main_session_key", sa.String(), nullable=True)
)
op.add_column(
"boards", sa.Column("gateway_workspace_root", sa.String(), nullable=True)
)
op.add_column("agents", sa.Column("board_id", sa.Uuid(), nullable=True))
op.create_foreign_key(
"agents_board_id_fkey", "agents", "boards", ["board_id"], ["id"]
)
op.create_index(op.f("ix_agents_board_id"), "agents", ["board_id"], unique=False)
def downgrade() -> None:
op.drop_index(op.f("ix_agents_board_id"), table_name="agents")
op.drop_constraint("agents_board_id_fkey", "agents", type_="foreignkey")
op.drop_column("agents", "board_id")
op.drop_column("boards", "gateway_workspace_root")
op.drop_column("boards", "gateway_main_session_key")
op.drop_column("boards", "gateway_token")
op.drop_column("boards", "gateway_url")

View File

@@ -208,7 +208,9 @@ async def create_agent(
)
session.commit()
try:
await send_provisioning_message(agent, board, raw_token, provision_token)
await send_provisioning_message(
agent, board, raw_token, provision_token, auth.user
)
record_activity(
session,
event_type="agent.provision.requested",
@@ -288,7 +290,9 @@ async def update_agent(
session.commit()
session.refresh(agent)
try:
await send_update_message(agent, board, raw_token, provision_token)
await send_update_message(
agent, board, raw_token, provision_token, auth.user
)
record_activity(
session,
event_type="agent.update.requested",
@@ -375,7 +379,9 @@ async def heartbeat_or_create_agent(
)
session.commit()
try:
await send_provisioning_message(agent, board, raw_token, provision_token)
await send_provisioning_message(
agent, board, raw_token, provision_token, actor.user
)
record_activity(
session,
event_type="agent.provision.requested",
@@ -405,7 +411,9 @@ async def heartbeat_or_create_agent(
try:
board = _require_board(session, str(agent.board_id) if agent.board_id else None)
config = _require_gateway_config(board)
await send_provisioning_message(agent, board, raw_token, provision_token)
await send_provisioning_message(
agent, board, raw_token, provision_token, actor.user
)
record_activity(
session,
event_type="agent.provision.requested",

View File

@@ -101,6 +101,10 @@ def create_board(
data = payload.model_dump()
if data.get("gateway_token") == "":
data["gateway_token"] = None
if data.get("identity_template") == "":
data["identity_template"] = None
if data.get("soul_template") == "":
data["soul_template"] = None
if data.get("gateway_url"):
if not data.get("gateway_main_session_key"):
raise HTTPException(
@@ -137,6 +141,10 @@ def update_board(
updates = payload.model_dump(exclude_unset=True)
if updates.get("gateway_token") == "":
updates["gateway_token"] = None
if updates.get("identity_template") == "":
updates["identity_template"] = None
if updates.get("soul_template") == "":
updates["soul_template"] = None
for key, value in updates.items():
setattr(board, key, value)
if board.gateway_url:

View File

@@ -3,7 +3,7 @@ from __future__ import annotations
from datetime import datetime
from uuid import UUID
from fastapi import APIRouter, Depends, HTTPException, status
from fastapi import APIRouter, Depends, HTTPException, Query, status
from sqlalchemy import asc, desc
from sqlmodel import Session, col, select
@@ -70,11 +70,26 @@ def has_valid_recent_comment(
@router.get("", response_model=list[TaskRead])
def list_tasks(
status_filter: str | None = Query(default=None, alias="status"),
assigned_agent_id: UUID | None = None,
unassigned: bool | None = None,
limit: int | None = Query(default=None, ge=1, le=200),
board: Board = Depends(get_board_or_404),
session: Session = Depends(get_session),
actor: ActorContext = Depends(require_admin_or_agent),
) -> list[Task]:
return list(session.exec(select(Task).where(Task.board_id == board.id)))
statement = select(Task).where(Task.board_id == board.id)
if status_filter:
statuses = [s.strip() for s in status_filter.split(",") if s.strip()]
if statuses:
statement = statement.where(col(Task.status).in_(statuses))
if assigned_agent_id is not None:
statement = statement.where(col(Task.assigned_agent_id) == assigned_agent_id)
if unassigned:
statement = statement.where(col(Task.assigned_agent_id).is_(None))
if limit is not None:
statement = statement.limit(limit)
return list(session.exec(statement))
@router.post("", response_model=TaskRead)

36
backend/app/api/users.py Normal file
View File

@@ -0,0 +1,36 @@
from __future__ import annotations
from fastapi import APIRouter, Depends, HTTPException, status
from sqlmodel import Session
from app.core.auth import AuthContext, get_auth_context
from app.db.session import get_session
from app.models.users import User
from app.schemas.users import UserRead, UserUpdate
router = APIRouter(prefix="/users", tags=["users"])
@router.get("/me", response_model=UserRead)
async def get_me(auth: AuthContext = Depends(get_auth_context)) -> UserRead:
if auth.actor_type != "user" or auth.user is None:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED)
return UserRead.model_validate(auth.user)
@router.patch("/me", response_model=UserRead)
async def update_me(
payload: UserUpdate,
session: Session = Depends(get_session),
auth: AuthContext = Depends(get_auth_context),
) -> UserRead:
if auth.actor_type != "user" or auth.user is None:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED)
updates = payload.model_dump(exclude_unset=True)
user: User = auth.user
for key, value in updates.items():
setattr(user, key, value)
session.add(user)
session.commit()
session.refresh(user)
return UserRead.model_validate(user)

View File

@@ -25,5 +25,10 @@ class Settings(BaseSettings):
# Database lifecycle
db_auto_migrate: bool = False
# Logging
log_level: str = "INFO"
log_format: str = "text"
log_use_utc: bool = False
settings = Settings()

View File

@@ -1,14 +1,171 @@
from __future__ import annotations
import json
import logging
import os
import sys
import time
from datetime import datetime, timezone
from typing import Any
from app.core.config import settings
from app.core.version import APP_NAME, APP_VERSION
TRACE_LEVEL = 5
logging.addLevelName(TRACE_LEVEL, "TRACE")
def _trace(self: logging.Logger, message: str, *args: Any, **kwargs: Any) -> None:
if self.isEnabledFor(TRACE_LEVEL):
self._log(TRACE_LEVEL, message, args, **kwargs)
logging.Logger.trace = _trace # type: ignore[attr-defined]
_STANDARD_LOG_RECORD_ATTRS = {
"args",
"asctime",
"created",
"exc_info",
"exc_text",
"filename",
"funcName",
"levelname",
"levelno",
"lineno",
"module",
"msecs",
"message",
"msg",
"name",
"pathname",
"process",
"processName",
"relativeCreated",
"stack_info",
"thread",
"threadName",
"taskName",
"app",
"version",
}
class AppLogFilter(logging.Filter):
def __init__(self, app_name: str, version: str) -> None:
super().__init__()
self._app_name = app_name
self._version = version
def filter(self, record: logging.LogRecord) -> bool:
record.app = self._app_name
record.version = self._version
return True
class JsonFormatter(logging.Formatter):
def format(self, record: logging.LogRecord) -> str:
payload: dict[str, Any] = {
"timestamp": datetime.fromtimestamp(
record.created, tz=timezone.utc
).isoformat(),
"level": record.levelname,
"logger": record.name,
"message": record.getMessage(),
"app": getattr(record, "app", APP_NAME),
"version": getattr(record, "version", APP_VERSION),
"module": record.module,
"function": record.funcName,
"line": record.lineno,
}
if record.exc_info:
payload["exception"] = self.formatException(record.exc_info)
if record.stack_info:
payload["stack"] = self.formatStack(record.stack_info)
for key, value in record.__dict__.items():
if key in _STANDARD_LOG_RECORD_ATTRS or key in payload:
continue
payload[key] = value
return json.dumps(payload, separators=(",", ":"), default=str)
class KeyValueFormatter(logging.Formatter):
def format(self, record: logging.LogRecord) -> str:
base = super().format(record)
extras = {
key: value
for key, value in record.__dict__.items()
if key not in _STANDARD_LOG_RECORD_ATTRS
}
if not extras:
return base
extra_bits = " ".join(f"{key}={value}" for key, value in extras.items())
return f"{base} {extra_bits}"
class AppLogger:
_configured = False
@classmethod
def _resolve_level(cls) -> tuple[str, int]:
level_name = (settings.log_level or os.getenv("LOG_LEVEL", "INFO")).upper()
if level_name == "TRACE":
return level_name, TRACE_LEVEL
if level_name.isdigit():
return level_name, int(level_name)
return level_name, logging._nameToLevel.get(level_name, logging.INFO)
@classmethod
def configure(cls, *, force: bool = False) -> None:
if cls._configured and not force:
return
level_name, level = cls._resolve_level()
handler = logging.StreamHandler(sys.stdout)
handler.addFilter(AppLogFilter(APP_NAME, APP_VERSION))
format_name = (settings.log_format or "text").lower()
if format_name == "json":
formatter: logging.Formatter = JsonFormatter()
else:
formatter = KeyValueFormatter(
"%(asctime)s %(levelname)s %(name)s %(message)s app=%(app)s version=%(version)s"
)
if settings.log_use_utc:
formatter.converter = time.gmtime
handler.setFormatter(formatter)
root = logging.getLogger()
root.setLevel(level)
root.handlers.clear()
root.addHandler(handler)
# Uvicorn & HTTP clients
for logger_name in ("uvicorn", "uvicorn.error", "uvicorn.access"):
logging.getLogger(logger_name).setLevel(level)
logging.getLogger("httpx").setLevel(logging.WARNING)
logging.getLogger("httpcore").setLevel(logging.WARNING)
# SQL logs only at TRACE
sql_loggers = ("sqlalchemy", "sqlalchemy.engine", "sqlalchemy.pool")
if level_name == "TRACE":
for name in sql_loggers:
logger = logging.getLogger(name)
logger.disabled = False
logger.setLevel(logging.INFO)
else:
for name in sql_loggers:
logger = logging.getLogger(name)
logger.disabled = True
cls._configured = True
@classmethod
def get_logger(cls, name: str | None = None) -> logging.Logger:
if not cls._configured:
cls.configure()
return logging.getLogger(name)
def configure_logging() -> None:
level_name = os.getenv("LOG_LEVEL", "INFO").upper()
level = logging._nameToLevel.get(level_name, logging.INFO)
logging.basicConfig(
level=level,
format="%(asctime)s %(levelname)s %(name)s %(message)s",
force=True,
)
AppLogger.configure()

View File

@@ -0,0 +1,2 @@
APP_NAME = "mission-control"
APP_VERSION = "0.1.0"

View File

@@ -9,6 +9,7 @@ from app.api.auth import router as auth_router
from app.api.boards import router as boards_router
from app.api.gateway import router as gateway_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
from app.core.logging import configure_logging
from app.db.session import init_db
@@ -38,6 +39,16 @@ def health() -> dict[str, bool]:
return {"ok": True}
@app.get("/healthz")
def healthz() -> dict[str, bool]:
return {"ok": True}
@app.get("/readyz")
def readyz() -> dict[str, bool]:
return {"ok": True}
api_v1 = APIRouter(prefix="/api/v1")
api_v1.include_router(auth_router)
api_v1.include_router(agents_router)
@@ -45,4 +56,5 @@ api_v1.include_router(activity_router)
api_v1.include_router(gateway_router)
api_v1.include_router(boards_router)
api_v1.include_router(tasks_router)
api_v1.include_router(users_router)
app.include_router(api_v1)

View File

@@ -18,5 +18,7 @@ class Board(TenantScoped, table=True):
gateway_token: str | None = Field(default=None)
gateway_main_session_key: str | None = Field(default=None)
gateway_workspace_root: str | None = Field(default=None)
identity_template: str | None = Field(default=None)
soul_template: str | None = Field(default=None)
created_at: datetime = Field(default_factory=datetime.utcnow)
updated_at: datetime = Field(default_factory=datetime.utcnow)

View File

@@ -12,4 +12,9 @@ class User(SQLModel, table=True):
clerk_user_id: str = Field(index=True, unique=True)
email: str | None = Field(default=None, index=True)
name: str | None = None
preferred_name: str | None = None
pronouns: str | None = None
timezone: str | None = None
notes: str | None = None
context: str | None = None
is_super_admin: bool = Field(default=False)

View File

@@ -2,7 +2,7 @@ from app.schemas.activity_events import ActivityEventRead
from app.schemas.agents import AgentCreate, AgentRead, AgentUpdate
from app.schemas.boards import BoardCreate, BoardRead, BoardUpdate
from app.schemas.tasks import TaskCreate, TaskRead, TaskUpdate
from app.schemas.users import UserCreate, UserRead
from app.schemas.users import UserCreate, UserRead, UserUpdate
__all__ = [
"ActivityEventRead",
@@ -17,4 +17,5 @@ __all__ = [
"TaskUpdate",
"UserCreate",
"UserRead",
"UserUpdate",
]

View File

@@ -12,6 +12,8 @@ class BoardBase(SQLModel):
gateway_url: str | None = None
gateway_main_session_key: str | None = None
gateway_workspace_root: str | None = None
identity_template: str | None = None
soul_template: str | None = None
class BoardCreate(BoardBase):
@@ -25,6 +27,8 @@ class BoardUpdate(SQLModel):
gateway_token: str | None = None
gateway_main_session_key: str | None = None
gateway_workspace_root: str | None = None
identity_template: str | None = None
soul_template: str | None = None
class BoardRead(BoardBase):

View File

@@ -9,12 +9,26 @@ class UserBase(SQLModel):
clerk_user_id: str
email: str | None = None
name: str | None = None
preferred_name: str | None = None
pronouns: str | None = None
timezone: str | None = None
notes: str | None = None
context: str | None = None
class UserCreate(UserBase):
pass
class UserUpdate(SQLModel):
name: str | None = None
preferred_name: str | None = None
pronouns: str | None = None
timezone: str | None = None
notes: str | None = None
context: str | None = None
class UserRead(UserBase):
id: UUID
is_super_admin: bool

View File

@@ -12,6 +12,7 @@ from app.core.config import settings
from app.integrations.openclaw_gateway import GatewayConfig, ensure_session, send_message
from app.models.agents import Agent
from app.models.boards import Board
from app.models.users import User
TEMPLATE_FILES = [
"AGENTS.md",
@@ -64,11 +65,18 @@ def _template_env() -> Environment:
)
def _read_templates(context: dict[str, str]) -> dict[str, str]:
def _read_templates(
context: dict[str, str], overrides: dict[str, str] | None = None
) -> dict[str, str]:
env = _template_env()
templates: dict[str, str] = {}
override_map = overrides or {}
for name in TEMPLATE_FILES:
path = _templates_root() / name
override = override_map.get(name)
if override:
templates[name] = env.from_string(override).render(**context).strip()
continue
if not path.exists():
templates[name] = ""
continue
@@ -90,7 +98,9 @@ def _workspace_path(agent_name: str, workspace_root: str) -> str:
return f"{root}/workspace-{_slugify(agent_name)}"
def _build_context(agent: Agent, board: Board, auth_token: str) -> dict[str, str]:
def _build_context(
agent: Agent, board: Board, auth_token: str, user: User | None
) -> dict[str, str]:
if not board.gateway_workspace_root:
raise ValueError("gateway_workspace_root is required")
if not board.gateway_main_session_key:
@@ -111,25 +121,32 @@ def _build_context(agent: Agent, board: Board, auth_token: str) -> dict[str, str
"auth_token": auth_token,
"main_session_key": main_session_key,
"workspace_root": workspace_root,
"user_name": "Unset",
"user_preferred_name": "Unset",
"user_timezone": "Unset",
"user_notes": "Fill in user context.",
"user_name": user.name if user else "",
"user_preferred_name": user.preferred_name if user else "",
"user_pronouns": user.pronouns if user else "",
"user_timezone": user.timezone if user else "",
"user_notes": user.notes if user else "",
"user_context": user.context if user else "",
}
def _build_file_blocks(context: dict[str, str]) -> str:
templates = _read_templates(context)
def _build_file_blocks(context: dict[str, str], board: Board) -> str:
overrides: dict[str, str] = {}
if board.identity_template:
overrides["IDENTITY.md"] = board.identity_template
if board.soul_template:
overrides["SOUL.md"] = board.soul_template
templates = _read_templates(context, overrides=overrides)
return "".join(
_render_file_block(name, templates.get(name, "")) for name in TEMPLATE_FILES
)
def build_provisioning_message(
agent: Agent, board: Board, auth_token: str, confirm_token: str
agent: Agent, board: Board, auth_token: str, confirm_token: str, user: User | None
) -> str:
context = _build_context(agent, board, auth_token)
file_blocks = _build_file_blocks(context)
context = _build_context(agent, board, auth_token, user)
file_blocks = _build_file_blocks(context, board)
heartbeat_snippet = json.dumps(
{
"id": _agent_key(agent),
@@ -173,10 +190,10 @@ def build_provisioning_message(
def build_update_message(
agent: Agent, board: Board, auth_token: str, confirm_token: str
agent: Agent, board: Board, auth_token: str, confirm_token: str, user: User | None
) -> str:
context = _build_context(agent, board, auth_token)
file_blocks = _build_file_blocks(context)
context = _build_context(agent, board, auth_token, user)
file_blocks = _build_file_blocks(context, board)
heartbeat_snippet = json.dumps(
{
"id": _agent_key(agent),
@@ -223,6 +240,7 @@ async def send_provisioning_message(
board: Board,
auth_token: str,
confirm_token: str,
user: User | None,
) -> None:
if not board.gateway_url:
return
@@ -231,7 +249,7 @@ async def send_provisioning_message(
main_session = board.gateway_main_session_key
config = GatewayConfig(url=board.gateway_url, token=board.gateway_token)
await ensure_session(main_session, config=config, label="Main Agent")
message = build_provisioning_message(agent, board, auth_token, confirm_token)
message = build_provisioning_message(agent, board, auth_token, confirm_token, user)
await send_message(message, session_key=main_session, config=config, deliver=False)
@@ -240,6 +258,7 @@ async def send_update_message(
board: Board,
auth_token: str,
confirm_token: str,
user: User | None,
) -> None:
if not board.gateway_url:
return
@@ -248,5 +267,5 @@ async def send_update_message(
main_session = board.gateway_main_session_key
config = GatewayConfig(url=board.gateway_url, token=board.gateway_token)
await ensure_session(main_session, config=config, label="Main Agent")
message = build_update_message(agent, board, auth_token, confirm_token)
message = build_update_message(agent, board, auth_token, confirm_token, user)
await send_message(message, session_key=main_session, config=config, deliver=False)

View File

@@ -4,8 +4,17 @@ const nextConfig: NextConfig = {
allowedDevOrigins: [
"http://localhost:3000",
"http://127.0.0.1:3000",
"http://192.168.1.101",
"http://192.168.1.101:3000",
],
images: {
remotePatterns: [
{
protocol: "https",
hostname: "img.clerk.com",
},
],
},
};
export default nextConfig;

View File

@@ -10,11 +10,13 @@
"dependencies": {
"@clerk/nextjs": "^6.37.1",
"@radix-ui/react-dialog": "^1.1.2",
"@radix-ui/react-popover": "^1.1.15",
"@radix-ui/react-select": "^2.2.6",
"@radix-ui/react-tabs": "^1.1.1",
"@radix-ui/react-tooltip": "^1.1.2",
"@tanstack/react-query": "^5.90.20",
"@tanstack/react-table": "^8.21.3",
"cmdk": "^1.1.1",
"next": "16.1.6",
"react": "19.2.3",
"react-dom": "19.2.3"
@@ -2221,6 +2223,43 @@
}
}
},
"node_modules/@radix-ui/react-popover": {
"version": "1.1.15",
"resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.15.tgz",
"integrity": "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==",
"license": "MIT",
"dependencies": {
"@radix-ui/primitive": "1.1.3",
"@radix-ui/react-compose-refs": "1.1.2",
"@radix-ui/react-context": "1.1.2",
"@radix-ui/react-dismissable-layer": "1.1.11",
"@radix-ui/react-focus-guards": "1.1.3",
"@radix-ui/react-focus-scope": "1.1.7",
"@radix-ui/react-id": "1.1.1",
"@radix-ui/react-popper": "1.2.8",
"@radix-ui/react-portal": "1.1.9",
"@radix-ui/react-presence": "1.1.5",
"@radix-ui/react-primitive": "2.1.3",
"@radix-ui/react-slot": "1.2.3",
"@radix-ui/react-use-controllable-state": "1.2.2",
"aria-hidden": "^1.2.4",
"react-remove-scroll": "^2.6.3"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-popper": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz",
@@ -4232,6 +4271,22 @@
"node": ">=6"
}
},
"node_modules/cmdk": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/cmdk/-/cmdk-1.1.1.tgz",
"integrity": "sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg==",
"license": "MIT",
"dependencies": {
"@radix-ui/react-compose-refs": "^1.1.1",
"@radix-ui/react-dialog": "^1.1.6",
"@radix-ui/react-id": "^1.1.0",
"@radix-ui/react-primitive": "^2.0.2"
},
"peerDependencies": {
"react": "^18 || ^19 || ^19.0.0-rc",
"react-dom": "^18 || ^19 || ^19.0.0-rc"
}
},
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",

View File

@@ -12,12 +12,14 @@
},
"dependencies": {
"@clerk/nextjs": "^6.37.1",
"@radix-ui/react-popover": "^1.1.15",
"@radix-ui/react-dialog": "^1.1.2",
"@radix-ui/react-select": "^2.2.6",
"@radix-ui/react-tabs": "^1.1.1",
"@radix-ui/react-tooltip": "^1.1.2",
"@tanstack/react-query": "^5.90.20",
"@tanstack/react-table": "^8.21.3",
"cmdk": "^1.1.1",
"next": "16.1.6",
"react": "19.2.3",
"react-dom": "19.2.3"

View File

@@ -0,0 +1,238 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
import { useQuery } from "@tanstack/react-query";
import type {
DataTag,
DefinedInitialDataOptions,
DefinedUseQueryResult,
QueryClient,
QueryFunction,
QueryKey,
UndefinedInitialDataOptions,
UseQueryOptions,
UseQueryResult,
} from "@tanstack/react-query";
import type {
ActivityEventRead,
HTTPValidationError,
ListActivityApiV1ActivityGetParams,
} from ".././model";
import { customFetch } from "../../mutator";
type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
/**
* @summary List Activity
*/
export type listActivityApiV1ActivityGetResponse200 = {
data: ActivityEventRead[];
status: 200;
};
export type listActivityApiV1ActivityGetResponse422 = {
data: HTTPValidationError;
status: 422;
};
export type listActivityApiV1ActivityGetResponseSuccess =
listActivityApiV1ActivityGetResponse200 & {
headers: Headers;
};
export type listActivityApiV1ActivityGetResponseError =
listActivityApiV1ActivityGetResponse422 & {
headers: Headers;
};
export type listActivityApiV1ActivityGetResponse =
| listActivityApiV1ActivityGetResponseSuccess
| listActivityApiV1ActivityGetResponseError;
export const getListActivityApiV1ActivityGetUrl = (
params?: ListActivityApiV1ActivityGetParams,
) => {
const normalizedParams = new URLSearchParams();
Object.entries(params || {}).forEach(([key, value]) => {
if (value !== undefined) {
normalizedParams.append(key, value === null ? "null" : value.toString());
}
});
const stringifiedParams = normalizedParams.toString();
return stringifiedParams.length > 0
? `/api/v1/activity?${stringifiedParams}`
: `/api/v1/activity`;
};
export const listActivityApiV1ActivityGet = async (
params?: ListActivityApiV1ActivityGetParams,
options?: RequestInit,
): Promise<listActivityApiV1ActivityGetResponse> => {
return customFetch<listActivityApiV1ActivityGetResponse>(
getListActivityApiV1ActivityGetUrl(params),
{
...options,
method: "GET",
},
);
};
export const getListActivityApiV1ActivityGetQueryKey = (
params?: ListActivityApiV1ActivityGetParams,
) => {
return [`/api/v1/activity`, ...(params ? [params] : [])] as const;
};
export const getListActivityApiV1ActivityGetQueryOptions = <
TData = Awaited<ReturnType<typeof listActivityApiV1ActivityGet>>,
TError = HTTPValidationError,
>(
params?: ListActivityApiV1ActivityGetParams,
options?: {
query?: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof listActivityApiV1ActivityGet>>,
TError,
TData
>
>;
request?: SecondParameter<typeof customFetch>;
},
) => {
const { query: queryOptions, request: requestOptions } = options ?? {};
const queryKey =
queryOptions?.queryKey ?? getListActivityApiV1ActivityGetQueryKey(params);
const queryFn: QueryFunction<
Awaited<ReturnType<typeof listActivityApiV1ActivityGet>>
> = ({ signal }) =>
listActivityApiV1ActivityGet(params, { signal, ...requestOptions });
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
Awaited<ReturnType<typeof listActivityApiV1ActivityGet>>,
TError,
TData
> & { queryKey: DataTag<QueryKey, TData, TError> };
};
export type ListActivityApiV1ActivityGetQueryResult = NonNullable<
Awaited<ReturnType<typeof listActivityApiV1ActivityGet>>
>;
export type ListActivityApiV1ActivityGetQueryError = HTTPValidationError;
export function useListActivityApiV1ActivityGet<
TData = Awaited<ReturnType<typeof listActivityApiV1ActivityGet>>,
TError = HTTPValidationError,
>(
params: undefined | ListActivityApiV1ActivityGetParams,
options: {
query: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof listActivityApiV1ActivityGet>>,
TError,
TData
>
> &
Pick<
DefinedInitialDataOptions<
Awaited<ReturnType<typeof listActivityApiV1ActivityGet>>,
TError,
Awaited<ReturnType<typeof listActivityApiV1ActivityGet>>
>,
"initialData"
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): DefinedUseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
};
export function useListActivityApiV1ActivityGet<
TData = Awaited<ReturnType<typeof listActivityApiV1ActivityGet>>,
TError = HTTPValidationError,
>(
params?: ListActivityApiV1ActivityGetParams,
options?: {
query?: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof listActivityApiV1ActivityGet>>,
TError,
TData
>
> &
Pick<
UndefinedInitialDataOptions<
Awaited<ReturnType<typeof listActivityApiV1ActivityGet>>,
TError,
Awaited<ReturnType<typeof listActivityApiV1ActivityGet>>
>,
"initialData"
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
};
export function useListActivityApiV1ActivityGet<
TData = Awaited<ReturnType<typeof listActivityApiV1ActivityGet>>,
TError = HTTPValidationError,
>(
params?: ListActivityApiV1ActivityGetParams,
options?: {
query?: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof listActivityApiV1ActivityGet>>,
TError,
TData
>
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
};
/**
* @summary List Activity
*/
export function useListActivityApiV1ActivityGet<
TData = Awaited<ReturnType<typeof listActivityApiV1ActivityGet>>,
TError = HTTPValidationError,
>(
params?: ListActivityApiV1ActivityGetParams,
options?: {
query?: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof listActivityApiV1ActivityGet>>,
TError,
TData
>
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
} {
const queryOptions = getListActivityApiV1ActivityGetQueryOptions(
params,
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

@@ -0,0 +1,121 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
import { useMutation } from "@tanstack/react-query";
import type {
MutationFunction,
QueryClient,
UseMutationOptions,
UseMutationResult,
} from "@tanstack/react-query";
import type { UserRead } from ".././model";
import { customFetch } from "../../mutator";
type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
/**
* @summary Bootstrap User
*/
export type bootstrapUserApiV1AuthBootstrapPostResponse200 = {
data: UserRead;
status: 200;
};
export type bootstrapUserApiV1AuthBootstrapPostResponseSuccess =
bootstrapUserApiV1AuthBootstrapPostResponse200 & {
headers: Headers;
};
export type bootstrapUserApiV1AuthBootstrapPostResponse =
bootstrapUserApiV1AuthBootstrapPostResponseSuccess;
export const getBootstrapUserApiV1AuthBootstrapPostUrl = () => {
return `/api/v1/auth/bootstrap`;
};
export const bootstrapUserApiV1AuthBootstrapPost = async (
options?: RequestInit,
): Promise<bootstrapUserApiV1AuthBootstrapPostResponse> => {
return customFetch<bootstrapUserApiV1AuthBootstrapPostResponse>(
getBootstrapUserApiV1AuthBootstrapPostUrl(),
{
...options,
method: "POST",
},
);
};
export const getBootstrapUserApiV1AuthBootstrapPostMutationOptions = <
TError = unknown,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof bootstrapUserApiV1AuthBootstrapPost>>,
TError,
void,
TContext
>;
request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
Awaited<ReturnType<typeof bootstrapUserApiV1AuthBootstrapPost>>,
TError,
void,
TContext
> => {
const mutationKey = ["bootstrapUserApiV1AuthBootstrapPost"];
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 bootstrapUserApiV1AuthBootstrapPost>>,
void
> = () => {
return bootstrapUserApiV1AuthBootstrapPost(requestOptions);
};
return { mutationFn, ...mutationOptions };
};
export type BootstrapUserApiV1AuthBootstrapPostMutationResult = NonNullable<
Awaited<ReturnType<typeof bootstrapUserApiV1AuthBootstrapPost>>
>;
export type BootstrapUserApiV1AuthBootstrapPostMutationError = unknown;
/**
* @summary Bootstrap User
*/
export const useBootstrapUserApiV1AuthBootstrapPost = <
TError = unknown,
TContext = unknown,
>(
options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof bootstrapUserApiV1AuthBootstrapPost>>,
TError,
void,
TContext
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseMutationResult<
Awaited<ReturnType<typeof bootstrapUserApiV1AuthBootstrapPost>>,
TError,
void,
TContext
> => {
return useMutation(
getBootstrapUserApiV1AuthBootstrapPostMutationOptions(options),
queryClient,
);
};

View File

@@ -0,0 +1,767 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
import { useMutation, useQuery } from "@tanstack/react-query";
import type {
DataTag,
DefinedInitialDataOptions,
DefinedUseQueryResult,
MutationFunction,
QueryClient,
QueryFunction,
QueryKey,
UndefinedInitialDataOptions,
UseMutationOptions,
UseMutationResult,
UseQueryOptions,
UseQueryResult,
} from "@tanstack/react-query";
import type {
BoardCreate,
BoardRead,
BoardUpdate,
DeleteBoardApiV1BoardsBoardIdDelete200,
HTTPValidationError,
} from ".././model";
import { customFetch } from "../../mutator";
type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
/**
* @summary List Boards
*/
export type listBoardsApiV1BoardsGetResponse200 = {
data: BoardRead[];
status: 200;
};
export type listBoardsApiV1BoardsGetResponse422 = {
data: HTTPValidationError;
status: 422;
};
export type listBoardsApiV1BoardsGetResponseSuccess =
listBoardsApiV1BoardsGetResponse200 & {
headers: Headers;
};
export type listBoardsApiV1BoardsGetResponseError =
listBoardsApiV1BoardsGetResponse422 & {
headers: Headers;
};
export type listBoardsApiV1BoardsGetResponse =
| listBoardsApiV1BoardsGetResponseSuccess
| listBoardsApiV1BoardsGetResponseError;
export const getListBoardsApiV1BoardsGetUrl = () => {
return `/api/v1/boards`;
};
export const listBoardsApiV1BoardsGet = async (
options?: RequestInit,
): Promise<listBoardsApiV1BoardsGetResponse> => {
return customFetch<listBoardsApiV1BoardsGetResponse>(
getListBoardsApiV1BoardsGetUrl(),
{
...options,
method: "GET",
},
);
};
export const getListBoardsApiV1BoardsGetQueryKey = () => {
return [`/api/v1/boards`] as const;
};
export const getListBoardsApiV1BoardsGetQueryOptions = <
TData = Awaited<ReturnType<typeof listBoardsApiV1BoardsGet>>,
TError = HTTPValidationError,
>(options?: {
query?: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof listBoardsApiV1BoardsGet>>,
TError,
TData
>
>;
request?: SecondParameter<typeof customFetch>;
}) => {
const { query: queryOptions, request: requestOptions } = options ?? {};
const queryKey =
queryOptions?.queryKey ?? getListBoardsApiV1BoardsGetQueryKey();
const queryFn: QueryFunction<
Awaited<ReturnType<typeof listBoardsApiV1BoardsGet>>
> = ({ signal }) => listBoardsApiV1BoardsGet({ signal, ...requestOptions });
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
Awaited<ReturnType<typeof listBoardsApiV1BoardsGet>>,
TError,
TData
> & { queryKey: DataTag<QueryKey, TData, TError> };
};
export type ListBoardsApiV1BoardsGetQueryResult = NonNullable<
Awaited<ReturnType<typeof listBoardsApiV1BoardsGet>>
>;
export type ListBoardsApiV1BoardsGetQueryError = HTTPValidationError;
export function useListBoardsApiV1BoardsGet<
TData = Awaited<ReturnType<typeof listBoardsApiV1BoardsGet>>,
TError = HTTPValidationError,
>(
options: {
query: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof listBoardsApiV1BoardsGet>>,
TError,
TData
>
> &
Pick<
DefinedInitialDataOptions<
Awaited<ReturnType<typeof listBoardsApiV1BoardsGet>>,
TError,
Awaited<ReturnType<typeof listBoardsApiV1BoardsGet>>
>,
"initialData"
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): DefinedUseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
};
export function useListBoardsApiV1BoardsGet<
TData = Awaited<ReturnType<typeof listBoardsApiV1BoardsGet>>,
TError = HTTPValidationError,
>(
options?: {
query?: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof listBoardsApiV1BoardsGet>>,
TError,
TData
>
> &
Pick<
UndefinedInitialDataOptions<
Awaited<ReturnType<typeof listBoardsApiV1BoardsGet>>,
TError,
Awaited<ReturnType<typeof listBoardsApiV1BoardsGet>>
>,
"initialData"
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
};
export function useListBoardsApiV1BoardsGet<
TData = Awaited<ReturnType<typeof listBoardsApiV1BoardsGet>>,
TError = HTTPValidationError,
>(
options?: {
query?: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof listBoardsApiV1BoardsGet>>,
TError,
TData
>
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
};
/**
* @summary List Boards
*/
export function useListBoardsApiV1BoardsGet<
TData = Awaited<ReturnType<typeof listBoardsApiV1BoardsGet>>,
TError = HTTPValidationError,
>(
options?: {
query?: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof listBoardsApiV1BoardsGet>>,
TError,
TData
>
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
} {
const queryOptions = getListBoardsApiV1BoardsGetQueryOptions(options);
const query = useQuery(queryOptions, queryClient) as UseQueryResult<
TData,
TError
> & { queryKey: DataTag<QueryKey, TData, TError> };
return { ...query, queryKey: queryOptions.queryKey };
}
/**
* @summary Create Board
*/
export type createBoardApiV1BoardsPostResponse200 = {
data: BoardRead;
status: 200;
};
export type createBoardApiV1BoardsPostResponse422 = {
data: HTTPValidationError;
status: 422;
};
export type createBoardApiV1BoardsPostResponseSuccess =
createBoardApiV1BoardsPostResponse200 & {
headers: Headers;
};
export type createBoardApiV1BoardsPostResponseError =
createBoardApiV1BoardsPostResponse422 & {
headers: Headers;
};
export type createBoardApiV1BoardsPostResponse =
| createBoardApiV1BoardsPostResponseSuccess
| createBoardApiV1BoardsPostResponseError;
export const getCreateBoardApiV1BoardsPostUrl = () => {
return `/api/v1/boards`;
};
export const createBoardApiV1BoardsPost = async (
boardCreate: BoardCreate,
options?: RequestInit,
): Promise<createBoardApiV1BoardsPostResponse> => {
return customFetch<createBoardApiV1BoardsPostResponse>(
getCreateBoardApiV1BoardsPostUrl(),
{
...options,
method: "POST",
headers: { "Content-Type": "application/json", ...options?.headers },
body: JSON.stringify(boardCreate),
},
);
};
export const getCreateBoardApiV1BoardsPostMutationOptions = <
TError = HTTPValidationError,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof createBoardApiV1BoardsPost>>,
TError,
{ data: BoardCreate },
TContext
>;
request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
Awaited<ReturnType<typeof createBoardApiV1BoardsPost>>,
TError,
{ data: BoardCreate },
TContext
> => {
const mutationKey = ["createBoardApiV1BoardsPost"];
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 createBoardApiV1BoardsPost>>,
{ data: BoardCreate }
> = (props) => {
const { data } = props ?? {};
return createBoardApiV1BoardsPost(data, requestOptions);
};
return { mutationFn, ...mutationOptions };
};
export type CreateBoardApiV1BoardsPostMutationResult = NonNullable<
Awaited<ReturnType<typeof createBoardApiV1BoardsPost>>
>;
export type CreateBoardApiV1BoardsPostMutationBody = BoardCreate;
export type CreateBoardApiV1BoardsPostMutationError = HTTPValidationError;
/**
* @summary Create Board
*/
export const useCreateBoardApiV1BoardsPost = <
TError = HTTPValidationError,
TContext = unknown,
>(
options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof createBoardApiV1BoardsPost>>,
TError,
{ data: BoardCreate },
TContext
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseMutationResult<
Awaited<ReturnType<typeof createBoardApiV1BoardsPost>>,
TError,
{ data: BoardCreate },
TContext
> => {
return useMutation(
getCreateBoardApiV1BoardsPostMutationOptions(options),
queryClient,
);
};
/**
* @summary Get Board
*/
export type getBoardApiV1BoardsBoardIdGetResponse200 = {
data: BoardRead;
status: 200;
};
export type getBoardApiV1BoardsBoardIdGetResponse422 = {
data: HTTPValidationError;
status: 422;
};
export type getBoardApiV1BoardsBoardIdGetResponseSuccess =
getBoardApiV1BoardsBoardIdGetResponse200 & {
headers: Headers;
};
export type getBoardApiV1BoardsBoardIdGetResponseError =
getBoardApiV1BoardsBoardIdGetResponse422 & {
headers: Headers;
};
export type getBoardApiV1BoardsBoardIdGetResponse =
| getBoardApiV1BoardsBoardIdGetResponseSuccess
| getBoardApiV1BoardsBoardIdGetResponseError;
export const getGetBoardApiV1BoardsBoardIdGetUrl = (boardId: string) => {
return `/api/v1/boards/${boardId}`;
};
export const getBoardApiV1BoardsBoardIdGet = async (
boardId: string,
options?: RequestInit,
): Promise<getBoardApiV1BoardsBoardIdGetResponse> => {
return customFetch<getBoardApiV1BoardsBoardIdGetResponse>(
getGetBoardApiV1BoardsBoardIdGetUrl(boardId),
{
...options,
method: "GET",
},
);
};
export const getGetBoardApiV1BoardsBoardIdGetQueryKey = (boardId: string) => {
return [`/api/v1/boards/${boardId}`] as const;
};
export const getGetBoardApiV1BoardsBoardIdGetQueryOptions = <
TData = Awaited<ReturnType<typeof getBoardApiV1BoardsBoardIdGet>>,
TError = HTTPValidationError,
>(
boardId: string,
options?: {
query?: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof getBoardApiV1BoardsBoardIdGet>>,
TError,
TData
>
>;
request?: SecondParameter<typeof customFetch>;
},
) => {
const { query: queryOptions, request: requestOptions } = options ?? {};
const queryKey =
queryOptions?.queryKey ?? getGetBoardApiV1BoardsBoardIdGetQueryKey(boardId);
const queryFn: QueryFunction<
Awaited<ReturnType<typeof getBoardApiV1BoardsBoardIdGet>>
> = ({ signal }) =>
getBoardApiV1BoardsBoardIdGet(boardId, { signal, ...requestOptions });
return {
queryKey,
queryFn,
enabled: !!boardId,
...queryOptions,
} as UseQueryOptions<
Awaited<ReturnType<typeof getBoardApiV1BoardsBoardIdGet>>,
TError,
TData
> & { queryKey: DataTag<QueryKey, TData, TError> };
};
export type GetBoardApiV1BoardsBoardIdGetQueryResult = NonNullable<
Awaited<ReturnType<typeof getBoardApiV1BoardsBoardIdGet>>
>;
export type GetBoardApiV1BoardsBoardIdGetQueryError = HTTPValidationError;
export function useGetBoardApiV1BoardsBoardIdGet<
TData = Awaited<ReturnType<typeof getBoardApiV1BoardsBoardIdGet>>,
TError = HTTPValidationError,
>(
boardId: string,
options: {
query: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof getBoardApiV1BoardsBoardIdGet>>,
TError,
TData
>
> &
Pick<
DefinedInitialDataOptions<
Awaited<ReturnType<typeof getBoardApiV1BoardsBoardIdGet>>,
TError,
Awaited<ReturnType<typeof getBoardApiV1BoardsBoardIdGet>>
>,
"initialData"
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): DefinedUseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
};
export function useGetBoardApiV1BoardsBoardIdGet<
TData = Awaited<ReturnType<typeof getBoardApiV1BoardsBoardIdGet>>,
TError = HTTPValidationError,
>(
boardId: string,
options?: {
query?: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof getBoardApiV1BoardsBoardIdGet>>,
TError,
TData
>
> &
Pick<
UndefinedInitialDataOptions<
Awaited<ReturnType<typeof getBoardApiV1BoardsBoardIdGet>>,
TError,
Awaited<ReturnType<typeof getBoardApiV1BoardsBoardIdGet>>
>,
"initialData"
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
};
export function useGetBoardApiV1BoardsBoardIdGet<
TData = Awaited<ReturnType<typeof getBoardApiV1BoardsBoardIdGet>>,
TError = HTTPValidationError,
>(
boardId: string,
options?: {
query?: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof getBoardApiV1BoardsBoardIdGet>>,
TError,
TData
>
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
};
/**
* @summary Get Board
*/
export function useGetBoardApiV1BoardsBoardIdGet<
TData = Awaited<ReturnType<typeof getBoardApiV1BoardsBoardIdGet>>,
TError = HTTPValidationError,
>(
boardId: string,
options?: {
query?: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof getBoardApiV1BoardsBoardIdGet>>,
TError,
TData
>
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
} {
const queryOptions = getGetBoardApiV1BoardsBoardIdGetQueryOptions(
boardId,
options,
);
const query = useQuery(queryOptions, queryClient) as UseQueryResult<
TData,
TError
> & { queryKey: DataTag<QueryKey, TData, TError> };
return { ...query, queryKey: queryOptions.queryKey };
}
/**
* @summary Update Board
*/
export type updateBoardApiV1BoardsBoardIdPatchResponse200 = {
data: BoardRead;
status: 200;
};
export type updateBoardApiV1BoardsBoardIdPatchResponse422 = {
data: HTTPValidationError;
status: 422;
};
export type updateBoardApiV1BoardsBoardIdPatchResponseSuccess =
updateBoardApiV1BoardsBoardIdPatchResponse200 & {
headers: Headers;
};
export type updateBoardApiV1BoardsBoardIdPatchResponseError =
updateBoardApiV1BoardsBoardIdPatchResponse422 & {
headers: Headers;
};
export type updateBoardApiV1BoardsBoardIdPatchResponse =
| updateBoardApiV1BoardsBoardIdPatchResponseSuccess
| updateBoardApiV1BoardsBoardIdPatchResponseError;
export const getUpdateBoardApiV1BoardsBoardIdPatchUrl = (boardId: string) => {
return `/api/v1/boards/${boardId}`;
};
export const updateBoardApiV1BoardsBoardIdPatch = async (
boardId: string,
boardUpdate: BoardUpdate,
options?: RequestInit,
): Promise<updateBoardApiV1BoardsBoardIdPatchResponse> => {
return customFetch<updateBoardApiV1BoardsBoardIdPatchResponse>(
getUpdateBoardApiV1BoardsBoardIdPatchUrl(boardId),
{
...options,
method: "PATCH",
headers: { "Content-Type": "application/json", ...options?.headers },
body: JSON.stringify(boardUpdate),
},
);
};
export const getUpdateBoardApiV1BoardsBoardIdPatchMutationOptions = <
TError = HTTPValidationError,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof updateBoardApiV1BoardsBoardIdPatch>>,
TError,
{ boardId: string; data: BoardUpdate },
TContext
>;
request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
Awaited<ReturnType<typeof updateBoardApiV1BoardsBoardIdPatch>>,
TError,
{ boardId: string; data: BoardUpdate },
TContext
> => {
const mutationKey = ["updateBoardApiV1BoardsBoardIdPatch"];
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 updateBoardApiV1BoardsBoardIdPatch>>,
{ boardId: string; data: BoardUpdate }
> = (props) => {
const { boardId, data } = props ?? {};
return updateBoardApiV1BoardsBoardIdPatch(boardId, data, requestOptions);
};
return { mutationFn, ...mutationOptions };
};
export type UpdateBoardApiV1BoardsBoardIdPatchMutationResult = NonNullable<
Awaited<ReturnType<typeof updateBoardApiV1BoardsBoardIdPatch>>
>;
export type UpdateBoardApiV1BoardsBoardIdPatchMutationBody = BoardUpdate;
export type UpdateBoardApiV1BoardsBoardIdPatchMutationError =
HTTPValidationError;
/**
* @summary Update Board
*/
export const useUpdateBoardApiV1BoardsBoardIdPatch = <
TError = HTTPValidationError,
TContext = unknown,
>(
options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof updateBoardApiV1BoardsBoardIdPatch>>,
TError,
{ boardId: string; data: BoardUpdate },
TContext
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseMutationResult<
Awaited<ReturnType<typeof updateBoardApiV1BoardsBoardIdPatch>>,
TError,
{ boardId: string; data: BoardUpdate },
TContext
> => {
return useMutation(
getUpdateBoardApiV1BoardsBoardIdPatchMutationOptions(options),
queryClient,
);
};
/**
* @summary Delete Board
*/
export type deleteBoardApiV1BoardsBoardIdDeleteResponse200 = {
data: DeleteBoardApiV1BoardsBoardIdDelete200;
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,
);
};

View File

@@ -0,0 +1,515 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
import { useQuery } from "@tanstack/react-query";
import type {
DataTag,
DefinedInitialDataOptions,
DefinedUseQueryResult,
QueryClient,
QueryFunction,
QueryKey,
UndefinedInitialDataOptions,
UseQueryOptions,
UseQueryResult,
} from "@tanstack/react-query";
import type {
HealthHealthGet200,
HealthzHealthzGet200,
ReadyzReadyzGet200,
} from ".././model";
import { customFetch } from "../../mutator";
type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
/**
* @summary Health
*/
export type healthHealthGetResponse200 = {
data: HealthHealthGet200;
status: 200;
};
export type healthHealthGetResponseSuccess = healthHealthGetResponse200 & {
headers: Headers;
};
export type healthHealthGetResponse = healthHealthGetResponseSuccess;
export const getHealthHealthGetUrl = () => {
return `/health`;
};
export const healthHealthGet = async (
options?: RequestInit,
): Promise<healthHealthGetResponse> => {
return customFetch<healthHealthGetResponse>(getHealthHealthGetUrl(), {
...options,
method: "GET",
});
};
export const getHealthHealthGetQueryKey = () => {
return [`/health`] as const;
};
export const getHealthHealthGetQueryOptions = <
TData = Awaited<ReturnType<typeof healthHealthGet>>,
TError = unknown,
>(options?: {
query?: Partial<
UseQueryOptions<Awaited<ReturnType<typeof healthHealthGet>>, TError, TData>
>;
request?: SecondParameter<typeof customFetch>;
}) => {
const { query: queryOptions, request: requestOptions } = options ?? {};
const queryKey = queryOptions?.queryKey ?? getHealthHealthGetQueryKey();
const queryFn: QueryFunction<Awaited<ReturnType<typeof healthHealthGet>>> = ({
signal,
}) => healthHealthGet({ signal, ...requestOptions });
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
Awaited<ReturnType<typeof healthHealthGet>>,
TError,
TData
> & { queryKey: DataTag<QueryKey, TData, TError> };
};
export type HealthHealthGetQueryResult = NonNullable<
Awaited<ReturnType<typeof healthHealthGet>>
>;
export type HealthHealthGetQueryError = unknown;
export function useHealthHealthGet<
TData = Awaited<ReturnType<typeof healthHealthGet>>,
TError = unknown,
>(
options: {
query: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof healthHealthGet>>,
TError,
TData
>
> &
Pick<
DefinedInitialDataOptions<
Awaited<ReturnType<typeof healthHealthGet>>,
TError,
Awaited<ReturnType<typeof healthHealthGet>>
>,
"initialData"
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): DefinedUseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
};
export function useHealthHealthGet<
TData = Awaited<ReturnType<typeof healthHealthGet>>,
TError = unknown,
>(
options?: {
query?: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof healthHealthGet>>,
TError,
TData
>
> &
Pick<
UndefinedInitialDataOptions<
Awaited<ReturnType<typeof healthHealthGet>>,
TError,
Awaited<ReturnType<typeof healthHealthGet>>
>,
"initialData"
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
};
export function useHealthHealthGet<
TData = Awaited<ReturnType<typeof healthHealthGet>>,
TError = unknown,
>(
options?: {
query?: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof healthHealthGet>>,
TError,
TData
>
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
};
/**
* @summary Health
*/
export function useHealthHealthGet<
TData = Awaited<ReturnType<typeof healthHealthGet>>,
TError = unknown,
>(
options?: {
query?: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof healthHealthGet>>,
TError,
TData
>
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
} {
const queryOptions = getHealthHealthGetQueryOptions(options);
const query = useQuery(queryOptions, queryClient) as UseQueryResult<
TData,
TError
> & { queryKey: DataTag<QueryKey, TData, TError> };
return { ...query, queryKey: queryOptions.queryKey };
}
/**
* @summary Healthz
*/
export type healthzHealthzGetResponse200 = {
data: HealthzHealthzGet200;
status: 200;
};
export type healthzHealthzGetResponseSuccess = healthzHealthzGetResponse200 & {
headers: Headers;
};
export type healthzHealthzGetResponse = healthzHealthzGetResponseSuccess;
export const getHealthzHealthzGetUrl = () => {
return `/healthz`;
};
export const healthzHealthzGet = async (
options?: RequestInit,
): Promise<healthzHealthzGetResponse> => {
return customFetch<healthzHealthzGetResponse>(getHealthzHealthzGetUrl(), {
...options,
method: "GET",
});
};
export const getHealthzHealthzGetQueryKey = () => {
return [`/healthz`] as const;
};
export const getHealthzHealthzGetQueryOptions = <
TData = Awaited<ReturnType<typeof healthzHealthzGet>>,
TError = unknown,
>(options?: {
query?: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof healthzHealthzGet>>,
TError,
TData
>
>;
request?: SecondParameter<typeof customFetch>;
}) => {
const { query: queryOptions, request: requestOptions } = options ?? {};
const queryKey = queryOptions?.queryKey ?? getHealthzHealthzGetQueryKey();
const queryFn: QueryFunction<
Awaited<ReturnType<typeof healthzHealthzGet>>
> = ({ signal }) => healthzHealthzGet({ signal, ...requestOptions });
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
Awaited<ReturnType<typeof healthzHealthzGet>>,
TError,
TData
> & { queryKey: DataTag<QueryKey, TData, TError> };
};
export type HealthzHealthzGetQueryResult = NonNullable<
Awaited<ReturnType<typeof healthzHealthzGet>>
>;
export type HealthzHealthzGetQueryError = unknown;
export function useHealthzHealthzGet<
TData = Awaited<ReturnType<typeof healthzHealthzGet>>,
TError = unknown,
>(
options: {
query: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof healthzHealthzGet>>,
TError,
TData
>
> &
Pick<
DefinedInitialDataOptions<
Awaited<ReturnType<typeof healthzHealthzGet>>,
TError,
Awaited<ReturnType<typeof healthzHealthzGet>>
>,
"initialData"
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): DefinedUseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
};
export function useHealthzHealthzGet<
TData = Awaited<ReturnType<typeof healthzHealthzGet>>,
TError = unknown,
>(
options?: {
query?: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof healthzHealthzGet>>,
TError,
TData
>
> &
Pick<
UndefinedInitialDataOptions<
Awaited<ReturnType<typeof healthzHealthzGet>>,
TError,
Awaited<ReturnType<typeof healthzHealthzGet>>
>,
"initialData"
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
};
export function useHealthzHealthzGet<
TData = Awaited<ReturnType<typeof healthzHealthzGet>>,
TError = unknown,
>(
options?: {
query?: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof healthzHealthzGet>>,
TError,
TData
>
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
};
/**
* @summary Healthz
*/
export function useHealthzHealthzGet<
TData = Awaited<ReturnType<typeof healthzHealthzGet>>,
TError = unknown,
>(
options?: {
query?: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof healthzHealthzGet>>,
TError,
TData
>
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
} {
const queryOptions = getHealthzHealthzGetQueryOptions(options);
const query = useQuery(queryOptions, queryClient) as UseQueryResult<
TData,
TError
> & { queryKey: DataTag<QueryKey, TData, TError> };
return { ...query, queryKey: queryOptions.queryKey };
}
/**
* @summary Readyz
*/
export type readyzReadyzGetResponse200 = {
data: ReadyzReadyzGet200;
status: 200;
};
export type readyzReadyzGetResponseSuccess = readyzReadyzGetResponse200 & {
headers: Headers;
};
export type readyzReadyzGetResponse = readyzReadyzGetResponseSuccess;
export const getReadyzReadyzGetUrl = () => {
return `/readyz`;
};
export const readyzReadyzGet = async (
options?: RequestInit,
): Promise<readyzReadyzGetResponse> => {
return customFetch<readyzReadyzGetResponse>(getReadyzReadyzGetUrl(), {
...options,
method: "GET",
});
};
export const getReadyzReadyzGetQueryKey = () => {
return [`/readyz`] as const;
};
export const getReadyzReadyzGetQueryOptions = <
TData = Awaited<ReturnType<typeof readyzReadyzGet>>,
TError = unknown,
>(options?: {
query?: Partial<
UseQueryOptions<Awaited<ReturnType<typeof readyzReadyzGet>>, TError, TData>
>;
request?: SecondParameter<typeof customFetch>;
}) => {
const { query: queryOptions, request: requestOptions } = options ?? {};
const queryKey = queryOptions?.queryKey ?? getReadyzReadyzGetQueryKey();
const queryFn: QueryFunction<Awaited<ReturnType<typeof readyzReadyzGet>>> = ({
signal,
}) => readyzReadyzGet({ signal, ...requestOptions });
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
Awaited<ReturnType<typeof readyzReadyzGet>>,
TError,
TData
> & { queryKey: DataTag<QueryKey, TData, TError> };
};
export type ReadyzReadyzGetQueryResult = NonNullable<
Awaited<ReturnType<typeof readyzReadyzGet>>
>;
export type ReadyzReadyzGetQueryError = unknown;
export function useReadyzReadyzGet<
TData = Awaited<ReturnType<typeof readyzReadyzGet>>,
TError = unknown,
>(
options: {
query: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof readyzReadyzGet>>,
TError,
TData
>
> &
Pick<
DefinedInitialDataOptions<
Awaited<ReturnType<typeof readyzReadyzGet>>,
TError,
Awaited<ReturnType<typeof readyzReadyzGet>>
>,
"initialData"
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): DefinedUseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
};
export function useReadyzReadyzGet<
TData = Awaited<ReturnType<typeof readyzReadyzGet>>,
TError = unknown,
>(
options?: {
query?: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof readyzReadyzGet>>,
TError,
TData
>
> &
Pick<
UndefinedInitialDataOptions<
Awaited<ReturnType<typeof readyzReadyzGet>>,
TError,
Awaited<ReturnType<typeof readyzReadyzGet>>
>,
"initialData"
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
};
export function useReadyzReadyzGet<
TData = Awaited<ReturnType<typeof readyzReadyzGet>>,
TError = unknown,
>(
options?: {
query?: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof readyzReadyzGet>>,
TError,
TData
>
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
};
/**
* @summary Readyz
*/
export function useReadyzReadyzGet<
TData = Awaited<ReturnType<typeof readyzReadyzGet>>,
TError = unknown,
>(
options?: {
query?: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof readyzReadyzGet>>,
TError,
TData
>
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
} {
const queryOptions = getReadyzReadyzGetQueryOptions(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

@@ -0,0 +1,15 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export interface ActivityEventRead {
id: string;
event_type: string;
message: string | null;
agent_id: string | null;
task_id: string | null;
created_at: string;
}

View File

@@ -0,0 +1,14 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
import type { AgentCreateHeartbeatConfig } from "./agentCreateHeartbeatConfig";
export interface AgentCreate {
board_id?: string | null;
name: string;
status?: string;
heartbeat_config?: AgentCreateHeartbeatConfig;
}

View File

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

View File

@@ -0,0 +1,10 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export interface AgentDeleteConfirm {
token: string;
}

View File

@@ -0,0 +1,10 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export interface AgentHeartbeat {
status?: string | null;
}

View File

@@ -0,0 +1,12 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export interface AgentHeartbeatCreate {
status?: string | null;
name: string;
board_id?: string | null;
}

View File

@@ -0,0 +1,11 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export interface AgentProvisionConfirm {
token: string;
action?: string | null;
}

View File

@@ -0,0 +1,19 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
import type { AgentReadHeartbeatConfig } from "./agentReadHeartbeatConfig";
export interface AgentRead {
board_id?: string | null;
name: string;
status?: string;
heartbeat_config?: AgentReadHeartbeatConfig;
id: string;
openclaw_session_id?: string | null;
last_seen_at: string | null;
created_at: string;
updated_at: string;
}

View File

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

View File

@@ -0,0 +1,14 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
import type { AgentUpdateHeartbeatConfig } from "./agentUpdateHeartbeatConfig";
export interface AgentUpdate {
board_id?: string | null;
name?: string | null;
status?: string | null;
heartbeat_config?: AgentUpdateHeartbeatConfig;
}

View File

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

View File

@@ -0,0 +1,17 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export interface BoardCreate {
name: string;
slug: string;
gateway_url?: string | null;
gateway_main_session_key?: string | null;
gateway_workspace_root?: string | null;
identity_template?: string | null;
soul_template?: string | null;
gateway_token?: string | null;
}

View File

@@ -0,0 +1,19 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export interface BoardRead {
name: string;
slug: string;
gateway_url?: string | null;
gateway_main_session_key?: string | null;
gateway_workspace_root?: string | null;
identity_template?: string | null;
soul_template?: string | null;
id: string;
created_at: string;
updated_at: string;
}

View File

@@ -0,0 +1,17 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export interface BoardUpdate {
name?: string | null;
slug?: string | null;
gateway_url?: string | null;
gateway_token?: string | null;
gateway_main_session_key?: string | null;
gateway_workspace_root?: string | null;
identity_template?: string | null;
soul_template?: string | null;
}

View File

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

View File

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

View File

@@ -0,0 +1,8 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export type DeleteAgentApiV1AgentsAgentIdDelete200 = { [key: string]: boolean };

View File

@@ -0,0 +1,8 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export type DeleteBoardApiV1BoardsBoardIdDelete200 = { [key: string]: boolean };

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,10 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export type GatewayStatusApiV1GatewayStatusGetParams = {
board_id?: string | null;
};

View File

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

View File

@@ -0,0 +1,10 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export type GetGatewaySessionApiV1GatewaySessionsSessionIdGetParams = {
board_id?: string | null;
};

View File

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

View File

@@ -0,0 +1,10 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export type GetSessionHistoryApiV1GatewaySessionsSessionIdHistoryGetParams = {
board_id?: string | null;
};

View File

@@ -0,0 +1,11 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
import type { ValidationError } from "./validationError";
export interface HTTPValidationError {
detail?: ValidationError[];
}

View File

@@ -0,0 +1,8 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export type HealthHealthGet200 = { [key: string]: boolean };

View File

@@ -0,0 +1,8 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export type HealthzHealthzGet200 = { [key: string]: boolean };

View File

@@ -0,0 +1,52 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export * from "./activityEventRead";
export * from "./agentCreate";
export * from "./agentCreateHeartbeatConfig";
export * from "./agentDeleteConfirm";
export * from "./agentHeartbeat";
export * from "./agentHeartbeatCreate";
export * from "./agentProvisionConfirm";
export * from "./agentRead";
export * from "./agentReadHeartbeatConfig";
export * from "./agentUpdate";
export * from "./agentUpdateHeartbeatConfig";
export * from "./boardCreate";
export * from "./boardRead";
export * from "./boardUpdate";
export * from "./confirmDeleteAgentApiV1AgentsAgentIdDeleteConfirmPost200";
export * from "./confirmProvisionAgentApiV1AgentsAgentIdProvisionConfirmPost200";
export * from "./deleteAgentApiV1AgentsAgentIdDelete200";
export * from "./deleteBoardApiV1BoardsBoardIdDelete200";
export * from "./deleteTaskApiV1BoardsBoardIdTasksTaskIdDelete200";
export * from "./gatewayCommandsApiV1GatewayCommandsGet200";
export * from "./gatewayStatusApiV1GatewayStatusGet200";
export * from "./gatewayStatusApiV1GatewayStatusGetParams";
export * from "./getGatewaySessionApiV1GatewaySessionsSessionIdGet200";
export * from "./getGatewaySessionApiV1GatewaySessionsSessionIdGetParams";
export * from "./getSessionHistoryApiV1GatewaySessionsSessionIdHistoryGet200";
export * from "./getSessionHistoryApiV1GatewaySessionsSessionIdHistoryGetParams";
export * from "./healthHealthGet200";
export * from "./healthzHealthzGet200";
export * from "./hTTPValidationError";
export * from "./listActivityApiV1ActivityGetParams";
export * from "./listSessionsApiV1GatewaySessionsGet200";
export * from "./listSessionsApiV1GatewaySessionsGetParams";
export * from "./listTasksApiV1BoardsBoardIdTasksGetParams";
export * from "./readyzReadyzGet200";
export * from "./sendSessionMessageApiV1GatewaySessionsSessionIdMessagePost200";
export * from "./sendSessionMessageApiV1GatewaySessionsSessionIdMessagePostBody";
export * from "./sendSessionMessageApiV1GatewaySessionsSessionIdMessagePostParams";
export * from "./taskCommentCreate";
export * from "./taskCommentRead";
export * from "./taskCreate";
export * from "./taskRead";
export * from "./taskUpdate";
export * from "./userRead";
export * from "./userUpdate";
export * from "./validationError";

View File

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

View File

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

View File

@@ -0,0 +1,10 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export type ListSessionsApiV1GatewaySessionsGetParams = {
board_id?: string | null;
};

View File

@@ -0,0 +1,13 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export type ListTasksApiV1BoardsBoardIdTasksGetParams = {
status?: string | null;
assigned_agent_id?: string | null;
unassigned?: boolean | null;
limit?: number | null;
};

View File

@@ -0,0 +1,8 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export type ReadyzReadyzGet200 = { [key: string]: boolean };

View File

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

View File

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

View File

@@ -0,0 +1,10 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export type SendSessionMessageApiV1GatewaySessionsSessionIdMessagePostParams = {
board_id?: string | null;
};

View File

@@ -0,0 +1,10 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export interface TaskCommentCreate {
message: string;
}

View File

@@ -0,0 +1,14 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export interface TaskCommentRead {
id: string;
message: string | null;
agent_id: string | null;
task_id: string | null;
created_at: string;
}

View File

@@ -0,0 +1,16 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export interface TaskCreate {
title: string;
description?: string | null;
status?: string;
priority?: string;
due_at?: string | null;
assigned_agent_id?: string | null;
created_by_user_id?: string | null;
}

View File

@@ -0,0 +1,21 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export interface TaskRead {
title: string;
description?: string | null;
status?: string;
priority?: string;
due_at?: string | null;
assigned_agent_id?: string | null;
id: string;
board_id: string | null;
created_by_user_id: string | null;
in_progress_at: string | null;
created_at: string;
updated_at: string;
}

View File

@@ -0,0 +1,16 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export interface TaskUpdate {
title?: string | null;
description?: string | null;
status?: string | null;
priority?: string | null;
due_at?: string | null;
assigned_agent_id?: string | null;
comment?: string | null;
}

View File

@@ -0,0 +1,19 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export interface UserRead {
clerk_user_id: string;
email?: string | null;
name?: string | null;
preferred_name?: string | null;
pronouns?: string | null;
timezone?: string | null;
notes?: string | null;
context?: string | null;
id: string;
is_super_admin: boolean;
}

View File

@@ -0,0 +1,15 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export interface UserUpdate {
name?: string | null;
preferred_name?: string | null;
pronouns?: string | null;
timezone?: string | null;
notes?: string | null;
context?: string | null;
}

View File

@@ -0,0 +1,12 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
export interface ValidationError {
loc: (string | number)[];
msg: string;
type: string;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,314 @@
/**
* Generated by orval v8.2.0 🍺
* Do not edit manually.
* Mission Control API
* OpenAPI spec version: 0.1.0
*/
import { useMutation, useQuery } from "@tanstack/react-query";
import type {
DataTag,
DefinedInitialDataOptions,
DefinedUseQueryResult,
MutationFunction,
QueryClient,
QueryFunction,
QueryKey,
UndefinedInitialDataOptions,
UseMutationOptions,
UseMutationResult,
UseQueryOptions,
UseQueryResult,
} from "@tanstack/react-query";
import type { HTTPValidationError, UserRead, UserUpdate } from ".././model";
import { customFetch } from "../../mutator";
type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
/**
* @summary Get Me
*/
export type getMeApiV1UsersMeGetResponse200 = {
data: UserRead;
status: 200;
};
export type getMeApiV1UsersMeGetResponseSuccess =
getMeApiV1UsersMeGetResponse200 & {
headers: Headers;
};
export type getMeApiV1UsersMeGetResponse = getMeApiV1UsersMeGetResponseSuccess;
export const getGetMeApiV1UsersMeGetUrl = () => {
return `/api/v1/users/me`;
};
export const getMeApiV1UsersMeGet = async (
options?: RequestInit,
): Promise<getMeApiV1UsersMeGetResponse> => {
return customFetch<getMeApiV1UsersMeGetResponse>(
getGetMeApiV1UsersMeGetUrl(),
{
...options,
method: "GET",
},
);
};
export const getGetMeApiV1UsersMeGetQueryKey = () => {
return [`/api/v1/users/me`] as const;
};
export const getGetMeApiV1UsersMeGetQueryOptions = <
TData = Awaited<ReturnType<typeof getMeApiV1UsersMeGet>>,
TError = unknown,
>(options?: {
query?: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof getMeApiV1UsersMeGet>>,
TError,
TData
>
>;
request?: SecondParameter<typeof customFetch>;
}) => {
const { query: queryOptions, request: requestOptions } = options ?? {};
const queryKey = queryOptions?.queryKey ?? getGetMeApiV1UsersMeGetQueryKey();
const queryFn: QueryFunction<
Awaited<ReturnType<typeof getMeApiV1UsersMeGet>>
> = ({ signal }) => getMeApiV1UsersMeGet({ signal, ...requestOptions });
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
Awaited<ReturnType<typeof getMeApiV1UsersMeGet>>,
TError,
TData
> & { queryKey: DataTag<QueryKey, TData, TError> };
};
export type GetMeApiV1UsersMeGetQueryResult = NonNullable<
Awaited<ReturnType<typeof getMeApiV1UsersMeGet>>
>;
export type GetMeApiV1UsersMeGetQueryError = unknown;
export function useGetMeApiV1UsersMeGet<
TData = Awaited<ReturnType<typeof getMeApiV1UsersMeGet>>,
TError = unknown,
>(
options: {
query: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof getMeApiV1UsersMeGet>>,
TError,
TData
>
> &
Pick<
DefinedInitialDataOptions<
Awaited<ReturnType<typeof getMeApiV1UsersMeGet>>,
TError,
Awaited<ReturnType<typeof getMeApiV1UsersMeGet>>
>,
"initialData"
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): DefinedUseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
};
export function useGetMeApiV1UsersMeGet<
TData = Awaited<ReturnType<typeof getMeApiV1UsersMeGet>>,
TError = unknown,
>(
options?: {
query?: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof getMeApiV1UsersMeGet>>,
TError,
TData
>
> &
Pick<
UndefinedInitialDataOptions<
Awaited<ReturnType<typeof getMeApiV1UsersMeGet>>,
TError,
Awaited<ReturnType<typeof getMeApiV1UsersMeGet>>
>,
"initialData"
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
};
export function useGetMeApiV1UsersMeGet<
TData = Awaited<ReturnType<typeof getMeApiV1UsersMeGet>>,
TError = unknown,
>(
options?: {
query?: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof getMeApiV1UsersMeGet>>,
TError,
TData
>
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
};
/**
* @summary Get Me
*/
export function useGetMeApiV1UsersMeGet<
TData = Awaited<ReturnType<typeof getMeApiV1UsersMeGet>>,
TError = unknown,
>(
options?: {
query?: Partial<
UseQueryOptions<
Awaited<ReturnType<typeof getMeApiV1UsersMeGet>>,
TError,
TData
>
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseQueryResult<TData, TError> & {
queryKey: DataTag<QueryKey, TData, TError>;
} {
const queryOptions = getGetMeApiV1UsersMeGetQueryOptions(options);
const query = useQuery(queryOptions, queryClient) as UseQueryResult<
TData,
TError
> & { queryKey: DataTag<QueryKey, TData, TError> };
return { ...query, queryKey: queryOptions.queryKey };
}
/**
* @summary Update Me
*/
export type updateMeApiV1UsersMePatchResponse200 = {
data: UserRead;
status: 200;
};
export type updateMeApiV1UsersMePatchResponse422 = {
data: HTTPValidationError;
status: 422;
};
export type updateMeApiV1UsersMePatchResponseSuccess =
updateMeApiV1UsersMePatchResponse200 & {
headers: Headers;
};
export type updateMeApiV1UsersMePatchResponseError =
updateMeApiV1UsersMePatchResponse422 & {
headers: Headers;
};
export type updateMeApiV1UsersMePatchResponse =
| updateMeApiV1UsersMePatchResponseSuccess
| updateMeApiV1UsersMePatchResponseError;
export const getUpdateMeApiV1UsersMePatchUrl = () => {
return `/api/v1/users/me`;
};
export const updateMeApiV1UsersMePatch = async (
userUpdate: UserUpdate,
options?: RequestInit,
): Promise<updateMeApiV1UsersMePatchResponse> => {
return customFetch<updateMeApiV1UsersMePatchResponse>(
getUpdateMeApiV1UsersMePatchUrl(),
{
...options,
method: "PATCH",
headers: { "Content-Type": "application/json", ...options?.headers },
body: JSON.stringify(userUpdate),
},
);
};
export const getUpdateMeApiV1UsersMePatchMutationOptions = <
TError = HTTPValidationError,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof updateMeApiV1UsersMePatch>>,
TError,
{ data: UserUpdate },
TContext
>;
request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
Awaited<ReturnType<typeof updateMeApiV1UsersMePatch>>,
TError,
{ data: UserUpdate },
TContext
> => {
const mutationKey = ["updateMeApiV1UsersMePatch"];
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 updateMeApiV1UsersMePatch>>,
{ data: UserUpdate }
> = (props) => {
const { data } = props ?? {};
return updateMeApiV1UsersMePatch(data, requestOptions);
};
return { mutationFn, ...mutationOptions };
};
export type UpdateMeApiV1UsersMePatchMutationResult = NonNullable<
Awaited<ReturnType<typeof updateMeApiV1UsersMePatch>>
>;
export type UpdateMeApiV1UsersMePatchMutationBody = UserUpdate;
export type UpdateMeApiV1UsersMePatchMutationError = HTTPValidationError;
/**
* @summary Update Me
*/
export const useUpdateMeApiV1UsersMePatch = <
TError = HTTPValidationError,
TContext = unknown,
>(
options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof updateMeApiV1UsersMePatch>>,
TError,
{ data: UserUpdate },
TContext
>;
request?: SecondParameter<typeof customFetch>;
},
queryClient?: QueryClient,
): UseMutationResult<
Awaited<ReturnType<typeof updateMeApiV1UsersMePatch>>,
TError,
{ data: UserUpdate },
TContext
> => {
return useMutation(
getUpdateMeApiV1UsersMePatchMutationOptions(options),
queryClient,
);
};

View File

@@ -2,7 +2,11 @@ export const customFetch = async <T>(
url: string,
options: RequestInit
): Promise<T> => {
const baseUrl = process.env.NEXT_PUBLIC_API_URL ?? "http://localhost:8000";
const rawBaseUrl = process.env.NEXT_PUBLIC_API_URL;
if (!rawBaseUrl) {
throw new Error("NEXT_PUBLIC_API_URL is not set.");
}
const baseUrl = rawBaseUrl.replace(/\/+$/, "");
const response = await fetch(`${baseUrl}${url}`, {
...options,
headers: {

View File

@@ -9,6 +9,7 @@ import { DashboardSidebar } from "@/components/organisms/DashboardSidebar";
import { DashboardShell } from "@/components/templates/DashboardShell";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { getApiBaseUrl } from "@/lib/api-base";
import {
Select,
SelectContent,
@@ -17,9 +18,7 @@ import {
SelectValue,
} from "@/components/ui/select";
const apiBase =
process.env.NEXT_PUBLIC_API_URL?.replace(/\/+$/, "") ||
"http://localhost:8000";
const apiBase = getApiBaseUrl();
type Agent = {
id: string;

View File

@@ -18,10 +18,9 @@ import {
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { getApiBaseUrl } from "@/lib/api-base";
const apiBase =
process.env.NEXT_PUBLIC_API_URL?.replace(/\/+$/, "") ||
"http://localhost:8000";
const apiBase = getApiBaseUrl();
type Agent = {
id: string;

View File

@@ -9,6 +9,7 @@ import { DashboardSidebar } from "@/components/organisms/DashboardSidebar";
import { DashboardShell } from "@/components/templates/DashboardShell";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { getApiBaseUrl } from "@/lib/api-base";
import {
Select,
SelectContent,
@@ -17,9 +18,7 @@ import {
SelectValue,
} from "@/components/ui/select";
const apiBase =
process.env.NEXT_PUBLIC_API_URL?.replace(/\/+$/, "") ||
"http://localhost:8000";
const apiBase = getApiBaseUrl();
type Agent = {
id: string;

View File

@@ -33,10 +33,9 @@ import {
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { getApiBaseUrl } from "@/lib/api-base";
const apiBase =
process.env.NEXT_PUBLIC_API_URL?.replace(/\/+$/, "") ||
"http://localhost:8000";
const apiBase = getApiBaseUrl();
type Agent = {
id: string;

View File

@@ -9,10 +9,10 @@ import { DashboardSidebar } from "@/components/organisms/DashboardSidebar";
import { DashboardShell } from "@/components/templates/DashboardShell";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
import { getApiBaseUrl } from "@/lib/api-base";
const apiBase =
process.env.NEXT_PUBLIC_API_URL?.replace(/\/+$/, "") ||
"http://localhost:8000";
const apiBase = getApiBaseUrl();
type Board = {
id: string;
@@ -21,6 +21,8 @@ type Board = {
gateway_url?: string | null;
gateway_main_session_key?: string | null;
gateway_workspace_root?: string | null;
identity_template?: string | null;
soul_template?: string | null;
};
const slugify = (value: string) =>
@@ -44,6 +46,8 @@ export default function EditBoardPage() {
const [gatewayToken, setGatewayToken] = useState("");
const [gatewayMainSessionKey, setGatewayMainSessionKey] = useState("");
const [gatewayWorkspaceRoot, setGatewayWorkspaceRoot] = useState("");
const [identityTemplate, setIdentityTemplate] = useState("");
const [soulTemplate, setSoulTemplate] = useState("");
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
@@ -66,6 +70,8 @@ export default function EditBoardPage() {
setGatewayUrl(data.gateway_url ?? "");
setGatewayMainSessionKey(data.gateway_main_session_key ?? "");
setGatewayWorkspaceRoot(data.gateway_workspace_root ?? "");
setIdentityTemplate(data.identity_template ?? "");
setSoulTemplate(data.soul_template ?? "");
} catch (err) {
setError(err instanceof Error ? err.message : "Something went wrong.");
} finally {
@@ -96,6 +102,8 @@ export default function EditBoardPage() {
gateway_url: gatewayUrl.trim() || null,
gateway_main_session_key: gatewayMainSessionKey.trim() || null,
gateway_workspace_root: gatewayWorkspaceRoot.trim() || null,
identity_template: identityTemplate.trim() || null,
soul_template: soulTemplate.trim() || null,
};
if (gatewayToken.trim()) {
payload.gateway_token = gatewayToken.trim();
@@ -210,6 +218,28 @@ export default function EditBoardPage() {
disabled={isLoading}
/>
</div>
<div className="space-y-2">
<label className="text-sm font-medium text-strong">
Identity template (optional)
</label>
<Textarea
value={identityTemplate}
onChange={(event) => setIdentityTemplate(event.target.value)}
placeholder="Override IDENTITY.md for agents in this board."
className="min-h-[140px]"
/>
</div>
<div className="space-y-2">
<label className="text-sm font-medium text-strong">
Soul template (optional)
</label>
<Textarea
value={soulTemplate}
onChange={(event) => setSoulTemplate(event.target.value)}
placeholder="Override SOUL.md for agents in this board."
className="min-h-[160px]"
/>
</div>
{error ? (
<div className="rounded-lg border border-[color:var(--border)] bg-[color:var(--surface-muted)] p-3 text-xs text-muted">
{error}

View File

@@ -26,6 +26,7 @@ import {
SelectValue,
} from "@/components/ui/select";
import { Textarea } from "@/components/ui/textarea";
import { getApiBaseUrl } from "@/lib/api-base";
type Board = {
id: string;
@@ -57,9 +58,7 @@ type TaskComment = {
created_at: string;
};
const apiBase =
process.env.NEXT_PUBLIC_API_URL?.replace(/\/+$/, "") ||
"http://localhost:8000";
const apiBase = getApiBaseUrl();
const priorities = [
{ value: "low", label: "Low" },

View File

@@ -9,6 +9,8 @@ import { DashboardSidebar } from "@/components/organisms/DashboardSidebar";
import { DashboardShell } from "@/components/templates/DashboardShell";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
import { getApiBaseUrl } from "@/lib/api-base";
type Board = {
id: string;
@@ -18,11 +20,11 @@ type Board = {
gateway_token?: string | null;
gateway_main_session_key?: string | null;
gateway_workspace_root?: string | null;
identity_template?: string | null;
soul_template?: string | null;
};
const apiBase =
process.env.NEXT_PUBLIC_API_URL?.replace(/\/+$/, "") ||
"http://localhost:8000";
const apiBase = getApiBaseUrl();
const slugify = (value: string) =>
value
@@ -39,6 +41,8 @@ export default function NewBoardPage() {
const [gatewayToken, setGatewayToken] = useState("");
const [gatewayMainSessionKey, setGatewayMainSessionKey] = useState("");
const [gatewayWorkspaceRoot, setGatewayWorkspaceRoot] = useState("");
const [identityTemplate, setIdentityTemplate] = useState("");
const [soulTemplate, setSoulTemplate] = useState("");
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
@@ -63,6 +67,12 @@ export default function NewBoardPage() {
if (gatewayWorkspaceRoot.trim()) {
payload.gateway_workspace_root = gatewayWorkspaceRoot.trim();
}
if (identityTemplate.trim()) {
payload.identity_template = identityTemplate.trim();
}
if (soulTemplate.trim()) {
payload.soul_template = soulTemplate.trim();
}
const response = await fetch(`${apiBase}/api/v1/boards`, {
method: "POST",
headers: {
@@ -170,6 +180,28 @@ export default function NewBoardPage() {
disabled={isLoading}
/>
</div>
<div className="space-y-2">
<label className="text-sm font-medium text-strong">
Identity template (optional)
</label>
<Textarea
value={identityTemplate}
onChange={(event) => setIdentityTemplate(event.target.value)}
placeholder="Override IDENTITY.md for agents in this board."
className="min-h-[140px]"
/>
</div>
<div className="space-y-2">
<label className="text-sm font-medium text-strong">
Soul template (optional)
</label>
<Textarea
value={soulTemplate}
onChange={(event) => setSoulTemplate(event.target.value)}
placeholder="Override SOUL.md for agents in this board."
className="min-h-[160px]"
/>
</div>
{error ? (
<div className="rounded-lg border border-[color:var(--border)] bg-[color:var(--surface-muted)] p-3 text-xs text-muted">
{error}

View File

@@ -15,6 +15,7 @@ import {
import { DashboardSidebar } from "@/components/organisms/DashboardSidebar";
import { DashboardShell } from "@/components/templates/DashboardShell";
import { Button } from "@/components/ui/button";
import { getApiBaseUrl } from "@/lib/api-base";
import {
Dialog,
DialogContent,
@@ -30,9 +31,7 @@ type Board = {
slug: string;
};
const apiBase =
process.env.NEXT_PUBLIC_API_URL?.replace(/\/+$/, "") ||
"http://localhost:8000";
const apiBase = getApiBaseUrl();
export default function BoardsPage() {
const { getToken, isSignedIn } = useAuth();

View File

@@ -20,8 +20,8 @@ export default function DashboardPage() {
</p>
<SignInButton
mode="modal"
forceRedirectUrl="/boards"
signUpForceRedirectUrl="/boards"
forceRedirectUrl="/onboarding"
signUpForceRedirectUrl="/onboarding"
>
<Button>Sign in</Button>
</SignInButton>

View File

@@ -0,0 +1,275 @@
"use client";
import { useEffect, useMemo, useState } from "react";
import { useRouter } from "next/navigation";
import { SignInButton, SignedIn, SignedOut, useAuth, useUser } from "@clerk/nextjs";
import { Globe, Info, RotateCcw, Save, User } from "lucide-react";
import { DashboardShell } from "@/components/templates/DashboardShell";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import SearchableSelect from "@/components/ui/searchable-select";
import { getApiBaseUrl } from "@/lib/api-base";
const apiBase = getApiBaseUrl();
type UserProfile = {
id: string;
name?: string | null;
preferred_name?: string | null;
pronouns?: string | null;
timezone?: string | null;
notes?: string | null;
context?: string | null;
};
const isCompleteProfile = (profile: UserProfile | null) => {
if (!profile) return false;
const resolvedName = profile.preferred_name?.trim() || profile.name?.trim();
return Boolean(resolvedName) && Boolean(profile.timezone?.trim());
};
export default function OnboardingPage() {
const router = useRouter();
const { getToken, isSignedIn } = useAuth();
const { user } = useUser();
const [profile, setProfile] = useState<UserProfile | null>(null);
const [name, setName] = useState("");
const [timezone, setTimezone] = useState("");
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const requiredMissing = useMemo(
() => [name, timezone].some((value) => !value.trim()),
[name, timezone]
);
const timezones = useMemo(() => {
if (typeof Intl !== "undefined" && "supportedValuesOf" in Intl) {
return (Intl as typeof Intl & { supportedValuesOf: (key: string) => string[] })
.supportedValuesOf("timeZone")
.sort();
}
return [
"America/Los_Angeles",
"America/Denver",
"America/Chicago",
"America/New_York",
"America/Sao_Paulo",
"Europe/London",
"Europe/Berlin",
"Europe/Paris",
"Asia/Dubai",
"Asia/Kolkata",
"Asia/Singapore",
"Asia/Tokyo",
"Australia/Sydney",
];
}, []);
const timezoneOptions = useMemo(
() => timezones.map((tz) => ({ value: tz, label: tz })),
[timezones],
);
const loadProfile = async () => {
if (!isSignedIn) return;
setIsLoading(true);
setError(null);
try {
const token = await getToken();
const response = await fetch(`${apiBase}/api/v1/users/me`, {
headers: { Authorization: token ? `Bearer ${token}` : "" },
});
if (!response.ok) {
throw new Error("Unable to load profile.");
}
const data = (await response.json()) as UserProfile;
setProfile(data);
const fallbackName =
user?.fullName ?? user?.firstName ?? user?.username ?? "";
setName(data.preferred_name ?? data.name ?? fallbackName);
setTimezone(data.timezone ?? "");
if (isCompleteProfile(data)) {
router.replace("/boards");
}
} catch (err) {
setError(err instanceof Error ? err.message : "Something went wrong.");
} finally {
setIsLoading(false);
}
};
useEffect(() => {
if (!name.trim() && user) {
const fallbackName =
user.fullName ?? user.firstName ?? user.username ?? "";
if (fallbackName) {
setName(fallbackName);
}
}
}, [user, name]);
useEffect(() => {
loadProfile();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isSignedIn]);
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
if (!isSignedIn) return;
if (requiredMissing) {
setError("Please complete the required fields.");
return;
}
setIsLoading(true);
setError(null);
try {
const token = await getToken();
const normalizedName = name.trim();
const payload = {
name: normalizedName,
preferred_name: normalizedName,
timezone: timezone.trim(),
};
const response = await fetch(`${apiBase}/api/v1/users/me`, {
method: "PATCH",
headers: {
"Content-Type": "application/json",
Authorization: token ? `Bearer ${token}` : "",
},
body: JSON.stringify(payload),
});
if (!response.ok) {
throw new Error("Unable to update profile.");
}
router.replace("/boards");
} catch (err) {
setError(err instanceof Error ? err.message : "Something went wrong.");
} finally {
setIsLoading(false);
}
};
return (
<DashboardShell>
<SignedOut>
<div className="lg:col-span-2 flex min-h-[70vh] items-center justify-center">
<div className="w-full max-w-2xl rounded-xl border border-slate-200 bg-white shadow-sm">
<div className="border-b border-slate-100 px-6 py-5">
<h1 className="text-2xl font-semibold tracking-tight text-slate-900">
Mission Control profile
</h1>
<p className="mt-1 text-sm text-slate-600">
Sign in to configure your profile and timezone.
</p>
</div>
<div className="px-6 py-6">
<SignInButton
mode="modal"
forceRedirectUrl="/onboarding"
signUpForceRedirectUrl="/onboarding"
>
<Button size="lg">Sign in</Button>
</SignInButton>
</div>
</div>
</div>
</SignedOut>
<SignedIn>
<div className="lg:col-span-2 flex min-h-[70vh] items-center justify-center">
<section className="w-full max-w-2xl rounded-xl border border-slate-200 bg-white shadow-sm">
<div className="border-b border-slate-100 px-6 py-5">
<h1 className="text-2xl font-semibold tracking-tight text-slate-900">
Mission Control profile
</h1>
<p className="mt-1 text-sm text-slate-600">
Configure your mission control settings and preferences.
</p>
</div>
<div className="px-6 py-6">
<form onSubmit={handleSubmit} className="space-y-6">
<div className="grid gap-6 md:grid-cols-2">
<div className="space-y-2">
<label className="text-sm font-medium text-slate-700 flex items-center gap-2">
<User className="h-4 w-4 text-slate-500" />
Name
<span className="text-red-500">*</span>
</label>
<Input
value={name}
onChange={(event) => setName(event.target.value)}
placeholder="Enter your name"
disabled={isLoading}
className="border-slate-300 text-slate-900 focus-visible:ring-blue-500"
/>
</div>
<div className="space-y-2">
<label className="text-sm font-medium text-slate-700 flex items-center gap-2">
<Globe className="h-4 w-4 text-slate-500" />
Timezone
<span className="text-red-500">*</span>
</label>
<SearchableSelect
ariaLabel="Select timezone"
value={timezone}
onValueChange={setTimezone}
options={timezoneOptions}
placeholder="Select timezone"
searchPlaceholder="Search timezones..."
emptyMessage="No matching timezones."
triggerClassName="w-full h-11 rounded-xl border border-slate-300 bg-white px-3 py-2 text-sm font-medium text-slate-900 shadow-sm focus:border-blue-500 focus:ring-2 focus:ring-blue-200"
contentClassName="rounded-xl border border-slate-200 shadow-lg"
itemClassName="px-4 py-3 text-sm text-slate-700 data-[selected=true]:bg-slate-50 data-[selected=true]:text-slate-900"
/>
</div>
</div>
<div className="rounded-lg border border-blue-200 bg-blue-50 p-4 text-sm text-blue-800 flex items-start gap-3">
<Info className="mt-0.5 h-4 w-4 text-blue-600" />
<p>
<strong>Note:</strong> Your timezone is used to display all
timestamps and schedule mission-critical events accurately.
</p>
</div>
{error ? (
<div className="rounded-lg border border-slate-200 bg-slate-50 p-3 text-xs text-slate-600">
{error}
</div>
) : null}
<div className="flex flex-wrap gap-3 pt-2">
<Button
type="submit"
className="flex-1 bg-blue-600 text-white hover:bg-blue-700 py-2.5"
disabled={isLoading || requiredMissing}
>
<Save className="h-4 w-4" />
{isLoading ? "Saving…" : "Save Profile"}
</Button>
<button
type="button"
onClick={() => {
setName("");
setTimezone("");
setError(null);
}}
className="flex-1 rounded-md border border-slate-300 px-4 py-2.5 text-sm font-medium text-slate-700 transition-colors hover:bg-slate-50"
>
<span className="inline-flex items-center gap-2">
<RotateCcw className="h-4 w-4" />
Reset
</span>
</button>
</div>
</form>
</div>
</section>
</div>
</SignedIn>
</DashboardShell>
);
}

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