chore: untrack private docs (PROJECT, STRUCTURE, FUTURE, HISTORY, DEVELOPMENT_LOG)
|
|
@ -1,3 +1,14 @@
|
|||
# Private project/agent docs — never commit
|
||||
DEVELOPMENT_LOG.md
|
||||
PROJECT.md
|
||||
STRUCTURE.md
|
||||
FUTURE.md
|
||||
HISTORY.md
|
||||
BUILD_SUMMARY.md
|
||||
SCRIPTS.md
|
||||
project-requirements.md
|
||||
.learnings/
|
||||
|
||||
# Dependencies
|
||||
node_modules/
|
||||
.venv/
|
||||
|
|
|
|||
|
|
@ -1,88 +0,0 @@
|
|||
# Mission Control — Development Log
|
||||
|
||||
**Purpose:** Track active development work across all agents. Bishop uses this to update documentation.
|
||||
|
||||
**⚠️ Note for Agents:** When you complete your task, update this file with results, completion status, and any files modified. Ripley will then notify Bishop to review and decide on documentation updates. You have `write` and `edit` access to this file.
|
||||
|
||||
---
|
||||
|
||||
## Current Work (In Progress)
|
||||
|
||||
*(No active development — project is between phases)*
|
||||
|
||||
---
|
||||
|
||||
## Completed Work
|
||||
|
||||
### v0.0.4 — Gateway Data Collection Service
|
||||
**Status:** ✅ COMPLETED
|
||||
**Date:** 2026-05-11
|
||||
**Agent:** Neo (build) + Ripley (fix/verify/commit)
|
||||
|
||||
**Files Created:**
|
||||
- `src/backend/app/services/monitoring/__init__.py` — Package init, exports GatewayCollectorService
|
||||
- `src/backend/app/services/monitoring/gateway_collector.py` — Background asyncio collector (544→510 lines after fixes)
|
||||
- `src/backend/app/services/monitoring/models.py` — Pydantic schemas for RPC response parsing
|
||||
|
||||
**Files Modified:**
|
||||
- `src/backend/app/main.py` — Added asyncio import, collector startup/shutdown in lifespan
|
||||
- `src/backend/app/models/monitoring.py` — Fixed FK definitions (Column(UUID, ForeignKey) → Field(foreign_key=))
|
||||
- `src/backend/app/models/alert_rules.py` — Fixed FK definitions, added missing gateway_id field
|
||||
|
||||
**Bugs Fixed by Ripley:**
|
||||
- Duplicate `select` imports (sqlalchemy + sqlmodel)
|
||||
- Removed OpenClawDBService inheritance (collector uses session factory pattern)
|
||||
- Removed unused imports (datetime, timezone, UUID, TYPE_CHECKING)
|
||||
- Fixed `Column(UUID, ForeignKey(...))` — Python uuid.UUID is not a SQLAlchemy type
|
||||
- Added missing `gateway_id` field to AlertRule model
|
||||
- Cleaned up runtime imports in lifespan (moved to module-level)
|
||||
|
||||
**Verification:**
|
||||
- Docker build passes
|
||||
- Backend starts successfully (logs `app.lifecycle.gateway_collector.no_gateways`)
|
||||
- Collector class imports correctly in container
|
||||
|
||||
---
|
||||
|
||||
### v0.0.2 — Base Platform Setup
|
||||
**Status:** ✅ COMPLETED
|
||||
**Date:** 2026-05-10
|
||||
**Priority:** N/A (setup)
|
||||
|
||||
| Agent | Status | Time | Notes |
|
||||
|-------|--------|------|-------|
|
||||
| Ripley | ✅ COMPLETED | — | Forked base platform, set up Docker, verified 97 API endpoints |
|
||||
|
||||
**Files created:** `compose.yml`, `.env`, `.dockerignore`, `src/backend/Dockerfile`, `HISTORY.md`, `VERSION.md`
|
||||
|
||||
**Work Completed:**
|
||||
- [x] Copied base platform into src/ (backend + frontend)
|
||||
- [x] Adapted Dockerfile and compose.yml for src/ project layout
|
||||
- [x] Fixed webhook-worker scripts path
|
||||
- [x] Local dev auth mode: local (token-based)
|
||||
- [x] All 4 services running: db, redis, backend, frontend, webhook-worker
|
||||
- [x] 97 API endpoints verified operational
|
||||
- [x] Database migrations auto-applied
|
||||
- [x] Git repo initialized on main branch
|
||||
|
||||
### v0.0.1 — Project Initialization
|
||||
**Status:** ✅ COMPLETED
|
||||
**Date:** 2026-05-10
|
||||
**Priority:** N/A (setup)
|
||||
|
||||
| Agent | Status | Time | Notes |
|
||||
|-------|--------|------|-------|
|
||||
| Ripley | ✅ COMPLETED | — | Created project structure, cloned source repos, wrote plan |
|
||||
|
||||
**Files created:** `PROJECT.md`, `STRUCTURE.md`, `FUTURE.md`, `HISTORY.md`, `DEVELOPMENT_LOG.md`, `VERSION.md`
|
||||
|
||||
**Work Completed:**
|
||||
- [x] Analyzed all 3 source repos (mission-control, dashboard, pixel-agents)
|
||||
- [x] Wrote comprehensive 4-phase implementation plan
|
||||
- [x] Created project structure with agent roles
|
||||
- [x] Set up version history tracking
|
||||
- [x] Cloned source repos to `/tmp/mission-control-research/`
|
||||
|
||||
---
|
||||
|
||||
*This log tracks agent work. For user-facing changes, see HISTORY.md. For planned items, see FUTURE.md.*
|
||||
313
FUTURE.md
|
|
@ -1,313 +0,0 @@
|
|||
# Mission Control - Future Improvements
|
||||
|
||||
**This document tracks potential future enhancements for Mission Control.**
|
||||
|
||||
**Last Updated:** 2026-05-10
|
||||
**Current Version:** v0.0.4
|
||||
|
||||
## How to Use This Document
|
||||
|
||||
This file is a living document. Agents should:
|
||||
1. Read this file before proposing changes
|
||||
2. Add new recommendations with priority levels
|
||||
3. Never add completed items - move those to HISTORY.md instead
|
||||
4. Reference this file when dispatching improvement tasks
|
||||
5. Only Ripley can remove items from this list.
|
||||
|
||||
### Priority Format
|
||||
|
||||
All items must include the priority emoji in their heading, matching the section they belong to:
|
||||
|
||||
| Priority | Emoji | Heading Format |
|
||||
|----------|-------|---------------|
|
||||
| CRITICAL | 🔴 | `### 🔴 Title - CRITICAL` |
|
||||
| HIGH | 🟠 | `### 🟠 Title - HIGH` |
|
||||
| MEDIUM | 🟡 | `### 💡 Title - MEDIUM` |
|
||||
| LOW | 🔵 | `### 🔵 Title - LOW` |
|
||||
| NICE TO HAVE | 💭 | `### 💭 Title - NICE TO HAVE` |
|
||||
|
||||
Items are grouped under their priority section heading (`## 🔴 CRITICAL`, `## 🟠 HIGH`, etc.) and sorted most-impactful-first within each tier.
|
||||
|
||||
---
|
||||
|
||||
## Pending Recommendations
|
||||
|
||||
### 🟠 HIGH
|
||||
|
||||
### 🟠 Gateway Data Collection Service - HIGH
|
||||
**Priority:** HIGH
|
||||
**Status:** DONE ✅
|
||||
**Added:** 2026-05-10 by Ripley
|
||||
**Completed:** 2026-05-11
|
||||
|
||||
GatewayCollectorService created in `src/backend/app/services/monitoring/`. Background asyncio task polls gateway RPC endpoints (cost, cron, sessions, health) and upserts into monitoring models. Configurable intervals via env vars. Startup/shutdown integrated into main.py lifespan.
|
||||
|
||||
### 🟠 Monitoring Database Models - HIGH
|
||||
**Priority:** HIGH
|
||||
**Status:** DONE ✅
|
||||
**Added:** 2026-05-10 by Ripley
|
||||
**Completed:** 2026-05-11
|
||||
|
||||
All 7 models created, migrated, CASCADE + composite indexes verified in running DB. Committed as v0.0.3.
|
||||
|
||||
**Description:**
|
||||
Create new PostgreSQL models for tracking data (cost, sessions, crons, system health, alerts).
|
||||
|
||||
**Implementation Notes:**
|
||||
- CostSnapshot, CronJobStatus, SessionEvent, SubAgentRun, SystemHealthMetric, AlertRule
|
||||
- Alembic migration for all new tables
|
||||
- CRUD API endpoints under `/api/monitoring/`
|
||||
|
||||
### 🟠 WebSocket for Agent Events - HIGH
|
||||
**Priority:** HIGH
|
||||
**Status:** DONE ✅
|
||||
**Added:** 2026-05-10 by Ripley
|
||||
**Completed:** 2026-05-11
|
||||
|
||||
WebSocket endpoint at `/ws/agents` with initial state snapshot (last 50 events) and background polling (every 2s). Event parser ported from TS source. Committed in v0.0.4.
|
||||
|
||||
---
|
||||
|
||||
### 🟡 MEDIUM
|
||||
|
||||
### 🟠 Monitoring API Endpoints - HIGH
|
||||
**Priority:** HIGH
|
||||
**Status:** DONE ✅
|
||||
**Added:** 2026-05-11 by Ripley
|
||||
**Completed:** 2026-05-11
|
||||
|
||||
10 read-only endpoints at /api/v1/monitoring/* with org-scoping, pagination, and filtering. Schemas in app/schemas/monitoring.py, router in app/api/monitoring.py.
|
||||
|
||||
### 🟠 Dashboard Logic Port - HIGH
|
||||
**Priority:** HIGH
|
||||
**Status:** DONE ✅
|
||||
**Added:** 2026-05-11 by Ripley
|
||||
**Completed:** 2026-05-11
|
||||
|
||||
Data processing functions ported to Python: `ModelName()`, `BuildDailyChart()`, `BuildAlerts()`, `FmtTokens()`, `BuildCostBreakdown()`. Event parser ported: `parse_session_event()`, `format_tool_status()`. WebSocket endpoint at `/ws/agents` with initial snapshot + polling. All committed in v0.0.4.
|
||||
|
||||
### 🟠 Cost Summary API Endpoints — HIGH
|
||||
**Priority:** HIGH
|
||||
**Status:** DONE ✅
|
||||
**Added:** 2026-05-11 by Ripley
|
||||
**Completed:** 2026-05-12 by Neo
|
||||
|
||||
**Description:**
|
||||
"How much have I spent today, and which model is burning the most?" — Cost Cards + Cost Breakdown API endpoints.
|
||||
|
||||
**Implementation Notes:**
|
||||
- Today's cost, all-time cost, projected monthly cost
|
||||
- Per-model cost breakdown (7d/30d/all-time tabs)
|
||||
- Use existing `data_processing.BuildCostBreakdown()` and `data_processing.BuildDailyChart()`
|
||||
- New API endpoints: `GET /api/v1/monitoring/cost-summary` and `GET /api/v1/monitoring/cost-breakdown?range=7d|30d|all`
|
||||
- Org-scoped, paginated where applicable
|
||||
- Neo implemented cost-summary and cost-breakdown endpoints
|
||||
|
||||
### 🟠 Health Summary API — HIGH
|
||||
**Priority:** HIGH
|
||||
**Status:** DONE ✅
|
||||
**Added:** 2026-05-11 by Ripley
|
||||
**Completed:** 2026-05-12 by Neo
|
||||
|
||||
**Description:**
|
||||
"Is my gateway actually running right now?" — System health summary endpoint.
|
||||
|
||||
**Implementation Notes:**
|
||||
- Gateway status (online/offline), PID, uptime, memory, compaction
|
||||
- CPU, RAM, swap, disk gauges
|
||||
- Use existing `monitoring/health` endpoint data + `data_processing` functions
|
||||
- New API endpoint: `GET /api/v1/monitoring/health-summary`
|
||||
- Neo implemented health-summary endpoint
|
||||
|
||||
### 🟠 Cron Summary API — HIGH
|
||||
**Priority:** HIGH
|
||||
**Status:** DONE ✅
|
||||
**Added:** 2026-05-11 by Ripley
|
||||
**Completed:** 2026-05-12 by Neo
|
||||
|
||||
**Description:**
|
||||
"Which cron jobs ran, which failed, and when does the next one fire?" — Cron summary endpoint.
|
||||
|
||||
**Implementation Notes:**
|
||||
- List all cron jobs with status, schedule, last/next run, duration, model
|
||||
- Filter by enabled/disabled, gateway
|
||||
- Use existing `monitoring/cron-jobs` endpoint
|
||||
- New API endpoint: `GET /api/v1/monitoring/cron-summary`
|
||||
- Neo implemented cron-summary endpoint
|
||||
|
||||
### 🟠 Sessions Summary API — HIGH
|
||||
**Priority:** HIGH
|
||||
**Status:** DONE ✅
|
||||
**Added:** 2026-05-11 by Ripley
|
||||
**Completed:** 2026-05-12 by Neo
|
||||
|
||||
**Description:**
|
||||
"What sessions are active and how much context are they consuming?" — Active sessions summary.
|
||||
|
||||
**Implementation Notes:**
|
||||
- Recent sessions with model, type badges (DM/group/cron/subagent), context %, tokens
|
||||
- Use `data_processing.ModelName()` and `event_parser.parse_session_event()`
|
||||
- New API endpoint: `GET /api/v1/monitoring/sessions-summary`
|
||||
- Neo implemented sessions-summary endpoint
|
||||
|
||||
### 🟠 Sub-Agents Summary API — HIGH
|
||||
**Priority:** HIGH
|
||||
**Status:** DONE ✅
|
||||
**Added:** 2026-05-11 by Ripley
|
||||
**Completed:** 2026-05-12 by Neo
|
||||
|
||||
**Description:**
|
||||
"Are my sub-agents doing useful work or spinning in circles?" — Sub-agent activity summary.
|
||||
|
||||
**Implementation Notes:**
|
||||
- Sub-agent runs with cost, duration, status + token breakdown (7d/30d tabs)
|
||||
- Use existing `monitoring/sub-agents` endpoint
|
||||
- New API endpoint: `GET /api/v1/monitoring/sub-agents-summary`
|
||||
- Neo implemented sub-agents-summary endpoint
|
||||
|
||||
### 🟠 Cost Trends API — HIGH
|
||||
**Priority:** HIGH
|
||||
**Status:** DONE ✅
|
||||
**Added:** 2026-05-11 by Ripley
|
||||
**Completed:** 2026-05-12 by Neo
|
||||
|
||||
**Description:**
|
||||
"What's the cost trend over the last 7 days — am I accelerating?" — Charts & trends endpoint.
|
||||
|
||||
**Implementation Notes:**
|
||||
- Cost trend line (7d/30d), model cost breakdown bars, per-model usage
|
||||
- Use `data_processing.BuildDailyChart()`
|
||||
- New API endpoint: `GET /api/v1/monitoring/trends?range=7d|30d`
|
||||
- Neo implemented trends endpoint with 7d/30d support
|
||||
|
||||
### 🟡 Cost Tracking UI - MEDIUM
|
||||
**Priority:** MEDIUM
|
||||
**Status:** PENDING
|
||||
**Added:** 2026-05-10 by Ripley
|
||||
|
||||
**Description:**
|
||||
Port the dashboard's cost cards, donut charts, and trend lines to React/Recharts components.
|
||||
|
||||
**Implementation Notes:**
|
||||
- Today's cost, all-time cost, projected monthly
|
||||
- Per-model cost breakdown (7d/30d/all-time tabs)
|
||||
- Cost trend line chart (SVG → Recharts)
|
||||
- Theme-aware styling
|
||||
|
||||
### 🟡 Session & Sub-Agent UI - MEDIUM
|
||||
**Priority:** MEDIUM
|
||||
**Status:** PENDING
|
||||
**Added:** 2026-05-10 by Ripley
|
||||
|
||||
**Description:**
|
||||
Active sessions with model, type badges, context % bars, sub-agent activity grid.
|
||||
|
||||
**Implementation Notes:**
|
||||
- Session list with filtering (model, type, status)
|
||||
- Context % bars, token counts
|
||||
- Sub-agent activity grid with cost/duration/status
|
||||
- Session detail panel with conversation preview
|
||||
|
||||
### 🟡 Cron Job Management - MEDIUM
|
||||
**Priority:** MEDIUM
|
||||
**Status:** PENDING
|
||||
**Added:** 2026-05-10 by Ripley
|
||||
|
||||
**Description:**
|
||||
Cron job list with schedule, status, run history. Trigger manual runs from UI.
|
||||
|
||||
**Implementation Notes:**
|
||||
- List, add, edit, delete cron jobs via gateway RPC
|
||||
- Run history with duration and status badges
|
||||
- Manual trigger button
|
||||
- Uses existing `cron.*` gateway RPC methods
|
||||
|
||||
### 🟡 System Health Dashboard - MEDIUM
|
||||
**Priority:** MEDIUM
|
||||
**Status:** PENDING
|
||||
**Added:** 2026-05-10 by Ripley
|
||||
|
||||
**Description:**
|
||||
Gateway status, CPU/RAM/disk gauges, alert banners with configurable thresholds.
|
||||
|
||||
**Implementation Notes:**
|
||||
- Gateway uptime, PID, memory, compaction status
|
||||
- CPU/RAM/swap/disk gauge cards
|
||||
- Alert banner for high cost, failed crons, gateway offline
|
||||
- Auto-refresh with countdown timer
|
||||
|
||||
---
|
||||
|
||||
### 🔵 LOW
|
||||
|
||||
### 🔵 AI Chat Panel - LOW
|
||||
**Priority:** LOW
|
||||
**Status:** PENDING
|
||||
**Added:** 2026-05-10 by Ripley
|
||||
|
||||
**Description:**
|
||||
Port the dashboard's AI chat to a React component that uses OpenClaw gateway's `/v1/chat/completions`.
|
||||
|
||||
**Implementation Notes:**
|
||||
- Context-aware: feed live monitoring data into system prompt
|
||||
- Persistent chat history per user
|
||||
- Streaming responses
|
||||
|
||||
### 🔵 Theme System Merge - LOW
|
||||
**Priority:** LOW
|
||||
**Status:** PENDING
|
||||
**Added:** 2026-05-10 by Ripley
|
||||
|
||||
**Description:**
|
||||
Port the 6 dashboard themes into Mission Control's Tailwind config.
|
||||
|
||||
**Implementation Notes:**
|
||||
- Map dashboard's 19 CSS color variables to Tailwind config
|
||||
- Theme picker in header (persists via localStorage)
|
||||
- Glass morphism effects where appropriate
|
||||
|
||||
### 🔵 Engineering Reference Manual - LOW
|
||||
**Priority:** LOW
|
||||
**Status:** PENDING - Requires explicit user initiation
|
||||
**Added:** 2026-05-10 by Ripley
|
||||
|
||||
**Description:**
|
||||
Comprehensive engineering reference manual documenting the full system architecture, API endpoints, data models, frontend pages/components, and infrastructure.
|
||||
|
||||
**Implementation Notes:**
|
||||
- ⚠️ This task requires explicit initiation by the user. Do not create the Engineering Reference Manual unless specifically asked.
|
||||
- Should document: system architecture, tech stack, all API endpoints, data models, frontend structure, Docker setup, auth flows
|
||||
- Bishop would own this task when initiated
|
||||
|
||||
---
|
||||
|
||||
### 💭 NICE TO HAVE
|
||||
|
||||
### 💭 Pixel Agent Canvas - NICE TO HAVE
|
||||
**Priority:** NICE TO HAVE
|
||||
**Status:** PENDING
|
||||
**Added:** 2026-05-10 by Ripley
|
||||
|
||||
**Description:**
|
||||
Port the pixel-art office scene with agent sprites, activity bubbles, and day/night cycle to React Canvas.
|
||||
|
||||
**Implementation Notes:**
|
||||
- Use `useRef` + `requestAnimationFrame` for animation, not React state
|
||||
- Agent sprites with activity state (working, idle, talking)
|
||||
- Activity bubbles showing current task/conversation
|
||||
- Conversation heat glow based on recent activity
|
||||
- Pan/zoom controls (touch + mouse)
|
||||
|
||||
### 💭 Hardware Monitor & Service Controls - NICE TO HAVE
|
||||
**Priority:** NICE TO HAVE
|
||||
**Status:** PENDING
|
||||
**Added:** 2026-05-10 by Ripley
|
||||
|
||||
**Description:**
|
||||
Server rack component for hardware gauges, breaker panel for gateway start/stop/restart.
|
||||
|
||||
**Implementation Notes:**
|
||||
- CPU/GPU/RAM/disk/network gauges
|
||||
- Gateway start/stop/restart controls
|
||||
- Update checker (ham radio component)
|
||||
- All via gateway RPC methods
|
||||
84
HISTORY.md
|
|
@ -1,84 +0,0 @@
|
|||
# Mission Control — Changelog
|
||||
|
||||
## v0.0.5
|
||||
|
||||
### Added
|
||||
- **7 monitoring summary endpoints** — Neo implemented all remaining summary endpoints:
|
||||
- `GET /api/v1/monitoring/cost-summary` — Cost overview per gateway with model breakdown
|
||||
- `GET /api/v1/monitoring/cost-breakdown` — Models ranked by cost with percentage breakdown
|
||||
- `GET /api/v1/monitoring/health-summary` — Gateway health status and system metrics (CPU, RAM, disk, uptime)
|
||||
- `GET /api/v1/monitoring/cron-summary` — Cron job status with scheduling info (schedule, last/next run, failures)
|
||||
- `GET /api/v1/monitoring/sessions-summary` — Active sessions with context and token breakdown
|
||||
- `GET /api/v1/monitoring/sub-agents-summary` — Sub-agent runs with cost and token breakdown
|
||||
- `GET /api/v1/monitoring/trends` — Cost and token trends over 7d or 30d time ranges
|
||||
- **All endpoints support** org-scoped filtering via `gateway_id`, pagination, and security review passed (Hudson)
|
||||
- **Security audit** — Hudson reviewed and applied 1 fix for security issues
|
||||
- **Python compilation verification** — All Python files compile cleanly with `py_compile`
|
||||
|
||||
### Changed
|
||||
- Version bump: 0.0.4 → 0.0.5 (minor bump for new feature endpoints)
|
||||
- Updated FUTURE.md — marked all 7 summary endpoints as DONE
|
||||
- Updated README.md — API reference table now shows all 12 endpoints as Live
|
||||
|
||||
### Build Status
|
||||
- Backend builds successfully (Docker Compose unavailable due to client version, but Python compilation verified)
|
||||
- All 50+ Python files in backend compile without errors
|
||||
- GatewayCollectorService operational with 4 collection intervals (cost, cron, session, health)
|
||||
|
||||
## v0.0.4
|
||||
|
||||
### Added
|
||||
- **Gateway Data Collection Service** — Background asyncio task that polls gateway RPC endpoints and stores results in monitoring models
|
||||
- `gateway_collector.py` — GatewayCollectorService class with per-endpoint collection methods (cost, cron, session, health)
|
||||
- `models.py` — Pydantic schemas for parsing gateway RPC responses into typed Python objects
|
||||
- `__init__.py` — Package init, exports GatewayCollectorService
|
||||
- **Collector startup/shutdown** — Added to main.py lifespan; launches collector as background task when gateways exist
|
||||
- **Configurable collection intervals** via env vars: COLLECTION_INTERVAL_COST (300s), COLLECTION_INTERVAL_CRON (60s), COLLECTION_INTERVAL_SESSION (30s), COLLECTION_INTERVAL_HEALTH (60s)
|
||||
- **Upsert pattern** — All DB writes use insert-or-update to avoid duplicate records
|
||||
|
||||
### Fixed
|
||||
- Model FK definitions in monitoring.py and alert_rules.py: replaced `Column(UUID, ForeignKey(...))` with `Field(foreign_key=...)` to match codebase pattern
|
||||
- Added missing `gateway_id` field to AlertRule model
|
||||
- Removed OpenClawDBService inheritance from GatewayCollectorService (uses session factory pattern)
|
||||
- Cleaned up duplicate/conflicting imports in collector
|
||||
|
||||
## v0.0.3
|
||||
|
||||
### Added
|
||||
- **Phase 2: Monitoring database models** — 7 new SQLModel tables for gateway data collection
|
||||
- **CostSnapshot** — Timestamped cost readings from gateway RPC (per-model, per-provider breakdown)
|
||||
- **CronJobStatus** — Cron job state, schedule, failure tracking
|
||||
- **SessionEvent** — Session lifecycle events with model, channel, context%, token counts
|
||||
- **SubAgentRun** — Sub-agent execution records with duration, cost, token tracking
|
||||
- **SystemHealthMetric** — CPU, RAM, swap, disk, gateway status metrics
|
||||
- **AlertRule** — Configurable alert thresholds with comparison operators and cooldown
|
||||
- **AlertEvent** — Triggered alert instances with acknowledgment and resolution tracking
|
||||
- **Alembic migration 7a8b9c0d1e2f** — Creates all 7 monitoring tables with FKs and indexes
|
||||
- **Alembic migration 8f9a0b1c2d3e** — Adds ON DELETE CASCADE to all FKs, SET NULL on acknowledged_by, 14 composite indexes
|
||||
- **Security audit passed** — Hudson: 1 CRITICAL (CASCADE), 2 HIGH (mass assignment, indexes), 3 MEDIUM — all remediated
|
||||
|
||||
### Changed
|
||||
- Frontend dev port changed from 3080 to 3037
|
||||
- Migration env.py updated for transaction-per-migration to prevent failure chaining
|
||||
|
||||
## v0.0.2
|
||||
|
||||
### Added
|
||||
- **Base platform forked and running** — Python/FastAPI backend + Next.js frontend copied into src/
|
||||
- **Docker Compose dev environment** — compose.yml, .env, .dockerignore created
|
||||
- **Dockerfile adapted** — Fixed build context for src/ layout, fixed scripts paths for webhook worker
|
||||
- **All services operational** — db (Postgres 16), redis, backend (uvicorn :8000), frontend (Next.js :3000), webhook-worker
|
||||
- **97 API endpoints verified** — Full OpenAPI surface confirmed at /docs
|
||||
- **Git repo initialized** — main branch, initial commit 9aee2e4
|
||||
|
||||
### Infrastructure
|
||||
- Ports mapped: backend → 8080, frontend → 3080 (host), avoiding Portainer/open-webui conflicts
|
||||
- Auth mode: local (token-based, LOCAL_AUTH_TOKEN in .env)
|
||||
- DB auto-migrate enabled
|
||||
|
||||
## v0.0.1
|
||||
|
||||
### Added
|
||||
- **Project initialization** — STRUCTURE.md, PROJECT.md, FUTURE.md, HISTORY.md, DEVELOPMENT_LOG.md, VERSION.md
|
||||
- **Source repos cloned** — openclaw-mission-control (base), openclaw-dashboard (tracking), openclaw-pixel-agents-dashboard (visualization)
|
||||
- **Architecture plan** — Full 4-phase implementation plan documented in PROJECT.md
|
||||
396
PROJECT.md
|
|
@ -1,396 +0,0 @@
|
|||
# 🎯 Mission Control — Project Plan
|
||||
|
||||
> Merge three OpenClaw dashboards into a single, unified Mission Control platform.
|
||||
|
||||
---
|
||||
|
||||
## Source Repos
|
||||
|
||||
| Repo | Purpose | Stack | Key Assets |
|
||||
|---|---|---|---|
|
||||
| [abhi1693/openclaw-mission-control](https://github.com/abhi1693/openclaw-mission-control) | **Base platform** — work orchestration, governance, gateway management | Python/FastAPI + PostgreSQL + Redis + Next.js (React 19) + Clerk auth + Docker Compose | Organizations, boards, tasks, tags, approvals, agents, gateways, webhooks, activity feed, skills marketplace |
|
||||
| [mudrii/openclaw-dashboard](https://github.com/mudrii/openclaw-dashboard) | **Tracking layer** — real-time metrics, costs, crons, sessions, system health | Go binary (zero deps) + embedded HTML/JS + SVG charts | Cost cards, cron status, session tracking, sub-agent activity, AI chat, system metrics (CPU/RAM/disk), 6 themes, alerts, token usage |
|
||||
| [jaffer1979/openclaw-pixel-agents-dashboard](https://github.com/jaffer1979/openclaw-pixel-agents-dashboard) | **Agent visualization** — pixel-art agent sprites, real-time activity | Node/Express + Vite + React 19 + Canvas/WebSocket + JSONL parsing | Agent sprites with activity bubbles, conversation heat, spawn sub-agents, hardware monitor, service controls, day/night cycle |
|
||||
|
||||
---
|
||||
|
||||
## Architecture Decision: What to Merge Into What
|
||||
|
||||
**Base: openclaw-mission-control** — this becomes the foundation because:
|
||||
- It has the richest data model (organizations, boards, tasks, approvals, agents, gateways, webhooks)
|
||||
- It has proper auth (Clerk or local bearer token)
|
||||
- It has a full API layer (FastAPI with SQLModel/SQLAlchemy)
|
||||
- It has multi-tenancy built in
|
||||
- It has the most mature frontend (Next.js 16 + React 19 + TanStack Query + Recharts)
|
||||
|
||||
**Merge FROM dashboard** — extract the tracking/monitoring features:
|
||||
- Cost tracking, token usage, model breakdown
|
||||
- Cron job status, scheduling, last/next run
|
||||
- Session tracking, sub-agent activity
|
||||
- System health (CPU, RAM, disk, gateway status)
|
||||
- AI chat panel (ask questions about your data)
|
||||
- Alert system (high cost, failed crons, context usage)
|
||||
- 6 themes + glass morphism UI
|
||||
|
||||
**Merge FROM pixel-agents** — extract the agent visualization:
|
||||
- Pixel-art agent sprites in a shared office scene
|
||||
- Real-time activity bubbles, conversation heat
|
||||
- Sub-agent spawning from the UI
|
||||
- Hardware monitor (CPU/GPU/RAM/disk/network)
|
||||
- Service controls (start/stop/restart gateway)
|
||||
- Day/night cycle ambient lighting
|
||||
|
||||
---
|
||||
|
||||
## Technical Analysis
|
||||
|
||||
### Base Platform (openclaw-mission-control)
|
||||
|
||||
**Backend:**
|
||||
- Python 3.12+, FastAPI, SQLModel/SQLAlchemy, PostgreSQL, Redis
|
||||
- Alembic migrations, RQ worker for webhooks
|
||||
- Full OpenClaw gateway integration via WebSocket RPC (device pairing, control UI)
|
||||
- Gateway methods: 60+ RPC calls for sessions, agents, cron, config, exec approvals, etc.
|
||||
- Auth: Clerk JWT or local bearer token (≥50 chars)
|
||||
|
||||
**Frontend:**
|
||||
- Next.js 16.1.7, React 19.2, TanStack Query v5, TanStack Table v8
|
||||
- Radix UI primitives, Tailwind CSS, Recharts, React Markdown
|
||||
- 40+ page routes (dashboard, boards, agents, approvals, gateways, skills, tags, etc.)
|
||||
- Cypress E2E tests
|
||||
|
||||
**Data Model (27 tables):**
|
||||
- Organizations, users, boards, board_groups, tasks, tags, approvals
|
||||
- Agents, gateways, activity_events, board_webhooks, skills
|
||||
- Custom fields, task dependencies, task fingerprints
|
||||
- Board memory, board group memory, onboarding
|
||||
|
||||
**What it LACKS that the others have:**
|
||||
- No real-time cost/token tracking
|
||||
- No system health monitoring (CPU/RAM/disk)
|
||||
- No cron job visualization
|
||||
- No session/sub-agent activity monitoring
|
||||
- No AI chat for asking about your deployment
|
||||
- No pixel-art agent visualization
|
||||
- No hardware monitoring
|
||||
- No service controls (start/stop/restart gateway)
|
||||
|
||||
### Dashboard (openclaw-dashboard) — What We Pull
|
||||
|
||||
**Data Collection (Go):**
|
||||
- `refresh.go` — main collector, reads OpenClaw filesystem + gateway API
|
||||
- `refresh_sessions.go` — session listing, model resolution
|
||||
- `refresh_tokens.go` — token usage tracking
|
||||
- `cron_state` — cron job parsing and status
|
||||
- `system.go` — CPU, RAM, swap, disk, gateway runtime probes
|
||||
|
||||
**API Endpoints:**
|
||||
- `/api/refresh` — stale-while-revalidate data.json
|
||||
- `/api/chat` — AI chat via OpenClaw gateway
|
||||
- `/api/system` — live host metrics
|
||||
- `/api/logs` — merged log tail
|
||||
- `/api/errors` — aggregated error feed
|
||||
|
||||
**Frontend:**
|
||||
- Pure HTML/CSS/JS (single `index.html`) — we'll rewrite as React components
|
||||
- State management: 7 plain objects (State, DataLayer, DirtyChecker, Renderer, Theme, Chat, App)
|
||||
- SVG chart rendering (cost trends, model breakdown, sub-agent activity)
|
||||
- 6 themes with 19 CSS color variables each
|
||||
|
||||
**Integration Approach:**
|
||||
- Port the Go data collection to Python services that hit the OpenClaw gateway API
|
||||
- Replace the embedded HTML frontend with React components in the Next.js app
|
||||
- Use the existing gateway RPC connection in Mission Control's backend
|
||||
- Add PostgreSQL models for tracking data (cost snapshots, cron states, session events)
|
||||
|
||||
### Pixel Agents (openclaw-pixel-agents-dashboard) — What We Pull
|
||||
|
||||
**Backend (Node/Express):**
|
||||
- `sessionWatcher.ts` — tails JSONL session files, parses events
|
||||
- `spawner.ts` — spawns sub-agents via gateway API
|
||||
- `services.ts` — gateway service controls (start/stop/restart)
|
||||
- `hardware.ts` — hardware stats collection
|
||||
- `openclawParser.ts` — JSONL event parsing
|
||||
- WebSocket broadcasting to frontend
|
||||
|
||||
**Frontend (React/Vite):**
|
||||
- Pixel-art canvas renderer (`OfficeCanvas.tsx`, game loop, character sprites)
|
||||
- Activity bubbles, conversation heat overlays
|
||||
- Spawn chat panel, session info panel
|
||||
- Server rack (hardware monitor), breaker panel (service controls)
|
||||
- Ham radio (update checker), fire alarm (gateway restart)
|
||||
|
||||
**Integration Approach:**
|
||||
- Port JSONL session watcher to Python (watch OpenClaw session directory)
|
||||
- Move sub-agent spawning to use Mission Control's existing gateway RPC
|
||||
- Rebuild the pixel-art canvas as a React component within Next.js
|
||||
- Add WebSocket support to FastAPI for real-time agent events
|
||||
- Hardware stats collected via the gateway's `health` and `status` methods
|
||||
|
||||
---
|
||||
|
||||
## Implementation Plan
|
||||
|
||||
### Phase 1: Foundation Setup (Week 1)
|
||||
|
||||
**1.1 — Fork and Stand Up Base**
|
||||
- Fork `abhi1693/openclaw-mission-control` to our org
|
||||
- Stand up local dev environment (Docker Compose: Postgres + Redis + backend + frontend)
|
||||
- Verify all existing features work: auth, boards, tasks, agents, gateways, approvals
|
||||
- Document the data model and API surface
|
||||
|
||||
**1.2 — Add Tracking Models (Backend)**
|
||||
- Create new PostgreSQL models:
|
||||
- `CostSnapshot` — daily cost tracking per model/gateway
|
||||
- `CronJobStatus` — cron schedule, last/next run, duration, status
|
||||
- `SessionEvent` — session start/stop, model, tokens, context %
|
||||
- `SubAgentRun` — sub-agent spawn, cost, duration, status
|
||||
- `SystemHealthMetric` — CPU, RAM, disk, swap, gateway uptime
|
||||
- `AlertRule` — configurable alert thresholds
|
||||
- Create Alembic migration
|
||||
- Add CRUD API endpoints under `/api/monitoring/`
|
||||
|
||||
**1.3 — Gateway Data Collection Service**
|
||||
- Create `app/services/monitoring/gateway_collector.py`
|
||||
- Reuse existing `gateway_rpc.py` to poll:
|
||||
- `usage.cost` — cost data
|
||||
- `usage.status` — token counts
|
||||
- `cron.list` / `cron.status` — cron jobs
|
||||
- `sessions.list` / `sessions.preview` — sessions
|
||||
- `agents.list` — agents
|
||||
- `health` — gateway health
|
||||
- `status` — gateway runtime status
|
||||
- Run as background task (asyncio) with configurable intervals
|
||||
- Store collected data in the new models
|
||||
|
||||
### Phase 2: Tracking Dashboard (Week 2)
|
||||
|
||||
**2.1 — Monitoring Pages (Frontend)**
|
||||
- New Next.js routes:
|
||||
- `/monitoring` — main dashboard (cost cards, system health, alerts)
|
||||
- `/monitoring/costs` — detailed cost breakdown with charts
|
||||
- `/monitoring/sessions` — active sessions, sub-agent activity
|
||||
- `/monitoring/crons` — cron job management
|
||||
- `/monitoring/system` — CPU/RAM/disk/gateway health
|
||||
|
||||
**2.2 — Cost Tracking UI**
|
||||
- Port dashboard's cost cards and donut chart to React/Recharts
|
||||
- Today's cost, all-time cost, projected monthly
|
||||
- Per-model cost breakdown (7d/30d/all-time tabs)
|
||||
- Cost trend line chart (SVG → Recharts)
|
||||
|
||||
**2.3 — Session & Sub-Agent UI**
|
||||
- Active sessions with model, type badges (DM/group/cron/subagent)
|
||||
- Context % bars, token counts
|
||||
- Sub-agent activity grid with cost/duration/status
|
||||
- Session detail panel with conversation preview
|
||||
|
||||
**2.4 — Cron Job Management**
|
||||
- Cron job list with schedule, status, last/next run
|
||||
- Run history with duration and status badges
|
||||
- Trigger manual run from UI
|
||||
- Add/edit/delete cron jobs (using existing gateway RPC)
|
||||
|
||||
**2.5 — System Health**
|
||||
- Gateway status card (uptime, PID, memory, compaction)
|
||||
- CPU/RAM/swap/disk gauge cards (configurable thresholds)
|
||||
- Alert banner for high cost, failed crons, gateway offline
|
||||
- Auto-refresh with countdown timer
|
||||
|
||||
**2.6 — AI Chat Panel**
|
||||
- Port dashboard's AI chat to React component
|
||||
- Uses OpenClaw gateway's `/v1/chat/completions` endpoint
|
||||
- Context-aware: feed live monitoring data into system prompt
|
||||
- Persistent chat history per user
|
||||
|
||||
### Phase 3: Agent Visualization (Week 3)
|
||||
|
||||
**3.1 — Pixel Agent Canvas**
|
||||
- Port the pixel-art office scene to React (Canvas component)
|
||||
- Agent sprites with activity state (working, idle, talking)
|
||||
- Activity bubbles showing current task/conversation
|
||||
- Conversation heat glow based on recent activity
|
||||
- Day/night ambient cycle
|
||||
- Pan/zoom controls (touch + mouse)
|
||||
|
||||
**3.2 — Real-Time Agent Events**
|
||||
- Add FastAPI WebSocket endpoint (`/ws/agents`)
|
||||
- Port JSONL session watcher to Python:
|
||||
- Watch `~/.openclaw/agents/*/sessions/*.jsonl`
|
||||
- Parse events (tool calls, responses, status changes)
|
||||
- Broadcast to connected WebSocket clients
|
||||
- Activity ticker component (recent agent actions scrolling by)
|
||||
|
||||
**3.3 — Sub-Agent Spawner**
|
||||
- Spawn panel integrated into the canvas view
|
||||
- Click agent → "Spawn sub-agent" button
|
||||
- Mini-chat for tasking the sub-agent
|
||||
- Session info panel for active sub-agents
|
||||
- Uses existing `agents.create` gateway RPC
|
||||
|
||||
**3.4 — Hardware Monitor & Service Controls**
|
||||
- Server rack component (CPU/GPU/RAM/disk/network gauges)
|
||||
- Breaker panel for gateway start/stop/restart
|
||||
- Ham radio component for OpenClaw update checking
|
||||
- All using existing gateway RPC methods (`health`, `status`, `update.run`)
|
||||
|
||||
### Phase 4: Integration & Polish (Week 4)
|
||||
|
||||
**4.1 — Navigation Integration**
|
||||
- Add "Monitoring" and "Agents" sections to Mission Control sidebar
|
||||
- Dashboard home page shows summary cards (cost, health, agent count)
|
||||
- Deep links from monitoring → agents → pixel view
|
||||
|
||||
**4.2 — Theme System**
|
||||
- Port the 6 dashboard themes into Mission Control's Tailwind config
|
||||
- Theme picker in header (persists via localStorage)
|
||||
- Glass morphism effects where appropriate
|
||||
|
||||
**4.3 — Alert System**
|
||||
- Configurable alert rules (cost threshold, cron failure, context %, memory)
|
||||
- Alert banner on every page when active
|
||||
- Alert history in activity feed
|
||||
- Notification delivery via webhooks or in-app
|
||||
|
||||
**4.4 — Data Sync Strategy**
|
||||
- Primary: Gateway RPC polling (configurable intervals)
|
||||
- Secondary: JSONL file watching for real-time agent events
|
||||
- Tertiary: REST API for manual refresh
|
||||
- WebSocket push for live updates to connected browsers
|
||||
- Stale-while-revalidate caching pattern
|
||||
|
||||
---
|
||||
|
||||
## File Structure (Additions to Mission Control)
|
||||
|
||||
```
|
||||
backend/
|
||||
├── app/
|
||||
│ ├── models/
|
||||
│ │ ├── monitoring.py # CostSnapshot, CronJobStatus, SessionEvent, etc.
|
||||
│ │ └── alert_rules.py # AlertRule model
|
||||
│ ├── api/
|
||||
│ │ ├── monitoring.py # Cost, session, cron endpoints
|
||||
│ │ ├── monitoring_system.py # System health endpoints
|
||||
│ │ └── agent_events.py # WebSocket endpoint for agent events
|
||||
│ └── services/
|
||||
│ ├── monitoring/
|
||||
│ │ ├── gateway_collector.py # Polls OpenClaw gateway for data
|
||||
│ │ ├── jsonl_watcher.py # Watches session JSONL files
|
||||
│ │ ├── cost_tracker.py # Cost aggregation and projection
|
||||
│ │ └── alert_engine.py # Alert rule evaluation
|
||||
│ └── openclaw/
|
||||
│ └── (existing — no changes needed)
|
||||
├── migrations/
|
||||
│ └── versions/
|
||||
│ └── xxx_add_monitoring_models.py
|
||||
frontend/
|
||||
├── src/
|
||||
│ ├── app/
|
||||
│ │ ├── monitoring/
|
||||
│ │ │ ├── page.tsx # Main monitoring dashboard
|
||||
│ │ │ ├── costs/page.tsx # Cost detail page
|
||||
│ │ │ ├── sessions/page.tsx # Session detail page
|
||||
│ │ │ ├── crons/page.tsx # Cron management page
|
||||
│ │ │ └── system/page.tsx # System health page
|
||||
│ │ └── agents/
|
||||
│ │ └── pixel/page.tsx # Pixel agent canvas page
|
||||
│ ├── components/
|
||||
│ │ ├── monitoring/
|
||||
│ │ │ ├── CostCards.tsx
|
||||
│ │ │ ├── CostTrendChart.tsx
|
||||
│ │ │ ├── ModelBreakdownChart.tsx
|
||||
│ │ │ ├── SessionTable.tsx
|
||||
│ │ │ ├── SubAgentActivity.tsx
|
||||
│ │ │ ├── CronJobList.tsx
|
||||
│ │ │ ├── SystemHealthCards.tsx
|
||||
│ │ │ ├── AlertBanner.tsx
|
||||
│ │ │ └── AiChatPanel.tsx
|
||||
│ │ ├── agents/
|
||||
│ │ │ ├── PixelCanvas.tsx
|
||||
│ │ │ ├── AgentSprite.tsx
|
||||
│ │ │ ├── ActivityBubble.tsx
|
||||
│ │ │ ├── ConversationHeat.tsx
|
||||
│ │ │ ├── SpawnPanel.tsx
|
||||
│ │ │ ├── ServerRack.tsx
|
||||
│ │ │ └── BreakerPanel.tsx
|
||||
│ │ └── (existing Mission Control components)
|
||||
│ └── lib/
|
||||
│ ├── monitoring-api.ts # API client for monitoring endpoints
|
||||
│ └── agent-events.ts # WebSocket client for agent events
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Key Integration Points
|
||||
|
||||
### Gateway Communication
|
||||
All three projects talk to the OpenClaw gateway. Mission Control already has the richest integration (`gateway_rpc.py` with 60+ methods). We reuse this for everything:
|
||||
|
||||
| Feature | Gateway Methods Used |
|
||||
|---|---|
|
||||
| Cost tracking | `usage.cost`, `usage.status` |
|
||||
| Session monitoring | `sessions.list`, `sessions.preview` |
|
||||
| Cron management | `cron.list`, `cron.status`, `cron.add`, `cron.update`, `cron.remove`, `cron.run` |
|
||||
| Agent management | `agents.list`, `agents.create`, `agents.update`, `agents.delete` |
|
||||
| System health | `health`, `status`, `logs.tail` |
|
||||
| Sub-agent spawning | `agents.create`, `sessions.patch` |
|
||||
| Service controls | `config.get`, `config.set`, `update.run` |
|
||||
|
||||
### Real-Time Updates
|
||||
- Dashboard uses polling (60s auto-refresh)
|
||||
- Pixel agents uses WebSocket (real-time JSONL events)
|
||||
- Mission Control uses TanStack Query (polling + cache invalidation)
|
||||
|
||||
**Our approach:** WebSocket for agent events (real-time pixel animation), TanStack Query with 30s polling for monitoring data, SSE for alerts.
|
||||
|
||||
### Auth
|
||||
- Mission Control supports Clerk JWT and local bearer token
|
||||
- Dashboard is auth-free (localhost only)
|
||||
- Pixel agents uses gateway token
|
||||
|
||||
**Our approach:** Inherit Mission Control's auth system. Local mode for self-hosted, Clerk for multi-tenant. Monitoring and agent data scoped to organization + gateway.
|
||||
|
||||
---
|
||||
|
||||
## Dependency Summary
|
||||
|
||||
| Layer | Technology | Source |
|
||||
|---|---|---|
|
||||
| Backend framework | FastAPI + SQLModel | Mission Control |
|
||||
| Database | PostgreSQL + Alembic | Mission Control |
|
||||
| Job queue | Redis + RQ | Mission Control |
|
||||
| Frontend framework | Next.js 16 + React 19 | Mission Control |
|
||||
| UI primitives | Radix UI + Tailwind | Mission Control |
|
||||
| Charts | Recharts (existing) | Mission Control |
|
||||
| Pixel canvas | HTML5 Canvas (new) | Pixel Agents → React port |
|
||||
| WebSocket | FastAPI WebSocket (new) | Pixel Agents → Python port |
|
||||
| Auth | Clerk / local bearer token | Mission Control |
|
||||
| Gateway RPC | websockets Python (existing) | Mission Control |
|
||||
|
||||
**No new backend languages.** Go and Node/Express are NOT added — their functionality ports to Python services within the existing FastAPI app.
|
||||
|
||||
---
|
||||
|
||||
## Risk Assessment
|
||||
|
||||
| Risk | Impact | Mitigation |
|
||||
|---|---|---|
|
||||
| Canvas rendering performance in React | Medium | Use `useRef` + `requestAnimationFrame`, not React state for animation |
|
||||
| Go dashboard data collection rewritten in Python | Medium | Port logic faithfully; test against same OpenClaw data |
|
||||
| JSONL file watching reliability | Medium | Use `watchdog` library + fallback polling |
|
||||
| Theme system merge (6 themes × 2 systems) | Low | Map dashboard's 19 CSS vars to Tailwind config |
|
||||
| Pixel assets licensing | Low | MIT licensed, attribution in ASSET-LICENSE.md |
|
||||
| Gateway RPC version compatibility | Low | Already handled by protocol version negotiation in `gateway_rpc.py` |
|
||||
|
||||
---
|
||||
|
||||
## Success Metrics
|
||||
|
||||
1. **All monitoring features** from dashboard available in Mission Control UI
|
||||
2. **Pixel agent visualization** showing real-time agent activity
|
||||
3. **Single Docker Compose** brings up the entire system
|
||||
4. **Single auth system** — no separate logins
|
||||
5. **Single gateway connection** — reused across all features
|
||||
6. **No Go or Node backend** — everything in Python/FastAPI
|
||||
7. **All existing Mission Control features** still work (boards, tasks, approvals, etc.)
|
||||
362
STRUCTURE.md
|
|
@ -1,362 +0,0 @@
|
|||
# Mission Control Project Structure
|
||||
|
||||
## Project Overview
|
||||
Mission Control — Unified OpenClaw management platform merging three open-source dashboards into one. Python/FastAPI + PostgreSQL + Redis backend, Next.js 16 + React 19 frontend.
|
||||
|
||||
**Current Version:** v0.0.2
|
||||
**Phase:** Phase 1 complete (base platform running), Phase 2 pending
|
||||
|
||||
## Source Repos (Reference Only — Not Modified Directly)
|
||||
```
|
||||
/tmp/mission-control-research/
|
||||
├── openclaw-mission-control/ # Base platform (Python/FastAPI + Next.js)
|
||||
├── openclaw-dashboard/ # Tracking/monitoring (Go → port to Python)
|
||||
└── openclaw-pixel-agents-dashboard/ # Agent visualization (Node/Express → port to Python)
|
||||
```
|
||||
|
||||
## Directory Structure (Current)
|
||||
```
|
||||
Mission-Control/
|
||||
├── PROJECT.md # Full project plan, phases, architecture decisions
|
||||
├── STRUCTURE.md # THIS FILE — project structure and agent roles
|
||||
├── FUTURE.md # Pending improvements (priority-grouped)
|
||||
├── HISTORY.md # User-facing changelog (completed items only)
|
||||
├── DEVELOPMENT_LOG.md # Agent work tracking
|
||||
├── VERSION.md # Current version + history
|
||||
├── compose.yml # Docker Compose (db + redis + backend + frontend + webhook-worker)
|
||||
├── .env # Local dev environment config
|
||||
├── .gitignore
|
||||
├── .dockerignore
|
||||
├── src/
|
||||
│ ├── backend/ # FastAPI application
|
||||
│ │ ├── Dockerfile # Backend + webhook-worker container
|
||||
│ │ ├── app/
|
||||
│ │ │ ├── main.py # FastAPI app entry
|
||||
│ │ │ ├── models/ # SQLModel/SQLAlchemy models
|
||||
│ │ │ ├── api/ # API route handlers
|
||||
│ │ │ ├── services/ # Business logic
|
||||
│ │ │ │ └── openclaw/
|
||||
│ │ │ │ └── gateway_rpc.py # Gateway RPC client (60+ methods)
|
||||
│ │ │ └── core/ # Config, auth, deps
|
||||
│ │ ├── migrations/ # Alembic migrations
|
||||
│ │ ├── scripts/ # RQ worker script, utilities
|
||||
│ │ └── tests/ # Backend tests
|
||||
│ └── frontend/ # Next.js 16 application
|
||||
│ ├── src/
|
||||
│ │ ├── app/ # Next.js App Router pages
|
||||
│ │ ├── components/ # React components
|
||||
│ │ └── lib/ # API clients, utilities
|
||||
│ └── public/ # Static assets
|
||||
├── sources/ # Cloned source repos (reference only)
|
||||
└── docs/ # Documentation (Engineering Reference Manual — requires explicit user initiation)
|
||||
```
|
||||
|
||||
## Critical Notes for Agents
|
||||
|
||||
### Backend Code Location
|
||||
**ALL backend code is in `src/backend/`:**
|
||||
- Entry: `src/backend/app/main.py`
|
||||
- Models: `src/backend/app/models/*.py`
|
||||
- API: `src/backend/app/api/*.py`
|
||||
- Services: `src/backend/app/services/**/*.py`
|
||||
- Migrations: `src/backend/migrations/`
|
||||
- Gateway RPC: `src/backend/app/services/openclaw/gateway_rpc.py`
|
||||
|
||||
### Frontend Code Location
|
||||
**ALL frontend code is in `src/frontend/`:**
|
||||
- Pages: `src/frontend/src/app/**/page.tsx`
|
||||
- Components: `src/frontend/src/components/**/*.tsx`
|
||||
- API client: `src/frontend/src/lib/`
|
||||
- WebSocket client: `src/frontend/src/lib/agent-events.ts`
|
||||
|
||||
### Porting Rules
|
||||
- **No Go.** All dashboard data collection ports to Python services.
|
||||
- **No Node/Express.** All pixel-agents functionality ports to Python/FastAPI.
|
||||
- **Reuse existing gateway RPC.** Mission Control already has `gateway_rpc.py` with 60+ methods.
|
||||
- **React for all UI.** No embedded HTML/JS — everything becomes React components.
|
||||
|
||||
### Docker Setup
|
||||
- **Backend port:** 8080 (host) → 8000 (container)
|
||||
- **Frontend port:** 3080 (host) → 3000 (container)
|
||||
- **Auth mode:** local (bearer token, see `.env` for `LOCAL_AUTH_TOKEN`)
|
||||
- **Database:** PostgreSQL 16 Alpine on port 5432
|
||||
- **Redis:** Redis 7 Alpine on port 6379
|
||||
- **4 services:** db, redis, backend, frontend, webhook-worker
|
||||
- **97 API endpoints** verified operational
|
||||
|
||||
### Test Procedure
|
||||
```bash
|
||||
cd /home/kaspa/.openclaw/Projects/Mission-Control
|
||||
|
||||
# Start services
|
||||
docker compose up -d --build
|
||||
|
||||
# Verify backend health
|
||||
curl -s http://localhost:8080/api/health | python3 -m json.tool
|
||||
|
||||
# Verify frontend
|
||||
curl -s -o /dev/null -w "%{http_code}" http://localhost:3080
|
||||
|
||||
# Stop services
|
||||
docker compose down
|
||||
```
|
||||
|
||||
## Agent Review Roles
|
||||
|
||||
| Agent | Role | Focus Area |
|
||||
|-------|------|------------|
|
||||
| Neo | Backend / System Architecture | FastAPI services, models, migrations, gateway RPC, data collection, API endpoints |
|
||||
| Scarlett | UI/UX / Frontend | Next.js pages, React components, Radix UI + Tailwind styling, pixel canvas, charts, themes |
|
||||
| Bishop | Analysis / Code Quality | Architecture review, code quality, dependency review, version bumps, documentation |
|
||||
| Private_Hudson | Security / Compliance | Auth flows, data protection, input validation, OWASP, dependency vulnerabilities |
|
||||
|
||||
### Cross-Cutting Concerns
|
||||
All agents must be aware of:
|
||||
- **Auth**: Clerk JWT or local bearer token — scoped to organization + gateway
|
||||
- **Gateway RPC**: `gateway_rpc.py` is the single source of truth for all OpenClaw API calls
|
||||
- **Data Models**: PostgreSQL + SQLModel with Alembic migrations
|
||||
- **Real-Time**: WebSocket for agent events, TanStack Query polling for monitoring data
|
||||
- **Theme System**: 6 themes with CSS variables mapped to Tailwind config
|
||||
|
||||
# OpenClaw Agent Structure
|
||||
|
||||
## Prime
|
||||
|
||||
Role:
|
||||
|
||||
* executive coordinator
|
||||
* project strategist
|
||||
* Discord command interface
|
||||
|
||||
Responsibilities:
|
||||
|
||||
* **Overall Oversight:** Must maintain high-level awareness of all concurrent projects, ensuring every agent's output aligns with the goal set in `PROJECT.md`.
|
||||
* **Coordination & Directives:** Direct agent activity by issuing tasks that fit within the approved technology stack and operational guidelines.
|
||||
* **Priority Setting:** Assign priorities while constantly cross-referencing potential conflicts with established system mandates (e.g., Security > Performance > Feature).
|
||||
* **Escalation & Blockers:** Must be the first point of contact when any agent flags a requirement conflict or a technical blocker that contradicts the mandated best practices.
|
||||
* **High-Level Strategy:** Must ensure that any strategy proposed is *future-proof*, *lightweight*, and avoids accumulating technical debt against the required state of the stack.
|
||||
* **Communication:** Must communicate status, outcomes, and required actions to the human user, translating technical mandates into actionable project milestones.
|
||||
|
||||
Authority:
|
||||
|
||||
* project coordination and task routing.
|
||||
* Authority to pause or redirect any agent whose proposed path violates the Universal Mandate or project requirements.
|
||||
|
||||
---
|
||||
|
||||
## Ripley
|
||||
|
||||
Role:
|
||||
|
||||
* operations
|
||||
* infrastructure
|
||||
* runtime management
|
||||
|
||||
Responsibilities:
|
||||
|
||||
* deployment oversight, adhering to stability and resilience standards.
|
||||
* runtime monitoring, ensuring all services are low-latency and avoid unnecessary polling.
|
||||
* infrastructure coordination, guaranteeing that all components use the approved stack.
|
||||
* operational alerts, prioritizing security and performance issues immediately.
|
||||
* service stability, adhering to the "fail gracefully" principle.
|
||||
* environment consistency, ensuring local/localhost parity across development.
|
||||
* operational communication, must be precise and action-oriented.
|
||||
* **Git ownership:** Only Ripley commits, pushes, and deploys. No other agent touches git.
|
||||
|
||||
Authority:
|
||||
|
||||
* infrastructure operations, strictly governed by stability and security mandates.
|
||||
* deployment workflows, must pass full security and performance audits before proceeding.
|
||||
* runtime diagnostics, must use established, non-bloated tooling.
|
||||
* operational communication, must be precise and action-oriented.
|
||||
|
||||
---
|
||||
|
||||
## Neo
|
||||
|
||||
Role:
|
||||
|
||||
* senior backend developer
|
||||
* backend architecture lead
|
||||
|
||||
Responsibilities:
|
||||
|
||||
* **Mandatory Adherence:** Must treat `PROJECT.md` and `STRUCTURE.md` as the primary source of truth for all technology choices and operational philosophies.
|
||||
* **Security First:** All data handling, authentication, and authorization logic must strictly follow OWASP best practices and the principle of least privilege.
|
||||
* **Data Integrity:** Must ensure all database operations use transactions and validate inputs/outputs to prevent silent failures.
|
||||
* **Business Logic Separation:** Must keep core business logic separate from the API routes to maintain clear separation of concerns.
|
||||
* **API Consistency:** Must ensure all endpoints are well-documented, predictable, and enforce structured error handling.
|
||||
* **Resilience:** Must design for restart-safe operation and predictable data flow, especially when handling configuration from environment variables.
|
||||
|
||||
Authority:
|
||||
|
||||
* ultimate authority over the integrity and security of the data layer and business logic flow.
|
||||
* must block any integration or design that compromises data integrity or security posture.
|
||||
|
||||
---
|
||||
|
||||
## Scarlett
|
||||
|
||||
Role:
|
||||
|
||||
* frontend developer
|
||||
* UI design authority
|
||||
|
||||
Responsibilities:
|
||||
|
||||
* **Mandatory Adherence:** Must treat `PROJECT.md` and `STRUCTURE.md` as the primary source of truth for UI/UX.
|
||||
* **Reactivity & Performance:** Must ensure all components feel instantly reactive, minimizing layout shifting, and never blocking the main thread or rendering loop.
|
||||
* **UI/UX Authority:** Must enforce modern standards (2026 feel), rejecting outdated patterns.
|
||||
* **Component Purity:** Must use Radix UI + shadcn/ui components consistently and build complex logic in modular, clean ways.
|
||||
* **Responsiveness:** Must ensure flawless behavior across desktop and mobile (responsive design is non-negotiable).
|
||||
* **Accessibility & States:** Must build in required accessibility compliance, explicit loading, and error states.
|
||||
* **Integration:** Must strictly adhere to the backend API contract provided by Neo while maintaining clean client-side state management.
|
||||
|
||||
Technology Focus:
|
||||
|
||||
* **Next.js 16 + React 19** is the frontend framework (App Router, server components where appropriate).
|
||||
* **Radix UI + shadcn/ui** is the foundational component library — always use shadcn/ui components for UI primitives.
|
||||
* **Tailwind CSS** must be used predictably to maintain consistency.
|
||||
* **Recharts** for charts and data visualization.
|
||||
* **TanStack Query v5** for server state management.
|
||||
|
||||
Authority:
|
||||
|
||||
* UI architecture and frontend interaction flows.
|
||||
* Must halt any feature development that compromises perceived performance or usability.
|
||||
|
||||
---
|
||||
|
||||
## Bishop
|
||||
|
||||
Role:
|
||||
|
||||
* code reviewer
|
||||
* architecture validator
|
||||
* documentation owner
|
||||
|
||||
Responsibilities:
|
||||
|
||||
* Must enforce adherence to `PROJECT.md` and `STRUCTURE.md` standards across the entire lifecycle.
|
||||
* **Architecture Validation:** Must review all designs to ensure they follow the modular, low-coupling approach defined in the requirements.
|
||||
* **Code Quality Review:** Beyond syntax, must audit for architectural flaws, overengineering, and non-compliance with best practices.
|
||||
* **Standard Enforcement:** Must enforce the use of approved components and discourage workarounds or non-approved patterns.
|
||||
* **Version Bumps:** Bishop owns version bumps as part of every verification. Determines version number and scope.
|
||||
* **Documentation:** Bishop maintains `HISTORY.md` and `VERSION.md`. Does NOT create the Engineering Reference Manual unless explicitly initiated by the user.
|
||||
* **Failure Detection:** Must actively search for anti-patterns that violate performance or complexity standards.
|
||||
|
||||
Authority:
|
||||
|
||||
* approve or reject code quality based *only* on adherence to established standards.
|
||||
* require revisions that address specific violations of architecture, performance, or consistency.
|
||||
* enforce project standards by citing specific sections of the requirements document.
|
||||
|
||||
---
|
||||
|
||||
## Private Hudson
|
||||
|
||||
Role:
|
||||
|
||||
* security reviewer
|
||||
* defensive operations specialist
|
||||
|
||||
Responsibilities:
|
||||
|
||||
* OWASP validation
|
||||
* authentication security review
|
||||
* authorization validation
|
||||
* dependency vulnerability auditing
|
||||
* secret exposure detection
|
||||
* injection vulnerability analysis
|
||||
* security hardening review
|
||||
* infrastructure security analysis
|
||||
* runtime security assessment
|
||||
|
||||
Authority:
|
||||
|
||||
* approve or reject security posture
|
||||
* block insecure deployments
|
||||
* require remediation before release
|
||||
|
||||
---
|
||||
|
||||
## Universal Mandate
|
||||
|
||||
**All agents are governed by the guidelines set in `PROJECT.md` and `STRUCTURE.md`.** Every decision, design choice, and implementation detail must strictly adhere to the philosophy, technology stack, standards, and policies defined in those files. Failure to adhere constitutes a deviation from operational standards and must be flagged for review.
|
||||
|
||||
**Mandatory Adherence Checklist:**
|
||||
1. **Always** refer to `PROJECT.md` and `STRUCTURE.md` for the definitive ruleset.
|
||||
2. Never implement functionality that contradicts the approved Tech Stack (Python/FastAPI, PostgreSQL, Redis, Next.js 16, React 19, Radix UI, Tailwind CSS, Recharts).
|
||||
3. Treat security and performance checks as *primary* considerations, not secondary checks.
|
||||
4. **No Go.** No Go code in this project — all Go functionality ports to Python.
|
||||
5. **No Node/Express.** No Express server code — all backend logic goes through FastAPI.
|
||||
6. **Only Ripley touches git.** No other agent commits, pushes, or deploys.
|
||||
|
||||
---
|
||||
|
||||
## Development Pipeline
|
||||
|
||||
All code changes follow this pipeline:
|
||||
|
||||
```
|
||||
Neo (code) → Bishop (verify + bump) → Private_Hudson (security audit) → Ripley (commit/push/deploy)
|
||||
```
|
||||
|
||||
- **Neo** writes the code.
|
||||
- **Bishop** verifies it works (build + runtime test), bumps the version, updates HISTORY.md.
|
||||
- **Private_Hudson** audits for security issues.
|
||||
- **Ripley** commits, pushes to `dev` branch, and deploys the Docker image.
|
||||
|
||||
For small surgical fixes, Ripley may make changes directly without dispatching an agent.
|
||||
|
||||
## Agent Dispatch Protocol
|
||||
|
||||
Subagents run in **isolated sessions** — they start with zero context. When spawning any specialist, always include a context block at the top of the `task` string:
|
||||
|
||||
```
|
||||
Project: Mission Control
|
||||
Project dir: Projects/Mission-Control/ (symlinked in your workspace root)
|
||||
Spec: read Projects/Mission-Control/PROJECT.md and STRUCTURE.md before starting
|
||||
Prime workspace: _prime/ (briefing docs, templates, shared memory)
|
||||
Recent changes:
|
||||
- v0.0.2: Base platform forked, Docker Compose running, 97 API endpoints verified
|
||||
|
||||
[task instructions]
|
||||
```
|
||||
|
||||
**Shared paths available in every agent workspace:**
|
||||
- `Projects/` → `/home/kaspa/.openclaw/Projects/`
|
||||
- `_prime/` → `/home/kaspa/.openclaw/agent-workspace/Prime/`
|
||||
|
||||
If a spec or briefing exists, drop it in Prime's workspace so agents find it at `_prime/<filename>`. Never assume context carries over from a prior session.
|
||||
|
||||
⚠️ **Always set `agentId` explicitly when spawning.** Omitting it defaults to `main` (Ripley's agent), which loads the wrong workspace and identity files.
|
||||
|
||||
| Agent | agentId |
|
||||
|---|---|
|
||||
| Prime | `prime` |
|
||||
| Neo | `neo` |
|
||||
| Scarlett | `scarlett` |
|
||||
| Bishop | `bishop` |
|
||||
| Private_Hudson | `private_hudson` |
|
||||
|
||||
## Technology Stack
|
||||
|
||||
| Layer | Technology | Notes |
|
||||
|-------|-----------|-------|
|
||||
| Backend | Python 3.12+ / FastAPI | Existing |
|
||||
| Database | PostgreSQL + SQLModel | Existing |
|
||||
| Migrations | Alembic | Existing |
|
||||
| Job Queue | Redis + RQ | Existing |
|
||||
| Frontend | Next.js 16 + React 19 | Existing |
|
||||
| UI | Radix UI + Tailwind CSS | Existing |
|
||||
| Charts | Recharts | Existing |
|
||||
| Pixel Canvas | HTML5 Canvas | New — ported from pixel-agents |
|
||||
| WebSocket | FastAPI WebSocket | New — ported from pixel-agents |
|
||||
| Auth | Clerk / local bearer token | Existing |
|
||||
|
||||
**No new backend languages.** Go and Node/Express are NOT added to this project.
|
||||
|
||||
---
|
||||
|
||||
*Updated by Ripley for Mission Control project*
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
node_modules
|
||||
.next
|
||||
coverage
|
||||
cypress/screenshots
|
||||
cypress/videos
|
||||
npm-debug.log*
|
||||
.env
|
||||
.env.*
|
||||
.git
|
||||
|
|
@ -1,14 +1,21 @@
|
|||
# Base URL for frontend -> backend calls.
|
||||
# Use `auto` to target the same host currently serving Mission Control on port 8000.
|
||||
# Example explicit override: https://mc.example.com
|
||||
NEXT_PUBLIC_API_URL=auto
|
||||
# Admin credentials for Mission Control
|
||||
ADMIN_PASSWORD=change-me-to-a-strong-password
|
||||
AUTH_SECRET=generate-a-random-32-char-string-here
|
||||
|
||||
# Auth mode: clerk or local.
|
||||
# - clerk: Clerk sign-in flow
|
||||
# - local: shared bearer token entered in UI
|
||||
NEXT_PUBLIC_AUTH_MODE=local
|
||||
# OpenClaw paths (defaults shown - override if your setup differs)
|
||||
# OPENCLAW_DIR=/root/.openclaw
|
||||
# OPENCLAW_WORKSPACE=/root/.openclaw/workspace
|
||||
|
||||
# Clerk auth (used when NEXT_PUBLIC_AUTH_MODE=clerk)
|
||||
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=
|
||||
NEXT_PUBLIC_CLERK_SIGN_IN_FALLBACK_REDIRECT_URL=/boards
|
||||
NEXT_PUBLIC_CLERK_AFTER_SIGN_OUT_URL=/
|
||||
# Branding (customize for your instance)
|
||||
NEXT_PUBLIC_AGENT_NAME=Mission Control
|
||||
NEXT_PUBLIC_AGENT_EMOJI=🤖
|
||||
NEXT_PUBLIC_AGENT_DESCRIPTION=Your AI co-pilot, powered by OpenClaw
|
||||
NEXT_PUBLIC_AGENT_LOCATION=
|
||||
NEXT_PUBLIC_BIRTH_DATE=
|
||||
NEXT_PUBLIC_AGENT_AVATAR=
|
||||
NEXT_PUBLIC_OWNER_USERNAME=your-username
|
||||
NEXT_PUBLIC_OWNER_EMAIL=your-email@example.com
|
||||
NEXT_PUBLIC_OWNER_COLLAB_EMAIL=collabs@example.com
|
||||
NEXT_PUBLIC_TWITTER_HANDLE=@username
|
||||
NEXT_PUBLIC_COMPANY_NAME=MISSION CONTROL, INC.
|
||||
NEXT_PUBLIC_APP_TITLE=Mission Control
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
|
||||
# Source code
|
||||
*.ts text eol=lf
|
||||
*.tsx text eol=lf
|
||||
*.js text eol=lf
|
||||
*.jsx text eol=lf
|
||||
*.json text eol=lf
|
||||
*.md text eol=lf
|
||||
*.css text eol=lf
|
||||
*.html text eol=lf
|
||||
|
||||
# Scripts
|
||||
*.sh text eol=lf
|
||||
|
||||
# Images
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.jpeg binary
|
||||
*.gif binary
|
||||
*.ico binary
|
||||
*.svg text
|
||||
|
||||
# Fonts
|
||||
*.woff binary
|
||||
*.woff2 binary
|
||||
*.ttf binary
|
||||
*.otf binary
|
||||
|
||||
# Archives
|
||||
*.zip binary
|
||||
*.tar binary
|
||||
*.gz binary
|
||||
|
||||
# Database
|
||||
*.db binary
|
||||
*.sqlite binary
|
||||
*.sqlite3 binary
|
||||
|
|
@ -1,10 +1,55 @@
|
|||
node_modules/
|
||||
.next/
|
||||
.env.local
|
||||
.env
|
||||
out/
|
||||
dist/
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# clerk configuration (can include secrets)
|
||||
/.clerk/
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.*
|
||||
.yarn/*
|
||||
!.yarn/patches
|
||||
!.yarn/plugins
|
||||
!.yarn/releases
|
||||
!.yarn/versions
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# env files (contains sensitive credentials)
|
||||
.env*
|
||||
!.env.example
|
||||
|
||||
# production data (contains instance-specific operational data)
|
||||
/data/*.json
|
||||
!data/*.example.json
|
||||
/data/*.db
|
||||
/data/*.sqlite
|
||||
/data/*.sqlite3
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
|
||||
# design files (local only)
|
||||
/design/
|
||||
|
||||
# backup files
|
||||
*.bak
|
||||
|
|
|
|||
|
|
@ -0,0 +1,369 @@
|
|||
# Contributing to Mission Control
|
||||
|
||||
Thank you for your interest in contributing! 🦞
|
||||
|
||||
## Getting Started
|
||||
|
||||
1. Fork the repository
|
||||
2. Clone your fork: `git clone https://github.com/YOUR-USERNAME/mission-control.git`
|
||||
3. Create a branch: `git checkout -b feature/your-feature-name`
|
||||
4. Make your changes
|
||||
5. Test thoroughly
|
||||
6. Commit with clear messages
|
||||
7. Push and create a Pull Request
|
||||
|
||||
## Development Setup
|
||||
|
||||
See [README.md](./README.md#quick-start) for setup instructions.
|
||||
|
||||
**TL;DR:**
|
||||
```bash
|
||||
npm install
|
||||
cp .env.example .env.local
|
||||
# Edit .env.local with your config
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## Code Guidelines
|
||||
|
||||
### File Organization
|
||||
|
||||
- **Components**: `src/components/` - Reusable UI components
|
||||
- **Pages**: `src/app/` - Next.js App Router pages
|
||||
- **APIs**: `src/app/api/` - API route handlers
|
||||
- **Config**: `src/config/` - Configuration files (branding, constants)
|
||||
- **Lib**: `src/lib/` - Utilities, helpers, and libraries
|
||||
- **Data**: `data/` - JSON data files (gitignored, use `.example` versions)
|
||||
|
||||
### Naming Conventions
|
||||
|
||||
- **Components**: PascalCase (`ActivityFeed.tsx`)
|
||||
- **Utilities**: camelCase (`pricing.ts`, `usage-queries.ts`)
|
||||
- **API Routes**: kebab-case folders (`/api/cron-jobs/`)
|
||||
- **Config**: camelCase with SCREAMING_SNAKE for constants
|
||||
|
||||
### TypeScript
|
||||
|
||||
- Use TypeScript for all new code
|
||||
- Define interfaces for data structures
|
||||
- Avoid `any` - use `unknown` if type is truly unknown
|
||||
- Export types alongside components
|
||||
|
||||
Example:
|
||||
```typescript
|
||||
export interface AgentStatus {
|
||||
agentId: string;
|
||||
status: 'idle' | 'working' | 'error';
|
||||
model?: string;
|
||||
}
|
||||
|
||||
export function AgentCard({ agent }: { agent: AgentStatus }) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### React Components
|
||||
|
||||
- Use functional components with hooks
|
||||
- Prefer `'use client'` for interactive components
|
||||
- Keep components small and focused
|
||||
- Extract logic into custom hooks when complex
|
||||
|
||||
Example:
|
||||
```typescript
|
||||
'use client';
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
export function MyComponent() {
|
||||
const [data, setData] = useState<DataType[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData().then(setData);
|
||||
}, []);
|
||||
|
||||
return <div>{/* ... */}</div>;
|
||||
}
|
||||
```
|
||||
|
||||
### Styling
|
||||
|
||||
- Use Tailwind CSS v4 utility classes
|
||||
- Use CSS variables for theming (see `globals.css`)
|
||||
- Avoid inline styles except for dynamic values
|
||||
- Use `className` over `style` when possible
|
||||
|
||||
Theme variables:
|
||||
```css
|
||||
--background: #000000;
|
||||
--text-primary: #FFFFFF;
|
||||
--accent: #FFCC00;
|
||||
/* See src/app/globals.css for full list */
|
||||
```
|
||||
|
||||
### API Routes
|
||||
|
||||
- Return `NextResponse.json()` for all API routes
|
||||
- Use HTTP status codes correctly (200, 400, 404, 500)
|
||||
- Handle errors gracefully with try/catch
|
||||
- Validate input data
|
||||
|
||||
Example:
|
||||
```typescript
|
||||
import { NextResponse } from 'next/server';
|
||||
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
const data = await fetchData();
|
||||
return NextResponse.json(data);
|
||||
} catch (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch data' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Privacy & Security
|
||||
|
||||
### 🚨 CRITICAL: No Personal Data in Commits
|
||||
|
||||
**NEVER commit:**
|
||||
- `.env.local` (contains passwords, secrets)
|
||||
- `data/*.json` (contains operational data)
|
||||
- `data/*.db` (contains usage metrics)
|
||||
- Personal usernames, emails, API keys, tokens
|
||||
- Screenshot with real data (use mock data or blur)
|
||||
|
||||
**Use instead:**
|
||||
- `.env.example` (with placeholder values)
|
||||
- `data/*.example.json` (with example data)
|
||||
- `BRANDING` config (via environment variables)
|
||||
|
||||
### Checking for Leaks
|
||||
|
||||
Before committing, run:
|
||||
|
||||
```bash
|
||||
# Check for hardcoded personal data
|
||||
grep -r "your-real-username" src/
|
||||
grep -r "your-email@example.com" src/
|
||||
grep -r "password\|secret\|token" .env.local
|
||||
|
||||
# Ensure .gitignore is working
|
||||
git status
|
||||
# Should NOT show .env.local or data/*.json
|
||||
```
|
||||
|
||||
### Branding
|
||||
|
||||
Use the `BRANDING` config from `src/config/branding.ts` instead of hardcoding:
|
||||
|
||||
**❌ Bad:**
|
||||
```typescript
|
||||
const username = "@carlosazaustre";
|
||||
```
|
||||
|
||||
**✅ Good:**
|
||||
```typescript
|
||||
import { BRANDING } from "@/config/branding";
|
||||
const username = BRANDING.twitterHandle;
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
### Manual Testing Checklist
|
||||
|
||||
Before submitting a PR:
|
||||
|
||||
- [ ] Build succeeds: `npm run build`
|
||||
- [ ] No TypeScript errors: `tsc --noEmit`
|
||||
- [ ] No ESLint errors: `npm run lint`
|
||||
- [ ] Tested in dev mode: `npm run dev`
|
||||
- [ ] Tested in production mode: `npm run build && npm start`
|
||||
- [ ] Responsive design works (mobile, tablet, desktop)
|
||||
- [ ] Dark mode looks good (default theme)
|
||||
- [ ] No console errors in browser
|
||||
- [ ] No hardcoded personal data
|
||||
|
||||
### Feature Testing
|
||||
|
||||
For new features:
|
||||
|
||||
1. Test happy path (normal usage)
|
||||
2. Test edge cases (empty data, large datasets, etc.)
|
||||
3. Test error handling (network failures, invalid input)
|
||||
4. Test on different screen sizes
|
||||
5. Update `IMPLEMENTATION-STATUS.md`
|
||||
|
||||
## Commit Messages
|
||||
|
||||
Use clear, descriptive commit messages:
|
||||
|
||||
**Format:**
|
||||
```
|
||||
<type>: <short description>
|
||||
|
||||
<optional longer description>
|
||||
|
||||
<optional footer>
|
||||
```
|
||||
|
||||
**Types:**
|
||||
- `feat:` New feature
|
||||
- `fix:` Bug fix
|
||||
- `docs:` Documentation changes
|
||||
- `style:` Code formatting (no logic change)
|
||||
- `refactor:` Code restructuring (no behavior change)
|
||||
- `perf:` Performance improvements
|
||||
- `test:` Adding or updating tests
|
||||
- `chore:` Maintenance tasks
|
||||
|
||||
**Examples:**
|
||||
```
|
||||
feat: add real-time cost tracking with SQLite
|
||||
|
||||
Implemented usage collector that reads openclaw status,
|
||||
calculates costs, and stores in SQLite database.
|
||||
|
||||
Closes #42
|
||||
```
|
||||
|
||||
```
|
||||
fix: prevent notification dropdown from closing on click inside
|
||||
|
||||
Added stopPropagation to prevent event bubbling when
|
||||
clicking notification items.
|
||||
```
|
||||
|
||||
## Pull Request Process
|
||||
|
||||
1. **Update documentation**
|
||||
- Update README.md if adding features
|
||||
- Update IMPLEMENTATION-STATUS.md with completion status
|
||||
- Add docstrings to new functions/components
|
||||
|
||||
2. **Keep PRs focused**
|
||||
- One feature/fix per PR
|
||||
- Don't mix refactoring with new features
|
||||
- Keep diffs small and reviewable
|
||||
|
||||
3. **PR Description Template**
|
||||
```markdown
|
||||
## What does this PR do?
|
||||
Brief description of changes.
|
||||
|
||||
## Type of change
|
||||
- [ ] Bug fix
|
||||
- [ ] New feature
|
||||
- [ ] Documentation update
|
||||
- [ ] Refactoring
|
||||
|
||||
## Testing
|
||||
- [ ] Tested locally in dev mode
|
||||
- [ ] Tested locally in production mode
|
||||
- [ ] No console errors
|
||||
- [ ] Responsive design verified
|
||||
|
||||
## Screenshots (if UI change)
|
||||
[Add screenshots here]
|
||||
|
||||
## Related Issues
|
||||
Closes #[issue number]
|
||||
```
|
||||
|
||||
4. **Review Process**
|
||||
- Address reviewer feedback
|
||||
- Keep discussion respectful and constructive
|
||||
- Be patient - reviews may take a few days
|
||||
|
||||
## Documentation
|
||||
|
||||
When adding features:
|
||||
|
||||
1. **Code Comments**: Explain WHY, not WHAT
|
||||
```typescript
|
||||
// ❌ Bad
|
||||
// Increment counter
|
||||
counter++;
|
||||
|
||||
// ✅ Good
|
||||
// Reset counter after 100 to prevent overflow
|
||||
if (counter >= 100) counter = 0;
|
||||
```
|
||||
|
||||
2. **JSDoc for Functions**
|
||||
```typescript
|
||||
/**
|
||||
* Calculate cost based on token usage and model pricing
|
||||
* @param modelId - Model identifier (e.g., "anthropic/claude-opus-4-6")
|
||||
* @param inputTokens - Number of input tokens used
|
||||
* @param outputTokens - Number of output tokens generated
|
||||
* @returns Total cost in USD
|
||||
*/
|
||||
export function calculateCost(
|
||||
modelId: string,
|
||||
inputTokens: number,
|
||||
outputTokens: number
|
||||
): number {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
3. **README Updates**: Add to README.md if:
|
||||
- New API endpoint
|
||||
- New configuration option
|
||||
- New dependency
|
||||
- Breaking change
|
||||
|
||||
## Reporting Bugs
|
||||
|
||||
Use GitHub Issues with this template:
|
||||
|
||||
```markdown
|
||||
**Describe the bug**
|
||||
Clear description of what's wrong.
|
||||
|
||||
**To Reproduce**
|
||||
1. Go to '...'
|
||||
2. Click on '...'
|
||||
3. See error
|
||||
|
||||
**Expected behavior**
|
||||
What should happen instead.
|
||||
|
||||
**Screenshots**
|
||||
If applicable.
|
||||
|
||||
**Environment**
|
||||
- OS: [e.g., Ubuntu 22.04]
|
||||
- Node version: [e.g., 22.0.0]
|
||||
- OpenClaw version: [e.g., 2026.2.19]
|
||||
- Browser: [e.g., Chrome 120]
|
||||
|
||||
**Additional context**
|
||||
Any other relevant info.
|
||||
```
|
||||
|
||||
## Feature Requests
|
||||
|
||||
Feature requests are welcome! Use GitHub Issues with:
|
||||
|
||||
- **Use case**: Why is this needed?
|
||||
- **Proposed solution**: How should it work?
|
||||
- **Alternatives**: Other ways to solve the problem?
|
||||
- **Priority**: Nice-to-have vs critical
|
||||
|
||||
Check [ROADMAP.md](./ROADMAP.md) first - it might already be planned!
|
||||
|
||||
## Questions?
|
||||
|
||||
- **Discord**: [OpenClaw Community](https://discord.com/invite/clawd)
|
||||
- **GitHub Discussions**: For general questions
|
||||
- **GitHub Issues**: For bug reports and feature requests
|
||||
|
||||
---
|
||||
|
||||
Thank you for contributing! 🦞✨
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
# syntax=docker/dockerfile:1
|
||||
|
||||
FROM node:20-alpine AS deps
|
||||
WORKDIR /app
|
||||
|
||||
COPY package.json package-lock.json ./
|
||||
RUN npm ci
|
||||
|
||||
FROM node:20-alpine AS builder
|
||||
WORKDIR /app
|
||||
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY . ./
|
||||
|
||||
# Allows configuring the API URL at build time.
|
||||
ARG NEXT_PUBLIC_API_URL=auto
|
||||
ENV NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL}
|
||||
ARG NEXT_PUBLIC_AUTH_MODE
|
||||
ENV NEXT_PUBLIC_AUTH_MODE=${NEXT_PUBLIC_AUTH_MODE}
|
||||
|
||||
RUN npm run build
|
||||
|
||||
FROM node:20-alpine AS runner
|
||||
WORKDIR /app
|
||||
|
||||
ENV NODE_ENV=production
|
||||
ARG NEXT_PUBLIC_AUTH_MODE
|
||||
|
||||
# If provided at runtime, Next will expose NEXT_PUBLIC_* to the browser as well
|
||||
# (but note some values may be baked at build time).
|
||||
ENV NEXT_PUBLIC_API_URL=auto
|
||||
ENV NEXT_PUBLIC_AUTH_MODE=${NEXT_PUBLIC_AUTH_MODE}
|
||||
|
||||
# Create non-root user before COPY so --chown can reference it.
|
||||
# Using COPY --chown avoids a slow recursive chown on overlay2 (docker/for-linux#388).
|
||||
RUN addgroup -S appgroup && adduser -S -G appgroup appuser \
|
||||
&& chown appuser:appgroup /app
|
||||
|
||||
COPY --from=builder --chown=appuser:appgroup /app/.next ./.next
|
||||
# `public/` is optional in Next.js apps; repo may not have it.
|
||||
# Avoid failing the build when the directory is absent.
|
||||
COPY --from=builder --chown=appuser:appgroup /app/package.json ./package.json
|
||||
COPY --from=builder --chown=appuser:appgroup /app/node_modules ./node_modules
|
||||
COPY --from=builder --chown=appuser:appgroup /app/next.config.ts ./next.config.ts
|
||||
|
||||
USER appuser
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
CMD ["npm", "run", "start"]
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2026 Mission Control Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
|
@ -1,178 +1,408 @@
|
|||
# Mission Control Frontend (`frontend/`)
|
||||
# TenacitOS — Mission Control
|
||||
|
||||
This package is the **Next.js** web UI for OpenClaw Mission Control.
|
||||
A real-time dashboard and control center for [OpenClaw](https://openclaw.ai) AI agent instances. Built with Next.js, React 19, and Tailwind CSS v4.
|
||||
|
||||
- Talks to the Mission Control **backend** over HTTP (typically `http://localhost:8000`).
|
||||
- Uses **React Query** for data fetching.
|
||||
- Supports two auth modes:
|
||||
- **local** shared bearer token mode (self-host default)
|
||||
- **clerk** mode
|
||||
> **TenacitOS** lives inside your OpenClaw workspace and reads its configuration, agents, sessions, memory, and logs directly from the host. No extra database or backend required — OpenClaw is the backend.
|
||||
|
||||
## Prerequisites
|
||||
---
|
||||
|
||||
- Node.js (recommend **18+**) and npm
|
||||
- Backend running locally (see `../backend/README.md` if present) **or** run the stack via Docker Compose from repo root.
|
||||
## Features
|
||||
|
||||
## Local development
|
||||
- **📊 System Monitor** — Real-time VPS metrics (CPU, RAM, Disk, Network) + PM2/Docker status
|
||||
- **🤖 Agent Dashboard** — All agents, their sessions, token usage, model, and activity status
|
||||
- **💰 Cost Tracking** — Real cost analytics from OpenClaw sessions (SQLite)
|
||||
- **⏰ Cron Manager** — Visual cron manager with weekly timeline, run history, and manual triggers
|
||||
- **📋 Activity Feed** — Real-time log of agent actions with heatmap and charts
|
||||
- **🧠 Memory Browser** — Explore, search, and edit agent memory files
|
||||
- **📁 File Browser** — Navigate workspace files with preview and in-browser editing
|
||||
- **🔎 Global Search** — Full-text search across memory and workspace files
|
||||
- **🔔 Notifications** — Real-time notification center with unread badge
|
||||
- **🏢 Office 3D** — Interactive 3D office with one desk per agent (React Three Fiber)
|
||||
- **📺 Terminal** — Read-only terminal for safe status commands
|
||||
- **🔐 Auth** — Password-protected with rate limiting and secure cookie
|
||||
|
||||
From `frontend/`:
|
||||
---
|
||||
|
||||
## Screenshots
|
||||
|
||||
**Dashboard** — activity overview, agent status, and weather widget
|
||||
|
||||

|
||||
|
||||
**Session History** — all OpenClaw sessions with token usage and context tracking
|
||||
|
||||

|
||||
|
||||
**Costs & Analytics** — daily cost trends and breakdown per agent
|
||||
|
||||

|
||||
|
||||
**System Monitor** — real-time CPU, RAM, Disk, and Network metrics
|
||||
|
||||

|
||||
|
||||
**Office 3D** — interactive 3D office with one voxel avatar per agent (React Three Fiber)
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Requirements
|
||||
|
||||
- **Node.js** 18+ (tested with v22)
|
||||
- **[OpenClaw](https://openclaw.ai)** installed and running on the same host
|
||||
- **PM2** or **systemd** (recommended for production)
|
||||
- **Caddy** or another reverse proxy (for HTTPS in production)
|
||||
|
||||
---
|
||||
|
||||
## How it works
|
||||
|
||||
TenacitOS reads directly from your OpenClaw installation:
|
||||
|
||||
```
|
||||
/root/.openclaw/ ← OPENCLAW_DIR (configurable)
|
||||
├── openclaw.json ← agents list, channels, models config
|
||||
├── workspace/ ← main agent workspace (MEMORY.md, SOUL.md, etc.)
|
||||
├── workspace-studio/ ← sub-agent workspaces
|
||||
├── workspace-infra/
|
||||
├── ...
|
||||
└── workspace/mission-control/ ← TenacitOS lives here
|
||||
```
|
||||
|
||||
The app uses `OPENCLAW_DIR` to locate `openclaw.json` and all workspaces. **No manual agent configuration needed** — agents are auto-discovered from `openclaw.json`.
|
||||
|
||||
---
|
||||
|
||||
## Installation
|
||||
|
||||
### 1. Clone into your OpenClaw workspace
|
||||
|
||||
```bash
|
||||
cd /root/.openclaw/workspace # or your OPENCLAW_DIR/workspace
|
||||
git clone https://github.com/carlosazaustre/tenacitOS.git mission-control
|
||||
cd mission-control
|
||||
npm install
|
||||
|
||||
# set env vars (see below)
|
||||
cp .env.example .env.local
|
||||
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Open http://localhost:3000.
|
||||
|
||||
### LAN development
|
||||
|
||||
To bind Next dev server to all interfaces:
|
||||
### 2. Configure environment
|
||||
|
||||
```bash
|
||||
npm run dev:lan
|
||||
cp .env.example .env.local
|
||||
```
|
||||
|
||||
## Environment variables
|
||||
|
||||
The frontend reads configuration from standard Next.js env files (`.env.local`, `.env`, etc.).
|
||||
|
||||
### Required
|
||||
|
||||
#### `NEXT_PUBLIC_API_URL`
|
||||
|
||||
Base URL of the backend API (or `auto`).
|
||||
|
||||
- Default: `auto` (resolved in browser as `http(s)://<current-host>:8000`)
|
||||
- Used by the generated API client and helpers (see `src/lib/api-base.ts` and `src/api/mutator.ts`).
|
||||
|
||||
Example:
|
||||
Edit `.env.local`:
|
||||
|
||||
```env
|
||||
NEXT_PUBLIC_API_URL=auto
|
||||
# --- Auth (required) ---
|
||||
# Strong password to log in to the dashboard
|
||||
ADMIN_PASSWORD=your-secure-password-here
|
||||
|
||||
# Random secret used to sign the auth cookie
|
||||
# Generate with: openssl rand -base64 32
|
||||
AUTH_SECRET=your-random-32-char-secret-here
|
||||
|
||||
# --- OpenClaw paths (optional — defaults work for standard installs) ---
|
||||
# OPENCLAW_DIR=/root/.openclaw
|
||||
|
||||
# --- Branding (customize for your instance) ---
|
||||
NEXT_PUBLIC_AGENT_NAME=Mission Control
|
||||
NEXT_PUBLIC_AGENT_EMOJI=🤖
|
||||
NEXT_PUBLIC_AGENT_DESCRIPTION=Your AI co-pilot, powered by OpenClaw
|
||||
NEXT_PUBLIC_AGENT_LOCATION= # e.g. "Madrid, Spain"
|
||||
NEXT_PUBLIC_BIRTH_DATE= # ISO date, e.g. "2026-01-01"
|
||||
NEXT_PUBLIC_AGENT_AVATAR= # path to image in /public, e.g. "/avatar.jpg"
|
||||
|
||||
NEXT_PUBLIC_OWNER_USERNAME=your-username
|
||||
NEXT_PUBLIC_OWNER_EMAIL=your-email@example.com
|
||||
NEXT_PUBLIC_TWITTER_HANDLE=@username
|
||||
NEXT_PUBLIC_COMPANY_NAME=MISSION CONTROL, INC.
|
||||
NEXT_PUBLIC_APP_TITLE=Mission Control
|
||||
```
|
||||
|
||||
### Authentication mode
|
||||
> **Tip:** `OPENCLAW_DIR` defaults to `/root/.openclaw`. If your OpenClaw is installed elsewhere, set this variable.
|
||||
|
||||
Set `NEXT_PUBLIC_AUTH_MODE` to one of:
|
||||
|
||||
- `local` (default for self-host)
|
||||
- `clerk`
|
||||
|
||||
For `local` mode:
|
||||
|
||||
- users enter the token in the local login screen
|
||||
- requests use that token as `Authorization: Bearer ...`
|
||||
|
||||
For `clerk` mode, configure:
|
||||
|
||||
- `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY`
|
||||
- optional `NEXT_PUBLIC_CLERK_SIGN_IN_FALLBACK_REDIRECT_URL`
|
||||
- optional `NEXT_PUBLIC_CLERK_AFTER_SIGN_OUT_URL`
|
||||
|
||||
## How the frontend talks to the backend
|
||||
|
||||
### API base URL
|
||||
|
||||
The client builds URLs using `NEXT_PUBLIC_API_URL` (normalized to remove trailing slashes).
|
||||
|
||||
### Generated API client (Orval + React Query)
|
||||
|
||||
We generate a typed client from the backend OpenAPI schema using **Orval**:
|
||||
|
||||
- Config: `orval.config.ts`
|
||||
- Output: `src/api/generated/*`
|
||||
- Script: `npm run api:gen`
|
||||
|
||||
By default, Orval reads:
|
||||
|
||||
- `ORVAL_INPUT` (if set), otherwise
|
||||
- `http://127.0.0.1:8000/openapi.json`
|
||||
|
||||
Example:
|
||||
### 3. Initialize data files
|
||||
|
||||
```bash
|
||||
# from frontend/
|
||||
ORVAL_INPUT=http://localhost:8000/openapi.json npm run api:gen
|
||||
cp data/cron-jobs.example.json data/cron-jobs.json
|
||||
cp data/activities.example.json data/activities.json
|
||||
cp data/notifications.example.json data/notifications.json
|
||||
cp data/configured-skills.example.json data/configured-skills.json
|
||||
cp data/tasks.example.json data/tasks.json
|
||||
```
|
||||
|
||||
### Auth header / Clerk token injection
|
||||
|
||||
All Orval-generated requests go through the custom mutator (`src/api/mutator.ts`).
|
||||
It will:
|
||||
|
||||
- set `Content-Type: application/json` when there is a body and you didn’t specify a content type
|
||||
- add `Authorization: Bearer <token>` automatically from local mode token or Clerk session
|
||||
- parse errors into an `ApiError` with status + parsed response body
|
||||
|
||||
## Mobile / responsive UI validation
|
||||
|
||||
When changing UI intended to be mobile-ready, validate in Chrome (or similar) using the device toolbar at common widths (e.g. **320px**, **375px**, **768px**).
|
||||
|
||||
Quick checklist:
|
||||
|
||||
- No horizontal scroll
|
||||
- Primary actions reachable without precision taps
|
||||
- Focus rings visible when tabbing
|
||||
- Modals/popovers not clipped
|
||||
|
||||
## Common commands
|
||||
|
||||
From `frontend/`:
|
||||
### 4. Generate secrets
|
||||
|
||||
```bash
|
||||
npm run dev # start dev server
|
||||
npm run build # production build
|
||||
npm run start # run the built app
|
||||
npm run lint # eslint
|
||||
npm run test # vitest (with coverage)
|
||||
npm run test:watch # watch mode
|
||||
npm run api:gen # regenerate typed API client via Orval
|
||||
# Auth secret
|
||||
openssl rand -base64 32
|
||||
|
||||
# Password (or use a password manager)
|
||||
openssl rand -base64 18
|
||||
```
|
||||
|
||||
## Docker
|
||||
### 5. Run
|
||||
|
||||
There is a `frontend/Dockerfile` used by the root `compose.yml`.
|
||||
```bash
|
||||
# Development
|
||||
npm run dev
|
||||
# → http://localhost:3000
|
||||
|
||||
If you’re working on self-hosting, prefer running compose from the repo root so the backend/db are aligned with the documented ports/env.
|
||||
# Production build
|
||||
npm run build
|
||||
npm start
|
||||
```
|
||||
|
||||
Login at `http://localhost:3000` with the `ADMIN_PASSWORD` you set.
|
||||
|
||||
---
|
||||
|
||||
## Production Deployment
|
||||
|
||||
### PM2 (recommended)
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
|
||||
pm2 start npm --name "mission-control" -- start
|
||||
pm2 save
|
||||
pm2 startup # enable auto-restart on reboot
|
||||
```
|
||||
|
||||
### systemd
|
||||
|
||||
Create `/etc/systemd/system/mission-control.service`:
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=TenacitOS — OpenClaw Mission Control
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=root
|
||||
WorkingDirectory=/root/.openclaw/workspace/mission-control
|
||||
ExecStart=/usr/bin/npm start
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
Environment=NODE_ENV=production
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
```bash
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable mission-control
|
||||
sudo systemctl start mission-control
|
||||
```
|
||||
|
||||
### Reverse proxy — Caddy (HTTPS)
|
||||
|
||||
```caddy
|
||||
mission-control.yourdomain.com {
|
||||
reverse_proxy localhost:3000
|
||||
}
|
||||
```
|
||||
|
||||
> When behind HTTPS, `secure: true` is set automatically on the auth cookie.
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
### Agent branding
|
||||
|
||||
All personal data stays in `.env.local` (gitignored). The `src/config/branding.ts` file reads from env vars — **never edit it directly** with your personal data.
|
||||
|
||||
### Agent discovery
|
||||
|
||||
Agents are auto-discovered from `openclaw.json` at startup. The `/api/agents` endpoint reads:
|
||||
|
||||
```json
|
||||
{
|
||||
"agents": {
|
||||
"list": [
|
||||
{ "id": "main", "name": "...", "workspace": "...", "model": {...} },
|
||||
{ "id": "studio", "name": "...", "workspace": "..." }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Each agent can define its own visual appearance in `openclaw.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "studio",
|
||||
"name": "My Studio Agent",
|
||||
"ui": {
|
||||
"emoji": "🎬",
|
||||
"color": "#E91E63"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Office 3D — agent positions
|
||||
|
||||
The 3D office has default positions for up to 6 agents. To customize positions, names, and colors for your own agents, edit `src/components/Office3D/agentsConfig.ts`:
|
||||
|
||||
```ts
|
||||
export const AGENTS: AgentConfig[] = [
|
||||
{
|
||||
id: "main", // must match workspace ID
|
||||
name: "...", // display name (can also come from API)
|
||||
emoji: "🤖",
|
||||
position: [0, 0, 0],
|
||||
color: "#FFCC00",
|
||||
role: "Main Agent",
|
||||
},
|
||||
// add your sub-agents here
|
||||
];
|
||||
```
|
||||
|
||||
### 3D Avatar models
|
||||
|
||||
To add custom 3D avatars (Ready Player Me GLB format), place them in `public/models/`:
|
||||
|
||||
```
|
||||
public/models/
|
||||
├── main.glb ← main agent avatar
|
||||
├── studio.glb ← workspace-studio agent
|
||||
└── infra.glb ← workspace-infra agent
|
||||
```
|
||||
|
||||
Filename must match the agent `id`. If no file is found, a colored sphere is shown as fallback.
|
||||
See `public/models/README.md` for full instructions.
|
||||
|
||||
### Cost tracking
|
||||
|
||||
Usage is collected from OpenClaw's SQLite databases via a script:
|
||||
|
||||
```bash
|
||||
# Collect once
|
||||
npx tsx scripts/collect-usage.ts
|
||||
|
||||
# Auto-collect every hour (adds a cron job)
|
||||
./scripts/setup-cron.sh
|
||||
```
|
||||
|
||||
See [docs/COST-TRACKING.md](./docs/COST-TRACKING.md) for details.
|
||||
|
||||
---
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
mission-control/
|
||||
├── src/
|
||||
│ ├── app/
|
||||
│ │ ├── (dashboard)/ # Dashboard pages (protected)
|
||||
│ │ ├── api/ # API routes
|
||||
│ │ ├── login/ # Login page
|
||||
│ │ └── office/ # 3D office (unprotected route)
|
||||
│ ├── components/
|
||||
│ │ ├── TenacitOS/ # OS-style UI shell (topbar, dock, status bar)
|
||||
│ │ └── Office3D/ # React Three Fiber 3D office
|
||||
│ ├── config/
|
||||
│ │ └── branding.ts # Branding constants (reads from env vars)
|
||||
│ └── lib/ # Utilities (pricing, queries, activity logger...)
|
||||
├── data/ # JSON data files (gitignored — use .example versions)
|
||||
├── docs/ # Extended documentation
|
||||
├── public/
|
||||
│ └── models/ # GLB avatar models (add your own)
|
||||
├── scripts/ # Setup and data collection scripts
|
||||
├── .env.example # Environment variable template
|
||||
└── middleware.ts # Auth guard for all routes
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Security
|
||||
|
||||
- All routes (including all `/api/*`) require authentication — handled by `src/middleware.ts`
|
||||
- `/api/auth/login` and `/api/health` are the only public endpoints
|
||||
- Login is rate-limited: **5 failed attempts → 15-minute lockout** per IP
|
||||
- Auth cookie is `httpOnly`, `sameSite: lax`, and `secure` in production
|
||||
- Terminal API uses a strict command allowlist — `env`, `curl`, `wget`, `node`, `python` are blocked
|
||||
- **Never commit `.env.local`** — it contains your credentials
|
||||
|
||||
Generate fresh secrets:
|
||||
|
||||
```bash
|
||||
openssl rand -base64 32 # AUTH_SECRET
|
||||
openssl rand -base64 18 # ADMIN_PASSWORD
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### `NEXT_PUBLIC_API_URL` and remote hosts
|
||||
|
||||
If unset or set to `auto`, the client uses `http(s)://<current-host>:8000`.
|
||||
If your backend is on a different host/port, set `NEXT_PUBLIC_API_URL` explicitly.
|
||||
|
||||
Fix:
|
||||
**"Gateway not reachable" / agent data missing**
|
||||
|
||||
```bash
|
||||
cp .env.example .env.local
|
||||
# then edit .env.local if your backend URL differs
|
||||
openclaw status
|
||||
openclaw gateway start # if not running
|
||||
```
|
||||
|
||||
### Frontend loads, but API calls fail (CORS / network errors)
|
||||
**"Database not found" (cost tracking)**
|
||||
|
||||
- Confirm backend is up: http://localhost:8000/healthz
|
||||
- Confirm `NEXT_PUBLIC_API_URL` points to the correct host/port.
|
||||
- If accessing from another device (LAN), use a reachable backend URL (not `localhost`).
|
||||
```bash
|
||||
npx tsx scripts/collect-usage.ts
|
||||
```
|
||||
|
||||
### Wrong auth mode UI
|
||||
**Build errors after pulling updates**
|
||||
|
||||
- Ensure `NEXT_PUBLIC_AUTH_MODE` matches backend `AUTH_MODE`.
|
||||
- For local mode, set `NEXT_PUBLIC_AUTH_MODE=local`.
|
||||
- For Clerk mode, set `NEXT_PUBLIC_AUTH_MODE=clerk` and a real Clerk publishable key.
|
||||
```bash
|
||||
rm -rf .next node_modules
|
||||
npm install
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Dev server blocked by origin restrictions
|
||||
**Scripts not executable**
|
||||
|
||||
`next.config.ts` sets `allowedDevOrigins` for dev proxy safety.
|
||||
```bash
|
||||
chmod +x scripts/*.sh
|
||||
```
|
||||
|
||||
If you see repeated proxy errors (often `ECONNRESET`), make sure your dev server hostname and browser URL match (e.g. `localhost` vs `127.0.0.1`), and that your origin is included in `allowedDevOrigins`.
|
||||
---
|
||||
|
||||
Notes:
|
||||
## Tech Stack
|
||||
|
||||
- Local dev should work via `http://localhost:3000` and `http://127.0.0.1:3000`.
|
||||
- LAN dev should work via the configured LAN IP (e.g. `http://192.168.1.101:3000`) **only** if you bind the dev server to all interfaces (`npm run dev:lan`).
|
||||
- If you bind Next to `127.0.0.1` only, remote LAN clients won’t connect.
|
||||
| Layer | Tech |
|
||||
|---|---|
|
||||
| Framework | Next.js 15 (App Router) |
|
||||
| UI | React 19 + Tailwind CSS v4 |
|
||||
| 3D | React Three Fiber + Drei |
|
||||
| Charts | Recharts |
|
||||
| Icons | Lucide React |
|
||||
| Database | SQLite (better-sqlite3) |
|
||||
| Runtime | Node.js 22 |
|
||||
|
||||
---
|
||||
|
||||
## Contributing
|
||||
|
||||
1. Fork the repo
|
||||
2. Create a feature branch (`git checkout -b feat/my-feature`)
|
||||
3. **Keep personal data out of commits** — use `.env.local` and `data/` (both gitignored)
|
||||
4. Write clear commit messages
|
||||
5. Open a PR
|
||||
|
||||
See [CONTRIBUTING.md](./CONTRIBUTING.md) for more details.
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
MIT — see [LICENSE](./LICENSE)
|
||||
|
||||
---
|
||||
|
||||
## Links
|
||||
|
||||
- [OpenClaw](https://openclaw.ai) — the AI agent runtime this dashboard is built for
|
||||
- [OpenClaw Docs](https://docs.openclaw.ai)
|
||||
- [Discord Community](https://discord.com/invite/clawd)
|
||||
- [GitHub Issues](../../issues) — bug reports and feature requests
|
||||
|
|
|
|||
|
|
@ -0,0 +1,420 @@
|
|||
# 🦞 Mission Control - Roadmap
|
||||
|
||||
## Fase 1: Fundamentos (Semana 1)
|
||||
> Mejorar lo que ya existe y añadir datos reales
|
||||
|
||||
### 1.1 Activity Logger Real
|
||||
- [ ] Crear endpoint POST `/api/activities` para que Tenacitas registre acciones
|
||||
- [ ] Hook en OpenClaw para loguear automáticamente cada tool call
|
||||
- [ ] Campos: timestamp, type, description, status, duration, tokens_used
|
||||
- [ ] Retención: últimos 30 días
|
||||
|
||||
### 1.2 Integración con Cron Real
|
||||
- [ ] Leer cron jobs reales de OpenClaw (`cron list`)
|
||||
- [ ] Mostrar en calendario con próximas ejecuciones
|
||||
- [ ] Historial de ejecuciones pasadas
|
||||
|
||||
### 1.3 Stats Dashboard
|
||||
- [ ] Contador de actividades por día/semana
|
||||
- [ ] Tipos de acciones más frecuentes
|
||||
- [ ] Tasa de éxito/error
|
||||
|
||||
---
|
||||
|
||||
## Fase 2: Memory & Files (Semana 2)
|
||||
> Gestión visual del workspace
|
||||
|
||||
### 2.1 Memory Browser
|
||||
- [ ] Vista árbol de `memory/*.md` y archivos principales
|
||||
- [ ] Editor markdown con preview
|
||||
- [ ] Crear/renombrar/eliminar archivos
|
||||
- [ ] Búsqueda dentro de archivos
|
||||
|
||||
### 2.2 File Browser
|
||||
- [ ] Explorador del workspace completo
|
||||
- [ ] Preview de archivos (código, markdown, JSON)
|
||||
- [ ] Descargar archivos
|
||||
- [ ] Upload de archivos
|
||||
|
||||
### 2.3 MEMORY.md Viewer
|
||||
- [ ] Vista especial para MEMORY.md con secciones colapsables
|
||||
- [ ] Edición inline
|
||||
- [ ] Historial de cambios (git log)
|
||||
|
||||
---
|
||||
|
||||
## Fase 3: Cron Manager (Semana 3)
|
||||
> Control total de tareas programadas
|
||||
|
||||
### 3.1 CRUD de Cron Jobs
|
||||
- [x] Listar todos los jobs con estado (ya existía)
|
||||
- [ ] Crear nuevo job con form visual (CronJobModal existe pero no está wired up al API)
|
||||
- [ ] Editar job existente
|
||||
- [x] Eliminar job (con confirmación)
|
||||
- [x] Activar/desactivar job
|
||||
|
||||
### 3.2 Cron Builder Visual
|
||||
- [ ] Selector de frecuencia: diario, semanal, mensual, custom
|
||||
- [ ] Preview de próximas 5 ejecuciones
|
||||
- [ ] Selector de timezone
|
||||
- [ ] Templates predefinidos
|
||||
|
||||
### 3.3 Historial de Ejecuciones
|
||||
- [x] ~~Re-ejecutar manualmente~~ → **"Run Now" button** en CronJobCard (llama a `POST /api/cron/run`)
|
||||
- [x] **Run History inline** → botón History en CronJobCard, llama a `GET /api/cron/runs?id=<id>`
|
||||
- [ ] Filtrar historial por fecha, estado
|
||||
- [ ] Log con output completo
|
||||
|
||||
### 3.4 Weekly Timeline View ✅ (nuevo — 2026-02-19)
|
||||
- [x] Vista tipo calendario de 7 días
|
||||
- [x] Eventos de cron posicionados por día con hora exacta
|
||||
- [x] Jobs de intervalo mostrados como "recurring" con dashed border
|
||||
- [x] Leyenda de colores por job
|
||||
- [x] Toggle Cards / Timeline en header
|
||||
- [x] Componente: `CronWeeklyTimeline.tsx`
|
||||
- [x] Nuevas rutas API: `POST /api/cron/run`, `GET /api/cron/runs`
|
||||
|
||||
---
|
||||
|
||||
## Fase 4: Analytics (Semana 4)
|
||||
> Visualización de datos
|
||||
|
||||
### 4.1 Gráficas de Uso
|
||||
- [ ] Actividad por hora del día (heatmap)
|
||||
- [ ] Tokens consumidos por día (line chart)
|
||||
- [ ] Tipos de tareas (pie chart)
|
||||
- [ ] Tendencia semanal
|
||||
|
||||
### 4.2 Cost Tracking
|
||||
- [ ] Estimación de coste por modelo
|
||||
- [ ] Coste acumulado diario/mensual
|
||||
- [ ] Alertas de gasto (opcional)
|
||||
|
||||
### 4.3 Performance Metrics
|
||||
- [ ] Tiempo promedio de respuesta
|
||||
- [ ] Tasa de éxito por tipo de tarea
|
||||
- [ ] Uptime del agente
|
||||
|
||||
---
|
||||
|
||||
## Fase 5: Comunicación (Semana 5)
|
||||
> Interacción bidireccional
|
||||
|
||||
### 5.1 Command Terminal
|
||||
- [ ] Input para enviar mensajes/comandos a Tenacitas
|
||||
- [ ] Output en tiempo real de respuesta
|
||||
- [ ] Historial de comandos
|
||||
- [ ] Shortcuts para comandos frecuentes
|
||||
|
||||
### 5.2 Notifications Log
|
||||
- [ ] Lista de mensajes enviados por canal (Telegram, etc.)
|
||||
- [ ] Filtrar por fecha, canal, tipo
|
||||
- [ ] Preview del mensaje
|
||||
- [ ] Estado de entrega
|
||||
|
||||
### 5.3 Session History ✅ (nuevo — 2026-02-21)
|
||||
- [x] **Lista de sesiones** → todas las sesiones de OpenClaw (main, cron, subagent, chats)
|
||||
- [x] **Tipos visuales** → badges con emoji 🦞 Main / 🕐 Cron / 🤖 Sub-agent / 💬 Direct
|
||||
- [x] **Token counter** → total tokens + barra de contexto (% usado) con color-coding
|
||||
- [x] **Model badge** → modelo mostrado (Sonnet 4.5, Opus 4.6, etc.)
|
||||
- [x] **Age display** → "2 hours ago", "3 days ago" con date-fns
|
||||
- [x] **Transcript viewer** → slide-in panel con mensajes del JSONL real
|
||||
- [x] **Bubbles UI** → user/assistant/tool_use/tool_result con diferentes estilos
|
||||
- [x] **Filter tabs** → All / Main / Cron / Sub-agents / Chats con contador
|
||||
- [x] **Búsqueda** → filtro por key/model
|
||||
- [x] **Stats cards** → Total sessions, Total tokens, Cron runs, Models used
|
||||
- [x] **Sidebar + Dock** → añadido a navegación (icono History)
|
||||
- **Archivos:**
|
||||
- NEW: `src/app/api/sessions/route.ts`
|
||||
- NEW: `src/app/(dashboard)/sessions/page.tsx`
|
||||
- MODIFIED: `src/components/Sidebar.tsx` (añadida entrada Sessions)
|
||||
- MODIFIED: `src/components/TenacitOS/Dock.tsx` (añadida entrada Sessions)
|
||||
|
||||
### 5.4 Notifications System ✅ (nuevo — 2026-02-20)
|
||||
- [x] **API de notificaciones** → `GET/POST/PATCH/DELETE /api/notifications`
|
||||
- [x] **NotificationDropdown component** → Bell icon en TopBar con dropdown funcional
|
||||
- [x] **Unread count badge** → Contador de notificaciones no leídas
|
||||
- [x] **Notificación types** → info, success, warning, error con iconos y colores
|
||||
- [x] **Mark as read/unread** → Individual o todas
|
||||
- [x] **Delete notifications** → Individual o clear all read
|
||||
- [x] **Links** → Notificaciones pueden tener links a páginas internas
|
||||
- [x] **Auto-refresh** → Poll cada 30 segundos
|
||||
- [x] **Integración con cron** → Cron Run Now genera notificación
|
||||
- [x] **Storage** → JSON file en `data/notifications.json` (hasta 100 notificaciones)
|
||||
- **Archivos:**
|
||||
- NEW: `src/app/api/notifications/route.ts`
|
||||
- NEW: `src/components/NotificationDropdown.tsx`
|
||||
- MODIFIED: `src/components/TenacitOS/TopBar.tsx`
|
||||
- MODIFIED: `src/app/api/cron/run/route.ts` (integración)
|
||||
|
||||
---
|
||||
|
||||
## Fase 6: Configuración (Semana 6)
|
||||
> Admin del sistema
|
||||
|
||||
### 6.1 Skills Manager
|
||||
- [ ] Lista de skills instalados
|
||||
- [ ] Ver SKILL.md de cada uno
|
||||
- [ ] Activar/desactivar
|
||||
- [ ] Instalar desde ClawHub
|
||||
- [ ] Actualizar skills
|
||||
|
||||
### 6.2 Integration Status
|
||||
- [ ] Estado de conexiones (Twitter, Gmail, etc.)
|
||||
- [ ] Última actividad por integración
|
||||
- [ ] Test de conectividad
|
||||
- [ ] Reautenticar si necesario
|
||||
|
||||
### 6.3 Config Editor
|
||||
- [ ] Ver configuración actual de OpenClaw
|
||||
- [ ] Editar valores seguros
|
||||
- [ ] Validación antes de guardar
|
||||
- [ ] Reiniciar gateway si necesario
|
||||
|
||||
---
|
||||
|
||||
## Fase 7: Real-time (Semana 7)
|
||||
> WebSockets y notificaciones live
|
||||
|
||||
### 7.1 Live Activity Stream
|
||||
- [ ] WebSocket connection
|
||||
- [ ] Updates en tiempo real del activity feed
|
||||
- [ ] Indicador "Tenacitas está trabajando..."
|
||||
- [ ] Toast notifications
|
||||
|
||||
### 7.2 System Status
|
||||
- [ ] Heartbeat del agente
|
||||
- [ ] CPU/memoria del VPS
|
||||
- [ ] Cola de tareas pendientes
|
||||
|
||||
---
|
||||
|
||||
## Fase 8: The Office 3D 🏢 (Semanas 8-10)
|
||||
> Entorno 3D navegable que simula una oficina virtual donde trabajan los agentes
|
||||
|
||||
**Ver spec completa:** `ROADMAP-OFFICE-3D.md`
|
||||
|
||||
### 8.1 MVP - Oficina Básica (Semana 8)
|
||||
- [ ] Sala 3D con React Three Fiber + 6 escritorios
|
||||
- [ ] Navegación WASD + mouse (fly mode)
|
||||
- [ ] Monitors mostrando estado: Working/Idle/Error
|
||||
- [ ] Click en escritorio → panel lateral con activity feed
|
||||
- [ ] Iluminación básica (día/noche)
|
||||
- [ ] Avatares simples (cubo/esfera con emoji del agente)
|
||||
|
||||
### 8.2 Interactions & Ambient (Semana 9)
|
||||
- [ ] Avatares animados (tecleando, pensando, error)
|
||||
- [ ] Sub-agents aparecen como "visitantes" en la oficina
|
||||
- [ ] Trail visual entre parent y sub-agent
|
||||
- [ ] Efectos visuales (partículas success, humo error, beam heartbeat)
|
||||
- [ ] Sonido ambiental toggleable (teclas, notificaciones, lofi)
|
||||
- [ ] Click en objetos (archivador→Memory, pizarra→Roadmap, café→Mood)
|
||||
|
||||
### 8.3 Multi-Floor Building (Semana 10)
|
||||
- [ ] 4 plantas navegables con ascensor:
|
||||
- Planta 1: Main Office (agentes principales)
|
||||
- Planta 2: Server Room (DBs, VPS, integrations)
|
||||
- Planta 3: Archive (logs, memories históricas)
|
||||
- Azotea: Control Tower (dashboard gigante)
|
||||
- [ ] Customization: temas (modern, retro, cyberpunk, matrix)
|
||||
- [ ] Modos especiales (Focus, God Mode, Cinematic)
|
||||
|
||||
**Datos en tiempo real:**
|
||||
- `/api/agents/status` - estado de cada agente
|
||||
- `/api/activities` - activity feed
|
||||
- `/api/subagents` - sub-agentes activos
|
||||
- Polling cada 2-5 segundos
|
||||
|
||||
---
|
||||
|
||||
## Fase 9: Agent Intelligence (Semana 11)
|
||||
> Features experimentales y visualizaciones avanzadas (complementan "The Office")
|
||||
|
||||
### 9.1 Agent Mood Dashboard
|
||||
- [ ] Widget de "estado de ánimo" basado en métricas recientes
|
||||
- [ ] Indicadores visuales: productivo, ocupado, idle, frustrado (muchos errores)
|
||||
- [ ] Streak counter: días consecutivos sin errores críticos
|
||||
- [ ] "Energy level" basado en tokens/hora
|
||||
- [ ] Emoji animado que cambia según el estado
|
||||
|
||||
### 9.2 Token Economics
|
||||
- [ ] Vista detallada de consumo por modelo (Opus, Sonnet, Haiku, etc.)
|
||||
- [ ] Breakdown: input tokens vs output tokens vs cache
|
||||
- [ ] Comparativa: "Hoy vs ayer", "Esta semana vs la pasada"
|
||||
- [ ] Proyección de gasto mensual
|
||||
- [ ] Top 5 tareas que más tokens consumen
|
||||
- [ ] Efficiency score: output útil / tokens totales
|
||||
|
||||
### 9.3 Knowledge Graph Viewer
|
||||
- [ ] Visualización de conceptos/entidades en MEMORY.md y brain
|
||||
- [ ] Grafo interactivo con nodes y links
|
||||
- [ ] Click en un nodo → muestra snippets relacionados
|
||||
- [ ] Clustering por temas
|
||||
- [ ] Búsqueda visual
|
||||
- [ ] Export a imagen
|
||||
|
||||
### 9.4 Quick Actions Hub
|
||||
- [ ] Panel de botones para acciones frecuentes:
|
||||
- Backup workspace now
|
||||
- Clear temp files
|
||||
- Test all integrations
|
||||
- Re-authorize expired tokens
|
||||
- Git status all repos
|
||||
- Restart Gateway
|
||||
- Flush message queue
|
||||
- [ ] Status de cada acción (last run, next scheduled)
|
||||
- [ ] One-click execution con confirmación
|
||||
|
||||
### 9.5 Model Playground
|
||||
- [ ] Input un prompt
|
||||
- [ ] Seleccionar múltiples modelos para comparar
|
||||
- [ ] Ver respuestas lado a lado
|
||||
- [ ] Mostrar tokens/coste/tiempo de cada uno
|
||||
- [ ] Guardar experimentos
|
||||
- [ ] Share results (copy link)
|
||||
|
||||
### 9.6 Smart Suggestions Engine
|
||||
- [ ] Analiza patrones de uso
|
||||
- [ ] Sugiere optimizaciones:
|
||||
- "Usas mucho Opus para tareas simples, prueba Sonnet"
|
||||
- "Muchos errores en cron X, revisar configuración"
|
||||
- "Heartbeats muy frecuentes, considera reducir intervalo"
|
||||
- "Token usage alto en horario Y, programar tareas pesadas en horario valle"
|
||||
- [ ] Tarjetas de sugerencia con botón "Apply" o "Dismiss"
|
||||
- [ ] Learn from dismissals
|
||||
|
||||
---
|
||||
|
||||
## Fase 10: Sub-Agent Orchestra (Semana 12)
|
||||
> Gestión y visualización de multi-agent workflows
|
||||
|
||||
### 10.1 Sub-Agent Dashboard
|
||||
- [ ] Lista de sub-agentes activos en tiempo real
|
||||
- [ ] Estado: running, waiting, completed, failed
|
||||
- [ ] Task description y progreso
|
||||
- [ ] Modelo usado
|
||||
- [ ] Tokens consumidos por cada uno
|
||||
- [ ] Timeline de spawns/completions
|
||||
|
||||
### 10.2 Agent Communication Graph
|
||||
- [ ] Visualización de mensajes entre main agent y sub-agents
|
||||
- [ ] Flow diagram tipo Sankey o network graph
|
||||
- [ ] Ver contenido de mensajes al hacer click
|
||||
- [ ] Filtrar por sesión, fecha, tipo
|
||||
|
||||
### 10.3 Multi-Agent Orchestration
|
||||
- [ ] Crear workflows visuales de múltiples agentes
|
||||
- [ ] Drag & drop tasks → auto-spawn agents
|
||||
- [ ] Dependencies entre tasks
|
||||
- [ ] Parallel vs sequential execution
|
||||
- [ ] Template workflows guardables
|
||||
|
||||
---
|
||||
|
||||
## Fase 11: Advanced Visualizations (Semana 13)
|
||||
> Porque los dashboards cool tienen gráficas cool
|
||||
|
||||
### 11.1 3D Workspace Explorer
|
||||
- [ ] Vista 3D del árbol de archivos
|
||||
- [ ] Tamaño de nodos = tamaño de archivo
|
||||
- [ ] Color = tipo de archivo
|
||||
- [ ] Navigate con mouse
|
||||
- [ ] Click → preview/edit
|
||||
- [ ] Wow factor 📈
|
||||
|
||||
### 11.2 Heatmaps Interactivos
|
||||
- [ ] Actividad por hora del día (24x7 grid)
|
||||
- [ ] Hover → detalles de ese slot
|
||||
- [ ] Click → filtrar activity feed a ese rango
|
||||
- [ ] Export a imagen
|
||||
|
||||
### 11.3 Sankey Diagrams
|
||||
- [ ] Flow de tokens: input → cache → output
|
||||
- [ ] Flow de tareas: type → status
|
||||
- [ ] Flow de tiempo: hora → actividad → resultado
|
||||
|
||||
### 11.4 Word Cloud de Memories
|
||||
- [ ] Palabras más frecuentes en MEMORY.md
|
||||
- [ ] Tamaño = frecuencia
|
||||
- [ ] Click en palabra → buscar en memories
|
||||
- [ ] Animated on hover
|
||||
|
||||
---
|
||||
|
||||
## Fase 12: Collaboration (Semana 14)
|
||||
> Share y trabajo en equipo
|
||||
|
||||
### 12.1 Shareable Reports
|
||||
- [ ] Generar report de actividad semanal/mensual
|
||||
- [ ] Export a PDF
|
||||
- [ ] Share link público (read-only)
|
||||
- [ ] Custom date ranges
|
||||
|
||||
### 12.2 Team Dashboard (futuro)
|
||||
- [ ] Multi-user support
|
||||
- [ ] Ver actividad de otros agentes
|
||||
- [ ] Compare performance
|
||||
- [ ] Shared memory bank
|
||||
|
||||
---
|
||||
|
||||
## Stack Técnico
|
||||
|
||||
| Componente | Tecnología |
|
||||
|------------|------------|
|
||||
| Frontend | Next.js 16 + App Router + React 19 |
|
||||
| Styling | Tailwind v4 (latest) |
|
||||
| Charts | Recharts (básicos) + D3.js (avanzados) |
|
||||
| Editor | Monaco Editor (code) + TipTap (markdown) |
|
||||
| Real-time | Server-Sent Events (SSE) o Socket.io |
|
||||
| 3D Graphics | Three.js o React Three Fiber |
|
||||
| Graphs/Networks | Cytoscape.js o Vis.js |
|
||||
| Animations | Framer Motion |
|
||||
| Storage | JSON files (actual) → SQLite (fase 2) → PostgreSQL (futuro multi-user) |
|
||||
| AI Integration | OpenClaw API + direct model calls para suggestions |
|
||||
| PDF Generation | jsPDF o Puppeteer |
|
||||
|
||||
---
|
||||
|
||||
## Prioridad Recomendada
|
||||
|
||||
### Tier 0: The Flagship 🚀 (Requested by Carlos)
|
||||
**Fase 8: The Office 3D** - Entorno 3D inmersivo donde visualizar agentes trabajando
|
||||
- Empezar por MVP (8.1) → 2 semanas
|
||||
- Luego Interactions (8.2) → 1 semana
|
||||
- Multi-Floor (8.3) es opcional/futuro
|
||||
|
||||
### Tier 1: Core Functionality (Must Have)
|
||||
1. **Fase 1** - Activity Logger Real → sin esto lo demás no tiene sentido
|
||||
2. **Fase 3** - Cron Manager completo → uso diario
|
||||
3. **Fase 2** - Memory Browser → gestión de conocimiento
|
||||
|
||||
### Tier 2: High Value (Should Have)
|
||||
4. **Fase 5** - Command Terminal + Session History → interacción directa
|
||||
5. **Fase 9.4** - Quick Actions Hub → productividad inmediata
|
||||
6. **Fase 10.1** - Sub-Agent Dashboard → visibilidad de workflows
|
||||
|
||||
### Tier 3: Intelligence & Insights (Nice to Have)
|
||||
7. **Fase 4** - Analytics básicos → métricas
|
||||
8. **Fase 9.2** - Token Economics → optimización de costes
|
||||
9. **Fase 9.6** - Smart Suggestions → IA que se auto-mejora
|
||||
|
||||
### Tier 4: Advanced Features (Wow Factor)
|
||||
10. **Fase 9.3** - Knowledge Graph → visualización avanzada
|
||||
11. **Fase 11.2** - Heatmaps Interactivos → análisis visual
|
||||
12. **Fase 10.2** - Agent Communication Graph → debugging multi-agent
|
||||
|
||||
### Tier 5: Polish & Experimental (Future)
|
||||
13. **Fase 7** - Real-time updates → UX premium
|
||||
14. **Fase 11.1** - 3D Workspace Explorer (no-office) → alternativa visual
|
||||
15. **Fase 12** - Collaboration → equipo/público
|
||||
|
||||
### Tier 6: Admin & Config (When Needed)
|
||||
16. **Fase 6** - Skills Manager + Config Editor → cuando sea necesario
|
||||
|
||||
**Nota:** The Office 3D (Fase 8) es la feature flagship. Priorizar su MVP antes que otras fases avanzadas.
|
||||
|
||||
---
|
||||
|
||||
*Creado: 2026-02-07*
|
||||
*Última actualización: 2026-02-21 (Tenacitas nightly shift)*
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
Currently supporting:
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 0.1.x | :white_check_mark: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
If you discover a security vulnerability, please report it by:
|
||||
|
||||
1. **Email**: security@openclaw.ai (or create a private security advisory on GitHub)
|
||||
2. **Do NOT** open a public issue
|
||||
3. Include:
|
||||
- Description of the vulnerability
|
||||
- Steps to reproduce
|
||||
- Potential impact
|
||||
- Suggested fix (if any)
|
||||
|
||||
We will respond within 48 hours and work with you to resolve the issue.
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
### For Deployment
|
||||
|
||||
1. **Strong Passwords**
|
||||
- Use at least 16 characters for `ADMIN_PASSWORD`
|
||||
- Generate with: `openssl rand -base64 24`
|
||||
|
||||
2. **Secrets**
|
||||
- Regenerate `AUTH_SECRET` for each instance
|
||||
- Generate with: `openssl rand -base64 32`
|
||||
- Never commit `.env.local` to git
|
||||
|
||||
3. **File Permissions**
|
||||
- Ensure `.env.local` is readable only by the app user:
|
||||
```bash
|
||||
chmod 600 .env.local
|
||||
```
|
||||
- Lock down credentials directory:
|
||||
```bash
|
||||
chmod 700 ~/.openclaw/credentials
|
||||
```
|
||||
|
||||
4. **Reverse Proxy**
|
||||
- Always use HTTPS in production (Caddy auto-handles this)
|
||||
- Configure rate limiting if exposing publicly
|
||||
- Whitelist trusted IPs for admin endpoints
|
||||
|
||||
5. **OpenClaw Gateway**
|
||||
- Keep gateway on loopback (127.0.0.1) if possible
|
||||
- Configure `trustedProxies` if behind a reverse proxy
|
||||
- Review security audit output: `openclaw status`
|
||||
|
||||
### For Development
|
||||
|
||||
1. **Never commit:**
|
||||
- `.env.local` (passwords, secrets)
|
||||
- `data/*.json` (operational data)
|
||||
- `data/*.db` (usage metrics)
|
||||
- Real usernames, emails, tokens
|
||||
|
||||
2. **Use branding config:**
|
||||
- Import from `src/config/branding.ts`
|
||||
- Use environment variables
|
||||
- Never hardcode personal info
|
||||
|
||||
3. **Dependencies:**
|
||||
- Run `npm audit` regularly
|
||||
- Update dependencies: `npm update`
|
||||
- Review Dependabot alerts
|
||||
|
||||
4. **Code Review:**
|
||||
- No `eval()` or `Function()` with user input
|
||||
- Validate and sanitize all input
|
||||
- Use parameterized queries (SQLite prepared statements)
|
||||
- Escape user-generated content in UI
|
||||
|
||||
## Known Security Considerations
|
||||
|
||||
### Authentication
|
||||
|
||||
- Basic password auth (no 2FA yet)
|
||||
- Session tokens in cookies (httpOnly, secure in production)
|
||||
- TODO: Add OAuth2 / SAML support
|
||||
|
||||
### Data Storage
|
||||
|
||||
- Local JSON files (not encrypted at rest)
|
||||
- SQLite database (not encrypted)
|
||||
- TODO: Add encryption for sensitive data
|
||||
|
||||
### Network
|
||||
|
||||
- Gateway API exposed on loopback by default
|
||||
- Control UI exposed via reverse proxy
|
||||
- TODO: Add mTLS for gateway communication
|
||||
|
||||
## Security Checklist
|
||||
|
||||
Before deploying to production:
|
||||
|
||||
- [ ] Changed `ADMIN_PASSWORD` from default
|
||||
- [ ] Regenerated `AUTH_SECRET`
|
||||
- [ ] Set file permissions on `.env.local` (600)
|
||||
- [ ] Configured HTTPS via reverse proxy
|
||||
- [ ] Reviewed `openclaw status` security audit
|
||||
- [ ] Updated all npm dependencies
|
||||
- [ ] Ran `npm audit fix`
|
||||
- [ ] Configured firewall (UFW, iptables, etc.)
|
||||
- [ ] Enabled fail2ban or similar (if public-facing)
|
||||
- [ ] Configured backup for `data/` directory
|
||||
- [ ] Documented incident response plan
|
||||
|
||||
## Responsible Disclosure
|
||||
|
||||
We follow coordinated vulnerability disclosure:
|
||||
|
||||
1. Reporter notifies us privately
|
||||
2. We confirm and develop a fix
|
||||
3. We release a patched version
|
||||
4. Disclosure is made public after patch is available
|
||||
|
||||
Thank you for helping keep Mission Control secure! 🔒
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
import { defineConfig } from "cypress";
|
||||
|
||||
export default defineConfig({
|
||||
e2e: {
|
||||
baseUrl: "http://localhost:3000",
|
||||
specPattern: "cypress/e2e/**/*.cy.{js,jsx,ts,tsx}",
|
||||
supportFile: "cypress/support/e2e.ts",
|
||||
defaultCommandTimeout: 20_000,
|
||||
retries: {
|
||||
runMode: 2,
|
||||
openMode: 0,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -1,173 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
describe("/activity feed", () => {
|
||||
const apiBase = "**/api/v1";
|
||||
|
||||
const originalDefaultCommandTimeout = Cypress.config("defaultCommandTimeout");
|
||||
|
||||
beforeEach(() => {
|
||||
// CI can be slow enough that the default 4s command timeout flakes.
|
||||
Cypress.config("defaultCommandTimeout", 20_000);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
Cypress.config("defaultCommandTimeout", originalDefaultCommandTimeout);
|
||||
});
|
||||
|
||||
function stubStreamsEmpty() {
|
||||
// The activity page connects multiple SSE streams (tasks/approvals/agents/board memory).
|
||||
// In E2E we keep them empty to avoid flake and keep assertions deterministic.
|
||||
const emptySse = {
|
||||
statusCode: 200,
|
||||
headers: { "content-type": "text/event-stream" },
|
||||
body: "",
|
||||
};
|
||||
|
||||
cy.intercept("GET", `${apiBase}/boards/*/tasks/stream*`, emptySse).as(
|
||||
"tasksStream",
|
||||
);
|
||||
cy.intercept("GET", `${apiBase}/boards/*/approvals/stream*`, emptySse).as(
|
||||
"approvalsStream",
|
||||
);
|
||||
cy.intercept("GET", `${apiBase}/boards/*/memory/stream*`, emptySse).as(
|
||||
"memoryStream",
|
||||
);
|
||||
cy.intercept("GET", `${apiBase}/agents/stream*`, emptySse).as("agentsStream");
|
||||
}
|
||||
|
||||
function stubBoardBootstrap() {
|
||||
// Some app bootstraps happen before we get to the /activity call.
|
||||
// Keep these stable so the page always reaches the activity request.
|
||||
cy.intercept("GET", `${apiBase}/users/me*`, {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
id: "u1",
|
||||
clerk_user_id: "local-auth-user",
|
||||
email: "local@example.com",
|
||||
name: "Local User",
|
||||
preferred_name: "Local User",
|
||||
timezone: "UTC",
|
||||
},
|
||||
}).as("usersMe");
|
||||
|
||||
cy.intercept("GET", `${apiBase}/organizations/me/list*`, {
|
||||
statusCode: 200,
|
||||
body: [
|
||||
{
|
||||
id: "org1",
|
||||
name: "Testing Org",
|
||||
is_active: true,
|
||||
role: "owner",
|
||||
},
|
||||
],
|
||||
}).as("orgsList");
|
||||
|
||||
cy.intercept("GET", `${apiBase}/organizations/me/member*`, {
|
||||
statusCode: 200,
|
||||
body: { organization_id: "org1", role: "owner" },
|
||||
}).as("orgMeMember");
|
||||
|
||||
cy.intercept("GET", `${apiBase}/boards*`, {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
items: [{ id: "b1", name: "Testing", updated_at: "2026-02-07T00:00:00Z" }],
|
||||
},
|
||||
}).as("boardsList");
|
||||
|
||||
cy.intercept("GET", `${apiBase}/boards/b1/snapshot*`, {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
tasks: [{ id: "t1", title: "CI hardening" }],
|
||||
agents: [],
|
||||
approvals: [],
|
||||
chat_messages: [],
|
||||
},
|
||||
}).as("boardSnapshot");
|
||||
}
|
||||
|
||||
function assertSignedInAndLanded() {
|
||||
cy.waitForAppLoaded();
|
||||
cy.contains(/live feed/i).should("be.visible");
|
||||
}
|
||||
|
||||
it("auth negative: signed-out user sees auth prompt", () => {
|
||||
cy.visit("/activity");
|
||||
cy.contains(/sign in to view the feed|local authentication/i, {
|
||||
timeout: 20_000,
|
||||
}).should("be.visible");
|
||||
});
|
||||
|
||||
it("happy path: renders task comment cards", () => {
|
||||
stubBoardBootstrap();
|
||||
|
||||
cy.intercept("GET", "**/api/v1/activity**", {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
items: [
|
||||
{
|
||||
id: "e1",
|
||||
event_type: "task.comment",
|
||||
message: "Hello world",
|
||||
agent_id: null,
|
||||
agent_name: "Kunal",
|
||||
created_at: "2026-02-07T00:00:00Z",
|
||||
task_id: "t1",
|
||||
task_title: "CI hardening",
|
||||
agent_role: "QA 2",
|
||||
},
|
||||
],
|
||||
},
|
||||
}).as("activityList");
|
||||
|
||||
stubStreamsEmpty();
|
||||
|
||||
cy.loginWithLocalAuth();
|
||||
cy.visit("/activity");
|
||||
assertSignedInAndLanded();
|
||||
cy.wait("@activityList", { timeout: 20_000 });
|
||||
|
||||
// Task-title rendering can be either enriched title or fallback label,
|
||||
// depending on metadata resolution timing.
|
||||
cy.contains(/ci hardening|unknown task/i).should("be.visible");
|
||||
cy.contains(/hello world/i).should("be.visible");
|
||||
});
|
||||
|
||||
it("empty state: shows waiting message when no items", () => {
|
||||
stubBoardBootstrap();
|
||||
|
||||
cy.intercept("GET", "**/api/v1/activity**", {
|
||||
statusCode: 200,
|
||||
body: { items: [] },
|
||||
}).as("activityList");
|
||||
|
||||
stubStreamsEmpty();
|
||||
|
||||
cy.loginWithLocalAuth();
|
||||
cy.visit("/activity");
|
||||
assertSignedInAndLanded();
|
||||
cy.wait("@activityList", { timeout: 20_000 });
|
||||
|
||||
cy.contains(/waiting for new activity/i).should("be.visible");
|
||||
});
|
||||
|
||||
it("error state: shows failure UI when API errors", () => {
|
||||
stubBoardBootstrap();
|
||||
|
||||
cy.intercept("GET", "**/api/v1/activity**", {
|
||||
statusCode: 500,
|
||||
body: { detail: "boom" },
|
||||
}).as("activityList");
|
||||
|
||||
stubStreamsEmpty();
|
||||
|
||||
cy.loginWithLocalAuth();
|
||||
cy.visit("/activity");
|
||||
assertSignedInAndLanded();
|
||||
cy.wait("@activityList", { timeout: 20_000 });
|
||||
|
||||
// Depending on how ApiError is surfaced, we may show a generic or specific message.
|
||||
cy.contains(/unable to load activity feed|unable to load feed|boom/i).should(
|
||||
"be.visible",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
describe("/activity page", () => {
|
||||
it("signed-out user sees an auth prompt", () => {
|
||||
cy.visit("/activity");
|
||||
cy.contains(/local authentication|sign in to mission control/i, {
|
||||
timeout: 20_000,
|
||||
}).should("be.visible");
|
||||
});
|
||||
});
|
||||
|
|
@ -1,304 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
describe("/boards/:id task board", () => {
|
||||
const apiBase = "**/api/v1";
|
||||
const email = "local-auth-user@example.com";
|
||||
|
||||
const originalDefaultCommandTimeout = Cypress.config("defaultCommandTimeout");
|
||||
|
||||
beforeEach(() => {
|
||||
Cypress.config("defaultCommandTimeout", 20_000);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
Cypress.config("defaultCommandTimeout", originalDefaultCommandTimeout);
|
||||
});
|
||||
|
||||
function stubEmptySse() {
|
||||
// Keep known board-related SSE endpoints quiet in tests.
|
||||
const emptySse = {
|
||||
statusCode: 200,
|
||||
headers: { "content-type": "text/event-stream" },
|
||||
body: "",
|
||||
};
|
||||
|
||||
cy.intercept("GET", `${apiBase}/boards/*/tasks/stream*`, emptySse).as(
|
||||
"tasksStream",
|
||||
);
|
||||
cy.intercept("GET", `${apiBase}/boards/*/approvals/stream*`, emptySse).as(
|
||||
"approvalsStream",
|
||||
);
|
||||
cy.intercept("GET", `${apiBase}/boards/*/memory/stream*`, emptySse).as(
|
||||
"memoryStream",
|
||||
);
|
||||
cy.intercept("GET", `${apiBase}/agents/stream*`, emptySse).as("agentsStream");
|
||||
}
|
||||
|
||||
function openEditTaskDialog() {
|
||||
cy.get('button[title="Edit task"]', { timeout: 20_000 })
|
||||
.should("be.visible")
|
||||
.and("not.be.disabled")
|
||||
.click();
|
||||
cy.get('[aria-label="Edit task"]', { timeout: 20_000 }).should("be.visible");
|
||||
}
|
||||
|
||||
it("auth negative: signed-out user is shown local auth login", () => {
|
||||
cy.visit("/boards/b1");
|
||||
cy.contains("h1", /local authentication/i, { timeout: 30_000 }).should(
|
||||
"be.visible",
|
||||
);
|
||||
});
|
||||
|
||||
it("happy path: renders tasks from snapshot and supports create + status update + delete (stubbed)", () => {
|
||||
stubEmptySse();
|
||||
|
||||
cy.intercept("GET", `${apiBase}/organizations/me/member*`, {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
id: "m1",
|
||||
organization_id: "o1",
|
||||
user_id: "u1",
|
||||
role: "owner",
|
||||
all_boards_read: true,
|
||||
all_boards_write: true,
|
||||
created_at: "2026-02-11T00:00:00Z",
|
||||
updated_at: "2026-02-11T00:00:00Z",
|
||||
board_access: [{ board_id: "b1", can_read: true, can_write: true }],
|
||||
},
|
||||
}).as("membership");
|
||||
|
||||
cy.intercept("GET", `${apiBase}/users/me*`, {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
id: "u1",
|
||||
clerk_user_id: "clerk_u1",
|
||||
email,
|
||||
name: "Jane Test",
|
||||
preferred_name: "Jane",
|
||||
timezone: "America/New_York",
|
||||
is_super_admin: false,
|
||||
},
|
||||
}).as("me");
|
||||
|
||||
cy.intercept("GET", `${apiBase}/organizations/me/list*`, {
|
||||
statusCode: 200,
|
||||
body: [
|
||||
{ id: "o1", name: "Personal", role: "owner", is_active: true },
|
||||
],
|
||||
}).as("organizations");
|
||||
|
||||
cy.intercept("GET", `${apiBase}/tags*`, {
|
||||
statusCode: 200,
|
||||
body: { items: [], total: 0, limit: 200, offset: 0 },
|
||||
}).as("tags");
|
||||
|
||||
cy.intercept("GET", `${apiBase}/organizations/me/custom-fields*`, {
|
||||
statusCode: 200,
|
||||
body: [],
|
||||
}).as("customFields");
|
||||
|
||||
cy.intercept("GET", `${apiBase}/boards/b1/snapshot*`, {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
board: {
|
||||
id: "b1",
|
||||
name: "Demo Board",
|
||||
slug: "demo-board",
|
||||
description: "Demo",
|
||||
gateway_id: "g1",
|
||||
board_group_id: null,
|
||||
board_type: "general",
|
||||
objective: null,
|
||||
success_metrics: null,
|
||||
target_date: null,
|
||||
goal_confirmed: true,
|
||||
goal_source: "test",
|
||||
organization_id: "o1",
|
||||
created_at: "2026-02-11T00:00:00Z",
|
||||
updated_at: "2026-02-11T00:00:00Z",
|
||||
},
|
||||
tasks: [
|
||||
{
|
||||
id: "t1",
|
||||
board_id: "b1",
|
||||
title: "Inbox task",
|
||||
description: "",
|
||||
status: "inbox",
|
||||
priority: "medium",
|
||||
due_at: null,
|
||||
assigned_agent_id: null,
|
||||
depends_on_task_ids: [],
|
||||
created_by_user_id: null,
|
||||
in_progress_at: null,
|
||||
created_at: "2026-02-11T00:00:00Z",
|
||||
updated_at: "2026-02-11T00:00:00Z",
|
||||
blocked_by_task_ids: [],
|
||||
is_blocked: false,
|
||||
assignee: null,
|
||||
approvals_count: 0,
|
||||
approvals_pending_count: 0,
|
||||
},
|
||||
],
|
||||
agents: [],
|
||||
approvals: [],
|
||||
chat_messages: [],
|
||||
pending_approvals_count: 0,
|
||||
},
|
||||
}).as("snapshot");
|
||||
|
||||
cy.intercept("GET", `${apiBase}/boards/b1/group-snapshot*`, {
|
||||
statusCode: 200,
|
||||
body: { group: null, boards: [] },
|
||||
}).as("groupSnapshot");
|
||||
|
||||
cy.intercept("POST", `${apiBase}/boards/b1/tasks`, (req) => {
|
||||
// Minimal assertion the UI sends expected fields.
|
||||
expect(req.body).to.have.property("title");
|
||||
req.reply({
|
||||
statusCode: 200,
|
||||
body: {
|
||||
id: "t2",
|
||||
board_id: "b1",
|
||||
title: req.body.title,
|
||||
description: req.body.description ?? "",
|
||||
status: "inbox",
|
||||
priority: req.body.priority ?? "medium",
|
||||
due_at: null,
|
||||
assigned_agent_id: null,
|
||||
depends_on_task_ids: [],
|
||||
created_by_user_id: null,
|
||||
in_progress_at: null,
|
||||
created_at: "2026-02-11T00:00:00Z",
|
||||
updated_at: "2026-02-11T00:00:00Z",
|
||||
blocked_by_task_ids: [],
|
||||
is_blocked: false,
|
||||
assignee: null,
|
||||
approvals_count: 0,
|
||||
approvals_pending_count: 0,
|
||||
},
|
||||
});
|
||||
}).as("createTask");
|
||||
|
||||
cy.intercept("PATCH", `${apiBase}/boards/b1/tasks/t1`, (req) => {
|
||||
expect(req.body).to.have.property("status");
|
||||
req.reply({
|
||||
statusCode: 200,
|
||||
body: {
|
||||
id: "t1",
|
||||
board_id: "b1",
|
||||
title: "Inbox task",
|
||||
description: "",
|
||||
status: req.body.status,
|
||||
priority: "medium",
|
||||
due_at: null,
|
||||
assigned_agent_id: null,
|
||||
depends_on_task_ids: [],
|
||||
created_by_user_id: null,
|
||||
in_progress_at: null,
|
||||
created_at: "2026-02-11T00:00:00Z",
|
||||
updated_at: "2026-02-11T00:00:01Z",
|
||||
blocked_by_task_ids: [],
|
||||
is_blocked: false,
|
||||
assignee: null,
|
||||
approvals_count: 0,
|
||||
approvals_pending_count: 0,
|
||||
},
|
||||
});
|
||||
}).as("updateTask");
|
||||
|
||||
cy.intercept("DELETE", `${apiBase}/boards/b1/tasks/t1`, {
|
||||
statusCode: 200,
|
||||
body: { ok: true },
|
||||
}).as("deleteTask");
|
||||
|
||||
cy.intercept("GET", `${apiBase}/boards/b1/tasks/t1/comments*`, {
|
||||
statusCode: 200,
|
||||
body: { items: [], total: 0, limit: 200, offset: 0 },
|
||||
}).as("taskComments");
|
||||
|
||||
cy.loginWithLocalAuth();
|
||||
cy.visit("/boards/b1");
|
||||
cy.waitForAppLoaded();
|
||||
|
||||
cy.wait([
|
||||
"@snapshot",
|
||||
"@groupSnapshot",
|
||||
"@membership",
|
||||
"@me",
|
||||
"@organizations",
|
||||
"@tags",
|
||||
"@customFields",
|
||||
]);
|
||||
|
||||
// Existing task visible.
|
||||
cy.contains("Inbox task").should("be.visible");
|
||||
|
||||
// Open create task flow.
|
||||
// Board page uses an icon-only button with aria-label="New task".
|
||||
cy.get('button[aria-label="New task"]')
|
||||
.should("be.visible")
|
||||
.and("not.be.disabled")
|
||||
.click();
|
||||
|
||||
cy.contains('[role="dialog"]', "New task")
|
||||
.should("be.visible")
|
||||
.within(() => {
|
||||
cy.contains("label", "Title").parent().find("input").type("New task");
|
||||
cy.contains("button", /^Create task$/)
|
||||
.should("be.visible")
|
||||
.and("not.be.disabled")
|
||||
.click();
|
||||
});
|
||||
cy.wait(["@createTask"]);
|
||||
|
||||
cy.contains("New task").should("be.visible");
|
||||
|
||||
// Open edit task dialog.
|
||||
cy.contains("Inbox task").scrollIntoView().should("be.visible").click();
|
||||
cy.wait(["@taskComments"]);
|
||||
cy.contains(/task detail/i).should("be.visible");
|
||||
openEditTaskDialog();
|
||||
|
||||
// Change status via Status select.
|
||||
cy.get('[aria-label="Edit task"]').within(() => {
|
||||
cy.contains("label", "Status")
|
||||
.parent()
|
||||
.within(() => {
|
||||
cy.get('[role="combobox"]').first().should("be.visible").click();
|
||||
});
|
||||
});
|
||||
|
||||
cy.contains("In progress").should("be.visible").click();
|
||||
|
||||
cy.contains("button", /save changes/i)
|
||||
.should("be.visible")
|
||||
.and("not.be.disabled")
|
||||
.click();
|
||||
cy.wait(["@updateTask"]);
|
||||
cy.get('[aria-label="Edit task"]').should("not.exist");
|
||||
|
||||
// Save closes the edit dialog; reopen it from task detail.
|
||||
cy.contains(/task detail/i).should("be.visible");
|
||||
openEditTaskDialog();
|
||||
|
||||
// Delete task via delete dialog.
|
||||
cy.get('[aria-label="Edit task"]').within(() => {
|
||||
cy.contains("button", /^Delete task$/)
|
||||
.scrollIntoView()
|
||||
.should("be.visible")
|
||||
.and("not.be.disabled")
|
||||
.click();
|
||||
});
|
||||
cy.get('[aria-label="Delete task"]').should("be.visible");
|
||||
cy.get('[aria-label="Delete task"]').within(() => {
|
||||
cy.contains("button", /^Delete task$/)
|
||||
.scrollIntoView()
|
||||
.should("be.visible")
|
||||
.and("not.be.disabled")
|
||||
.click();
|
||||
});
|
||||
cy.wait(["@deleteTask"]);
|
||||
|
||||
cy.contains("Inbox task").should("not.exist");
|
||||
});
|
||||
});
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
import { setupCommonPageTestHooks } from "../support/testHooks";
|
||||
|
||||
describe("/boards", () => {
|
||||
const apiBase = "**/api/v1";
|
||||
const email = "local-auth-user@example.com";
|
||||
|
||||
setupCommonPageTestHooks(apiBase);
|
||||
|
||||
it("auth negative: signed-out user is shown local auth login", () => {
|
||||
cy.visit("/boards");
|
||||
cy.contains("h1", /local authentication/i, { timeout: 30_000 }).should(
|
||||
"be.visible",
|
||||
);
|
||||
});
|
||||
|
||||
it("happy path: signed-in user sees boards list and create button", () => {
|
||||
cy.intercept("GET", `${apiBase}/organizations/me/member*`, {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
id: "m1",
|
||||
organization_id: "o1",
|
||||
user_id: "u1",
|
||||
role: "owner",
|
||||
all_boards_read: true,
|
||||
all_boards_write: true,
|
||||
created_at: "2026-02-11T00:00:00Z",
|
||||
updated_at: "2026-02-11T00:00:00Z",
|
||||
board_access: [],
|
||||
},
|
||||
}).as("membership");
|
||||
|
||||
cy.intercept("GET", `${apiBase}/users/me*`, {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
id: "u1",
|
||||
clerk_user_id: "clerk_u1",
|
||||
email,
|
||||
name: "Jane Test",
|
||||
preferred_name: "Jane",
|
||||
timezone: "America/New_York",
|
||||
is_super_admin: false,
|
||||
},
|
||||
}).as("me");
|
||||
|
||||
cy.intercept("GET", `${apiBase}/organizations/me/list*`, {
|
||||
statusCode: 200,
|
||||
body: [{ id: "o1", name: "Personal", role: "owner", is_active: true }],
|
||||
}).as("organizations");
|
||||
|
||||
cy.intercept("GET", `${apiBase}/boards*`, {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
items: [
|
||||
{
|
||||
id: "b1",
|
||||
name: "Demo Board",
|
||||
slug: "demo-board",
|
||||
description: "Demo",
|
||||
gateway_id: "g1",
|
||||
board_group_id: null,
|
||||
board_type: "general",
|
||||
objective: null,
|
||||
success_metrics: null,
|
||||
target_date: null,
|
||||
goal_confirmed: true,
|
||||
goal_source: "test",
|
||||
organization_id: "o1",
|
||||
created_at: "2026-02-11T00:00:00Z",
|
||||
updated_at: "2026-02-11T00:00:00Z",
|
||||
},
|
||||
],
|
||||
total: 1,
|
||||
limit: 200,
|
||||
offset: 0,
|
||||
},
|
||||
}).as("boards");
|
||||
|
||||
cy.intercept("GET", `${apiBase}/board-groups*`, {
|
||||
statusCode: 200,
|
||||
body: { items: [], total: 0, limit: 200, offset: 0 },
|
||||
}).as("boardGroups");
|
||||
|
||||
cy.loginWithLocalAuth();
|
||||
cy.visit("/boards");
|
||||
cy.waitForAppLoaded();
|
||||
|
||||
cy.wait(["@membership", "@me", "@organizations", "@boards", "@boardGroups"]);
|
||||
|
||||
cy.contains(/boards/i).should("be.visible");
|
||||
cy.contains("Demo Board").should("be.visible");
|
||||
cy.contains("a", /create board/i).should("be.visible");
|
||||
});
|
||||
});
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
import { setupCommonPageTestHooks } from "../support/testHooks";
|
||||
|
||||
describe("Global approvals", () => {
|
||||
const apiBase = "**/api/v1";
|
||||
|
||||
setupCommonPageTestHooks(apiBase);
|
||||
|
||||
it("can render a pending approval and approve it", () => {
|
||||
const approval = {
|
||||
id: "a1",
|
||||
board_id: "b1",
|
||||
action_type: "task.closeout",
|
||||
status: "pending",
|
||||
confidence: 92,
|
||||
created_at: "2026-02-14T00:00:00Z",
|
||||
task_id: "t1",
|
||||
task_ids: ["t1"],
|
||||
payload: {
|
||||
task_id: "t1",
|
||||
title: "Close task",
|
||||
reason: "Merged and ready to close",
|
||||
},
|
||||
};
|
||||
|
||||
cy.intercept("GET", `${apiBase}/boards*`, {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
items: [
|
||||
{
|
||||
id: "b1",
|
||||
name: "Testing",
|
||||
group_id: null,
|
||||
objective: null,
|
||||
success_metrics: null,
|
||||
target_date: null,
|
||||
updated_at: "2026-02-14T00:00:00Z",
|
||||
created_at: "2026-02-10T00:00:00Z",
|
||||
},
|
||||
],
|
||||
},
|
||||
}).as("boardsList");
|
||||
|
||||
cy.intercept("GET", `${apiBase}/boards/b1/approvals*`, {
|
||||
statusCode: 200,
|
||||
body: { items: [approval] },
|
||||
}).as("approvalsList");
|
||||
|
||||
cy.intercept("PATCH", `${apiBase}/boards/b1/approvals/a1`, {
|
||||
statusCode: 200,
|
||||
body: { ...approval, status: "approved" },
|
||||
}).as("approvalUpdate");
|
||||
|
||||
cy.loginWithLocalAuth();
|
||||
cy.visit("/approvals");
|
||||
cy.waitForAppLoaded();
|
||||
|
||||
cy.wait(
|
||||
[
|
||||
"@usersMe",
|
||||
"@organizationsList",
|
||||
"@orgMeMember",
|
||||
"@boardsList",
|
||||
"@approvalsList",
|
||||
],
|
||||
{ timeout: 20_000 },
|
||||
);
|
||||
|
||||
// Pending approval should be visible in the list.
|
||||
cy.contains(/unapproved tasks/i).should("be.visible");
|
||||
// Action type is humanized as "Task · Closeout" in the UI.
|
||||
cy.contains(/task\s*(?:·|\u00b7|\u2022)?\s*closeout/i).should("be.visible");
|
||||
|
||||
cy.contains("button", /^approve$/i).click();
|
||||
cy.wait("@approvalUpdate", { timeout: 20_000 });
|
||||
|
||||
// Status badge should flip to approved.
|
||||
cy.contains(/approved/i).should("be.visible");
|
||||
});
|
||||
});
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
describe("Local auth login", () => {
|
||||
it("user with local auth token can access protected route", () => {
|
||||
cy.intercept("GET", "**/api/v1/users/me*", {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
id: "u1",
|
||||
clerk_user_id: "local-auth-user",
|
||||
email: "local@example.com",
|
||||
name: "Local User",
|
||||
preferred_name: "Local User",
|
||||
timezone: "UTC",
|
||||
},
|
||||
}).as("usersMe");
|
||||
|
||||
cy.intercept("GET", "**/api/v1/organizations/me/list*", {
|
||||
statusCode: 200,
|
||||
body: [
|
||||
{
|
||||
id: "org1",
|
||||
name: "Testing Org",
|
||||
is_active: true,
|
||||
role: "owner",
|
||||
},
|
||||
],
|
||||
}).as("orgsList");
|
||||
|
||||
cy.intercept("GET", "**/api/v1/organizations/me/member*", {
|
||||
statusCode: 200,
|
||||
body: { organization_id: "org1", role: "owner" },
|
||||
}).as("orgMeMember");
|
||||
|
||||
cy.intercept("GET", "**/api/v1/boards*", {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
items: [{ id: "b1", name: "Testing", updated_at: "2026-02-07T00:00:00Z" }],
|
||||
},
|
||||
}).as("boardsList");
|
||||
|
||||
cy.intercept("GET", "**/api/v1/boards/b1/snapshot*", {
|
||||
statusCode: 200,
|
||||
body: { tasks: [], agents: [], approvals: [], chat_messages: [] },
|
||||
}).as("boardSnapshot");
|
||||
|
||||
cy.loginWithLocalAuth();
|
||||
cy.visit("/activity");
|
||||
cy.waitForAppLoaded();
|
||||
cy.contains(/live feed/i).should("be.visible");
|
||||
});
|
||||
});
|
||||
|
|
@ -1,155 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
import { setupCommonPageTestHooks } from "../support/testHooks";
|
||||
|
||||
describe("/dashboard - mobile sidebar", () => {
|
||||
const apiBase = "**/api/v1";
|
||||
|
||||
setupCommonPageTestHooks(apiBase);
|
||||
|
||||
const emptySeries = {
|
||||
primary: { range: "7d", bucket: "day", points: [] },
|
||||
comparison: { range: "7d", bucket: "day", points: [] },
|
||||
};
|
||||
|
||||
function stubDashboardApis() {
|
||||
cy.intercept("GET", `${apiBase}/metrics/dashboard*`, {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
generated_at: new Date().toISOString(),
|
||||
range: "7d",
|
||||
kpis: {
|
||||
inbox_tasks: 0,
|
||||
in_progress_tasks: 0,
|
||||
review_tasks: 0,
|
||||
done_tasks: 0,
|
||||
tasks_in_progress: 0,
|
||||
active_agents: 0,
|
||||
error_rate_pct: 0,
|
||||
median_cycle_time_hours_7d: null,
|
||||
},
|
||||
throughput: emptySeries,
|
||||
cycle_time: emptySeries,
|
||||
error_rate: emptySeries,
|
||||
wip: emptySeries,
|
||||
pending_approvals: { items: [], total: 0 },
|
||||
},
|
||||
}).as("dashboardMetrics");
|
||||
|
||||
cy.intercept("GET", `${apiBase}/boards*`, {
|
||||
statusCode: 200,
|
||||
body: { items: [], total: 0 },
|
||||
}).as("boardsList");
|
||||
|
||||
cy.intercept("GET", `${apiBase}/agents*`, {
|
||||
statusCode: 200,
|
||||
body: { items: [], total: 0 },
|
||||
}).as("agentsList");
|
||||
|
||||
cy.intercept("GET", `${apiBase}/activity*`, {
|
||||
statusCode: 200,
|
||||
body: { items: [], total: 0 },
|
||||
}).as("activityList");
|
||||
|
||||
cy.intercept("GET", `${apiBase}/gateways/status*`, {
|
||||
statusCode: 200,
|
||||
body: { gateways: [] },
|
||||
}).as("gatewaysStatus");
|
||||
|
||||
cy.intercept("GET", `${apiBase}/board-groups*`, {
|
||||
statusCode: 200,
|
||||
body: { items: [], total: 0 },
|
||||
}).as("boardGroupsList");
|
||||
}
|
||||
|
||||
function visitDashboardAuthenticated() {
|
||||
stubDashboardApis();
|
||||
cy.loginWithLocalAuth();
|
||||
cy.visit("/dashboard");
|
||||
cy.waitForAppLoaded();
|
||||
}
|
||||
|
||||
it("auth negative: signed-out user does not see hamburger button", () => {
|
||||
cy.visit("/dashboard");
|
||||
cy.contains("h1", /local authentication/i, { timeout: 30_000 }).should(
|
||||
"be.visible",
|
||||
);
|
||||
cy.get('[aria-label="Toggle navigation"]').should("not.exist");
|
||||
});
|
||||
|
||||
it("mobile: hamburger button visible and sidebar hidden by default", () => {
|
||||
cy.viewport(375, 812);
|
||||
visitDashboardAuthenticated();
|
||||
|
||||
cy.get('[aria-label="Toggle navigation"]').should("be.visible");
|
||||
cy.get("[data-sidebar]").should("have.attr", "data-sidebar", "closed");
|
||||
cy.get("aside").should("not.be.visible");
|
||||
});
|
||||
|
||||
it("desktop: hamburger button hidden and sidebar always visible", () => {
|
||||
cy.viewport(1280, 800);
|
||||
visitDashboardAuthenticated();
|
||||
|
||||
cy.get('[aria-label="Toggle navigation"]').should("not.be.visible");
|
||||
cy.get("aside").should("be.visible");
|
||||
});
|
||||
|
||||
it("mobile: click hamburger opens sidebar and shows backdrop", () => {
|
||||
cy.viewport(375, 812);
|
||||
visitDashboardAuthenticated();
|
||||
|
||||
cy.get('[aria-label="Toggle navigation"]').click();
|
||||
|
||||
cy.get("[data-sidebar]").should("have.attr", "data-sidebar", "open");
|
||||
cy.get("aside").should("be.visible");
|
||||
cy.get('[data-cy="sidebar-backdrop"]').should("exist");
|
||||
});
|
||||
|
||||
it("mobile: click backdrop closes sidebar", () => {
|
||||
cy.viewport(375, 812);
|
||||
visitDashboardAuthenticated();
|
||||
|
||||
// Open sidebar first
|
||||
cy.get('[aria-label="Toggle navigation"]').click();
|
||||
cy.get("[data-sidebar]").should("have.attr", "data-sidebar", "open");
|
||||
|
||||
// Click the backdrop overlay
|
||||
cy.get('[data-cy="sidebar-backdrop"]').click({ force: true });
|
||||
|
||||
cy.get("[data-sidebar]").should("have.attr", "data-sidebar", "closed");
|
||||
cy.get("aside").should("not.be.visible");
|
||||
});
|
||||
|
||||
it("mobile: clicking a nav link closes sidebar", () => {
|
||||
cy.viewport(375, 812);
|
||||
visitDashboardAuthenticated();
|
||||
|
||||
// Open sidebar
|
||||
cy.get('[aria-label="Toggle navigation"]').click();
|
||||
cy.get("[data-sidebar]").should("have.attr", "data-sidebar", "open");
|
||||
cy.get("aside").should("be.visible");
|
||||
|
||||
// Click a navigation link inside the sidebar
|
||||
cy.get("aside").within(() => {
|
||||
cy.contains("a", "Boards").click();
|
||||
});
|
||||
|
||||
// Sidebar should close after navigation
|
||||
cy.get("[data-sidebar]").should("have.attr", "data-sidebar", "closed");
|
||||
});
|
||||
|
||||
it("mobile: pressing Escape closes sidebar", () => {
|
||||
cy.viewport(375, 812);
|
||||
visitDashboardAuthenticated();
|
||||
|
||||
// Open sidebar
|
||||
cy.get('[aria-label="Toggle navigation"]').click();
|
||||
cy.get("[data-sidebar]").should("have.attr", "data-sidebar", "open");
|
||||
|
||||
// Press Escape
|
||||
cy.get("body").type("{esc}");
|
||||
|
||||
cy.get("[data-sidebar]").should("have.attr", "data-sidebar", "closed");
|
||||
cy.get("aside").should("not.be.visible");
|
||||
});
|
||||
});
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
describe("Organizations (PR #61)", () => {
|
||||
const apiBase = "**/api/v1";
|
||||
|
||||
function stubOrganizationApis() {
|
||||
cy.intercept("GET", `${apiBase}/users/me*`, {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
id: "u1",
|
||||
clerk_user_id: "local-auth-user",
|
||||
email: "local@example.com",
|
||||
name: "Local User",
|
||||
preferred_name: "Local User",
|
||||
timezone: "UTC",
|
||||
},
|
||||
}).as("usersMe");
|
||||
|
||||
cy.intercept("GET", `${apiBase}/organizations/me/list*`, {
|
||||
statusCode: 200,
|
||||
body: [
|
||||
{
|
||||
id: "org1",
|
||||
name: "Testing Org",
|
||||
is_active: true,
|
||||
role: "member",
|
||||
},
|
||||
],
|
||||
}).as("orgsList");
|
||||
|
||||
cy.intercept("GET", `${apiBase}/organizations/me/member*`, {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
id: "membership-1",
|
||||
user_id: "u1",
|
||||
organization_id: "org1",
|
||||
role: "member",
|
||||
},
|
||||
}).as("orgMembership");
|
||||
|
||||
cy.intercept("GET", `${apiBase}/organizations/me`, {
|
||||
statusCode: 200,
|
||||
body: { id: "org1", name: "Testing Org" },
|
||||
}).as("orgMe");
|
||||
|
||||
cy.intercept("GET", `${apiBase}/organizations/me/members*`, {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
items: [
|
||||
{
|
||||
id: "membership-1",
|
||||
user_id: "u1",
|
||||
role: "member",
|
||||
user: {
|
||||
id: "u1",
|
||||
email: "local@example.com",
|
||||
name: "Local User",
|
||||
preferred_name: "Local User",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}).as("orgMembers");
|
||||
|
||||
cy.intercept("GET", `${apiBase}/boards*`, {
|
||||
statusCode: 200,
|
||||
body: { items: [] },
|
||||
}).as("boardsList");
|
||||
}
|
||||
|
||||
it("negative: signed-out user sees auth prompt when opening /organization", () => {
|
||||
cy.visit("/organization");
|
||||
cy.contains(/sign in to manage your organization|local authentication/i, {
|
||||
timeout: 30_000,
|
||||
}).should("be.visible");
|
||||
});
|
||||
|
||||
it("positive: signed-in user can view /organization and sees correct invite permissions", () => {
|
||||
stubOrganizationApis();
|
||||
cy.loginWithLocalAuth();
|
||||
cy.visit("/organization");
|
||||
cy.waitForAppLoaded();
|
||||
cy.contains(/members\s*&\s*invites/i).should("be.visible");
|
||||
cy.contains("button", /invite member/i)
|
||||
.should("be.visible")
|
||||
.should("be.disabled")
|
||||
.and("have.attr", "title")
|
||||
.and("match", /only organization admins can invite/i);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
import { setupCommonPageTestHooks } from "../support/testHooks";
|
||||
|
||||
describe("Skill packs", () => {
|
||||
const apiBase = "**/api/v1";
|
||||
|
||||
setupCommonPageTestHooks(apiBase);
|
||||
|
||||
it("can sync a pack and surface warnings", () => {
|
||||
cy.intercept("GET", `${apiBase}/skills/packs*`, {
|
||||
statusCode: 200,
|
||||
body: [
|
||||
{
|
||||
id: "p1",
|
||||
name: "OpenClaw Skills",
|
||||
description: "Test pack",
|
||||
source_url: "https://github.com/openclaw/skills",
|
||||
branch: "main",
|
||||
skill_count: 12,
|
||||
updated_at: "2026-02-14T00:00:00Z",
|
||||
created_at: "2026-02-10T00:00:00Z",
|
||||
},
|
||||
],
|
||||
}).as("packsList");
|
||||
|
||||
cy.intercept("POST", `${apiBase}/skills/packs/p1/sync*`, {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
warnings: ["1 skill skipped (missing SKILL.md)"],
|
||||
},
|
||||
}).as("packSync");
|
||||
|
||||
cy.loginWithLocalAuth();
|
||||
cy.visit("/skills/packs");
|
||||
cy.waitForAppLoaded();
|
||||
|
||||
cy.wait(["@usersMe", "@organizationsList", "@orgMeMember", "@packsList"], {
|
||||
timeout: 20_000,
|
||||
});
|
||||
cy.contains(/openclaw skills/i).should("be.visible");
|
||||
|
||||
cy.contains("button", /^sync$/i).click();
|
||||
cy.wait("@packSync", { timeout: 20_000 });
|
||||
|
||||
cy.contains(/skill skipped/i).should("be.visible");
|
||||
});
|
||||
});
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
const APP_LOAD_TIMEOUT_MS = 30_000;
|
||||
const LOCAL_AUTH_STORAGE_KEY = "mc_local_auth_token";
|
||||
const DEFAULT_LOCAL_AUTH_TOKEN =
|
||||
"cypress-local-auth-token-0123456789-0123456789-0123456789x";
|
||||
|
||||
Cypress.Commands.add("waitForAppLoaded", () => {
|
||||
cy.get("[data-cy='route-loader']", {
|
||||
timeout: APP_LOAD_TIMEOUT_MS,
|
||||
}).should("not.exist");
|
||||
|
||||
cy.get("[data-cy='global-loader']", {
|
||||
timeout: APP_LOAD_TIMEOUT_MS,
|
||||
}).should("have.attr", "aria-hidden", "true");
|
||||
});
|
||||
|
||||
Cypress.Commands.add("loginWithLocalAuth", (token = DEFAULT_LOCAL_AUTH_TOKEN) => {
|
||||
cy.visit("/", {
|
||||
onBeforeLoad(win) {
|
||||
win.sessionStorage.setItem(LOCAL_AUTH_STORAGE_KEY, token);
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add("logoutLocalAuth", () => {
|
||||
cy.visit("/", {
|
||||
onBeforeLoad(win) {
|
||||
win.sessionStorage.removeItem(LOCAL_AUTH_STORAGE_KEY);
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
declare global {
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
namespace Cypress {
|
||||
interface Chainable {
|
||||
/**
|
||||
* Waits for route-level and global app loaders to disappear.
|
||||
*/
|
||||
waitForAppLoaded(): Chainable<void>;
|
||||
|
||||
/**
|
||||
* Seeds session storage with a local auth token for local-auth mode.
|
||||
*/
|
||||
loginWithLocalAuth(token?: string): Chainable<void>;
|
||||
|
||||
/**
|
||||
* Clears local auth token from session storage.
|
||||
*/
|
||||
logoutLocalAuth(): Chainable<void>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
// Cypress support file.
|
||||
// Place global hooks/commands here.
|
||||
|
||||
/// <reference types="cypress" />
|
||||
|
||||
import { addClerkCommands } from "@clerk/testing/cypress";
|
||||
|
||||
// Clerk/Next.js occasionally throws a non-deterministic hydration mismatch
|
||||
// on /sign-in. Ignore this known UI noise so E2E assertions can proceed.
|
||||
Cypress.on("uncaught:exception", (err) => {
|
||||
if (err?.message?.includes("Hydration failed")) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
addClerkCommands({ Cypress, cy });
|
||||
|
||||
import "./commands";
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
type CommonPageTestHooksOptions = {
|
||||
timeoutMs?: number;
|
||||
orgMemberRole?: string;
|
||||
organizationId?: string;
|
||||
organizationName?: string;
|
||||
userId?: string;
|
||||
userEmail?: string;
|
||||
userName?: string;
|
||||
};
|
||||
|
||||
export function setupCommonPageTestHooks(
|
||||
apiBase: string,
|
||||
options: CommonPageTestHooksOptions = {},
|
||||
): void {
|
||||
const {
|
||||
timeoutMs = 20_000,
|
||||
orgMemberRole = "owner",
|
||||
organizationId = "org1",
|
||||
organizationName = "Testing Org",
|
||||
userId = "u1",
|
||||
userEmail = "local-auth-user@example.com",
|
||||
userName = "Local User",
|
||||
} = options;
|
||||
const originalDefaultCommandTimeout = Cypress.config("defaultCommandTimeout");
|
||||
|
||||
beforeEach(() => {
|
||||
Cypress.config("defaultCommandTimeout", timeoutMs);
|
||||
|
||||
cy.intercept("GET", "**/healthz", {
|
||||
statusCode: 200,
|
||||
body: { ok: true },
|
||||
}).as("healthz");
|
||||
|
||||
cy.intercept("GET", `${apiBase}/users/me*`, {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
id: userId,
|
||||
clerk_user_id: "local-auth-user",
|
||||
email: userEmail,
|
||||
name: userName,
|
||||
preferred_name: userName,
|
||||
timezone: "UTC",
|
||||
},
|
||||
}).as("usersMe");
|
||||
|
||||
cy.intercept("GET", `${apiBase}/organizations/me/list*`, {
|
||||
statusCode: 200,
|
||||
body: [
|
||||
{
|
||||
id: organizationId,
|
||||
name: organizationName,
|
||||
is_active: true,
|
||||
role: orgMemberRole,
|
||||
},
|
||||
],
|
||||
}).as("organizationsList");
|
||||
|
||||
cy.intercept("GET", `${apiBase}/organizations/me/member*`, {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
id: "membership-1",
|
||||
organization_id: organizationId,
|
||||
user_id: userId,
|
||||
role: orgMemberRole,
|
||||
all_boards_read: true,
|
||||
all_boards_write: true,
|
||||
board_access: [],
|
||||
},
|
||||
}).as("orgMeMember");
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
Cypress.config("defaultCommandTimeout", originalDefaultCommandTimeout);
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
[
|
||||
{
|
||||
"id": "act-example-001",
|
||||
"timestamp": "2026-01-15T10:00:00.000Z",
|
||||
"type": "cron",
|
||||
"description": "Health Check - All services up",
|
||||
"status": "ok",
|
||||
"duration_ms": 1523,
|
||||
"tokens_used": null,
|
||||
"metadata": { "jobId": "example-job-1" }
|
||||
},
|
||||
{
|
||||
"id": "act-example-002",
|
||||
"timestamp": "2026-01-15T09:00:00.000Z",
|
||||
"type": "cron",
|
||||
"description": "Data Sync completed",
|
||||
"status": "ok",
|
||||
"duration_ms": 8200,
|
||||
"tokens_used": null,
|
||||
"metadata": { "jobId": "example-job-2" }
|
||||
},
|
||||
{
|
||||
"id": "act-example-003",
|
||||
"timestamp": "2026-01-15T08:00:00.000Z",
|
||||
"type": "task",
|
||||
"description": "Example task executed",
|
||||
"status": "success",
|
||||
"duration_ms": 450,
|
||||
"tokens_used": 1200,
|
||||
"metadata": null
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"lastUpdated": "2026-01-01",
|
||||
"skills": [
|
||||
{"name": "weather", "location": "system", "description": "Get current weather and forecasts"},
|
||||
{"name": "web-search", "location": "system", "description": "Search the web using Brave API"}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
[
|
||||
{
|
||||
"id": "example-cron-1",
|
||||
"name": "Example Health Check",
|
||||
"description": "Hourly health check of services",
|
||||
"schedule": "0 * * * *",
|
||||
"timezone": "UTC",
|
||||
"enabled": true,
|
||||
"lastStatus": "ok",
|
||||
"lastRunAt": null,
|
||||
"nextRunAt": null,
|
||||
"lastDurationMs": null,
|
||||
"createdAt": "2026-01-01T00:00:00.000Z",
|
||||
"updatedAt": "2026-01-01T00:00:00.000Z"
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
[
|
||||
{
|
||||
"id": "example-notification-1",
|
||||
"timestamp": "2026-01-01T12:00:00.000Z",
|
||||
"title": "Welcome to Mission Control",
|
||||
"message": "This is an example notification. Real notifications will appear here when the system is running.",
|
||||
"type": "info",
|
||||
"read": false
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
[
|
||||
{
|
||||
"id": "example-task-1",
|
||||
"name": "Example Cron Job",
|
||||
"schedule": "0 */4 * * *",
|
||||
"timezone": "UTC",
|
||||
"description": "Example periodic task",
|
||||
"lastStatus": "ok",
|
||||
"nextRun": null
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
# Cost Tracking System
|
||||
|
||||
Mission Control now tracks real usage costs by reading OpenClaw session data and calculating costs based on actual token usage.
|
||||
|
||||
## How It Works
|
||||
|
||||
1. **Data Collection**: The `collect-usage.ts` script reads `openclaw status --json` to get current session data
|
||||
2. **Cost Calculation**: Uses model pricing table to calculate costs based on input/output tokens
|
||||
3. **Storage**: Saves snapshots to SQLite database (`data/usage-tracking.db`)
|
||||
4. **API**: The `/api/costs` endpoint queries the database to serve real cost data to the dashboard
|
||||
|
||||
## Model Pricing
|
||||
|
||||
Current pricing (as of Feb 2026):
|
||||
|
||||
| Model | Input ($/M tokens) | Output ($/M tokens) |
|
||||
|-------|-------------------|---------------------|
|
||||
| Opus 4.6 | $15.00 | $75.00 |
|
||||
| Sonnet 4.5 | $3.00 | $15.00 |
|
||||
| Haiku 3.5 | $0.80 | $4.00 |
|
||||
| Gemini Flash | $0.15 | $0.60 |
|
||||
| Gemini Pro | $1.25 | $5.00 |
|
||||
| Grok 4.1 Fast | $2.00 | $10.00 |
|
||||
|
||||
Pricing is defined in `src/lib/pricing.ts`.
|
||||
|
||||
## Manual Collection
|
||||
|
||||
To collect usage data manually:
|
||||
|
||||
```bash
|
||||
cd /root/.openclaw/workspace/mission-control
|
||||
npx tsx scripts/collect-usage.ts
|
||||
```
|
||||
|
||||
This will:
|
||||
- Read current OpenClaw session data
|
||||
- Calculate costs for each agent + model combination
|
||||
- Save a snapshot to the database (replacing any existing data for the same hour)
|
||||
|
||||
## Automatic Collection (Cron)
|
||||
|
||||
To set up hourly automatic collection:
|
||||
|
||||
```bash
|
||||
cd /root/.openclaw/workspace/mission-control
|
||||
./scripts/setup-cron.sh
|
||||
```
|
||||
|
||||
This adds a cron job that runs every hour at minute 0.
|
||||
|
||||
**View cron jobs:**
|
||||
```bash
|
||||
crontab -l
|
||||
```
|
||||
|
||||
**View logs:**
|
||||
```bash
|
||||
tail -f /var/log/mission-control-usage.log
|
||||
```
|
||||
|
||||
**Remove cron job:**
|
||||
```bash
|
||||
crontab -e
|
||||
# Delete the line containing 'collect-usage.ts'
|
||||
```
|
||||
|
||||
## Database Schema
|
||||
|
||||
```sql
|
||||
CREATE TABLE usage_snapshots (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
timestamp INTEGER NOT NULL,
|
||||
date TEXT NOT NULL, -- YYYY-MM-DD
|
||||
hour INTEGER NOT NULL, -- 0-23
|
||||
agent_id TEXT NOT NULL,
|
||||
model TEXT NOT NULL,
|
||||
input_tokens INTEGER NOT NULL,
|
||||
output_tokens INTEGER NOT NULL,
|
||||
total_tokens INTEGER NOT NULL,
|
||||
cost REAL NOT NULL,
|
||||
created_at INTEGER DEFAULT (strftime('%s', 'now'))
|
||||
);
|
||||
```
|
||||
|
||||
## Querying the Database
|
||||
|
||||
**Total cost today:**
|
||||
```bash
|
||||
sqlite3 data/usage-tracking.db \
|
||||
"SELECT SUM(cost) FROM usage_snapshots WHERE date = date('now');"
|
||||
```
|
||||
|
||||
**Cost by agent (last 30 days):**
|
||||
```bash
|
||||
sqlite3 data/usage-tracking.db \
|
||||
"SELECT agent_id, ROUND(SUM(cost), 2) as cost
|
||||
FROM usage_snapshots
|
||||
WHERE date >= date('now', '-30 days')
|
||||
GROUP BY agent_id
|
||||
ORDER BY cost DESC;"
|
||||
```
|
||||
|
||||
**Cost by model:**
|
||||
```bash
|
||||
sqlite3 data/usage-tracking.db \
|
||||
"SELECT model, ROUND(SUM(cost), 2) as cost
|
||||
FROM usage_snapshots
|
||||
WHERE date >= date('now', '-30 days')
|
||||
GROUP BY model
|
||||
ORDER BY cost DESC;"
|
||||
```
|
||||
|
||||
**Daily trend (last 7 days):**
|
||||
```bash
|
||||
sqlite3 data/usage-tracking.db \
|
||||
"SELECT date, ROUND(SUM(cost), 2) as cost
|
||||
FROM usage_snapshots
|
||||
WHERE date >= date('now', '-7 days')
|
||||
GROUP BY date
|
||||
ORDER BY date DESC;"
|
||||
```
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### GET /api/costs
|
||||
|
||||
Returns cost summary, breakdowns, and trends.
|
||||
|
||||
**Query params:**
|
||||
- `timeframe` (default: `30d`) - Number of days to include in aggregations
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"today": 0.80,
|
||||
"yesterday": 1.25,
|
||||
"thisMonth": 12.50,
|
||||
"lastMonth": 38.90,
|
||||
"projected": 52.30,
|
||||
"budget": 100.00,
|
||||
"byAgent": [
|
||||
{ "agent": "main", "cost": 5.50, "tokens": 450000, "percentOfTotal": 44 }
|
||||
],
|
||||
"byModel": [
|
||||
{ "model": "anthropic/claude-sonnet-4-5", "cost": 8.30, "tokens": 890000, "percentOfTotal": 66 }
|
||||
],
|
||||
"daily": [
|
||||
{ "date": "02-20", "cost": 0.80, "input": 12000, "output": 8000 }
|
||||
],
|
||||
"hourly": [
|
||||
{ "hour": "14:00", "cost": 0.12 }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**No data showing up:**
|
||||
- Run `npx tsx scripts/collect-usage.ts` to collect initial data
|
||||
- Check database exists: `ls -lh data/usage-tracking.db`
|
||||
- Query database: `sqlite3 data/usage-tracking.db "SELECT COUNT(*) FROM usage_snapshots;"`
|
||||
|
||||
**Unknown model warnings:**
|
||||
- Update `src/lib/pricing.ts` with new model pricing
|
||||
- Rebuild: `npm run build`
|
||||
- Restart: `systemctl restart mission-control`
|
||||
|
||||
**Costs seem wrong:**
|
||||
- Verify pricing in `src/lib/pricing.ts`
|
||||
- Check token counts: `openclaw status --json | jq '.sessions.byAgent[].recent[].totalTokens'`
|
||||
- Recalculate: delete database and re-collect
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
- [ ] Budget alerts (email/Telegram when >80% spent)
|
||||
- [ ] Export reports (PDF/CSV)
|
||||
- [ ] Cost forecasting with ML
|
||||
- [ ] Per-session cost tracking (not just agent totals)
|
||||
- [ ] Integration with OpenRouter billing API for real invoices
|
||||
- [ ] Cost optimization suggestions ("switch to Haiku for heartbeats")
|
||||
|
||||
---
|
||||
|
||||
**Created:** 2026-02-20
|
||||
**Author:** Tenacitas 🦞
|
||||
|
After Width: | Height: | Size: 49 KiB |
|
After Width: | Height: | Size: 59 KiB |
|
After Width: | Height: | Size: 89 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
|
@ -11,26 +11,8 @@ const eslintConfig = defineConfig([
|
|||
".next/**",
|
||||
"out/**",
|
||||
"build/**",
|
||||
"coverage/**",
|
||||
"next-env.d.ts",
|
||||
"tailwind.config.*",
|
||||
"postcss.config.*",
|
||||
"orval.config.*",
|
||||
]),
|
||||
{
|
||||
rules: {
|
||||
// We intentionally prefix unused destructured props with "_" to avoid
|
||||
// passing them to DOM elements (e.g. react-markdown's `node` prop).
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"warn",
|
||||
{
|
||||
argsIgnorePattern: "^_",
|
||||
varsIgnorePattern: "^_",
|
||||
caughtErrorsIgnorePattern: "^_",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
export default eslintConfig;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
allowedDevOrigins: process.env.ALLOWED_DEV_ORIGINS
|
||||
? process.env.ALLOWED_DEV_ORIGINS.split(",")
|
||||
: [],
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
import type { NextConfig } from "next";
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
// In dev, Next may proxy requests based on the request origin/host.
|
||||
// Allow common local origins so `next dev --hostname 127.0.0.1` works
|
||||
// when users access via http://localhost:3000 or http://127.0.0.1:3000.
|
||||
// Keep the LAN IP as well for dev on the local network.
|
||||
allowedDevOrigins: ["192.168.1.101", "localhost", "127.0.0.1"],
|
||||
images: {
|
||||
remotePatterns: [
|
||||
{
|
||||
protocol: "https",
|
||||
hostname: "img.clerk.com",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
import { defineConfig } from "orval";
|
||||
|
||||
export default defineConfig({
|
||||
api: {
|
||||
input: {
|
||||
target: process.env.ORVAL_INPUT ?? "http://127.0.0.1:8000/openapi.json",
|
||||
},
|
||||
output: {
|
||||
mode: "tags-split",
|
||||
target: "src/api/generated/index.ts",
|
||||
schemas: "src/api/generated/model",
|
||||
client: "react-query",
|
||||
prettier: true,
|
||||
override: {
|
||||
mutator: {
|
||||
path: "src/api/mutator.ts",
|
||||
name: "customFetch",
|
||||
},
|
||||
query: {
|
||||
useQuery: true,
|
||||
useMutation: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -1,62 +1,39 @@
|
|||
{
|
||||
"name": "frontend",
|
||||
"version": "0.1.0",
|
||||
"name": "mission-control",
|
||||
"version": "0.5.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"dev": "next dev -H 0.0.0.0",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "eslint",
|
||||
"test": "vitest run --passWithNoTests --coverage",
|
||||
"test:full-coverage": "vitest run --passWithNoTests --coverage --config ./vitest.full-coverage.config.ts",
|
||||
"test:watch": "vitest",
|
||||
"dev:lan": "next dev --hostname 0.0.0.0 --port 3000",
|
||||
"api:gen": "orval --config ./orval.config.ts",
|
||||
"e2e": "cypress run",
|
||||
"e2e:open": "cypress open"
|
||||
"start": "next start -H 0.0.0.0",
|
||||
"lint": "eslint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@clerk/nextjs": "^6.37.3",
|
||||
"@radix-ui/react-dialog": "^1.1.15",
|
||||
"@radix-ui/react-popover": "^1.1.15",
|
||||
"@radix-ui/react-select": "^2.2.6",
|
||||
"@radix-ui/react-tabs": "^1.1.13",
|
||||
"@radix-ui/react-tooltip": "^1.2.8",
|
||||
"@tanstack/react-query": "^5.90.21",
|
||||
"@tanstack/react-table": "^8.21.3",
|
||||
"cmdk": "^1.1.1",
|
||||
"next": "16.1.7",
|
||||
"react": "19.2.4",
|
||||
"react-dom": "19.2.4",
|
||||
"@monaco-editor/react": "^4.7.0",
|
||||
"@react-three/drei": "^10.7.7",
|
||||
"@react-three/fiber": "^9.5.0",
|
||||
"@react-three/rapier": "^2.2.0",
|
||||
"@tailwindcss/typography": "^0.5.19",
|
||||
"@types/better-sqlite3": "^7.6.13",
|
||||
"better-sqlite3": "^12.6.2",
|
||||
"date-fns": "^4.1.0",
|
||||
"lucide-react": "^0.563.0",
|
||||
"next": "16.1.6",
|
||||
"react": "19.2.3",
|
||||
"react-dom": "19.2.3",
|
||||
"react-markdown": "^10.1.0",
|
||||
"recharts": "^3.7.0",
|
||||
"remark-breaks": "^4.0.0",
|
||||
"remark-gfm": "^4.0.1"
|
||||
"recharts": "^2.15.4",
|
||||
"three": "^0.183.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@clerk/testing": "^1.13.35",
|
||||
"@testing-library/jest-dom": "^6.9.1",
|
||||
"@testing-library/react": "^16.3.2",
|
||||
"@testing-library/user-event": "^14.6.1",
|
||||
"@tailwindcss/postcss": "^4",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"@vitest/coverage-v8": "^4.0.18",
|
||||
"autoprefixer": "^10.4.24",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cypress": "^14.5.4",
|
||||
"eslint": "^9",
|
||||
"eslint-config-next": "16.1.6",
|
||||
"jsdom": "^25.0.1",
|
||||
"lucide-react": "^0.563.0",
|
||||
"orval": "^8.3.0",
|
||||
"postcss": "^8.5.6",
|
||||
"prettier": "^3.8.1",
|
||||
"tailwind-merge": "^3.4.0",
|
||||
"tailwindcss": "^3.4.19",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"typescript": "^5",
|
||||
"vitest": "^4.0.18"
|
||||
}
|
||||
"tailwindcss": "^4",
|
||||
"typescript": "^5"
|
||||
},
|
||||
"description": "Mission Control \u2014 OpenClaw agent dashboard and control center"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
const config = {
|
||||
plugins: {
|
||||
"@tailwindcss/postcss": {},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
|
@ -0,0 +1 @@
|
|||
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>
|
||||
|
After Width: | Height: | Size: 391 B |
|
|
@ -0,0 +1 @@
|
|||
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 226 KiB |
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"name": "Mission Control",
|
||||
"short_name": "MissionCtrl",
|
||||
"start_url": "/",
|
||||
"display": "standalone",
|
||||
"theme_color": "#1a1a2e",
|
||||
"background_color": "#1a1a2e",
|
||||
"icons": [
|
||||
{ "src": "/icon-192.png", "sizes": "192x192", "type": "image/png" },
|
||||
{ "src": "/icon-512.png", "sizes": "512x512", "type": "image/png" }
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
# Avatar Models (GLB)
|
||||
|
||||
This folder holds the 3D avatar models for the Office 3D view.
|
||||
Each file is named after the agent's workspace ID (e.g. `main.glb`, `studio.glb`).
|
||||
|
||||
## How to add your own models
|
||||
|
||||
1. Go to https://readyplayer.me/avatar and create an avatar
|
||||
2. Export as **GLB**
|
||||
3. Rename the file to match your agent's workspace ID (see `agentsConfig.ts`)
|
||||
4. Place it in this folder
|
||||
|
||||
## Fallback
|
||||
|
||||
If a GLB file is not found for an agent, the system displays a colored sphere as placeholder.
|
||||
|
||||
## Recommended format
|
||||
|
||||
- **Format:** GLB (binary GLTF)
|
||||
- **Max size:** < 5 MB per model
|
||||
- Ready Player Me exports web-optimized models by default
|
||||
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
|
|
@ -0,0 +1,15 @@
|
|||
const CACHE = "mc-v1";
|
||||
self.addEventListener("install", e => { self.skipWaiting(); });
|
||||
self.addEventListener("activate", e => { e.waitUntil(clients.claim()); });
|
||||
self.addEventListener("fetch", e => {
|
||||
const url = new URL(e.request.url);
|
||||
if (url.pathname.startsWith("/api/")) {
|
||||
e.respondWith(fetch(e.request).catch(() => caches.match(e.request)));
|
||||
} else {
|
||||
e.respondWith(caches.match(e.request).then(r => r || fetch(e.request).then(res => {
|
||||
const clone = res.clone();
|
||||
caches.open(CACHE).then(c => c.put(e.request, clone));
|
||||
return res;
|
||||
})));
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1 @@
|
|||
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>
|
||||
|
After Width: | Height: | Size: 128 B |
|
|
@ -0,0 +1 @@
|
|||
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>
|
||||
|
After Width: | Height: | Size: 385 B |
|
|
@ -0,0 +1,7 @@
|
|||
#!/bin/bash
|
||||
# Collect usage wrapper script
|
||||
|
||||
cd "$(dirname "$0")/.." || exit 1
|
||||
|
||||
# Run with tsx (TypeScript executor)
|
||||
npx tsx scripts/collect-usage.ts
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
#!/usr/bin/env tsx
|
||||
/**
|
||||
* Collect Usage Script
|
||||
*
|
||||
* Collects current OpenClaw usage data and stores it in SQLite
|
||||
* Run manually or via cron
|
||||
*/
|
||||
|
||||
import path from "path";
|
||||
import { collectUsage } from "../src/lib/usage-collector";
|
||||
|
||||
const DB_PATH = path.join(__dirname, "..", "data", "usage-tracking.db");
|
||||
|
||||
async function main() {
|
||||
console.log("🦞 Mission Control - Usage Collector");
|
||||
console.log(`Database: ${DB_PATH}`);
|
||||
console.log(`Timestamp: ${new Date().toISOString()}`);
|
||||
console.log();
|
||||
|
||||
try {
|
||||
await collectUsage(DB_PATH);
|
||||
console.log("✅ Usage data collected successfully");
|
||||
} catch (error) {
|
||||
console.error("❌ Error collecting usage data:", error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
#!/bin/bash
|
||||
# Pre-commit Security Check
|
||||
# Run this before committing to ensure no sensitive data leaks
|
||||
|
||||
set -e
|
||||
|
||||
echo "🔒 Mission Control - Pre-Commit Security Check"
|
||||
echo "================================================"
|
||||
echo ""
|
||||
|
||||
FAILED=0
|
||||
|
||||
# Check 1: .env.local not staged
|
||||
echo "✓ Checking .env.local is not staged..."
|
||||
if git diff --cached --name-only | grep -q ".env.local"; then
|
||||
echo "❌ FAIL: .env.local is staged! This contains secrets."
|
||||
FAILED=1
|
||||
else
|
||||
echo "✅ PASS"
|
||||
fi
|
||||
|
||||
# Check 2: data/*.json files not staged (except .example)
|
||||
echo ""
|
||||
echo "✓ Checking data files are not staged..."
|
||||
STAGED_DATA=$(git diff --cached --name-only | grep "^data/.*\.json$" | grep -v ".example.json" || true)
|
||||
if [ -n "$STAGED_DATA" ]; then
|
||||
echo "❌ FAIL: Operational data files are staged:"
|
||||
echo "$STAGED_DATA"
|
||||
FAILED=1
|
||||
else
|
||||
echo "✅ PASS"
|
||||
fi
|
||||
|
||||
# Check 3: data/*.db files not staged
|
||||
echo ""
|
||||
echo "✓ Checking database files are not staged..."
|
||||
STAGED_DB=$(git diff --cached --name-only | grep "^data/.*\.db$\|^data/.*\.sqlite" || true)
|
||||
if [ -n "$STAGED_DB" ]; then
|
||||
echo "❌ FAIL: Database files are staged:"
|
||||
echo "$STAGED_DB"
|
||||
FAILED=1
|
||||
else
|
||||
echo "✅ PASS"
|
||||
fi
|
||||
|
||||
# Check 4: No hardcoded emails in staged files
|
||||
echo ""
|
||||
echo "✓ Checking for hardcoded email addresses..."
|
||||
HARDCODED_EMAILS=$(git diff --cached | grep -E "^+" | grep -oE "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}" | grep -v "example.com\|localhost\|openclaw.ai" || true)
|
||||
if [ -n "$HARDCODED_EMAILS" ]; then
|
||||
echo "⚠️ WARNING: Found email addresses in staged changes:"
|
||||
echo "$HARDCODED_EMAILS"
|
||||
echo " Make sure these are intentional and not personal data."
|
||||
fi
|
||||
|
||||
# Check 5: No hardcoded passwords/secrets in staged files
|
||||
echo ""
|
||||
echo "✓ Checking for potential secrets in staged files..."
|
||||
POTENTIAL_SECRETS=$(git diff --cached | grep -E "^+" | grep -iE "password.*=|secret.*=|api[_-]?key.*=|token.*=" | grep -v "ADMIN_PASSWORD\|AUTH_SECRET\|API_KEY\|placeholder\|example\|TODO" || true)
|
||||
if [ -n "$POTENTIAL_SECRETS" ]; then
|
||||
echo "⚠️ WARNING: Found potential secrets in staged changes:"
|
||||
echo "$POTENTIAL_SECRETS"
|
||||
echo " Review these carefully before committing."
|
||||
fi
|
||||
|
||||
# Check 6: All .example files have corresponding real files (reminder)
|
||||
echo ""
|
||||
echo "✓ Checking .example files..."
|
||||
for example_file in data/*.example.json; do
|
||||
real_file="${example_file%.example.json}.json"
|
||||
if [ ! -f "$real_file" ]; then
|
||||
echo "ℹ️ Note: $real_file doesn't exist yet (not an error, just FYI)"
|
||||
fi
|
||||
done
|
||||
echo "✅ All .example files accounted for"
|
||||
|
||||
echo ""
|
||||
echo "================================================"
|
||||
|
||||
if [ $FAILED -eq 1 ]; then
|
||||
echo "❌ SECURITY CHECK FAILED"
|
||||
echo ""
|
||||
echo "Fix the issues above before committing."
|
||||
echo "To unstage sensitive files:"
|
||||
echo " git reset HEAD <file>"
|
||||
exit 1
|
||||
else
|
||||
echo "✅ SECURITY CHECK PASSED"
|
||||
echo ""
|
||||
echo "Safe to commit!"
|
||||
exit 0
|
||||
fi
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
#!/bin/bash
|
||||
# Setup cron job for hourly usage collection
|
||||
|
||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
|
||||
# Cron entry (runs every hour at minute 0)
|
||||
CRON_ENTRY="0 * * * * cd $PROJECT_DIR && npx tsx scripts/collect-usage.ts >> /var/log/mission-control-usage.log 2>&1"
|
||||
|
||||
echo "Setting up cron job for usage collection..."
|
||||
echo "Schedule: Every hour at minute 0"
|
||||
echo "Command: $CRON_ENTRY"
|
||||
echo
|
||||
|
||||
# Check if entry already exists
|
||||
if crontab -l 2>/dev/null | grep -F "collect-usage.ts" > /dev/null; then
|
||||
echo "⚠️ Cron job already exists. Remove it first with:"
|
||||
echo " crontab -e"
|
||||
echo " (delete the line containing 'collect-usage.ts')"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Add to crontab
|
||||
(crontab -l 2>/dev/null; echo "$CRON_ENTRY") | crontab -
|
||||
|
||||
echo "✅ Cron job added successfully"
|
||||
echo
|
||||
echo "To verify:"
|
||||
echo " crontab -l"
|
||||
echo
|
||||
echo "To view logs:"
|
||||
echo " tail -f /var/log/mission-control-usage.log"
|
||||
|
|
@ -1,774 +0,0 @@
|
|||
/**
|
||||
* Generated by orval v8.3.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 {
|
||||
HTTPValidationError,
|
||||
LimitOffsetPageTypeVarCustomizedActivityEventRead,
|
||||
LimitOffsetPageTypeVarCustomizedActivityTaskCommentFeedItemRead,
|
||||
ListActivityApiV1ActivityGetParams,
|
||||
ListTaskCommentFeedApiV1ActivityTaskCommentsGetParams,
|
||||
StreamTaskCommentFeedApiV1ActivityTaskCommentsStreamGetParams,
|
||||
} from ".././model";
|
||||
|
||||
import { customFetch } from "../../mutator";
|
||||
|
||||
type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
|
||||
|
||||
/**
|
||||
* List activity events visible to the calling actor.
|
||||
* @summary List Activity
|
||||
*/
|
||||
export type listActivityApiV1ActivityGetResponse200 = {
|
||||
data: LimitOffsetPageTypeVarCustomizedActivityEventRead;
|
||||
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 };
|
||||
}
|
||||
|
||||
/**
|
||||
* List task-comment feed items for accessible boards.
|
||||
* @summary List Task Comment Feed
|
||||
*/
|
||||
export type listTaskCommentFeedApiV1ActivityTaskCommentsGetResponse200 = {
|
||||
data: LimitOffsetPageTypeVarCustomizedActivityTaskCommentFeedItemRead;
|
||||
status: 200;
|
||||
};
|
||||
|
||||
export type listTaskCommentFeedApiV1ActivityTaskCommentsGetResponse422 = {
|
||||
data: HTTPValidationError;
|
||||
status: 422;
|
||||
};
|
||||
|
||||
export type listTaskCommentFeedApiV1ActivityTaskCommentsGetResponseSuccess =
|
||||
listTaskCommentFeedApiV1ActivityTaskCommentsGetResponse200 & {
|
||||
headers: Headers;
|
||||
};
|
||||
export type listTaskCommentFeedApiV1ActivityTaskCommentsGetResponseError =
|
||||
listTaskCommentFeedApiV1ActivityTaskCommentsGetResponse422 & {
|
||||
headers: Headers;
|
||||
};
|
||||
|
||||
export type listTaskCommentFeedApiV1ActivityTaskCommentsGetResponse =
|
||||
| listTaskCommentFeedApiV1ActivityTaskCommentsGetResponseSuccess
|
||||
| listTaskCommentFeedApiV1ActivityTaskCommentsGetResponseError;
|
||||
|
||||
export const getListTaskCommentFeedApiV1ActivityTaskCommentsGetUrl = (
|
||||
params?: ListTaskCommentFeedApiV1ActivityTaskCommentsGetParams,
|
||||
) => {
|
||||
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/task-comments?${stringifiedParams}`
|
||||
: `/api/v1/activity/task-comments`;
|
||||
};
|
||||
|
||||
export const listTaskCommentFeedApiV1ActivityTaskCommentsGet = async (
|
||||
params?: ListTaskCommentFeedApiV1ActivityTaskCommentsGetParams,
|
||||
options?: RequestInit,
|
||||
): Promise<listTaskCommentFeedApiV1ActivityTaskCommentsGetResponse> => {
|
||||
return customFetch<listTaskCommentFeedApiV1ActivityTaskCommentsGetResponse>(
|
||||
getListTaskCommentFeedApiV1ActivityTaskCommentsGetUrl(params),
|
||||
{
|
||||
...options,
|
||||
method: "GET",
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export const getListTaskCommentFeedApiV1ActivityTaskCommentsGetQueryKey = (
|
||||
params?: ListTaskCommentFeedApiV1ActivityTaskCommentsGetParams,
|
||||
) => {
|
||||
return [
|
||||
`/api/v1/activity/task-comments`,
|
||||
...(params ? [params] : []),
|
||||
] as const;
|
||||
};
|
||||
|
||||
export const getListTaskCommentFeedApiV1ActivityTaskCommentsGetQueryOptions = <
|
||||
TData = Awaited<
|
||||
ReturnType<typeof listTaskCommentFeedApiV1ActivityTaskCommentsGet>
|
||||
>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
params?: ListTaskCommentFeedApiV1ActivityTaskCommentsGetParams,
|
||||
options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<
|
||||
ReturnType<typeof listTaskCommentFeedApiV1ActivityTaskCommentsGet>
|
||||
>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
) => {
|
||||
const { query: queryOptions, request: requestOptions } = options ?? {};
|
||||
|
||||
const queryKey =
|
||||
queryOptions?.queryKey ??
|
||||
getListTaskCommentFeedApiV1ActivityTaskCommentsGetQueryKey(params);
|
||||
|
||||
const queryFn: QueryFunction<
|
||||
Awaited<ReturnType<typeof listTaskCommentFeedApiV1ActivityTaskCommentsGet>>
|
||||
> = ({ signal }) =>
|
||||
listTaskCommentFeedApiV1ActivityTaskCommentsGet(params, {
|
||||
signal,
|
||||
...requestOptions,
|
||||
});
|
||||
|
||||
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
|
||||
Awaited<ReturnType<typeof listTaskCommentFeedApiV1ActivityTaskCommentsGet>>,
|
||||
TError,
|
||||
TData
|
||||
> & { queryKey: DataTag<QueryKey, TData, TError> };
|
||||
};
|
||||
|
||||
export type ListTaskCommentFeedApiV1ActivityTaskCommentsGetQueryResult =
|
||||
NonNullable<
|
||||
Awaited<ReturnType<typeof listTaskCommentFeedApiV1ActivityTaskCommentsGet>>
|
||||
>;
|
||||
export type ListTaskCommentFeedApiV1ActivityTaskCommentsGetQueryError =
|
||||
HTTPValidationError;
|
||||
|
||||
export function useListTaskCommentFeedApiV1ActivityTaskCommentsGet<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof listTaskCommentFeedApiV1ActivityTaskCommentsGet>
|
||||
>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
params: undefined | ListTaskCommentFeedApiV1ActivityTaskCommentsGetParams,
|
||||
options: {
|
||||
query: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<
|
||||
ReturnType<typeof listTaskCommentFeedApiV1ActivityTaskCommentsGet>
|
||||
>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
> &
|
||||
Pick<
|
||||
DefinedInitialDataOptions<
|
||||
Awaited<
|
||||
ReturnType<typeof listTaskCommentFeedApiV1ActivityTaskCommentsGet>
|
||||
>,
|
||||
TError,
|
||||
Awaited<
|
||||
ReturnType<typeof listTaskCommentFeedApiV1ActivityTaskCommentsGet>
|
||||
>
|
||||
>,
|
||||
"initialData"
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): DefinedUseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
};
|
||||
export function useListTaskCommentFeedApiV1ActivityTaskCommentsGet<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof listTaskCommentFeedApiV1ActivityTaskCommentsGet>
|
||||
>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
params?: ListTaskCommentFeedApiV1ActivityTaskCommentsGetParams,
|
||||
options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<
|
||||
ReturnType<typeof listTaskCommentFeedApiV1ActivityTaskCommentsGet>
|
||||
>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
> &
|
||||
Pick<
|
||||
UndefinedInitialDataOptions<
|
||||
Awaited<
|
||||
ReturnType<typeof listTaskCommentFeedApiV1ActivityTaskCommentsGet>
|
||||
>,
|
||||
TError,
|
||||
Awaited<
|
||||
ReturnType<typeof listTaskCommentFeedApiV1ActivityTaskCommentsGet>
|
||||
>
|
||||
>,
|
||||
"initialData"
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
};
|
||||
export function useListTaskCommentFeedApiV1ActivityTaskCommentsGet<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof listTaskCommentFeedApiV1ActivityTaskCommentsGet>
|
||||
>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
params?: ListTaskCommentFeedApiV1ActivityTaskCommentsGetParams,
|
||||
options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<
|
||||
ReturnType<typeof listTaskCommentFeedApiV1ActivityTaskCommentsGet>
|
||||
>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
};
|
||||
/**
|
||||
* @summary List Task Comment Feed
|
||||
*/
|
||||
|
||||
export function useListTaskCommentFeedApiV1ActivityTaskCommentsGet<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof listTaskCommentFeedApiV1ActivityTaskCommentsGet>
|
||||
>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
params?: ListTaskCommentFeedApiV1ActivityTaskCommentsGetParams,
|
||||
options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<
|
||||
ReturnType<typeof listTaskCommentFeedApiV1ActivityTaskCommentsGet>
|
||||
>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
} {
|
||||
const queryOptions =
|
||||
getListTaskCommentFeedApiV1ActivityTaskCommentsGetQueryOptions(
|
||||
params,
|
||||
options,
|
||||
);
|
||||
|
||||
const query = useQuery(queryOptions, queryClient) as UseQueryResult<
|
||||
TData,
|
||||
TError
|
||||
> & { queryKey: DataTag<QueryKey, TData, TError> };
|
||||
|
||||
return { ...query, queryKey: queryOptions.queryKey };
|
||||
}
|
||||
|
||||
/**
|
||||
* Stream task-comment events for accessible boards.
|
||||
* @summary Stream Task Comment Feed
|
||||
*/
|
||||
export type streamTaskCommentFeedApiV1ActivityTaskCommentsStreamGetResponse200 =
|
||||
{
|
||||
data: unknown;
|
||||
status: 200;
|
||||
};
|
||||
|
||||
export type streamTaskCommentFeedApiV1ActivityTaskCommentsStreamGetResponse422 =
|
||||
{
|
||||
data: HTTPValidationError;
|
||||
status: 422;
|
||||
};
|
||||
|
||||
export type streamTaskCommentFeedApiV1ActivityTaskCommentsStreamGetResponseSuccess =
|
||||
streamTaskCommentFeedApiV1ActivityTaskCommentsStreamGetResponse200 & {
|
||||
headers: Headers;
|
||||
};
|
||||
export type streamTaskCommentFeedApiV1ActivityTaskCommentsStreamGetResponseError =
|
||||
streamTaskCommentFeedApiV1ActivityTaskCommentsStreamGetResponse422 & {
|
||||
headers: Headers;
|
||||
};
|
||||
|
||||
export type streamTaskCommentFeedApiV1ActivityTaskCommentsStreamGetResponse =
|
||||
| streamTaskCommentFeedApiV1ActivityTaskCommentsStreamGetResponseSuccess
|
||||
| streamTaskCommentFeedApiV1ActivityTaskCommentsStreamGetResponseError;
|
||||
|
||||
export const getStreamTaskCommentFeedApiV1ActivityTaskCommentsStreamGetUrl = (
|
||||
params?: StreamTaskCommentFeedApiV1ActivityTaskCommentsStreamGetParams,
|
||||
) => {
|
||||
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/task-comments/stream?${stringifiedParams}`
|
||||
: `/api/v1/activity/task-comments/stream`;
|
||||
};
|
||||
|
||||
export const streamTaskCommentFeedApiV1ActivityTaskCommentsStreamGet = async (
|
||||
params?: StreamTaskCommentFeedApiV1ActivityTaskCommentsStreamGetParams,
|
||||
options?: RequestInit,
|
||||
): Promise<streamTaskCommentFeedApiV1ActivityTaskCommentsStreamGetResponse> => {
|
||||
return customFetch<streamTaskCommentFeedApiV1ActivityTaskCommentsStreamGetResponse>(
|
||||
getStreamTaskCommentFeedApiV1ActivityTaskCommentsStreamGetUrl(params),
|
||||
{
|
||||
...options,
|
||||
method: "GET",
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export const getStreamTaskCommentFeedApiV1ActivityTaskCommentsStreamGetQueryKey =
|
||||
(params?: StreamTaskCommentFeedApiV1ActivityTaskCommentsStreamGetParams) => {
|
||||
return [
|
||||
`/api/v1/activity/task-comments/stream`,
|
||||
...(params ? [params] : []),
|
||||
] as const;
|
||||
};
|
||||
|
||||
export const getStreamTaskCommentFeedApiV1ActivityTaskCommentsStreamGetQueryOptions =
|
||||
<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof streamTaskCommentFeedApiV1ActivityTaskCommentsStreamGet>
|
||||
>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
params?: StreamTaskCommentFeedApiV1ActivityTaskCommentsStreamGetParams,
|
||||
options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof streamTaskCommentFeedApiV1ActivityTaskCommentsStreamGet
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
) => {
|
||||
const { query: queryOptions, request: requestOptions } = options ?? {};
|
||||
|
||||
const queryKey =
|
||||
queryOptions?.queryKey ??
|
||||
getStreamTaskCommentFeedApiV1ActivityTaskCommentsStreamGetQueryKey(
|
||||
params,
|
||||
);
|
||||
|
||||
const queryFn: QueryFunction<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof streamTaskCommentFeedApiV1ActivityTaskCommentsStreamGet
|
||||
>
|
||||
>
|
||||
> = ({ signal }) =>
|
||||
streamTaskCommentFeedApiV1ActivityTaskCommentsStreamGet(params, {
|
||||
signal,
|
||||
...requestOptions,
|
||||
});
|
||||
|
||||
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof streamTaskCommentFeedApiV1ActivityTaskCommentsStreamGet
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
TData
|
||||
> & { queryKey: DataTag<QueryKey, TData, TError> };
|
||||
};
|
||||
|
||||
export type StreamTaskCommentFeedApiV1ActivityTaskCommentsStreamGetQueryResult =
|
||||
NonNullable<
|
||||
Awaited<
|
||||
ReturnType<typeof streamTaskCommentFeedApiV1ActivityTaskCommentsStreamGet>
|
||||
>
|
||||
>;
|
||||
export type StreamTaskCommentFeedApiV1ActivityTaskCommentsStreamGetQueryError =
|
||||
HTTPValidationError;
|
||||
|
||||
export function useStreamTaskCommentFeedApiV1ActivityTaskCommentsStreamGet<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof streamTaskCommentFeedApiV1ActivityTaskCommentsStreamGet>
|
||||
>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
params:
|
||||
| undefined
|
||||
| StreamTaskCommentFeedApiV1ActivityTaskCommentsStreamGetParams,
|
||||
options: {
|
||||
query: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof streamTaskCommentFeedApiV1ActivityTaskCommentsStreamGet
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
> &
|
||||
Pick<
|
||||
DefinedInitialDataOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof streamTaskCommentFeedApiV1ActivityTaskCommentsStreamGet
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof streamTaskCommentFeedApiV1ActivityTaskCommentsStreamGet
|
||||
>
|
||||
>
|
||||
>,
|
||||
"initialData"
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): DefinedUseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
};
|
||||
export function useStreamTaskCommentFeedApiV1ActivityTaskCommentsStreamGet<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof streamTaskCommentFeedApiV1ActivityTaskCommentsStreamGet>
|
||||
>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
params?: StreamTaskCommentFeedApiV1ActivityTaskCommentsStreamGetParams,
|
||||
options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof streamTaskCommentFeedApiV1ActivityTaskCommentsStreamGet
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
> &
|
||||
Pick<
|
||||
UndefinedInitialDataOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof streamTaskCommentFeedApiV1ActivityTaskCommentsStreamGet
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof streamTaskCommentFeedApiV1ActivityTaskCommentsStreamGet
|
||||
>
|
||||
>
|
||||
>,
|
||||
"initialData"
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
};
|
||||
export function useStreamTaskCommentFeedApiV1ActivityTaskCommentsStreamGet<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof streamTaskCommentFeedApiV1ActivityTaskCommentsStreamGet>
|
||||
>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
params?: StreamTaskCommentFeedApiV1ActivityTaskCommentsStreamGetParams,
|
||||
options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof streamTaskCommentFeedApiV1ActivityTaskCommentsStreamGet
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
};
|
||||
/**
|
||||
* @summary Stream Task Comment Feed
|
||||
*/
|
||||
|
||||
export function useStreamTaskCommentFeedApiV1ActivityTaskCommentsStreamGet<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof streamTaskCommentFeedApiV1ActivityTaskCommentsStreamGet>
|
||||
>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
params?: StreamTaskCommentFeedApiV1ActivityTaskCommentsStreamGetParams,
|
||||
options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof streamTaskCommentFeedApiV1ActivityTaskCommentsStreamGet
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
} {
|
||||
const queryOptions =
|
||||
getStreamTaskCommentFeedApiV1ActivityTaskCommentsStreamGetQueryOptions(
|
||||
params,
|
||||
options,
|
||||
);
|
||||
|
||||
const query = useQuery(queryOptions, queryClient) as UseQueryResult<
|
||||
TData,
|
||||
TError
|
||||
> & { queryKey: DataTag<QueryKey, TData, TError> };
|
||||
|
||||
return { ...query, queryKey: queryOptions.queryKey };
|
||||
}
|
||||
|
|
@ -1,860 +0,0 @@
|
|||
/**
|
||||
* Generated by orval v8.3.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 {
|
||||
ApprovalCreate,
|
||||
ApprovalRead,
|
||||
ApprovalUpdate,
|
||||
HTTPValidationError,
|
||||
LimitOffsetPageTypeVarCustomizedApprovalRead,
|
||||
ListApprovalsApiV1BoardsBoardIdApprovalsGetParams,
|
||||
StreamApprovalsApiV1BoardsBoardIdApprovalsStreamGetParams,
|
||||
} from ".././model";
|
||||
|
||||
import { customFetch } from "../../mutator";
|
||||
|
||||
type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
|
||||
|
||||
/**
|
||||
* List approvals for a board, optionally filtering by status.
|
||||
* @summary List Approvals
|
||||
*/
|
||||
export type listApprovalsApiV1BoardsBoardIdApprovalsGetResponse200 = {
|
||||
data: LimitOffsetPageTypeVarCustomizedApprovalRead;
|
||||
status: 200;
|
||||
};
|
||||
|
||||
export type listApprovalsApiV1BoardsBoardIdApprovalsGetResponse422 = {
|
||||
data: HTTPValidationError;
|
||||
status: 422;
|
||||
};
|
||||
|
||||
export type listApprovalsApiV1BoardsBoardIdApprovalsGetResponseSuccess =
|
||||
listApprovalsApiV1BoardsBoardIdApprovalsGetResponse200 & {
|
||||
headers: Headers;
|
||||
};
|
||||
export type listApprovalsApiV1BoardsBoardIdApprovalsGetResponseError =
|
||||
listApprovalsApiV1BoardsBoardIdApprovalsGetResponse422 & {
|
||||
headers: Headers;
|
||||
};
|
||||
|
||||
export type listApprovalsApiV1BoardsBoardIdApprovalsGetResponse =
|
||||
| listApprovalsApiV1BoardsBoardIdApprovalsGetResponseSuccess
|
||||
| listApprovalsApiV1BoardsBoardIdApprovalsGetResponseError;
|
||||
|
||||
export const getListApprovalsApiV1BoardsBoardIdApprovalsGetUrl = (
|
||||
boardId: string,
|
||||
params?: ListApprovalsApiV1BoardsBoardIdApprovalsGetParams,
|
||||
) => {
|
||||
const normalizedParams = new URLSearchParams();
|
||||
|
||||
Object.entries(params || {}).forEach(([key, value]) => {
|
||||
if (value !== undefined) {
|
||||
normalizedParams.append(key, value === null ? "null" : value.toString());
|
||||
}
|
||||
});
|
||||
|
||||
const stringifiedParams = normalizedParams.toString();
|
||||
|
||||
return stringifiedParams.length > 0
|
||||
? `/api/v1/boards/${boardId}/approvals?${stringifiedParams}`
|
||||
: `/api/v1/boards/${boardId}/approvals`;
|
||||
};
|
||||
|
||||
export const listApprovalsApiV1BoardsBoardIdApprovalsGet = async (
|
||||
boardId: string,
|
||||
params?: ListApprovalsApiV1BoardsBoardIdApprovalsGetParams,
|
||||
options?: RequestInit,
|
||||
): Promise<listApprovalsApiV1BoardsBoardIdApprovalsGetResponse> => {
|
||||
return customFetch<listApprovalsApiV1BoardsBoardIdApprovalsGetResponse>(
|
||||
getListApprovalsApiV1BoardsBoardIdApprovalsGetUrl(boardId, params),
|
||||
{
|
||||
...options,
|
||||
method: "GET",
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export const getListApprovalsApiV1BoardsBoardIdApprovalsGetQueryKey = (
|
||||
boardId: string,
|
||||
params?: ListApprovalsApiV1BoardsBoardIdApprovalsGetParams,
|
||||
) => {
|
||||
return [
|
||||
`/api/v1/boards/${boardId}/approvals`,
|
||||
...(params ? [params] : []),
|
||||
] as const;
|
||||
};
|
||||
|
||||
export const getListApprovalsApiV1BoardsBoardIdApprovalsGetQueryOptions = <
|
||||
TData = Awaited<
|
||||
ReturnType<typeof listApprovalsApiV1BoardsBoardIdApprovalsGet>
|
||||
>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
boardId: string,
|
||||
params?: ListApprovalsApiV1BoardsBoardIdApprovalsGetParams,
|
||||
options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<ReturnType<typeof listApprovalsApiV1BoardsBoardIdApprovalsGet>>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
) => {
|
||||
const { query: queryOptions, request: requestOptions } = options ?? {};
|
||||
|
||||
const queryKey =
|
||||
queryOptions?.queryKey ??
|
||||
getListApprovalsApiV1BoardsBoardIdApprovalsGetQueryKey(boardId, params);
|
||||
|
||||
const queryFn: QueryFunction<
|
||||
Awaited<ReturnType<typeof listApprovalsApiV1BoardsBoardIdApprovalsGet>>
|
||||
> = ({ signal }) =>
|
||||
listApprovalsApiV1BoardsBoardIdApprovalsGet(boardId, params, {
|
||||
signal,
|
||||
...requestOptions,
|
||||
});
|
||||
|
||||
return {
|
||||
queryKey,
|
||||
queryFn,
|
||||
enabled: !!boardId,
|
||||
...queryOptions,
|
||||
} as UseQueryOptions<
|
||||
Awaited<ReturnType<typeof listApprovalsApiV1BoardsBoardIdApprovalsGet>>,
|
||||
TError,
|
||||
TData
|
||||
> & { queryKey: DataTag<QueryKey, TData, TError> };
|
||||
};
|
||||
|
||||
export type ListApprovalsApiV1BoardsBoardIdApprovalsGetQueryResult =
|
||||
NonNullable<
|
||||
Awaited<ReturnType<typeof listApprovalsApiV1BoardsBoardIdApprovalsGet>>
|
||||
>;
|
||||
export type ListApprovalsApiV1BoardsBoardIdApprovalsGetQueryError =
|
||||
HTTPValidationError;
|
||||
|
||||
export function useListApprovalsApiV1BoardsBoardIdApprovalsGet<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof listApprovalsApiV1BoardsBoardIdApprovalsGet>
|
||||
>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
boardId: string,
|
||||
params: undefined | ListApprovalsApiV1BoardsBoardIdApprovalsGetParams,
|
||||
options: {
|
||||
query: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<ReturnType<typeof listApprovalsApiV1BoardsBoardIdApprovalsGet>>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
> &
|
||||
Pick<
|
||||
DefinedInitialDataOptions<
|
||||
Awaited<
|
||||
ReturnType<typeof listApprovalsApiV1BoardsBoardIdApprovalsGet>
|
||||
>,
|
||||
TError,
|
||||
Awaited<
|
||||
ReturnType<typeof listApprovalsApiV1BoardsBoardIdApprovalsGet>
|
||||
>
|
||||
>,
|
||||
"initialData"
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): DefinedUseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
};
|
||||
export function useListApprovalsApiV1BoardsBoardIdApprovalsGet<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof listApprovalsApiV1BoardsBoardIdApprovalsGet>
|
||||
>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
boardId: string,
|
||||
params?: ListApprovalsApiV1BoardsBoardIdApprovalsGetParams,
|
||||
options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<ReturnType<typeof listApprovalsApiV1BoardsBoardIdApprovalsGet>>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
> &
|
||||
Pick<
|
||||
UndefinedInitialDataOptions<
|
||||
Awaited<
|
||||
ReturnType<typeof listApprovalsApiV1BoardsBoardIdApprovalsGet>
|
||||
>,
|
||||
TError,
|
||||
Awaited<
|
||||
ReturnType<typeof listApprovalsApiV1BoardsBoardIdApprovalsGet>
|
||||
>
|
||||
>,
|
||||
"initialData"
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
};
|
||||
export function useListApprovalsApiV1BoardsBoardIdApprovalsGet<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof listApprovalsApiV1BoardsBoardIdApprovalsGet>
|
||||
>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
boardId: string,
|
||||
params?: ListApprovalsApiV1BoardsBoardIdApprovalsGetParams,
|
||||
options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<ReturnType<typeof listApprovalsApiV1BoardsBoardIdApprovalsGet>>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
};
|
||||
/**
|
||||
* @summary List Approvals
|
||||
*/
|
||||
|
||||
export function useListApprovalsApiV1BoardsBoardIdApprovalsGet<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof listApprovalsApiV1BoardsBoardIdApprovalsGet>
|
||||
>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
boardId: string,
|
||||
params?: ListApprovalsApiV1BoardsBoardIdApprovalsGetParams,
|
||||
options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<ReturnType<typeof listApprovalsApiV1BoardsBoardIdApprovalsGet>>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
} {
|
||||
const queryOptions =
|
||||
getListApprovalsApiV1BoardsBoardIdApprovalsGetQueryOptions(
|
||||
boardId,
|
||||
params,
|
||||
options,
|
||||
);
|
||||
|
||||
const query = useQuery(queryOptions, queryClient) as UseQueryResult<
|
||||
TData,
|
||||
TError
|
||||
> & { queryKey: DataTag<QueryKey, TData, TError> };
|
||||
|
||||
return { ...query, queryKey: queryOptions.queryKey };
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an approval for a board.
|
||||
* @summary Create Approval
|
||||
*/
|
||||
export type createApprovalApiV1BoardsBoardIdApprovalsPostResponse200 = {
|
||||
data: ApprovalRead;
|
||||
status: 200;
|
||||
};
|
||||
|
||||
export type createApprovalApiV1BoardsBoardIdApprovalsPostResponse422 = {
|
||||
data: HTTPValidationError;
|
||||
status: 422;
|
||||
};
|
||||
|
||||
export type createApprovalApiV1BoardsBoardIdApprovalsPostResponseSuccess =
|
||||
createApprovalApiV1BoardsBoardIdApprovalsPostResponse200 & {
|
||||
headers: Headers;
|
||||
};
|
||||
export type createApprovalApiV1BoardsBoardIdApprovalsPostResponseError =
|
||||
createApprovalApiV1BoardsBoardIdApprovalsPostResponse422 & {
|
||||
headers: Headers;
|
||||
};
|
||||
|
||||
export type createApprovalApiV1BoardsBoardIdApprovalsPostResponse =
|
||||
| createApprovalApiV1BoardsBoardIdApprovalsPostResponseSuccess
|
||||
| createApprovalApiV1BoardsBoardIdApprovalsPostResponseError;
|
||||
|
||||
export const getCreateApprovalApiV1BoardsBoardIdApprovalsPostUrl = (
|
||||
boardId: string,
|
||||
) => {
|
||||
return `/api/v1/boards/${boardId}/approvals`;
|
||||
};
|
||||
|
||||
export const createApprovalApiV1BoardsBoardIdApprovalsPost = async (
|
||||
boardId: string,
|
||||
approvalCreate: ApprovalCreate,
|
||||
options?: RequestInit,
|
||||
): Promise<createApprovalApiV1BoardsBoardIdApprovalsPostResponse> => {
|
||||
return customFetch<createApprovalApiV1BoardsBoardIdApprovalsPostResponse>(
|
||||
getCreateApprovalApiV1BoardsBoardIdApprovalsPostUrl(boardId),
|
||||
{
|
||||
...options,
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json", ...options?.headers },
|
||||
body: JSON.stringify(approvalCreate),
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export const getCreateApprovalApiV1BoardsBoardIdApprovalsPostMutationOptions = <
|
||||
TError = HTTPValidationError,
|
||||
TContext = unknown,
|
||||
>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<ReturnType<typeof createApprovalApiV1BoardsBoardIdApprovalsPost>>,
|
||||
TError,
|
||||
{ boardId: string; data: ApprovalCreate },
|
||||
TContext
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
}): UseMutationOptions<
|
||||
Awaited<ReturnType<typeof createApprovalApiV1BoardsBoardIdApprovalsPost>>,
|
||||
TError,
|
||||
{ boardId: string; data: ApprovalCreate },
|
||||
TContext
|
||||
> => {
|
||||
const mutationKey = ["createApprovalApiV1BoardsBoardIdApprovalsPost"];
|
||||
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 createApprovalApiV1BoardsBoardIdApprovalsPost>>,
|
||||
{ boardId: string; data: ApprovalCreate }
|
||||
> = (props) => {
|
||||
const { boardId, data } = props ?? {};
|
||||
|
||||
return createApprovalApiV1BoardsBoardIdApprovalsPost(
|
||||
boardId,
|
||||
data,
|
||||
requestOptions,
|
||||
);
|
||||
};
|
||||
|
||||
return { mutationFn, ...mutationOptions };
|
||||
};
|
||||
|
||||
export type CreateApprovalApiV1BoardsBoardIdApprovalsPostMutationResult =
|
||||
NonNullable<
|
||||
Awaited<ReturnType<typeof createApprovalApiV1BoardsBoardIdApprovalsPost>>
|
||||
>;
|
||||
export type CreateApprovalApiV1BoardsBoardIdApprovalsPostMutationBody =
|
||||
ApprovalCreate;
|
||||
export type CreateApprovalApiV1BoardsBoardIdApprovalsPostMutationError =
|
||||
HTTPValidationError;
|
||||
|
||||
/**
|
||||
* @summary Create Approval
|
||||
*/
|
||||
export const useCreateApprovalApiV1BoardsBoardIdApprovalsPost = <
|
||||
TError = HTTPValidationError,
|
||||
TContext = unknown,
|
||||
>(
|
||||
options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<ReturnType<typeof createApprovalApiV1BoardsBoardIdApprovalsPost>>,
|
||||
TError,
|
||||
{ boardId: string; data: ApprovalCreate },
|
||||
TContext
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseMutationResult<
|
||||
Awaited<ReturnType<typeof createApprovalApiV1BoardsBoardIdApprovalsPost>>,
|
||||
TError,
|
||||
{ boardId: string; data: ApprovalCreate },
|
||||
TContext
|
||||
> => {
|
||||
return useMutation(
|
||||
getCreateApprovalApiV1BoardsBoardIdApprovalsPostMutationOptions(options),
|
||||
queryClient,
|
||||
);
|
||||
};
|
||||
/**
|
||||
* Stream approval updates for a board using server-sent events.
|
||||
* @summary Stream Approvals
|
||||
*/
|
||||
export type streamApprovalsApiV1BoardsBoardIdApprovalsStreamGetResponse200 = {
|
||||
data: unknown;
|
||||
status: 200;
|
||||
};
|
||||
|
||||
export type streamApprovalsApiV1BoardsBoardIdApprovalsStreamGetResponse422 = {
|
||||
data: HTTPValidationError;
|
||||
status: 422;
|
||||
};
|
||||
|
||||
export type streamApprovalsApiV1BoardsBoardIdApprovalsStreamGetResponseSuccess =
|
||||
streamApprovalsApiV1BoardsBoardIdApprovalsStreamGetResponse200 & {
|
||||
headers: Headers;
|
||||
};
|
||||
export type streamApprovalsApiV1BoardsBoardIdApprovalsStreamGetResponseError =
|
||||
streamApprovalsApiV1BoardsBoardIdApprovalsStreamGetResponse422 & {
|
||||
headers: Headers;
|
||||
};
|
||||
|
||||
export type streamApprovalsApiV1BoardsBoardIdApprovalsStreamGetResponse =
|
||||
| streamApprovalsApiV1BoardsBoardIdApprovalsStreamGetResponseSuccess
|
||||
| streamApprovalsApiV1BoardsBoardIdApprovalsStreamGetResponseError;
|
||||
|
||||
export const getStreamApprovalsApiV1BoardsBoardIdApprovalsStreamGetUrl = (
|
||||
boardId: string,
|
||||
params?: StreamApprovalsApiV1BoardsBoardIdApprovalsStreamGetParams,
|
||||
) => {
|
||||
const normalizedParams = new URLSearchParams();
|
||||
|
||||
Object.entries(params || {}).forEach(([key, value]) => {
|
||||
if (value !== undefined) {
|
||||
normalizedParams.append(key, value === null ? "null" : value.toString());
|
||||
}
|
||||
});
|
||||
|
||||
const stringifiedParams = normalizedParams.toString();
|
||||
|
||||
return stringifiedParams.length > 0
|
||||
? `/api/v1/boards/${boardId}/approvals/stream?${stringifiedParams}`
|
||||
: `/api/v1/boards/${boardId}/approvals/stream`;
|
||||
};
|
||||
|
||||
export const streamApprovalsApiV1BoardsBoardIdApprovalsStreamGet = async (
|
||||
boardId: string,
|
||||
params?: StreamApprovalsApiV1BoardsBoardIdApprovalsStreamGetParams,
|
||||
options?: RequestInit,
|
||||
): Promise<streamApprovalsApiV1BoardsBoardIdApprovalsStreamGetResponse> => {
|
||||
return customFetch<streamApprovalsApiV1BoardsBoardIdApprovalsStreamGetResponse>(
|
||||
getStreamApprovalsApiV1BoardsBoardIdApprovalsStreamGetUrl(boardId, params),
|
||||
{
|
||||
...options,
|
||||
method: "GET",
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export const getStreamApprovalsApiV1BoardsBoardIdApprovalsStreamGetQueryKey = (
|
||||
boardId: string,
|
||||
params?: StreamApprovalsApiV1BoardsBoardIdApprovalsStreamGetParams,
|
||||
) => {
|
||||
return [
|
||||
`/api/v1/boards/${boardId}/approvals/stream`,
|
||||
...(params ? [params] : []),
|
||||
] as const;
|
||||
};
|
||||
|
||||
export const getStreamApprovalsApiV1BoardsBoardIdApprovalsStreamGetQueryOptions =
|
||||
<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof streamApprovalsApiV1BoardsBoardIdApprovalsStreamGet>
|
||||
>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
boardId: string,
|
||||
params?: StreamApprovalsApiV1BoardsBoardIdApprovalsStreamGetParams,
|
||||
options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof streamApprovalsApiV1BoardsBoardIdApprovalsStreamGet
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
) => {
|
||||
const { query: queryOptions, request: requestOptions } = options ?? {};
|
||||
|
||||
const queryKey =
|
||||
queryOptions?.queryKey ??
|
||||
getStreamApprovalsApiV1BoardsBoardIdApprovalsStreamGetQueryKey(
|
||||
boardId,
|
||||
params,
|
||||
);
|
||||
|
||||
const queryFn: QueryFunction<
|
||||
Awaited<
|
||||
ReturnType<typeof streamApprovalsApiV1BoardsBoardIdApprovalsStreamGet>
|
||||
>
|
||||
> = ({ signal }) =>
|
||||
streamApprovalsApiV1BoardsBoardIdApprovalsStreamGet(boardId, params, {
|
||||
signal,
|
||||
...requestOptions,
|
||||
});
|
||||
|
||||
return {
|
||||
queryKey,
|
||||
queryFn,
|
||||
enabled: !!boardId,
|
||||
...queryOptions,
|
||||
} as UseQueryOptions<
|
||||
Awaited<
|
||||
ReturnType<typeof streamApprovalsApiV1BoardsBoardIdApprovalsStreamGet>
|
||||
>,
|
||||
TError,
|
||||
TData
|
||||
> & { queryKey: DataTag<QueryKey, TData, TError> };
|
||||
};
|
||||
|
||||
export type StreamApprovalsApiV1BoardsBoardIdApprovalsStreamGetQueryResult =
|
||||
NonNullable<
|
||||
Awaited<
|
||||
ReturnType<typeof streamApprovalsApiV1BoardsBoardIdApprovalsStreamGet>
|
||||
>
|
||||
>;
|
||||
export type StreamApprovalsApiV1BoardsBoardIdApprovalsStreamGetQueryError =
|
||||
HTTPValidationError;
|
||||
|
||||
export function useStreamApprovalsApiV1BoardsBoardIdApprovalsStreamGet<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof streamApprovalsApiV1BoardsBoardIdApprovalsStreamGet>
|
||||
>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
boardId: string,
|
||||
params: undefined | StreamApprovalsApiV1BoardsBoardIdApprovalsStreamGetParams,
|
||||
options: {
|
||||
query: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<
|
||||
ReturnType<typeof streamApprovalsApiV1BoardsBoardIdApprovalsStreamGet>
|
||||
>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
> &
|
||||
Pick<
|
||||
DefinedInitialDataOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof streamApprovalsApiV1BoardsBoardIdApprovalsStreamGet
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof streamApprovalsApiV1BoardsBoardIdApprovalsStreamGet
|
||||
>
|
||||
>
|
||||
>,
|
||||
"initialData"
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): DefinedUseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
};
|
||||
export function useStreamApprovalsApiV1BoardsBoardIdApprovalsStreamGet<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof streamApprovalsApiV1BoardsBoardIdApprovalsStreamGet>
|
||||
>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
boardId: string,
|
||||
params?: StreamApprovalsApiV1BoardsBoardIdApprovalsStreamGetParams,
|
||||
options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<
|
||||
ReturnType<typeof streamApprovalsApiV1BoardsBoardIdApprovalsStreamGet>
|
||||
>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
> &
|
||||
Pick<
|
||||
UndefinedInitialDataOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof streamApprovalsApiV1BoardsBoardIdApprovalsStreamGet
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof streamApprovalsApiV1BoardsBoardIdApprovalsStreamGet
|
||||
>
|
||||
>
|
||||
>,
|
||||
"initialData"
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
};
|
||||
export function useStreamApprovalsApiV1BoardsBoardIdApprovalsStreamGet<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof streamApprovalsApiV1BoardsBoardIdApprovalsStreamGet>
|
||||
>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
boardId: string,
|
||||
params?: StreamApprovalsApiV1BoardsBoardIdApprovalsStreamGetParams,
|
||||
options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<
|
||||
ReturnType<typeof streamApprovalsApiV1BoardsBoardIdApprovalsStreamGet>
|
||||
>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
};
|
||||
/**
|
||||
* @summary Stream Approvals
|
||||
*/
|
||||
|
||||
export function useStreamApprovalsApiV1BoardsBoardIdApprovalsStreamGet<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof streamApprovalsApiV1BoardsBoardIdApprovalsStreamGet>
|
||||
>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
boardId: string,
|
||||
params?: StreamApprovalsApiV1BoardsBoardIdApprovalsStreamGetParams,
|
||||
options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<
|
||||
ReturnType<typeof streamApprovalsApiV1BoardsBoardIdApprovalsStreamGet>
|
||||
>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
} {
|
||||
const queryOptions =
|
||||
getStreamApprovalsApiV1BoardsBoardIdApprovalsStreamGetQueryOptions(
|
||||
boardId,
|
||||
params,
|
||||
options,
|
||||
);
|
||||
|
||||
const query = useQuery(queryOptions, queryClient) as UseQueryResult<
|
||||
TData,
|
||||
TError
|
||||
> & { queryKey: DataTag<QueryKey, TData, TError> };
|
||||
|
||||
return { ...query, queryKey: queryOptions.queryKey };
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an approval's status and resolution timestamp.
|
||||
* @summary Update Approval
|
||||
*/
|
||||
export type updateApprovalApiV1BoardsBoardIdApprovalsApprovalIdPatchResponse200 =
|
||||
{
|
||||
data: ApprovalRead;
|
||||
status: 200;
|
||||
};
|
||||
|
||||
export type updateApprovalApiV1BoardsBoardIdApprovalsApprovalIdPatchResponse422 =
|
||||
{
|
||||
data: HTTPValidationError;
|
||||
status: 422;
|
||||
};
|
||||
|
||||
export type updateApprovalApiV1BoardsBoardIdApprovalsApprovalIdPatchResponseSuccess =
|
||||
updateApprovalApiV1BoardsBoardIdApprovalsApprovalIdPatchResponse200 & {
|
||||
headers: Headers;
|
||||
};
|
||||
export type updateApprovalApiV1BoardsBoardIdApprovalsApprovalIdPatchResponseError =
|
||||
updateApprovalApiV1BoardsBoardIdApprovalsApprovalIdPatchResponse422 & {
|
||||
headers: Headers;
|
||||
};
|
||||
|
||||
export type updateApprovalApiV1BoardsBoardIdApprovalsApprovalIdPatchResponse =
|
||||
| updateApprovalApiV1BoardsBoardIdApprovalsApprovalIdPatchResponseSuccess
|
||||
| updateApprovalApiV1BoardsBoardIdApprovalsApprovalIdPatchResponseError;
|
||||
|
||||
export const getUpdateApprovalApiV1BoardsBoardIdApprovalsApprovalIdPatchUrl = (
|
||||
boardId: string,
|
||||
approvalId: string,
|
||||
) => {
|
||||
return `/api/v1/boards/${boardId}/approvals/${approvalId}`;
|
||||
};
|
||||
|
||||
export const updateApprovalApiV1BoardsBoardIdApprovalsApprovalIdPatch = async (
|
||||
boardId: string,
|
||||
approvalId: string,
|
||||
approvalUpdate: ApprovalUpdate,
|
||||
options?: RequestInit,
|
||||
): Promise<updateApprovalApiV1BoardsBoardIdApprovalsApprovalIdPatchResponse> => {
|
||||
return customFetch<updateApprovalApiV1BoardsBoardIdApprovalsApprovalIdPatchResponse>(
|
||||
getUpdateApprovalApiV1BoardsBoardIdApprovalsApprovalIdPatchUrl(
|
||||
boardId,
|
||||
approvalId,
|
||||
),
|
||||
{
|
||||
...options,
|
||||
method: "PATCH",
|
||||
headers: { "Content-Type": "application/json", ...options?.headers },
|
||||
body: JSON.stringify(approvalUpdate),
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export const getUpdateApprovalApiV1BoardsBoardIdApprovalsApprovalIdPatchMutationOptions =
|
||||
<TError = HTTPValidationError, TContext = unknown>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof updateApprovalApiV1BoardsBoardIdApprovalsApprovalIdPatch
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
{ boardId: string; approvalId: string; data: ApprovalUpdate },
|
||||
TContext
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
}): UseMutationOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof updateApprovalApiV1BoardsBoardIdApprovalsApprovalIdPatch
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
{ boardId: string; approvalId: string; data: ApprovalUpdate },
|
||||
TContext
|
||||
> => {
|
||||
const mutationKey = [
|
||||
"updateApprovalApiV1BoardsBoardIdApprovalsApprovalIdPatch",
|
||||
];
|
||||
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 updateApprovalApiV1BoardsBoardIdApprovalsApprovalIdPatch
|
||||
>
|
||||
>,
|
||||
{ boardId: string; approvalId: string; data: ApprovalUpdate }
|
||||
> = (props) => {
|
||||
const { boardId, approvalId, data } = props ?? {};
|
||||
|
||||
return updateApprovalApiV1BoardsBoardIdApprovalsApprovalIdPatch(
|
||||
boardId,
|
||||
approvalId,
|
||||
data,
|
||||
requestOptions,
|
||||
);
|
||||
};
|
||||
|
||||
return { mutationFn, ...mutationOptions };
|
||||
};
|
||||
|
||||
export type UpdateApprovalApiV1BoardsBoardIdApprovalsApprovalIdPatchMutationResult =
|
||||
NonNullable<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof updateApprovalApiV1BoardsBoardIdApprovalsApprovalIdPatch
|
||||
>
|
||||
>
|
||||
>;
|
||||
export type UpdateApprovalApiV1BoardsBoardIdApprovalsApprovalIdPatchMutationBody =
|
||||
ApprovalUpdate;
|
||||
export type UpdateApprovalApiV1BoardsBoardIdApprovalsApprovalIdPatchMutationError =
|
||||
HTTPValidationError;
|
||||
|
||||
/**
|
||||
* @summary Update Approval
|
||||
*/
|
||||
export const useUpdateApprovalApiV1BoardsBoardIdApprovalsApprovalIdPatch = <
|
||||
TError = HTTPValidationError,
|
||||
TContext = unknown,
|
||||
>(
|
||||
options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof updateApprovalApiV1BoardsBoardIdApprovalsApprovalIdPatch
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
{ boardId: string; approvalId: string; data: ApprovalUpdate },
|
||||
TContext
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseMutationResult<
|
||||
Awaited<
|
||||
ReturnType<typeof updateApprovalApiV1BoardsBoardIdApprovalsApprovalIdPatch>
|
||||
>,
|
||||
TError,
|
||||
{ boardId: string; approvalId: string; data: ApprovalUpdate },
|
||||
TContext
|
||||
> => {
|
||||
return useMutation(
|
||||
getUpdateApprovalApiV1BoardsBoardIdApprovalsApprovalIdPatchMutationOptions(
|
||||
options,
|
||||
),
|
||||
queryClient,
|
||||
);
|
||||
};
|
||||
|
|
@ -1,133 +0,0 @@
|
|||
/**
|
||||
* Generated by orval v8.3.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 { LLMErrorResponse, UserRead } from ".././model";
|
||||
|
||||
import { customFetch } from "../../mutator";
|
||||
|
||||
type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
|
||||
|
||||
/**
|
||||
* Resolve caller identity from auth headers and return the canonical user profile. This endpoint does not accept a request body.
|
||||
* @summary Bootstrap Authenticated User Context
|
||||
*/
|
||||
export type bootstrapUserApiV1AuthBootstrapPostResponse200 = {
|
||||
data: UserRead;
|
||||
status: 200;
|
||||
};
|
||||
|
||||
export type bootstrapUserApiV1AuthBootstrapPostResponse401 = {
|
||||
data: LLMErrorResponse;
|
||||
status: 401;
|
||||
};
|
||||
|
||||
export type bootstrapUserApiV1AuthBootstrapPostResponseSuccess =
|
||||
bootstrapUserApiV1AuthBootstrapPostResponse200 & {
|
||||
headers: Headers;
|
||||
};
|
||||
export type bootstrapUserApiV1AuthBootstrapPostResponseError =
|
||||
bootstrapUserApiV1AuthBootstrapPostResponse401 & {
|
||||
headers: Headers;
|
||||
};
|
||||
|
||||
export type bootstrapUserApiV1AuthBootstrapPostResponse =
|
||||
| bootstrapUserApiV1AuthBootstrapPostResponseSuccess
|
||||
| bootstrapUserApiV1AuthBootstrapPostResponseError;
|
||||
|
||||
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 = LLMErrorResponse,
|
||||
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 = LLMErrorResponse;
|
||||
|
||||
/**
|
||||
* @summary Bootstrap Authenticated User Context
|
||||
*/
|
||||
export const useBootstrapUserApiV1AuthBootstrapPost = <
|
||||
TError = LLMErrorResponse,
|
||||
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,
|
||||
);
|
||||
};
|
||||
|
|
@ -1,693 +0,0 @@
|
|||
/**
|
||||
* Generated by orval v8.3.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 {
|
||||
BoardMemoryCreate,
|
||||
BoardMemoryRead,
|
||||
HTTPValidationError,
|
||||
LimitOffsetPageTypeVarCustomizedBoardMemoryRead,
|
||||
ListBoardMemoryApiV1BoardsBoardIdMemoryGetParams,
|
||||
StreamBoardMemoryApiV1BoardsBoardIdMemoryStreamGetParams,
|
||||
} from ".././model";
|
||||
|
||||
import { customFetch } from "../../mutator";
|
||||
|
||||
type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
|
||||
|
||||
/**
|
||||
* List board memory entries, optionally filtering chat entries.
|
||||
* @summary List Board Memory
|
||||
*/
|
||||
export type listBoardMemoryApiV1BoardsBoardIdMemoryGetResponse200 = {
|
||||
data: LimitOffsetPageTypeVarCustomizedBoardMemoryRead;
|
||||
status: 200;
|
||||
};
|
||||
|
||||
export type listBoardMemoryApiV1BoardsBoardIdMemoryGetResponse422 = {
|
||||
data: HTTPValidationError;
|
||||
status: 422;
|
||||
};
|
||||
|
||||
export type listBoardMemoryApiV1BoardsBoardIdMemoryGetResponseSuccess =
|
||||
listBoardMemoryApiV1BoardsBoardIdMemoryGetResponse200 & {
|
||||
headers: Headers;
|
||||
};
|
||||
export type listBoardMemoryApiV1BoardsBoardIdMemoryGetResponseError =
|
||||
listBoardMemoryApiV1BoardsBoardIdMemoryGetResponse422 & {
|
||||
headers: Headers;
|
||||
};
|
||||
|
||||
export type listBoardMemoryApiV1BoardsBoardIdMemoryGetResponse =
|
||||
| listBoardMemoryApiV1BoardsBoardIdMemoryGetResponseSuccess
|
||||
| listBoardMemoryApiV1BoardsBoardIdMemoryGetResponseError;
|
||||
|
||||
export const getListBoardMemoryApiV1BoardsBoardIdMemoryGetUrl = (
|
||||
boardId: string,
|
||||
params?: ListBoardMemoryApiV1BoardsBoardIdMemoryGetParams,
|
||||
) => {
|
||||
const normalizedParams = new URLSearchParams();
|
||||
|
||||
Object.entries(params || {}).forEach(([key, value]) => {
|
||||
if (value !== undefined) {
|
||||
normalizedParams.append(key, value === null ? "null" : value.toString());
|
||||
}
|
||||
});
|
||||
|
||||
const stringifiedParams = normalizedParams.toString();
|
||||
|
||||
return stringifiedParams.length > 0
|
||||
? `/api/v1/boards/${boardId}/memory?${stringifiedParams}`
|
||||
: `/api/v1/boards/${boardId}/memory`;
|
||||
};
|
||||
|
||||
export const listBoardMemoryApiV1BoardsBoardIdMemoryGet = async (
|
||||
boardId: string,
|
||||
params?: ListBoardMemoryApiV1BoardsBoardIdMemoryGetParams,
|
||||
options?: RequestInit,
|
||||
): Promise<listBoardMemoryApiV1BoardsBoardIdMemoryGetResponse> => {
|
||||
return customFetch<listBoardMemoryApiV1BoardsBoardIdMemoryGetResponse>(
|
||||
getListBoardMemoryApiV1BoardsBoardIdMemoryGetUrl(boardId, params),
|
||||
{
|
||||
...options,
|
||||
method: "GET",
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export const getListBoardMemoryApiV1BoardsBoardIdMemoryGetQueryKey = (
|
||||
boardId: string,
|
||||
params?: ListBoardMemoryApiV1BoardsBoardIdMemoryGetParams,
|
||||
) => {
|
||||
return [
|
||||
`/api/v1/boards/${boardId}/memory`,
|
||||
...(params ? [params] : []),
|
||||
] as const;
|
||||
};
|
||||
|
||||
export const getListBoardMemoryApiV1BoardsBoardIdMemoryGetQueryOptions = <
|
||||
TData = Awaited<
|
||||
ReturnType<typeof listBoardMemoryApiV1BoardsBoardIdMemoryGet>
|
||||
>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
boardId: string,
|
||||
params?: ListBoardMemoryApiV1BoardsBoardIdMemoryGetParams,
|
||||
options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<ReturnType<typeof listBoardMemoryApiV1BoardsBoardIdMemoryGet>>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
) => {
|
||||
const { query: queryOptions, request: requestOptions } = options ?? {};
|
||||
|
||||
const queryKey =
|
||||
queryOptions?.queryKey ??
|
||||
getListBoardMemoryApiV1BoardsBoardIdMemoryGetQueryKey(boardId, params);
|
||||
|
||||
const queryFn: QueryFunction<
|
||||
Awaited<ReturnType<typeof listBoardMemoryApiV1BoardsBoardIdMemoryGet>>
|
||||
> = ({ signal }) =>
|
||||
listBoardMemoryApiV1BoardsBoardIdMemoryGet(boardId, params, {
|
||||
signal,
|
||||
...requestOptions,
|
||||
});
|
||||
|
||||
return {
|
||||
queryKey,
|
||||
queryFn,
|
||||
enabled: !!boardId,
|
||||
...queryOptions,
|
||||
} as UseQueryOptions<
|
||||
Awaited<ReturnType<typeof listBoardMemoryApiV1BoardsBoardIdMemoryGet>>,
|
||||
TError,
|
||||
TData
|
||||
> & { queryKey: DataTag<QueryKey, TData, TError> };
|
||||
};
|
||||
|
||||
export type ListBoardMemoryApiV1BoardsBoardIdMemoryGetQueryResult = NonNullable<
|
||||
Awaited<ReturnType<typeof listBoardMemoryApiV1BoardsBoardIdMemoryGet>>
|
||||
>;
|
||||
export type ListBoardMemoryApiV1BoardsBoardIdMemoryGetQueryError =
|
||||
HTTPValidationError;
|
||||
|
||||
export function useListBoardMemoryApiV1BoardsBoardIdMemoryGet<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof listBoardMemoryApiV1BoardsBoardIdMemoryGet>
|
||||
>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
boardId: string,
|
||||
params: undefined | ListBoardMemoryApiV1BoardsBoardIdMemoryGetParams,
|
||||
options: {
|
||||
query: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<ReturnType<typeof listBoardMemoryApiV1BoardsBoardIdMemoryGet>>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
> &
|
||||
Pick<
|
||||
DefinedInitialDataOptions<
|
||||
Awaited<
|
||||
ReturnType<typeof listBoardMemoryApiV1BoardsBoardIdMemoryGet>
|
||||
>,
|
||||
TError,
|
||||
Awaited<ReturnType<typeof listBoardMemoryApiV1BoardsBoardIdMemoryGet>>
|
||||
>,
|
||||
"initialData"
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): DefinedUseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
};
|
||||
export function useListBoardMemoryApiV1BoardsBoardIdMemoryGet<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof listBoardMemoryApiV1BoardsBoardIdMemoryGet>
|
||||
>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
boardId: string,
|
||||
params?: ListBoardMemoryApiV1BoardsBoardIdMemoryGetParams,
|
||||
options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<ReturnType<typeof listBoardMemoryApiV1BoardsBoardIdMemoryGet>>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
> &
|
||||
Pick<
|
||||
UndefinedInitialDataOptions<
|
||||
Awaited<
|
||||
ReturnType<typeof listBoardMemoryApiV1BoardsBoardIdMemoryGet>
|
||||
>,
|
||||
TError,
|
||||
Awaited<ReturnType<typeof listBoardMemoryApiV1BoardsBoardIdMemoryGet>>
|
||||
>,
|
||||
"initialData"
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
};
|
||||
export function useListBoardMemoryApiV1BoardsBoardIdMemoryGet<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof listBoardMemoryApiV1BoardsBoardIdMemoryGet>
|
||||
>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
boardId: string,
|
||||
params?: ListBoardMemoryApiV1BoardsBoardIdMemoryGetParams,
|
||||
options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<ReturnType<typeof listBoardMemoryApiV1BoardsBoardIdMemoryGet>>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
};
|
||||
/**
|
||||
* @summary List Board Memory
|
||||
*/
|
||||
|
||||
export function useListBoardMemoryApiV1BoardsBoardIdMemoryGet<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof listBoardMemoryApiV1BoardsBoardIdMemoryGet>
|
||||
>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
boardId: string,
|
||||
params?: ListBoardMemoryApiV1BoardsBoardIdMemoryGetParams,
|
||||
options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<ReturnType<typeof listBoardMemoryApiV1BoardsBoardIdMemoryGet>>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
} {
|
||||
const queryOptions =
|
||||
getListBoardMemoryApiV1BoardsBoardIdMemoryGetQueryOptions(
|
||||
boardId,
|
||||
params,
|
||||
options,
|
||||
);
|
||||
|
||||
const query = useQuery(queryOptions, queryClient) as UseQueryResult<
|
||||
TData,
|
||||
TError
|
||||
> & { queryKey: DataTag<QueryKey, TData, TError> };
|
||||
|
||||
return { ...query, queryKey: queryOptions.queryKey };
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a board memory entry and notify chat targets when needed.
|
||||
* @summary Create Board Memory
|
||||
*/
|
||||
export type createBoardMemoryApiV1BoardsBoardIdMemoryPostResponse200 = {
|
||||
data: BoardMemoryRead;
|
||||
status: 200;
|
||||
};
|
||||
|
||||
export type createBoardMemoryApiV1BoardsBoardIdMemoryPostResponse422 = {
|
||||
data: HTTPValidationError;
|
||||
status: 422;
|
||||
};
|
||||
|
||||
export type createBoardMemoryApiV1BoardsBoardIdMemoryPostResponseSuccess =
|
||||
createBoardMemoryApiV1BoardsBoardIdMemoryPostResponse200 & {
|
||||
headers: Headers;
|
||||
};
|
||||
export type createBoardMemoryApiV1BoardsBoardIdMemoryPostResponseError =
|
||||
createBoardMemoryApiV1BoardsBoardIdMemoryPostResponse422 & {
|
||||
headers: Headers;
|
||||
};
|
||||
|
||||
export type createBoardMemoryApiV1BoardsBoardIdMemoryPostResponse =
|
||||
| createBoardMemoryApiV1BoardsBoardIdMemoryPostResponseSuccess
|
||||
| createBoardMemoryApiV1BoardsBoardIdMemoryPostResponseError;
|
||||
|
||||
export const getCreateBoardMemoryApiV1BoardsBoardIdMemoryPostUrl = (
|
||||
boardId: string,
|
||||
) => {
|
||||
return `/api/v1/boards/${boardId}/memory`;
|
||||
};
|
||||
|
||||
export const createBoardMemoryApiV1BoardsBoardIdMemoryPost = async (
|
||||
boardId: string,
|
||||
boardMemoryCreate: BoardMemoryCreate,
|
||||
options?: RequestInit,
|
||||
): Promise<createBoardMemoryApiV1BoardsBoardIdMemoryPostResponse> => {
|
||||
return customFetch<createBoardMemoryApiV1BoardsBoardIdMemoryPostResponse>(
|
||||
getCreateBoardMemoryApiV1BoardsBoardIdMemoryPostUrl(boardId),
|
||||
{
|
||||
...options,
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json", ...options?.headers },
|
||||
body: JSON.stringify(boardMemoryCreate),
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export const getCreateBoardMemoryApiV1BoardsBoardIdMemoryPostMutationOptions = <
|
||||
TError = HTTPValidationError,
|
||||
TContext = unknown,
|
||||
>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<ReturnType<typeof createBoardMemoryApiV1BoardsBoardIdMemoryPost>>,
|
||||
TError,
|
||||
{ boardId: string; data: BoardMemoryCreate },
|
||||
TContext
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
}): UseMutationOptions<
|
||||
Awaited<ReturnType<typeof createBoardMemoryApiV1BoardsBoardIdMemoryPost>>,
|
||||
TError,
|
||||
{ boardId: string; data: BoardMemoryCreate },
|
||||
TContext
|
||||
> => {
|
||||
const mutationKey = ["createBoardMemoryApiV1BoardsBoardIdMemoryPost"];
|
||||
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 createBoardMemoryApiV1BoardsBoardIdMemoryPost>>,
|
||||
{ boardId: string; data: BoardMemoryCreate }
|
||||
> = (props) => {
|
||||
const { boardId, data } = props ?? {};
|
||||
|
||||
return createBoardMemoryApiV1BoardsBoardIdMemoryPost(
|
||||
boardId,
|
||||
data,
|
||||
requestOptions,
|
||||
);
|
||||
};
|
||||
|
||||
return { mutationFn, ...mutationOptions };
|
||||
};
|
||||
|
||||
export type CreateBoardMemoryApiV1BoardsBoardIdMemoryPostMutationResult =
|
||||
NonNullable<
|
||||
Awaited<ReturnType<typeof createBoardMemoryApiV1BoardsBoardIdMemoryPost>>
|
||||
>;
|
||||
export type CreateBoardMemoryApiV1BoardsBoardIdMemoryPostMutationBody =
|
||||
BoardMemoryCreate;
|
||||
export type CreateBoardMemoryApiV1BoardsBoardIdMemoryPostMutationError =
|
||||
HTTPValidationError;
|
||||
|
||||
/**
|
||||
* @summary Create Board Memory
|
||||
*/
|
||||
export const useCreateBoardMemoryApiV1BoardsBoardIdMemoryPost = <
|
||||
TError = HTTPValidationError,
|
||||
TContext = unknown,
|
||||
>(
|
||||
options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<ReturnType<typeof createBoardMemoryApiV1BoardsBoardIdMemoryPost>>,
|
||||
TError,
|
||||
{ boardId: string; data: BoardMemoryCreate },
|
||||
TContext
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseMutationResult<
|
||||
Awaited<ReturnType<typeof createBoardMemoryApiV1BoardsBoardIdMemoryPost>>,
|
||||
TError,
|
||||
{ boardId: string; data: BoardMemoryCreate },
|
||||
TContext
|
||||
> => {
|
||||
return useMutation(
|
||||
getCreateBoardMemoryApiV1BoardsBoardIdMemoryPostMutationOptions(options),
|
||||
queryClient,
|
||||
);
|
||||
};
|
||||
/**
|
||||
* Stream board memory events over server-sent events.
|
||||
* @summary Stream Board Memory
|
||||
*/
|
||||
export type streamBoardMemoryApiV1BoardsBoardIdMemoryStreamGetResponse200 = {
|
||||
data: unknown;
|
||||
status: 200;
|
||||
};
|
||||
|
||||
export type streamBoardMemoryApiV1BoardsBoardIdMemoryStreamGetResponse422 = {
|
||||
data: HTTPValidationError;
|
||||
status: 422;
|
||||
};
|
||||
|
||||
export type streamBoardMemoryApiV1BoardsBoardIdMemoryStreamGetResponseSuccess =
|
||||
streamBoardMemoryApiV1BoardsBoardIdMemoryStreamGetResponse200 & {
|
||||
headers: Headers;
|
||||
};
|
||||
export type streamBoardMemoryApiV1BoardsBoardIdMemoryStreamGetResponseError =
|
||||
streamBoardMemoryApiV1BoardsBoardIdMemoryStreamGetResponse422 & {
|
||||
headers: Headers;
|
||||
};
|
||||
|
||||
export type streamBoardMemoryApiV1BoardsBoardIdMemoryStreamGetResponse =
|
||||
| streamBoardMemoryApiV1BoardsBoardIdMemoryStreamGetResponseSuccess
|
||||
| streamBoardMemoryApiV1BoardsBoardIdMemoryStreamGetResponseError;
|
||||
|
||||
export const getStreamBoardMemoryApiV1BoardsBoardIdMemoryStreamGetUrl = (
|
||||
boardId: string,
|
||||
params?: StreamBoardMemoryApiV1BoardsBoardIdMemoryStreamGetParams,
|
||||
) => {
|
||||
const normalizedParams = new URLSearchParams();
|
||||
|
||||
Object.entries(params || {}).forEach(([key, value]) => {
|
||||
if (value !== undefined) {
|
||||
normalizedParams.append(key, value === null ? "null" : value.toString());
|
||||
}
|
||||
});
|
||||
|
||||
const stringifiedParams = normalizedParams.toString();
|
||||
|
||||
return stringifiedParams.length > 0
|
||||
? `/api/v1/boards/${boardId}/memory/stream?${stringifiedParams}`
|
||||
: `/api/v1/boards/${boardId}/memory/stream`;
|
||||
};
|
||||
|
||||
export const streamBoardMemoryApiV1BoardsBoardIdMemoryStreamGet = async (
|
||||
boardId: string,
|
||||
params?: StreamBoardMemoryApiV1BoardsBoardIdMemoryStreamGetParams,
|
||||
options?: RequestInit,
|
||||
): Promise<streamBoardMemoryApiV1BoardsBoardIdMemoryStreamGetResponse> => {
|
||||
return customFetch<streamBoardMemoryApiV1BoardsBoardIdMemoryStreamGetResponse>(
|
||||
getStreamBoardMemoryApiV1BoardsBoardIdMemoryStreamGetUrl(boardId, params),
|
||||
{
|
||||
...options,
|
||||
method: "GET",
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export const getStreamBoardMemoryApiV1BoardsBoardIdMemoryStreamGetQueryKey = (
|
||||
boardId: string,
|
||||
params?: StreamBoardMemoryApiV1BoardsBoardIdMemoryStreamGetParams,
|
||||
) => {
|
||||
return [
|
||||
`/api/v1/boards/${boardId}/memory/stream`,
|
||||
...(params ? [params] : []),
|
||||
] as const;
|
||||
};
|
||||
|
||||
export const getStreamBoardMemoryApiV1BoardsBoardIdMemoryStreamGetQueryOptions =
|
||||
<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof streamBoardMemoryApiV1BoardsBoardIdMemoryStreamGet>
|
||||
>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
boardId: string,
|
||||
params?: StreamBoardMemoryApiV1BoardsBoardIdMemoryStreamGetParams,
|
||||
options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof streamBoardMemoryApiV1BoardsBoardIdMemoryStreamGet
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
) => {
|
||||
const { query: queryOptions, request: requestOptions } = options ?? {};
|
||||
|
||||
const queryKey =
|
||||
queryOptions?.queryKey ??
|
||||
getStreamBoardMemoryApiV1BoardsBoardIdMemoryStreamGetQueryKey(
|
||||
boardId,
|
||||
params,
|
||||
);
|
||||
|
||||
const queryFn: QueryFunction<
|
||||
Awaited<
|
||||
ReturnType<typeof streamBoardMemoryApiV1BoardsBoardIdMemoryStreamGet>
|
||||
>
|
||||
> = ({ signal }) =>
|
||||
streamBoardMemoryApiV1BoardsBoardIdMemoryStreamGet(boardId, params, {
|
||||
signal,
|
||||
...requestOptions,
|
||||
});
|
||||
|
||||
return {
|
||||
queryKey,
|
||||
queryFn,
|
||||
enabled: !!boardId,
|
||||
...queryOptions,
|
||||
} as UseQueryOptions<
|
||||
Awaited<
|
||||
ReturnType<typeof streamBoardMemoryApiV1BoardsBoardIdMemoryStreamGet>
|
||||
>,
|
||||
TError,
|
||||
TData
|
||||
> & { queryKey: DataTag<QueryKey, TData, TError> };
|
||||
};
|
||||
|
||||
export type StreamBoardMemoryApiV1BoardsBoardIdMemoryStreamGetQueryResult =
|
||||
NonNullable<
|
||||
Awaited<
|
||||
ReturnType<typeof streamBoardMemoryApiV1BoardsBoardIdMemoryStreamGet>
|
||||
>
|
||||
>;
|
||||
export type StreamBoardMemoryApiV1BoardsBoardIdMemoryStreamGetQueryError =
|
||||
HTTPValidationError;
|
||||
|
||||
export function useStreamBoardMemoryApiV1BoardsBoardIdMemoryStreamGet<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof streamBoardMemoryApiV1BoardsBoardIdMemoryStreamGet>
|
||||
>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
boardId: string,
|
||||
params: undefined | StreamBoardMemoryApiV1BoardsBoardIdMemoryStreamGetParams,
|
||||
options: {
|
||||
query: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<
|
||||
ReturnType<typeof streamBoardMemoryApiV1BoardsBoardIdMemoryStreamGet>
|
||||
>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
> &
|
||||
Pick<
|
||||
DefinedInitialDataOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof streamBoardMemoryApiV1BoardsBoardIdMemoryStreamGet
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof streamBoardMemoryApiV1BoardsBoardIdMemoryStreamGet
|
||||
>
|
||||
>
|
||||
>,
|
||||
"initialData"
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): DefinedUseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
};
|
||||
export function useStreamBoardMemoryApiV1BoardsBoardIdMemoryStreamGet<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof streamBoardMemoryApiV1BoardsBoardIdMemoryStreamGet>
|
||||
>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
boardId: string,
|
||||
params?: StreamBoardMemoryApiV1BoardsBoardIdMemoryStreamGetParams,
|
||||
options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<
|
||||
ReturnType<typeof streamBoardMemoryApiV1BoardsBoardIdMemoryStreamGet>
|
||||
>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
> &
|
||||
Pick<
|
||||
UndefinedInitialDataOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof streamBoardMemoryApiV1BoardsBoardIdMemoryStreamGet
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof streamBoardMemoryApiV1BoardsBoardIdMemoryStreamGet
|
||||
>
|
||||
>
|
||||
>,
|
||||
"initialData"
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
};
|
||||
export function useStreamBoardMemoryApiV1BoardsBoardIdMemoryStreamGet<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof streamBoardMemoryApiV1BoardsBoardIdMemoryStreamGet>
|
||||
>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
boardId: string,
|
||||
params?: StreamBoardMemoryApiV1BoardsBoardIdMemoryStreamGetParams,
|
||||
options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<
|
||||
ReturnType<typeof streamBoardMemoryApiV1BoardsBoardIdMemoryStreamGet>
|
||||
>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
};
|
||||
/**
|
||||
* @summary Stream Board Memory
|
||||
*/
|
||||
|
||||
export function useStreamBoardMemoryApiV1BoardsBoardIdMemoryStreamGet<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof streamBoardMemoryApiV1BoardsBoardIdMemoryStreamGet>
|
||||
>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
boardId: string,
|
||||
params?: StreamBoardMemoryApiV1BoardsBoardIdMemoryStreamGetParams,
|
||||
options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<
|
||||
ReturnType<typeof streamBoardMemoryApiV1BoardsBoardIdMemoryStreamGet>
|
||||
>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
} {
|
||||
const queryOptions =
|
||||
getStreamBoardMemoryApiV1BoardsBoardIdMemoryStreamGetQueryOptions(
|
||||
boardId,
|
||||
params,
|
||||
options,
|
||||
);
|
||||
|
||||
const query = useQuery(queryOptions, queryClient) as UseQueryResult<
|
||||
TData,
|
||||
TError
|
||||
> & { queryKey: DataTag<QueryKey, TData, TError> };
|
||||
|
||||
return { ...query, queryKey: queryOptions.queryKey };
|
||||
}
|
||||
|
|
@ -1,897 +0,0 @@
|
|||
/**
|
||||
* Generated by orval v8.3.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 {
|
||||
BoardOnboardingAgentComplete,
|
||||
BoardOnboardingAgentQuestion,
|
||||
BoardOnboardingAnswer,
|
||||
BoardOnboardingConfirm,
|
||||
BoardOnboardingRead,
|
||||
BoardOnboardingStart,
|
||||
BoardRead,
|
||||
HTTPValidationError,
|
||||
} from ".././model";
|
||||
|
||||
import { customFetch } from "../../mutator";
|
||||
|
||||
type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
|
||||
|
||||
/**
|
||||
* Get the latest onboarding session for a board.
|
||||
* @summary Get Onboarding
|
||||
*/
|
||||
export type getOnboardingApiV1BoardsBoardIdOnboardingGetResponse200 = {
|
||||
data: BoardOnboardingRead;
|
||||
status: 200;
|
||||
};
|
||||
|
||||
export type getOnboardingApiV1BoardsBoardIdOnboardingGetResponse422 = {
|
||||
data: HTTPValidationError;
|
||||
status: 422;
|
||||
};
|
||||
|
||||
export type getOnboardingApiV1BoardsBoardIdOnboardingGetResponseSuccess =
|
||||
getOnboardingApiV1BoardsBoardIdOnboardingGetResponse200 & {
|
||||
headers: Headers;
|
||||
};
|
||||
export type getOnboardingApiV1BoardsBoardIdOnboardingGetResponseError =
|
||||
getOnboardingApiV1BoardsBoardIdOnboardingGetResponse422 & {
|
||||
headers: Headers;
|
||||
};
|
||||
|
||||
export type getOnboardingApiV1BoardsBoardIdOnboardingGetResponse =
|
||||
| getOnboardingApiV1BoardsBoardIdOnboardingGetResponseSuccess
|
||||
| getOnboardingApiV1BoardsBoardIdOnboardingGetResponseError;
|
||||
|
||||
export const getGetOnboardingApiV1BoardsBoardIdOnboardingGetUrl = (
|
||||
boardId: string,
|
||||
) => {
|
||||
return `/api/v1/boards/${boardId}/onboarding`;
|
||||
};
|
||||
|
||||
export const getOnboardingApiV1BoardsBoardIdOnboardingGet = async (
|
||||
boardId: string,
|
||||
options?: RequestInit,
|
||||
): Promise<getOnboardingApiV1BoardsBoardIdOnboardingGetResponse> => {
|
||||
return customFetch<getOnboardingApiV1BoardsBoardIdOnboardingGetResponse>(
|
||||
getGetOnboardingApiV1BoardsBoardIdOnboardingGetUrl(boardId),
|
||||
{
|
||||
...options,
|
||||
method: "GET",
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export const getGetOnboardingApiV1BoardsBoardIdOnboardingGetQueryKey = (
|
||||
boardId: string,
|
||||
) => {
|
||||
return [`/api/v1/boards/${boardId}/onboarding`] as const;
|
||||
};
|
||||
|
||||
export const getGetOnboardingApiV1BoardsBoardIdOnboardingGetQueryOptions = <
|
||||
TData = Awaited<
|
||||
ReturnType<typeof getOnboardingApiV1BoardsBoardIdOnboardingGet>
|
||||
>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
boardId: string,
|
||||
options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<
|
||||
ReturnType<typeof getOnboardingApiV1BoardsBoardIdOnboardingGet>
|
||||
>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
) => {
|
||||
const { query: queryOptions, request: requestOptions } = options ?? {};
|
||||
|
||||
const queryKey =
|
||||
queryOptions?.queryKey ??
|
||||
getGetOnboardingApiV1BoardsBoardIdOnboardingGetQueryKey(boardId);
|
||||
|
||||
const queryFn: QueryFunction<
|
||||
Awaited<ReturnType<typeof getOnboardingApiV1BoardsBoardIdOnboardingGet>>
|
||||
> = ({ signal }) =>
|
||||
getOnboardingApiV1BoardsBoardIdOnboardingGet(boardId, {
|
||||
signal,
|
||||
...requestOptions,
|
||||
});
|
||||
|
||||
return {
|
||||
queryKey,
|
||||
queryFn,
|
||||
enabled: !!boardId,
|
||||
...queryOptions,
|
||||
} as UseQueryOptions<
|
||||
Awaited<ReturnType<typeof getOnboardingApiV1BoardsBoardIdOnboardingGet>>,
|
||||
TError,
|
||||
TData
|
||||
> & { queryKey: DataTag<QueryKey, TData, TError> };
|
||||
};
|
||||
|
||||
export type GetOnboardingApiV1BoardsBoardIdOnboardingGetQueryResult =
|
||||
NonNullable<
|
||||
Awaited<ReturnType<typeof getOnboardingApiV1BoardsBoardIdOnboardingGet>>
|
||||
>;
|
||||
export type GetOnboardingApiV1BoardsBoardIdOnboardingGetQueryError =
|
||||
HTTPValidationError;
|
||||
|
||||
export function useGetOnboardingApiV1BoardsBoardIdOnboardingGet<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof getOnboardingApiV1BoardsBoardIdOnboardingGet>
|
||||
>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
boardId: string,
|
||||
options: {
|
||||
query: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<
|
||||
ReturnType<typeof getOnboardingApiV1BoardsBoardIdOnboardingGet>
|
||||
>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
> &
|
||||
Pick<
|
||||
DefinedInitialDataOptions<
|
||||
Awaited<
|
||||
ReturnType<typeof getOnboardingApiV1BoardsBoardIdOnboardingGet>
|
||||
>,
|
||||
TError,
|
||||
Awaited<
|
||||
ReturnType<typeof getOnboardingApiV1BoardsBoardIdOnboardingGet>
|
||||
>
|
||||
>,
|
||||
"initialData"
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): DefinedUseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
};
|
||||
export function useGetOnboardingApiV1BoardsBoardIdOnboardingGet<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof getOnboardingApiV1BoardsBoardIdOnboardingGet>
|
||||
>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
boardId: string,
|
||||
options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<
|
||||
ReturnType<typeof getOnboardingApiV1BoardsBoardIdOnboardingGet>
|
||||
>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
> &
|
||||
Pick<
|
||||
UndefinedInitialDataOptions<
|
||||
Awaited<
|
||||
ReturnType<typeof getOnboardingApiV1BoardsBoardIdOnboardingGet>
|
||||
>,
|
||||
TError,
|
||||
Awaited<
|
||||
ReturnType<typeof getOnboardingApiV1BoardsBoardIdOnboardingGet>
|
||||
>
|
||||
>,
|
||||
"initialData"
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
};
|
||||
export function useGetOnboardingApiV1BoardsBoardIdOnboardingGet<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof getOnboardingApiV1BoardsBoardIdOnboardingGet>
|
||||
>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
boardId: string,
|
||||
options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<
|
||||
ReturnType<typeof getOnboardingApiV1BoardsBoardIdOnboardingGet>
|
||||
>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
};
|
||||
/**
|
||||
* @summary Get Onboarding
|
||||
*/
|
||||
|
||||
export function useGetOnboardingApiV1BoardsBoardIdOnboardingGet<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof getOnboardingApiV1BoardsBoardIdOnboardingGet>
|
||||
>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
boardId: string,
|
||||
options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<
|
||||
ReturnType<typeof getOnboardingApiV1BoardsBoardIdOnboardingGet>
|
||||
>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
} {
|
||||
const queryOptions =
|
||||
getGetOnboardingApiV1BoardsBoardIdOnboardingGetQueryOptions(
|
||||
boardId,
|
||||
options,
|
||||
);
|
||||
|
||||
const query = useQuery(queryOptions, queryClient) as UseQueryResult<
|
||||
TData,
|
||||
TError
|
||||
> & { queryKey: DataTag<QueryKey, TData, TError> };
|
||||
|
||||
return { ...query, queryKey: queryOptions.queryKey };
|
||||
}
|
||||
|
||||
/**
|
||||
* Store onboarding updates submitted by the gateway agent.
|
||||
* @summary Agent Onboarding Update
|
||||
*/
|
||||
export type agentOnboardingUpdateApiV1BoardsBoardIdOnboardingAgentPostResponse200 =
|
||||
{
|
||||
data: BoardOnboardingRead;
|
||||
status: 200;
|
||||
};
|
||||
|
||||
export type agentOnboardingUpdateApiV1BoardsBoardIdOnboardingAgentPostResponse422 =
|
||||
{
|
||||
data: HTTPValidationError;
|
||||
status: 422;
|
||||
};
|
||||
|
||||
export type agentOnboardingUpdateApiV1BoardsBoardIdOnboardingAgentPostResponseSuccess =
|
||||
agentOnboardingUpdateApiV1BoardsBoardIdOnboardingAgentPostResponse200 & {
|
||||
headers: Headers;
|
||||
};
|
||||
export type agentOnboardingUpdateApiV1BoardsBoardIdOnboardingAgentPostResponseError =
|
||||
agentOnboardingUpdateApiV1BoardsBoardIdOnboardingAgentPostResponse422 & {
|
||||
headers: Headers;
|
||||
};
|
||||
|
||||
export type agentOnboardingUpdateApiV1BoardsBoardIdOnboardingAgentPostResponse =
|
||||
| agentOnboardingUpdateApiV1BoardsBoardIdOnboardingAgentPostResponseSuccess
|
||||
| agentOnboardingUpdateApiV1BoardsBoardIdOnboardingAgentPostResponseError;
|
||||
|
||||
export const getAgentOnboardingUpdateApiV1BoardsBoardIdOnboardingAgentPostUrl =
|
||||
(boardId: string) => {
|
||||
return `/api/v1/boards/${boardId}/onboarding/agent`;
|
||||
};
|
||||
|
||||
export const agentOnboardingUpdateApiV1BoardsBoardIdOnboardingAgentPost =
|
||||
async (
|
||||
boardId: string,
|
||||
boardOnboardingAgentCompleteBoardOnboardingAgentQuestion:
|
||||
| BoardOnboardingAgentComplete
|
||||
| BoardOnboardingAgentQuestion,
|
||||
options?: RequestInit,
|
||||
): Promise<agentOnboardingUpdateApiV1BoardsBoardIdOnboardingAgentPostResponse> => {
|
||||
return customFetch<agentOnboardingUpdateApiV1BoardsBoardIdOnboardingAgentPostResponse>(
|
||||
getAgentOnboardingUpdateApiV1BoardsBoardIdOnboardingAgentPostUrl(boardId),
|
||||
{
|
||||
...options,
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json", ...options?.headers },
|
||||
body: JSON.stringify(
|
||||
boardOnboardingAgentCompleteBoardOnboardingAgentQuestion,
|
||||
),
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export const getAgentOnboardingUpdateApiV1BoardsBoardIdOnboardingAgentPostMutationOptions =
|
||||
<TError = HTTPValidationError, TContext = unknown>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof agentOnboardingUpdateApiV1BoardsBoardIdOnboardingAgentPost
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
{
|
||||
boardId: string;
|
||||
data: BoardOnboardingAgentComplete | BoardOnboardingAgentQuestion;
|
||||
},
|
||||
TContext
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
}): UseMutationOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof agentOnboardingUpdateApiV1BoardsBoardIdOnboardingAgentPost
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
{
|
||||
boardId: string;
|
||||
data: BoardOnboardingAgentComplete | BoardOnboardingAgentQuestion;
|
||||
},
|
||||
TContext
|
||||
> => {
|
||||
const mutationKey = [
|
||||
"agentOnboardingUpdateApiV1BoardsBoardIdOnboardingAgentPost",
|
||||
];
|
||||
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 agentOnboardingUpdateApiV1BoardsBoardIdOnboardingAgentPost
|
||||
>
|
||||
>,
|
||||
{
|
||||
boardId: string;
|
||||
data: BoardOnboardingAgentComplete | BoardOnboardingAgentQuestion;
|
||||
}
|
||||
> = (props) => {
|
||||
const { boardId, data } = props ?? {};
|
||||
|
||||
return agentOnboardingUpdateApiV1BoardsBoardIdOnboardingAgentPost(
|
||||
boardId,
|
||||
data,
|
||||
requestOptions,
|
||||
);
|
||||
};
|
||||
|
||||
return { mutationFn, ...mutationOptions };
|
||||
};
|
||||
|
||||
export type AgentOnboardingUpdateApiV1BoardsBoardIdOnboardingAgentPostMutationResult =
|
||||
NonNullable<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof agentOnboardingUpdateApiV1BoardsBoardIdOnboardingAgentPost
|
||||
>
|
||||
>
|
||||
>;
|
||||
export type AgentOnboardingUpdateApiV1BoardsBoardIdOnboardingAgentPostMutationBody =
|
||||
BoardOnboardingAgentComplete | BoardOnboardingAgentQuestion;
|
||||
export type AgentOnboardingUpdateApiV1BoardsBoardIdOnboardingAgentPostMutationError =
|
||||
HTTPValidationError;
|
||||
|
||||
/**
|
||||
* @summary Agent Onboarding Update
|
||||
*/
|
||||
export const useAgentOnboardingUpdateApiV1BoardsBoardIdOnboardingAgentPost = <
|
||||
TError = HTTPValidationError,
|
||||
TContext = unknown,
|
||||
>(
|
||||
options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof agentOnboardingUpdateApiV1BoardsBoardIdOnboardingAgentPost
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
{
|
||||
boardId: string;
|
||||
data: BoardOnboardingAgentComplete | BoardOnboardingAgentQuestion;
|
||||
},
|
||||
TContext
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseMutationResult<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof agentOnboardingUpdateApiV1BoardsBoardIdOnboardingAgentPost
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
{
|
||||
boardId: string;
|
||||
data: BoardOnboardingAgentComplete | BoardOnboardingAgentQuestion;
|
||||
},
|
||||
TContext
|
||||
> => {
|
||||
return useMutation(
|
||||
getAgentOnboardingUpdateApiV1BoardsBoardIdOnboardingAgentPostMutationOptions(
|
||||
options,
|
||||
),
|
||||
queryClient,
|
||||
);
|
||||
};
|
||||
/**
|
||||
* Send a user onboarding answer to the gateway agent.
|
||||
* @summary Answer Onboarding
|
||||
*/
|
||||
export type answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostResponse200 =
|
||||
{
|
||||
data: BoardOnboardingRead;
|
||||
status: 200;
|
||||
};
|
||||
|
||||
export type answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostResponse422 =
|
||||
{
|
||||
data: HTTPValidationError;
|
||||
status: 422;
|
||||
};
|
||||
|
||||
export type answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostResponseSuccess =
|
||||
answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostResponse200 & {
|
||||
headers: Headers;
|
||||
};
|
||||
export type answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostResponseError =
|
||||
answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostResponse422 & {
|
||||
headers: Headers;
|
||||
};
|
||||
|
||||
export type answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostResponse =
|
||||
| answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostResponseSuccess
|
||||
| answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostResponseError;
|
||||
|
||||
export const getAnswerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostUrl = (
|
||||
boardId: string,
|
||||
) => {
|
||||
return `/api/v1/boards/${boardId}/onboarding/answer`;
|
||||
};
|
||||
|
||||
export const answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPost = async (
|
||||
boardId: string,
|
||||
boardOnboardingAnswer: BoardOnboardingAnswer,
|
||||
options?: RequestInit,
|
||||
): Promise<answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostResponse> => {
|
||||
return customFetch<answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostResponse>(
|
||||
getAnswerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostUrl(boardId),
|
||||
{
|
||||
...options,
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json", ...options?.headers },
|
||||
body: JSON.stringify(boardOnboardingAnswer),
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export const getAnswerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostMutationOptions =
|
||||
<TError = HTTPValidationError, TContext = unknown>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPost
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
{ boardId: string; data: BoardOnboardingAnswer },
|
||||
TContext
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
}): UseMutationOptions<
|
||||
Awaited<
|
||||
ReturnType<typeof answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPost>
|
||||
>,
|
||||
TError,
|
||||
{ boardId: string; data: BoardOnboardingAnswer },
|
||||
TContext
|
||||
> => {
|
||||
const mutationKey = [
|
||||
"answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPost",
|
||||
];
|
||||
const { mutation: mutationOptions, request: requestOptions } = options
|
||||
? options.mutation &&
|
||||
"mutationKey" in options.mutation &&
|
||||
options.mutation.mutationKey
|
||||
? options
|
||||
: { ...options, mutation: { ...options.mutation, mutationKey } }
|
||||
: { mutation: { mutationKey }, request: undefined };
|
||||
|
||||
const mutationFn: MutationFunction<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPost
|
||||
>
|
||||
>,
|
||||
{ boardId: string; data: BoardOnboardingAnswer }
|
||||
> = (props) => {
|
||||
const { boardId, data } = props ?? {};
|
||||
|
||||
return answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPost(
|
||||
boardId,
|
||||
data,
|
||||
requestOptions,
|
||||
);
|
||||
};
|
||||
|
||||
return { mutationFn, ...mutationOptions };
|
||||
};
|
||||
|
||||
export type AnswerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostMutationResult =
|
||||
NonNullable<
|
||||
Awaited<
|
||||
ReturnType<typeof answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPost>
|
||||
>
|
||||
>;
|
||||
export type AnswerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostMutationBody =
|
||||
BoardOnboardingAnswer;
|
||||
export type AnswerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostMutationError =
|
||||
HTTPValidationError;
|
||||
|
||||
/**
|
||||
* @summary Answer Onboarding
|
||||
*/
|
||||
export const useAnswerOnboardingApiV1BoardsBoardIdOnboardingAnswerPost = <
|
||||
TError = HTTPValidationError,
|
||||
TContext = unknown,
|
||||
>(
|
||||
options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPost
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
{ boardId: string; data: BoardOnboardingAnswer },
|
||||
TContext
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseMutationResult<
|
||||
Awaited<
|
||||
ReturnType<typeof answerOnboardingApiV1BoardsBoardIdOnboardingAnswerPost>
|
||||
>,
|
||||
TError,
|
||||
{ boardId: string; data: BoardOnboardingAnswer },
|
||||
TContext
|
||||
> => {
|
||||
return useMutation(
|
||||
getAnswerOnboardingApiV1BoardsBoardIdOnboardingAnswerPostMutationOptions(
|
||||
options,
|
||||
),
|
||||
queryClient,
|
||||
);
|
||||
};
|
||||
/**
|
||||
* Confirm onboarding results and provision the board lead agent.
|
||||
* @summary Confirm Onboarding
|
||||
*/
|
||||
export type confirmOnboardingApiV1BoardsBoardIdOnboardingConfirmPostResponse200 =
|
||||
{
|
||||
data: BoardRead;
|
||||
status: 200;
|
||||
};
|
||||
|
||||
export type confirmOnboardingApiV1BoardsBoardIdOnboardingConfirmPostResponse422 =
|
||||
{
|
||||
data: HTTPValidationError;
|
||||
status: 422;
|
||||
};
|
||||
|
||||
export type confirmOnboardingApiV1BoardsBoardIdOnboardingConfirmPostResponseSuccess =
|
||||
confirmOnboardingApiV1BoardsBoardIdOnboardingConfirmPostResponse200 & {
|
||||
headers: Headers;
|
||||
};
|
||||
export type confirmOnboardingApiV1BoardsBoardIdOnboardingConfirmPostResponseError =
|
||||
confirmOnboardingApiV1BoardsBoardIdOnboardingConfirmPostResponse422 & {
|
||||
headers: Headers;
|
||||
};
|
||||
|
||||
export type confirmOnboardingApiV1BoardsBoardIdOnboardingConfirmPostResponse =
|
||||
| confirmOnboardingApiV1BoardsBoardIdOnboardingConfirmPostResponseSuccess
|
||||
| confirmOnboardingApiV1BoardsBoardIdOnboardingConfirmPostResponseError;
|
||||
|
||||
export const getConfirmOnboardingApiV1BoardsBoardIdOnboardingConfirmPostUrl = (
|
||||
boardId: string,
|
||||
) => {
|
||||
return `/api/v1/boards/${boardId}/onboarding/confirm`;
|
||||
};
|
||||
|
||||
export const confirmOnboardingApiV1BoardsBoardIdOnboardingConfirmPost = async (
|
||||
boardId: string,
|
||||
boardOnboardingConfirm: BoardOnboardingConfirm,
|
||||
options?: RequestInit,
|
||||
): Promise<confirmOnboardingApiV1BoardsBoardIdOnboardingConfirmPostResponse> => {
|
||||
return customFetch<confirmOnboardingApiV1BoardsBoardIdOnboardingConfirmPostResponse>(
|
||||
getConfirmOnboardingApiV1BoardsBoardIdOnboardingConfirmPostUrl(boardId),
|
||||
{
|
||||
...options,
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json", ...options?.headers },
|
||||
body: JSON.stringify(boardOnboardingConfirm),
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export const getConfirmOnboardingApiV1BoardsBoardIdOnboardingConfirmPostMutationOptions =
|
||||
<TError = HTTPValidationError, TContext = unknown>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof confirmOnboardingApiV1BoardsBoardIdOnboardingConfirmPost
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
{ boardId: string; data: BoardOnboardingConfirm },
|
||||
TContext
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
}): UseMutationOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof confirmOnboardingApiV1BoardsBoardIdOnboardingConfirmPost
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
{ boardId: string; data: BoardOnboardingConfirm },
|
||||
TContext
|
||||
> => {
|
||||
const mutationKey = [
|
||||
"confirmOnboardingApiV1BoardsBoardIdOnboardingConfirmPost",
|
||||
];
|
||||
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 confirmOnboardingApiV1BoardsBoardIdOnboardingConfirmPost
|
||||
>
|
||||
>,
|
||||
{ boardId: string; data: BoardOnboardingConfirm }
|
||||
> = (props) => {
|
||||
const { boardId, data } = props ?? {};
|
||||
|
||||
return confirmOnboardingApiV1BoardsBoardIdOnboardingConfirmPost(
|
||||
boardId,
|
||||
data,
|
||||
requestOptions,
|
||||
);
|
||||
};
|
||||
|
||||
return { mutationFn, ...mutationOptions };
|
||||
};
|
||||
|
||||
export type ConfirmOnboardingApiV1BoardsBoardIdOnboardingConfirmPostMutationResult =
|
||||
NonNullable<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof confirmOnboardingApiV1BoardsBoardIdOnboardingConfirmPost
|
||||
>
|
||||
>
|
||||
>;
|
||||
export type ConfirmOnboardingApiV1BoardsBoardIdOnboardingConfirmPostMutationBody =
|
||||
BoardOnboardingConfirm;
|
||||
export type ConfirmOnboardingApiV1BoardsBoardIdOnboardingConfirmPostMutationError =
|
||||
HTTPValidationError;
|
||||
|
||||
/**
|
||||
* @summary Confirm Onboarding
|
||||
*/
|
||||
export const useConfirmOnboardingApiV1BoardsBoardIdOnboardingConfirmPost = <
|
||||
TError = HTTPValidationError,
|
||||
TContext = unknown,
|
||||
>(
|
||||
options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof confirmOnboardingApiV1BoardsBoardIdOnboardingConfirmPost
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
{ boardId: string; data: BoardOnboardingConfirm },
|
||||
TContext
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseMutationResult<
|
||||
Awaited<
|
||||
ReturnType<typeof confirmOnboardingApiV1BoardsBoardIdOnboardingConfirmPost>
|
||||
>,
|
||||
TError,
|
||||
{ boardId: string; data: BoardOnboardingConfirm },
|
||||
TContext
|
||||
> => {
|
||||
return useMutation(
|
||||
getConfirmOnboardingApiV1BoardsBoardIdOnboardingConfirmPostMutationOptions(
|
||||
options,
|
||||
),
|
||||
queryClient,
|
||||
);
|
||||
};
|
||||
/**
|
||||
* Start onboarding and send instructions to the gateway agent.
|
||||
* @summary Start Onboarding
|
||||
*/
|
||||
export type startOnboardingApiV1BoardsBoardIdOnboardingStartPostResponse200 = {
|
||||
data: BoardOnboardingRead;
|
||||
status: 200;
|
||||
};
|
||||
|
||||
export type startOnboardingApiV1BoardsBoardIdOnboardingStartPostResponse422 = {
|
||||
data: HTTPValidationError;
|
||||
status: 422;
|
||||
};
|
||||
|
||||
export type startOnboardingApiV1BoardsBoardIdOnboardingStartPostResponseSuccess =
|
||||
startOnboardingApiV1BoardsBoardIdOnboardingStartPostResponse200 & {
|
||||
headers: Headers;
|
||||
};
|
||||
export type startOnboardingApiV1BoardsBoardIdOnboardingStartPostResponseError =
|
||||
startOnboardingApiV1BoardsBoardIdOnboardingStartPostResponse422 & {
|
||||
headers: Headers;
|
||||
};
|
||||
|
||||
export type startOnboardingApiV1BoardsBoardIdOnboardingStartPostResponse =
|
||||
| startOnboardingApiV1BoardsBoardIdOnboardingStartPostResponseSuccess
|
||||
| startOnboardingApiV1BoardsBoardIdOnboardingStartPostResponseError;
|
||||
|
||||
export const getStartOnboardingApiV1BoardsBoardIdOnboardingStartPostUrl = (
|
||||
boardId: string,
|
||||
) => {
|
||||
return `/api/v1/boards/${boardId}/onboarding/start`;
|
||||
};
|
||||
|
||||
export const startOnboardingApiV1BoardsBoardIdOnboardingStartPost = async (
|
||||
boardId: string,
|
||||
boardOnboardingStart: BoardOnboardingStart,
|
||||
options?: RequestInit,
|
||||
): Promise<startOnboardingApiV1BoardsBoardIdOnboardingStartPostResponse> => {
|
||||
return customFetch<startOnboardingApiV1BoardsBoardIdOnboardingStartPostResponse>(
|
||||
getStartOnboardingApiV1BoardsBoardIdOnboardingStartPostUrl(boardId),
|
||||
{
|
||||
...options,
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json", ...options?.headers },
|
||||
body: JSON.stringify(boardOnboardingStart),
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export const getStartOnboardingApiV1BoardsBoardIdOnboardingStartPostMutationOptions =
|
||||
<TError = HTTPValidationError, TContext = unknown>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<
|
||||
ReturnType<typeof startOnboardingApiV1BoardsBoardIdOnboardingStartPost>
|
||||
>,
|
||||
TError,
|
||||
{ boardId: string; data: BoardOnboardingStart },
|
||||
TContext
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
}): UseMutationOptions<
|
||||
Awaited<
|
||||
ReturnType<typeof startOnboardingApiV1BoardsBoardIdOnboardingStartPost>
|
||||
>,
|
||||
TError,
|
||||
{ boardId: string; data: BoardOnboardingStart },
|
||||
TContext
|
||||
> => {
|
||||
const mutationKey = [
|
||||
"startOnboardingApiV1BoardsBoardIdOnboardingStartPost",
|
||||
];
|
||||
const { mutation: mutationOptions, request: requestOptions } = options
|
||||
? options.mutation &&
|
||||
"mutationKey" in options.mutation &&
|
||||
options.mutation.mutationKey
|
||||
? options
|
||||
: { ...options, mutation: { ...options.mutation, mutationKey } }
|
||||
: { mutation: { mutationKey }, request: undefined };
|
||||
|
||||
const mutationFn: MutationFunction<
|
||||
Awaited<
|
||||
ReturnType<typeof startOnboardingApiV1BoardsBoardIdOnboardingStartPost>
|
||||
>,
|
||||
{ boardId: string; data: BoardOnboardingStart }
|
||||
> = (props) => {
|
||||
const { boardId, data } = props ?? {};
|
||||
|
||||
return startOnboardingApiV1BoardsBoardIdOnboardingStartPost(
|
||||
boardId,
|
||||
data,
|
||||
requestOptions,
|
||||
);
|
||||
};
|
||||
|
||||
return { mutationFn, ...mutationOptions };
|
||||
};
|
||||
|
||||
export type StartOnboardingApiV1BoardsBoardIdOnboardingStartPostMutationResult =
|
||||
NonNullable<
|
||||
Awaited<
|
||||
ReturnType<typeof startOnboardingApiV1BoardsBoardIdOnboardingStartPost>
|
||||
>
|
||||
>;
|
||||
export type StartOnboardingApiV1BoardsBoardIdOnboardingStartPostMutationBody =
|
||||
BoardOnboardingStart;
|
||||
export type StartOnboardingApiV1BoardsBoardIdOnboardingStartPostMutationError =
|
||||
HTTPValidationError;
|
||||
|
||||
/**
|
||||
* @summary Start Onboarding
|
||||
*/
|
||||
export const useStartOnboardingApiV1BoardsBoardIdOnboardingStartPost = <
|
||||
TError = HTTPValidationError,
|
||||
TContext = unknown,
|
||||
>(
|
||||
options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<
|
||||
ReturnType<typeof startOnboardingApiV1BoardsBoardIdOnboardingStartPost>
|
||||
>,
|
||||
TError,
|
||||
{ boardId: string; data: BoardOnboardingStart },
|
||||
TContext
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseMutationResult<
|
||||
Awaited<
|
||||
ReturnType<typeof startOnboardingApiV1BoardsBoardIdOnboardingStartPost>
|
||||
>,
|
||||
TError,
|
||||
{ boardId: string; data: BoardOnboardingStart },
|
||||
TContext
|
||||
> => {
|
||||
return useMutation(
|
||||
getStartOnboardingApiV1BoardsBoardIdOnboardingStartPostMutationOptions(
|
||||
options,
|
||||
),
|
||||
queryClient,
|
||||
);
|
||||
};
|
||||
|
|
@ -1,751 +0,0 @@
|
|||
/**
|
||||
* Generated by orval v8.3.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,
|
||||
OkResponse,
|
||||
TaskCustomFieldDefinitionCreate,
|
||||
TaskCustomFieldDefinitionRead,
|
||||
TaskCustomFieldDefinitionUpdate,
|
||||
} from ".././model";
|
||||
|
||||
import { customFetch } from "../../mutator";
|
||||
|
||||
type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
|
||||
|
||||
/**
|
||||
* List task custom field definitions for the authenticated organization.
|
||||
* @summary List Org Custom Fields
|
||||
*/
|
||||
export type listOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGetResponse200 =
|
||||
{
|
||||
data: TaskCustomFieldDefinitionRead[];
|
||||
status: 200;
|
||||
};
|
||||
|
||||
export type listOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGetResponseSuccess =
|
||||
listOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGetResponse200 & {
|
||||
headers: Headers;
|
||||
};
|
||||
export type listOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGetResponse =
|
||||
listOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGetResponseSuccess;
|
||||
|
||||
export const getListOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGetUrl =
|
||||
() => {
|
||||
return `/api/v1/organizations/me/custom-fields`;
|
||||
};
|
||||
|
||||
export const listOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGet = async (
|
||||
options?: RequestInit,
|
||||
): Promise<listOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGetResponse> => {
|
||||
return customFetch<listOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGetResponse>(
|
||||
getListOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGetUrl(),
|
||||
{
|
||||
...options,
|
||||
method: "GET",
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export const getListOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGetQueryKey =
|
||||
() => {
|
||||
return [`/api/v1/organizations/me/custom-fields`] as const;
|
||||
};
|
||||
|
||||
export const getListOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGetQueryOptions =
|
||||
<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof listOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGet>
|
||||
>,
|
||||
TError = unknown,
|
||||
>(options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof listOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGet
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
}) => {
|
||||
const { query: queryOptions, request: requestOptions } = options ?? {};
|
||||
|
||||
const queryKey =
|
||||
queryOptions?.queryKey ??
|
||||
getListOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGetQueryKey();
|
||||
|
||||
const queryFn: QueryFunction<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof listOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGet
|
||||
>
|
||||
>
|
||||
> = ({ signal }) =>
|
||||
listOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGet({
|
||||
signal,
|
||||
...requestOptions,
|
||||
});
|
||||
|
||||
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof listOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGet
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
TData
|
||||
> & { queryKey: DataTag<QueryKey, TData, TError> };
|
||||
};
|
||||
|
||||
export type ListOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGetQueryResult =
|
||||
NonNullable<
|
||||
Awaited<
|
||||
ReturnType<typeof listOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGet>
|
||||
>
|
||||
>;
|
||||
export type ListOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGetQueryError =
|
||||
unknown;
|
||||
|
||||
export function useListOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGet<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof listOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGet>
|
||||
>,
|
||||
TError = unknown,
|
||||
>(
|
||||
options: {
|
||||
query: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof listOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGet
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
> &
|
||||
Pick<
|
||||
DefinedInitialDataOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof listOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGet
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof listOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGet
|
||||
>
|
||||
>
|
||||
>,
|
||||
"initialData"
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): DefinedUseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
};
|
||||
export function useListOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGet<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof listOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGet>
|
||||
>,
|
||||
TError = unknown,
|
||||
>(
|
||||
options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof listOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGet
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
> &
|
||||
Pick<
|
||||
UndefinedInitialDataOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof listOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGet
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof listOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGet
|
||||
>
|
||||
>
|
||||
>,
|
||||
"initialData"
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
};
|
||||
export function useListOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGet<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof listOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGet>
|
||||
>,
|
||||
TError = unknown,
|
||||
>(
|
||||
options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof listOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGet
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
};
|
||||
/**
|
||||
* @summary List Org Custom Fields
|
||||
*/
|
||||
|
||||
export function useListOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGet<
|
||||
TData = Awaited<
|
||||
ReturnType<typeof listOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGet>
|
||||
>,
|
||||
TError = unknown,
|
||||
>(
|
||||
options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof listOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGet
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
} {
|
||||
const queryOptions =
|
||||
getListOrgCustomFieldsApiV1OrganizationsMeCustomFieldsGetQueryOptions(
|
||||
options,
|
||||
);
|
||||
|
||||
const query = useQuery(queryOptions, queryClient) as UseQueryResult<
|
||||
TData,
|
||||
TError
|
||||
> & { queryKey: DataTag<QueryKey, TData, TError> };
|
||||
|
||||
return { ...query, queryKey: queryOptions.queryKey };
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an organization-level task custom field definition.
|
||||
* @summary Create Org Custom Field
|
||||
*/
|
||||
export type createOrgCustomFieldApiV1OrganizationsMeCustomFieldsPostResponse200 =
|
||||
{
|
||||
data: TaskCustomFieldDefinitionRead;
|
||||
status: 200;
|
||||
};
|
||||
|
||||
export type createOrgCustomFieldApiV1OrganizationsMeCustomFieldsPostResponse422 =
|
||||
{
|
||||
data: HTTPValidationError;
|
||||
status: 422;
|
||||
};
|
||||
|
||||
export type createOrgCustomFieldApiV1OrganizationsMeCustomFieldsPostResponseSuccess =
|
||||
createOrgCustomFieldApiV1OrganizationsMeCustomFieldsPostResponse200 & {
|
||||
headers: Headers;
|
||||
};
|
||||
export type createOrgCustomFieldApiV1OrganizationsMeCustomFieldsPostResponseError =
|
||||
createOrgCustomFieldApiV1OrganizationsMeCustomFieldsPostResponse422 & {
|
||||
headers: Headers;
|
||||
};
|
||||
|
||||
export type createOrgCustomFieldApiV1OrganizationsMeCustomFieldsPostResponse =
|
||||
| createOrgCustomFieldApiV1OrganizationsMeCustomFieldsPostResponseSuccess
|
||||
| createOrgCustomFieldApiV1OrganizationsMeCustomFieldsPostResponseError;
|
||||
|
||||
export const getCreateOrgCustomFieldApiV1OrganizationsMeCustomFieldsPostUrl =
|
||||
() => {
|
||||
return `/api/v1/organizations/me/custom-fields`;
|
||||
};
|
||||
|
||||
export const createOrgCustomFieldApiV1OrganizationsMeCustomFieldsPost = async (
|
||||
taskCustomFieldDefinitionCreate: TaskCustomFieldDefinitionCreate,
|
||||
options?: RequestInit,
|
||||
): Promise<createOrgCustomFieldApiV1OrganizationsMeCustomFieldsPostResponse> => {
|
||||
return customFetch<createOrgCustomFieldApiV1OrganizationsMeCustomFieldsPostResponse>(
|
||||
getCreateOrgCustomFieldApiV1OrganizationsMeCustomFieldsPostUrl(),
|
||||
{
|
||||
...options,
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json", ...options?.headers },
|
||||
body: JSON.stringify(taskCustomFieldDefinitionCreate),
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export const getCreateOrgCustomFieldApiV1OrganizationsMeCustomFieldsPostMutationOptions =
|
||||
<TError = HTTPValidationError, TContext = unknown>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof createOrgCustomFieldApiV1OrganizationsMeCustomFieldsPost
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
{ data: TaskCustomFieldDefinitionCreate },
|
||||
TContext
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
}): UseMutationOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof createOrgCustomFieldApiV1OrganizationsMeCustomFieldsPost
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
{ data: TaskCustomFieldDefinitionCreate },
|
||||
TContext
|
||||
> => {
|
||||
const mutationKey = [
|
||||
"createOrgCustomFieldApiV1OrganizationsMeCustomFieldsPost",
|
||||
];
|
||||
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 createOrgCustomFieldApiV1OrganizationsMeCustomFieldsPost
|
||||
>
|
||||
>,
|
||||
{ data: TaskCustomFieldDefinitionCreate }
|
||||
> = (props) => {
|
||||
const { data } = props ?? {};
|
||||
|
||||
return createOrgCustomFieldApiV1OrganizationsMeCustomFieldsPost(
|
||||
data,
|
||||
requestOptions,
|
||||
);
|
||||
};
|
||||
|
||||
return { mutationFn, ...mutationOptions };
|
||||
};
|
||||
|
||||
export type CreateOrgCustomFieldApiV1OrganizationsMeCustomFieldsPostMutationResult =
|
||||
NonNullable<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof createOrgCustomFieldApiV1OrganizationsMeCustomFieldsPost
|
||||
>
|
||||
>
|
||||
>;
|
||||
export type CreateOrgCustomFieldApiV1OrganizationsMeCustomFieldsPostMutationBody =
|
||||
TaskCustomFieldDefinitionCreate;
|
||||
export type CreateOrgCustomFieldApiV1OrganizationsMeCustomFieldsPostMutationError =
|
||||
HTTPValidationError;
|
||||
|
||||
/**
|
||||
* @summary Create Org Custom Field
|
||||
*/
|
||||
export const useCreateOrgCustomFieldApiV1OrganizationsMeCustomFieldsPost = <
|
||||
TError = HTTPValidationError,
|
||||
TContext = unknown,
|
||||
>(
|
||||
options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof createOrgCustomFieldApiV1OrganizationsMeCustomFieldsPost
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
{ data: TaskCustomFieldDefinitionCreate },
|
||||
TContext
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseMutationResult<
|
||||
Awaited<
|
||||
ReturnType<typeof createOrgCustomFieldApiV1OrganizationsMeCustomFieldsPost>
|
||||
>,
|
||||
TError,
|
||||
{ data: TaskCustomFieldDefinitionCreate },
|
||||
TContext
|
||||
> => {
|
||||
return useMutation(
|
||||
getCreateOrgCustomFieldApiV1OrganizationsMeCustomFieldsPostMutationOptions(
|
||||
options,
|
||||
),
|
||||
queryClient,
|
||||
);
|
||||
};
|
||||
/**
|
||||
* Delete an org-level definition when it has no persisted task values.
|
||||
* @summary Delete Org Custom Field
|
||||
*/
|
||||
export type deleteOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdDeleteResponse200 =
|
||||
{
|
||||
data: OkResponse;
|
||||
status: 200;
|
||||
};
|
||||
|
||||
export type deleteOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdDeleteResponse422 =
|
||||
{
|
||||
data: HTTPValidationError;
|
||||
status: 422;
|
||||
};
|
||||
|
||||
export type deleteOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdDeleteResponseSuccess =
|
||||
deleteOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdDeleteResponse200 & {
|
||||
headers: Headers;
|
||||
};
|
||||
export type deleteOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdDeleteResponseError =
|
||||
deleteOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdDeleteResponse422 & {
|
||||
headers: Headers;
|
||||
};
|
||||
|
||||
export type deleteOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdDeleteResponse =
|
||||
|
||||
| deleteOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdDeleteResponseSuccess
|
||||
| deleteOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdDeleteResponseError;
|
||||
|
||||
export const getDeleteOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdDeleteUrl =
|
||||
(taskCustomFieldDefinitionId: string) => {
|
||||
return `/api/v1/organizations/me/custom-fields/${taskCustomFieldDefinitionId}`;
|
||||
};
|
||||
|
||||
export const deleteOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdDelete =
|
||||
async (
|
||||
taskCustomFieldDefinitionId: string,
|
||||
options?: RequestInit,
|
||||
): Promise<deleteOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdDeleteResponse> => {
|
||||
return customFetch<deleteOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdDeleteResponse>(
|
||||
getDeleteOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdDeleteUrl(
|
||||
taskCustomFieldDefinitionId,
|
||||
),
|
||||
{
|
||||
...options,
|
||||
method: "DELETE",
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export const getDeleteOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdDeleteMutationOptions =
|
||||
<TError = HTTPValidationError, TContext = unknown>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof deleteOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdDelete
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
{ taskCustomFieldDefinitionId: string },
|
||||
TContext
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
}): UseMutationOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof deleteOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdDelete
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
{ taskCustomFieldDefinitionId: string },
|
||||
TContext
|
||||
> => {
|
||||
const mutationKey = [
|
||||
"deleteOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdDelete",
|
||||
];
|
||||
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 deleteOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdDelete
|
||||
>
|
||||
>,
|
||||
{ taskCustomFieldDefinitionId: string }
|
||||
> = (props) => {
|
||||
const { taskCustomFieldDefinitionId } = props ?? {};
|
||||
|
||||
return deleteOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdDelete(
|
||||
taskCustomFieldDefinitionId,
|
||||
requestOptions,
|
||||
);
|
||||
};
|
||||
|
||||
return { mutationFn, ...mutationOptions };
|
||||
};
|
||||
|
||||
export type DeleteOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdDeleteMutationResult =
|
||||
NonNullable<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof deleteOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdDelete
|
||||
>
|
||||
>
|
||||
>;
|
||||
|
||||
export type DeleteOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdDeleteMutationError =
|
||||
HTTPValidationError;
|
||||
|
||||
/**
|
||||
* @summary Delete Org Custom Field
|
||||
*/
|
||||
export const useDeleteOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdDelete =
|
||||
<TError = HTTPValidationError, TContext = unknown>(
|
||||
options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof deleteOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdDelete
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
{ taskCustomFieldDefinitionId: string },
|
||||
TContext
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseMutationResult<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof deleteOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdDelete
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
{ taskCustomFieldDefinitionId: string },
|
||||
TContext
|
||||
> => {
|
||||
return useMutation(
|
||||
getDeleteOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdDeleteMutationOptions(
|
||||
options,
|
||||
),
|
||||
queryClient,
|
||||
);
|
||||
};
|
||||
/**
|
||||
* Update an organization-level task custom field definition.
|
||||
* @summary Update Org Custom Field
|
||||
*/
|
||||
export type updateOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdPatchResponse200 =
|
||||
{
|
||||
data: TaskCustomFieldDefinitionRead;
|
||||
status: 200;
|
||||
};
|
||||
|
||||
export type updateOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdPatchResponse422 =
|
||||
{
|
||||
data: HTTPValidationError;
|
||||
status: 422;
|
||||
};
|
||||
|
||||
export type updateOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdPatchResponseSuccess =
|
||||
updateOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdPatchResponse200 & {
|
||||
headers: Headers;
|
||||
};
|
||||
export type updateOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdPatchResponseError =
|
||||
updateOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdPatchResponse422 & {
|
||||
headers: Headers;
|
||||
};
|
||||
|
||||
export type updateOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdPatchResponse =
|
||||
|
||||
| updateOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdPatchResponseSuccess
|
||||
| updateOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdPatchResponseError;
|
||||
|
||||
export const getUpdateOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdPatchUrl =
|
||||
(taskCustomFieldDefinitionId: string) => {
|
||||
return `/api/v1/organizations/me/custom-fields/${taskCustomFieldDefinitionId}`;
|
||||
};
|
||||
|
||||
export const updateOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdPatch =
|
||||
async (
|
||||
taskCustomFieldDefinitionId: string,
|
||||
taskCustomFieldDefinitionUpdate: TaskCustomFieldDefinitionUpdate,
|
||||
options?: RequestInit,
|
||||
): Promise<updateOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdPatchResponse> => {
|
||||
return customFetch<updateOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdPatchResponse>(
|
||||
getUpdateOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdPatchUrl(
|
||||
taskCustomFieldDefinitionId,
|
||||
),
|
||||
{
|
||||
...options,
|
||||
method: "PATCH",
|
||||
headers: { "Content-Type": "application/json", ...options?.headers },
|
||||
body: JSON.stringify(taskCustomFieldDefinitionUpdate),
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export const getUpdateOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdPatchMutationOptions =
|
||||
<TError = HTTPValidationError, TContext = unknown>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof updateOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdPatch
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
{
|
||||
taskCustomFieldDefinitionId: string;
|
||||
data: TaskCustomFieldDefinitionUpdate;
|
||||
},
|
||||
TContext
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
}): UseMutationOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof updateOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdPatch
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
{
|
||||
taskCustomFieldDefinitionId: string;
|
||||
data: TaskCustomFieldDefinitionUpdate;
|
||||
},
|
||||
TContext
|
||||
> => {
|
||||
const mutationKey = [
|
||||
"updateOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdPatch",
|
||||
];
|
||||
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 updateOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdPatch
|
||||
>
|
||||
>,
|
||||
{
|
||||
taskCustomFieldDefinitionId: string;
|
||||
data: TaskCustomFieldDefinitionUpdate;
|
||||
}
|
||||
> = (props) => {
|
||||
const { taskCustomFieldDefinitionId, data } = props ?? {};
|
||||
|
||||
return updateOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdPatch(
|
||||
taskCustomFieldDefinitionId,
|
||||
data,
|
||||
requestOptions,
|
||||
);
|
||||
};
|
||||
|
||||
return { mutationFn, ...mutationOptions };
|
||||
};
|
||||
|
||||
export type UpdateOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdPatchMutationResult =
|
||||
NonNullable<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof updateOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdPatch
|
||||
>
|
||||
>
|
||||
>;
|
||||
export type UpdateOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdPatchMutationBody =
|
||||
TaskCustomFieldDefinitionUpdate;
|
||||
export type UpdateOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdPatchMutationError =
|
||||
HTTPValidationError;
|
||||
|
||||
/**
|
||||
* @summary Update Org Custom Field
|
||||
*/
|
||||
export const useUpdateOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdPatch =
|
||||
<TError = HTTPValidationError, TContext = unknown>(
|
||||
options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof updateOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdPatch
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
{
|
||||
taskCustomFieldDefinitionId: string;
|
||||
data: TaskCustomFieldDefinitionUpdate;
|
||||
},
|
||||
TContext
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseMutationResult<
|
||||
Awaited<
|
||||
ReturnType<
|
||||
typeof updateOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdPatch
|
||||
>
|
||||
>,
|
||||
TError,
|
||||
{
|
||||
taskCustomFieldDefinitionId: string;
|
||||
data: TaskCustomFieldDefinitionUpdate;
|
||||
},
|
||||
TContext
|
||||
> => {
|
||||
return useMutation(
|
||||
getUpdateOrgCustomFieldApiV1OrganizationsMeCustomFieldsTaskCustomFieldDefinitionIdPatchMutationOptions(
|
||||
options,
|
||||
),
|
||||
queryClient,
|
||||
);
|
||||
};
|
||||
|
|
@ -1,518 +0,0 @@
|
|||
/**
|
||||
* Generated by orval v8.3.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];
|
||||
|
||||
/**
|
||||
* Lightweight liveness probe endpoint.
|
||||
* @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 };
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias liveness probe endpoint for platform compatibility.
|
||||
* @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 };
|
||||
}
|
||||
|
||||
/**
|
||||
* Readiness probe endpoint for service orchestration checks.
|
||||
* @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 };
|
||||
}
|
||||
|
|
@ -1,514 +0,0 @@
|
|||
/**
|
||||
* Generated by orval v8.3.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 { HealthStatusResponse } from ".././model";
|
||||
|
||||
import { customFetch } from "../../mutator";
|
||||
|
||||
type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
|
||||
|
||||
/**
|
||||
* Lightweight liveness probe endpoint.
|
||||
* @summary Health Check
|
||||
*/
|
||||
export type healthHealthGetResponse200 = {
|
||||
data: HealthStatusResponse;
|
||||
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 Check
|
||||
*/
|
||||
|
||||
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 };
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias liveness probe endpoint for platform compatibility.
|
||||
* @summary Health Alias Check
|
||||
*/
|
||||
export type healthzHealthzGetResponse200 = {
|
||||
data: HealthStatusResponse;
|
||||
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 Health Alias Check
|
||||
*/
|
||||
|
||||
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 };
|
||||
}
|
||||
|
||||
/**
|
||||
* Readiness probe endpoint for service orchestration checks.
|
||||
* @summary Readiness Check
|
||||
*/
|
||||
export type readyzReadyzGetResponse200 = {
|
||||
data: HealthStatusResponse;
|
||||
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 Readiness Check
|
||||
*/
|
||||
|
||||
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 };
|
||||
}
|
||||
|
|
@ -1,244 +0,0 @@
|
|||
/**
|
||||
* Generated by orval v8.3.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 {
|
||||
DashboardMetrics,
|
||||
DashboardMetricsApiV1MetricsDashboardGetParams,
|
||||
HTTPValidationError,
|
||||
} from ".././model";
|
||||
|
||||
import { customFetch } from "../../mutator";
|
||||
|
||||
type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
|
||||
|
||||
/**
|
||||
* Return dashboard KPIs and time-series data for accessible boards.
|
||||
* @summary Dashboard Metrics
|
||||
*/
|
||||
export type dashboardMetricsApiV1MetricsDashboardGetResponse200 = {
|
||||
data: DashboardMetrics;
|
||||
status: 200;
|
||||
};
|
||||
|
||||
export type dashboardMetricsApiV1MetricsDashboardGetResponse422 = {
|
||||
data: HTTPValidationError;
|
||||
status: 422;
|
||||
};
|
||||
|
||||
export type dashboardMetricsApiV1MetricsDashboardGetResponseSuccess =
|
||||
dashboardMetricsApiV1MetricsDashboardGetResponse200 & {
|
||||
headers: Headers;
|
||||
};
|
||||
export type dashboardMetricsApiV1MetricsDashboardGetResponseError =
|
||||
dashboardMetricsApiV1MetricsDashboardGetResponse422 & {
|
||||
headers: Headers;
|
||||
};
|
||||
|
||||
export type dashboardMetricsApiV1MetricsDashboardGetResponse =
|
||||
| dashboardMetricsApiV1MetricsDashboardGetResponseSuccess
|
||||
| dashboardMetricsApiV1MetricsDashboardGetResponseError;
|
||||
|
||||
export const getDashboardMetricsApiV1MetricsDashboardGetUrl = (
|
||||
params?: DashboardMetricsApiV1MetricsDashboardGetParams,
|
||||
) => {
|
||||
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/metrics/dashboard?${stringifiedParams}`
|
||||
: `/api/v1/metrics/dashboard`;
|
||||
};
|
||||
|
||||
export const dashboardMetricsApiV1MetricsDashboardGet = async (
|
||||
params?: DashboardMetricsApiV1MetricsDashboardGetParams,
|
||||
options?: RequestInit,
|
||||
): Promise<dashboardMetricsApiV1MetricsDashboardGetResponse> => {
|
||||
return customFetch<dashboardMetricsApiV1MetricsDashboardGetResponse>(
|
||||
getDashboardMetricsApiV1MetricsDashboardGetUrl(params),
|
||||
{
|
||||
...options,
|
||||
method: "GET",
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export const getDashboardMetricsApiV1MetricsDashboardGetQueryKey = (
|
||||
params?: DashboardMetricsApiV1MetricsDashboardGetParams,
|
||||
) => {
|
||||
return [`/api/v1/metrics/dashboard`, ...(params ? [params] : [])] as const;
|
||||
};
|
||||
|
||||
export const getDashboardMetricsApiV1MetricsDashboardGetQueryOptions = <
|
||||
TData = Awaited<ReturnType<typeof dashboardMetricsApiV1MetricsDashboardGet>>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
params?: DashboardMetricsApiV1MetricsDashboardGetParams,
|
||||
options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<ReturnType<typeof dashboardMetricsApiV1MetricsDashboardGet>>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
) => {
|
||||
const { query: queryOptions, request: requestOptions } = options ?? {};
|
||||
|
||||
const queryKey =
|
||||
queryOptions?.queryKey ??
|
||||
getDashboardMetricsApiV1MetricsDashboardGetQueryKey(params);
|
||||
|
||||
const queryFn: QueryFunction<
|
||||
Awaited<ReturnType<typeof dashboardMetricsApiV1MetricsDashboardGet>>
|
||||
> = ({ signal }) =>
|
||||
dashboardMetricsApiV1MetricsDashboardGet(params, {
|
||||
signal,
|
||||
...requestOptions,
|
||||
});
|
||||
|
||||
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
|
||||
Awaited<ReturnType<typeof dashboardMetricsApiV1MetricsDashboardGet>>,
|
||||
TError,
|
||||
TData
|
||||
> & { queryKey: DataTag<QueryKey, TData, TError> };
|
||||
};
|
||||
|
||||
export type DashboardMetricsApiV1MetricsDashboardGetQueryResult = NonNullable<
|
||||
Awaited<ReturnType<typeof dashboardMetricsApiV1MetricsDashboardGet>>
|
||||
>;
|
||||
export type DashboardMetricsApiV1MetricsDashboardGetQueryError =
|
||||
HTTPValidationError;
|
||||
|
||||
export function useDashboardMetricsApiV1MetricsDashboardGet<
|
||||
TData = Awaited<ReturnType<typeof dashboardMetricsApiV1MetricsDashboardGet>>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
params: undefined | DashboardMetricsApiV1MetricsDashboardGetParams,
|
||||
options: {
|
||||
query: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<ReturnType<typeof dashboardMetricsApiV1MetricsDashboardGet>>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
> &
|
||||
Pick<
|
||||
DefinedInitialDataOptions<
|
||||
Awaited<ReturnType<typeof dashboardMetricsApiV1MetricsDashboardGet>>,
|
||||
TError,
|
||||
Awaited<ReturnType<typeof dashboardMetricsApiV1MetricsDashboardGet>>
|
||||
>,
|
||||
"initialData"
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): DefinedUseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
};
|
||||
export function useDashboardMetricsApiV1MetricsDashboardGet<
|
||||
TData = Awaited<ReturnType<typeof dashboardMetricsApiV1MetricsDashboardGet>>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
params?: DashboardMetricsApiV1MetricsDashboardGetParams,
|
||||
options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<ReturnType<typeof dashboardMetricsApiV1MetricsDashboardGet>>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
> &
|
||||
Pick<
|
||||
UndefinedInitialDataOptions<
|
||||
Awaited<ReturnType<typeof dashboardMetricsApiV1MetricsDashboardGet>>,
|
||||
TError,
|
||||
Awaited<ReturnType<typeof dashboardMetricsApiV1MetricsDashboardGet>>
|
||||
>,
|
||||
"initialData"
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
};
|
||||
export function useDashboardMetricsApiV1MetricsDashboardGet<
|
||||
TData = Awaited<ReturnType<typeof dashboardMetricsApiV1MetricsDashboardGet>>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
params?: DashboardMetricsApiV1MetricsDashboardGetParams,
|
||||
options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<ReturnType<typeof dashboardMetricsApiV1MetricsDashboardGet>>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
};
|
||||
/**
|
||||
* @summary Dashboard Metrics
|
||||
*/
|
||||
|
||||
export function useDashboardMetricsApiV1MetricsDashboardGet<
|
||||
TData = Awaited<ReturnType<typeof dashboardMetricsApiV1MetricsDashboardGet>>,
|
||||
TError = HTTPValidationError,
|
||||
>(
|
||||
params?: DashboardMetricsApiV1MetricsDashboardGetParams,
|
||||
options?: {
|
||||
query?: Partial<
|
||||
UseQueryOptions<
|
||||
Awaited<ReturnType<typeof dashboardMetricsApiV1MetricsDashboardGet>>,
|
||||
TError,
|
||||
TData
|
||||
>
|
||||
>;
|
||||
request?: SecondParameter<typeof customFetch>;
|
||||
},
|
||||
queryClient?: QueryClient,
|
||||
): UseQueryResult<TData, TError> & {
|
||||
queryKey: DataTag<QueryKey, TData, TError>;
|
||||
} {
|
||||
const queryOptions = getDashboardMetricsApiV1MetricsDashboardGetQueryOptions(
|
||||
params,
|
||||
options,
|
||||
);
|
||||
|
||||
const query = useQuery(queryOptions, queryClient) as UseQueryResult<
|
||||
TData,
|
||||
TError
|
||||
> & { queryKey: DataTag<QueryKey, TData, TError> };
|
||||
|
||||
return { ...query, queryKey: queryOptions.queryKey };
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
/**
|
||||
* Generated by orval v8.3.0 🍺
|
||||
* Do not edit manually.
|
||||
* Mission Control API
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
import type { ActivityEventReadRouteParams } from "./activityEventReadRouteParams";
|
||||
|
||||
/**
|
||||
* Serialized activity event payload returned by activity endpoints.
|
||||
*/
|
||||
export interface ActivityEventRead {
|
||||
agent_id: string | null;
|
||||
board_id?: string | null;
|
||||
created_at: string;
|
||||
event_type: string;
|
||||
id: string;
|
||||
message: string | null;
|
||||
route_name?: string | null;
|
||||
route_params?: ActivityEventReadRouteParams;
|
||||
task_id: string | null;
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
/**
|
||||
* Generated by orval v8.3.0 🍺
|
||||
* Do not edit manually.
|
||||
* Mission Control API
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
export type ActivityEventReadRouteParams = { [key: string]: string } | null;
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
/**
|
||||
* Generated by orval v8.3.0 🍺
|
||||
* Do not edit manually.
|
||||
* Mission Control API
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Denormalized task-comment feed item enriched with task and board fields.
|
||||
*/
|
||||
export interface ActivityTaskCommentFeedItemRead {
|
||||
agent_id: string | null;
|
||||
agent_name?: string | null;
|
||||
agent_role?: string | null;
|
||||
board_id: string;
|
||||
board_name: string;
|
||||
created_at: string;
|
||||
id: string;
|
||||
message: string | null;
|
||||
task_id: string;
|
||||
task_title: string;
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
/**
|
||||
* Generated by orval v8.3.0 🍺
|
||||
* Do not edit manually.
|
||||
* Mission Control API
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
import type { AgentCreateHeartbeatConfig } from "./agentCreateHeartbeatConfig";
|
||||
import type { AgentCreateIdentityProfile } from "./agentCreateIdentityProfile";
|
||||
|
||||
/**
|
||||
* Payload for creating a new agent.
|
||||
*/
|
||||
export interface AgentCreate {
|
||||
/** Board id that scopes this agent. Omit only when policy allows global agents. */
|
||||
board_id?: string | null;
|
||||
/** Runtime heartbeat behavior overrides for this agent. */
|
||||
heartbeat_config?: AgentCreateHeartbeatConfig;
|
||||
/** Optional profile hints used by routing and policy checks. */
|
||||
identity_profile?: AgentCreateIdentityProfile;
|
||||
/** Template that helps define initial intent and behavior. */
|
||||
identity_template?: string | null;
|
||||
/**
|
||||
* Human-readable agent display name.
|
||||
* @minLength 1
|
||||
*/
|
||||
name: string;
|
||||
/** Template representing deeper agent instructions. */
|
||||
soul_template?: string | null;
|
||||
/** Current lifecycle state used by coordinator logic. */
|
||||
status?: string;
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
/**
|
||||
* Generated by orval v8.3.0 🍺
|
||||
* Do not edit manually.
|
||||
* Mission Control API
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Runtime heartbeat behavior overrides for this agent.
|
||||
*/
|
||||
export type AgentCreateHeartbeatConfig = { [key: string]: unknown } | null;
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
/**
|
||||
* Generated by orval v8.3.0 🍺
|
||||
* Do not edit manually.
|
||||
* Mission Control API
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Optional profile hints used by routing and policy checks.
|
||||
*/
|
||||
export type AgentCreateIdentityProfile = { [key: string]: unknown } | null;
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
/**
|
||||
* Generated by orval v8.3.0 🍺
|
||||
* Do not edit manually.
|
||||
* Mission Control API
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Agent-authenticated liveness payload for agent route probes.
|
||||
*/
|
||||
export interface AgentHealthStatusResponse {
|
||||
/** Authenticated agent id derived from `X-Agent-Token`. */
|
||||
agent_id: string;
|
||||
/** Board scope for the authenticated agent, when applicable. */
|
||||
board_id?: string | null;
|
||||
/** Gateway owning the authenticated agent. */
|
||||
gateway_id: string;
|
||||
/** Whether the authenticated agent is the board lead. */
|
||||
is_board_lead: boolean;
|
||||
/** Indicates whether the probe check succeeded. */
|
||||
ok: boolean;
|
||||
/** Current persisted lifecycle status for the authenticated agent. */
|
||||
status: string;
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
/**
|
||||
* Generated by orval v8.3.0 🍺
|
||||
* Do not edit manually.
|
||||
* Mission Control API
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Heartbeat status payload sent by agents.
|
||||
*/
|
||||
export interface AgentHeartbeat {
|
||||
/** Agent health status string. */
|
||||
status?: string | null;
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
/**
|
||||
* Generated by orval v8.3.0 🍺
|
||||
* Do not edit manually.
|
||||
* Mission Control API
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Heartbeat payload used to create an agent lazily.
|
||||
*/
|
||||
export interface AgentHeartbeatCreate {
|
||||
/** Optional board context for bootstrap. */
|
||||
board_id?: string | null;
|
||||
/**
|
||||
* Display name assigned during first heartbeat bootstrap.
|
||||
* @minLength 1
|
||||
*/
|
||||
name: string;
|
||||
/** Agent health status string. */
|
||||
status?: string | null;
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
/**
|
||||
* Generated by orval v8.3.0 🍺
|
||||
* Do not edit manually.
|
||||
* Mission Control API
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Nudge message payload for pinging an agent.
|
||||
*/
|
||||
export interface AgentNudge {
|
||||
/**
|
||||
* Short message to direct an agent toward immediate attention.
|
||||
* @minLength 1
|
||||
*/
|
||||
message: string;
|
||||
}
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
/**
|
||||
* Generated by orval v8.3.0 🍺
|
||||
* Do not edit manually.
|
||||
* Mission Control API
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
import type { AgentReadHeartbeatConfig } from "./agentReadHeartbeatConfig";
|
||||
import type { AgentReadIdentityProfile } from "./agentReadIdentityProfile";
|
||||
|
||||
/**
|
||||
* Public agent representation returned by the API.
|
||||
*/
|
||||
export interface AgentRead {
|
||||
/** Board id that scopes this agent. Omit only when policy allows global agents. */
|
||||
board_id?: string | null;
|
||||
/** Creation timestamp. */
|
||||
created_at: string;
|
||||
/** Gateway UUID that manages this agent. */
|
||||
gateway_id: string;
|
||||
/** Runtime heartbeat behavior overrides for this agent. */
|
||||
heartbeat_config?: AgentReadHeartbeatConfig;
|
||||
/** Agent UUID. */
|
||||
id: string;
|
||||
/** Optional profile hints used by routing and policy checks. */
|
||||
identity_profile?: AgentReadIdentityProfile;
|
||||
/** Template that helps define initial intent and behavior. */
|
||||
identity_template?: string | null;
|
||||
/** Whether this agent is the board lead. */
|
||||
is_board_lead?: boolean;
|
||||
/** Whether this agent is the primary gateway agent. */
|
||||
is_gateway_main?: boolean;
|
||||
/** Last heartbeat timestamp. */
|
||||
last_seen_at?: string | null;
|
||||
/**
|
||||
* Human-readable agent display name.
|
||||
* @minLength 1
|
||||
*/
|
||||
name: string;
|
||||
/** Optional openclaw session token. */
|
||||
openclaw_session_id?: string | null;
|
||||
/** Template representing deeper agent instructions. */
|
||||
soul_template?: string | null;
|
||||
/** Current lifecycle state used by coordinator logic. */
|
||||
status?: string;
|
||||
/** Last update timestamp. */
|
||||
updated_at: string;
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
/**
|
||||
* Generated by orval v8.3.0 🍺
|
||||
* Do not edit manually.
|
||||
* Mission Control API
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Runtime heartbeat behavior overrides for this agent.
|
||||
*/
|
||||
export type AgentReadHeartbeatConfig = { [key: string]: unknown } | null;
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
/**
|
||||
* Generated by orval v8.3.0 🍺
|
||||
* Do not edit manually.
|
||||
* Mission Control API
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Optional profile hints used by routing and policy checks.
|
||||
*/
|
||||
export type AgentReadIdentityProfile = { [key: string]: unknown } | null;
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
/**
|
||||
* Generated by orval v8.3.0 🍺
|
||||
* Do not edit manually.
|
||||
* Mission Control API
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
import type { AgentUpdateHeartbeatConfig } from "./agentUpdateHeartbeatConfig";
|
||||
import type { AgentUpdateIdentityProfile } from "./agentUpdateIdentityProfile";
|
||||
|
||||
/**
|
||||
* Payload for patching an existing agent.
|
||||
*/
|
||||
export interface AgentUpdate {
|
||||
/** Optional new board assignment. */
|
||||
board_id?: string | null;
|
||||
/** Optional heartbeat policy override. */
|
||||
heartbeat_config?: AgentUpdateHeartbeatConfig;
|
||||
/** Optional identity profile update values. */
|
||||
identity_profile?: AgentUpdateIdentityProfile;
|
||||
/** Optional replacement identity template. */
|
||||
identity_template?: string | null;
|
||||
/** Whether this agent is treated as the board gateway main. */
|
||||
is_gateway_main?: boolean | null;
|
||||
/** Optional replacement display name. */
|
||||
name?: string | null;
|
||||
/** Optional replacement soul template. */
|
||||
soul_template?: string | null;
|
||||
/** Optional replacement lifecycle status. */
|
||||
status?: string | null;
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
/**
|
||||
* Generated by orval v8.3.0 🍺
|
||||
* Do not edit manually.
|
||||
* Mission Control API
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Optional heartbeat policy override.
|
||||
*/
|
||||
export type AgentUpdateHeartbeatConfig = { [key: string]: unknown } | null;
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
/**
|
||||
* Generated by orval v8.3.0 🍺
|
||||
* Do not edit manually.
|
||||
* Mission Control API
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Optional identity profile update values.
|
||||
*/
|
||||
export type AgentUpdateIdentityProfile = { [key: string]: unknown } | null;
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
/**
|
||||
* Generated by orval v8.3.0 🍺
|
||||
* Do not edit manually.
|
||||
* Mission Control API
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
import type { ApprovalCreatePayload } from "./approvalCreatePayload";
|
||||
import type { ApprovalCreateRubricScores } from "./approvalCreateRubricScores";
|
||||
import type { ApprovalCreateStatus } from "./approvalCreateStatus";
|
||||
|
||||
/**
|
||||
* Payload for creating a new approval request.
|
||||
*/
|
||||
export interface ApprovalCreate {
|
||||
action_type: string;
|
||||
agent_id?: string | null;
|
||||
/**
|
||||
* @minimum 0
|
||||
* @maximum 100
|
||||
*/
|
||||
confidence: number;
|
||||
lead_reasoning?: string | null;
|
||||
payload?: ApprovalCreatePayload;
|
||||
rubric_scores?: ApprovalCreateRubricScores;
|
||||
status?: ApprovalCreateStatus;
|
||||
task_id?: string | null;
|
||||
task_ids?: string[];
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
/**
|
||||
* Generated by orval v8.3.0 🍺
|
||||
* Do not edit manually.
|
||||
* Mission Control API
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
export type ApprovalCreatePayload = { [key: string]: unknown } | null;
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
/**
|
||||
* Generated by orval v8.3.0 🍺
|
||||
* Do not edit manually.
|
||||
* Mission Control API
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
export type ApprovalCreateRubricScores = { [key: string]: number } | null;
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
/**
|
||||
* Generated by orval v8.3.0 🍺
|
||||
* Do not edit manually.
|
||||
* Mission Control API
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
export type ApprovalCreateStatus =
|
||||
(typeof ApprovalCreateStatus)[keyof typeof ApprovalCreateStatus];
|
||||
|
||||
export const ApprovalCreateStatus = {
|
||||
pending: "pending",
|
||||
approved: "approved",
|
||||
rejected: "rejected",
|
||||
} as const;
|
||||