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
|
# Dependencies
|
||||||
node_modules/
|
node_modules/
|
||||||
.venv/
|
.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.
|
# Admin credentials for Mission Control
|
||||||
# Use `auto` to target the same host currently serving Mission Control on port 8000.
|
ADMIN_PASSWORD=change-me-to-a-strong-password
|
||||||
# Example explicit override: https://mc.example.com
|
AUTH_SECRET=generate-a-random-32-char-string-here
|
||||||
NEXT_PUBLIC_API_URL=auto
|
|
||||||
|
|
||||||
# Auth mode: clerk or local.
|
# OpenClaw paths (defaults shown - override if your setup differs)
|
||||||
# - clerk: Clerk sign-in flow
|
# OPENCLAW_DIR=/root/.openclaw
|
||||||
# - local: shared bearer token entered in UI
|
# OPENCLAW_WORKSPACE=/root/.openclaw/workspace
|
||||||
NEXT_PUBLIC_AUTH_MODE=local
|
|
||||||
|
|
||||||
# Clerk auth (used when NEXT_PUBLIC_AUTH_MODE=clerk)
|
# Branding (customize for your instance)
|
||||||
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=
|
NEXT_PUBLIC_AGENT_NAME=Mission Control
|
||||||
NEXT_PUBLIC_CLERK_SIGN_IN_FALLBACK_REDIRECT_URL=/boards
|
NEXT_PUBLIC_AGENT_EMOJI=🤖
|
||||||
NEXT_PUBLIC_CLERK_AFTER_SIGN_OUT_URL=/
|
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/
|
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||||
.next/
|
|
||||||
.env.local
|
|
||||||
.env
|
|
||||||
out/
|
|
||||||
dist/
|
|
||||||
|
|
||||||
# clerk configuration (can include secrets)
|
# dependencies
|
||||||
/.clerk/
|
/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
|
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`).
|
> **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.
|
||||||
- Uses **React Query** for data fetching.
|
|
||||||
- Supports two auth modes:
|
|
||||||
- **local** shared bearer token mode (self-host default)
|
|
||||||
- **clerk** mode
|
|
||||||
|
|
||||||
## Prerequisites
|
---
|
||||||
|
|
||||||
- Node.js (recommend **18+**) and npm
|
## Features
|
||||||
- Backend running locally (see `../backend/README.md` if present) **or** run the stack via Docker Compose from repo root.
|
|
||||||
|
|
||||||
## 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
|
```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
|
npm install
|
||||||
|
|
||||||
# set env vars (see below)
|
|
||||||
cp .env.example .env.local
|
|
||||||
|
|
||||||
npm run dev
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Open http://localhost:3000.
|
### 2. Configure environment
|
||||||
|
|
||||||
### LAN development
|
|
||||||
|
|
||||||
To bind Next dev server to all interfaces:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run dev:lan
|
cp .env.example .env.local
|
||||||
```
|
```
|
||||||
|
|
||||||
## Environment variables
|
Edit `.env.local`:
|
||||||
|
|
||||||
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:
|
|
||||||
|
|
||||||
```env
|
```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:
|
### 3. Initialize data files
|
||||||
|
|
||||||
- `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:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# from frontend/
|
cp data/cron-jobs.example.json data/cron-jobs.json
|
||||||
ORVAL_INPUT=http://localhost:8000/openapi.json npm run api:gen
|
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
|
### 4. Generate secrets
|
||||||
|
|
||||||
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/`:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run dev # start dev server
|
# Auth secret
|
||||||
npm run build # production build
|
openssl rand -base64 32
|
||||||
npm run start # run the built app
|
|
||||||
npm run lint # eslint
|
# Password (or use a password manager)
|
||||||
npm run test # vitest (with coverage)
|
openssl rand -base64 18
|
||||||
npm run test:watch # watch mode
|
|
||||||
npm run api:gen # regenerate typed API client via Orval
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 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
|
## Troubleshooting
|
||||||
|
|
||||||
### `NEXT_PUBLIC_API_URL` and remote hosts
|
**"Gateway not reachable" / agent data missing**
|
||||||
|
|
||||||
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:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cp .env.example .env.local
|
openclaw status
|
||||||
# then edit .env.local if your backend URL differs
|
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
|
```bash
|
||||||
- Confirm `NEXT_PUBLIC_API_URL` points to the correct host/port.
|
npx tsx scripts/collect-usage.ts
|
||||||
- If accessing from another device (LAN), use a reachable backend URL (not `localhost`).
|
```
|
||||||
|
|
||||||
### Wrong auth mode UI
|
**Build errors after pulling updates**
|
||||||
|
|
||||||
- Ensure `NEXT_PUBLIC_AUTH_MODE` matches backend `AUTH_MODE`.
|
```bash
|
||||||
- For local mode, set `NEXT_PUBLIC_AUTH_MODE=local`.
|
rm -rf .next node_modules
|
||||||
- For Clerk mode, set `NEXT_PUBLIC_AUTH_MODE=clerk` and a real Clerk publishable key.
|
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`.
|
| Layer | Tech |
|
||||||
- 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.
|
| 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/**",
|
".next/**",
|
||||||
"out/**",
|
"out/**",
|
||||||
"build/**",
|
"build/**",
|
||||||
"coverage/**",
|
|
||||||
"next-env.d.ts",
|
"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;
|
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",
|
"name": "mission-control",
|
||||||
"version": "0.1.0",
|
"version": "0.5.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev -H 0.0.0.0",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start": "next start -H 0.0.0.0",
|
||||||
"lint": "eslint",
|
"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"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@clerk/nextjs": "^6.37.3",
|
"@monaco-editor/react": "^4.7.0",
|
||||||
"@radix-ui/react-dialog": "^1.1.15",
|
"@react-three/drei": "^10.7.7",
|
||||||
"@radix-ui/react-popover": "^1.1.15",
|
"@react-three/fiber": "^9.5.0",
|
||||||
"@radix-ui/react-select": "^2.2.6",
|
"@react-three/rapier": "^2.2.0",
|
||||||
"@radix-ui/react-tabs": "^1.1.13",
|
"@tailwindcss/typography": "^0.5.19",
|
||||||
"@radix-ui/react-tooltip": "^1.2.8",
|
"@types/better-sqlite3": "^7.6.13",
|
||||||
"@tanstack/react-query": "^5.90.21",
|
"better-sqlite3": "^12.6.2",
|
||||||
"@tanstack/react-table": "^8.21.3",
|
"date-fns": "^4.1.0",
|
||||||
"cmdk": "^1.1.1",
|
"lucide-react": "^0.563.0",
|
||||||
"next": "16.1.7",
|
"next": "16.1.6",
|
||||||
"react": "19.2.4",
|
"react": "19.2.3",
|
||||||
"react-dom": "19.2.4",
|
"react-dom": "19.2.3",
|
||||||
"react-markdown": "^10.1.0",
|
"react-markdown": "^10.1.0",
|
||||||
"recharts": "^3.7.0",
|
"recharts": "^2.15.4",
|
||||||
"remark-breaks": "^4.0.0",
|
"three": "^0.183.0"
|
||||||
"remark-gfm": "^4.0.1"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@clerk/testing": "^1.13.35",
|
"@tailwindcss/postcss": "^4",
|
||||||
"@testing-library/jest-dom": "^6.9.1",
|
|
||||||
"@testing-library/react": "^16.3.2",
|
|
||||||
"@testing-library/user-event": "^14.6.1",
|
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^19",
|
"@types/react": "^19",
|
||||||
"@types/react-dom": "^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": "^9",
|
||||||
"eslint-config-next": "16.1.6",
|
"eslint-config-next": "16.1.6",
|
||||||
"jsdom": "^25.0.1",
|
"tailwindcss": "^4",
|
||||||
"lucide-react": "^0.563.0",
|
"typescript": "^5"
|
||||||
"orval": "^8.3.0",
|
},
|
||||||
"postcss": "^8.5.6",
|
"description": "Mission Control \u2014 OpenClaw agent dashboard and control center"
|
||||||
"prettier": "^3.8.1",
|
|
||||||
"tailwind-merge": "^3.4.0",
|
|
||||||
"tailwindcss": "^3.4.19",
|
|
||||||
"tailwindcss-animate": "^1.0.7",
|
|
||||||
"typescript": "^5",
|
|
||||||
"vitest": "^4.0.18"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
|
||||||