feat(delivery): the Application page + owner consoles (v2 phase A3-6)
The user-visible payoff of the whole delivery workstream. - (app)/app: four tabs — pipeline (runs + the eight steps + a live console), releases (with demo rollback), production (target summary, confirmed deploy, history), Git. The header answers "is it live": demo URL, live release, health state. - Live console: batches onto an animation frame, stops following the tail the moment the user scrolls away from the bottom, strips ANSI colour codes and carriage-return redraws. A console that yanks the view back is worse than none. - Production panel: the target is shown as the operator recognises their server plus has_secret/ثبت شده. No field anywhere could render a credential. - contracts: the v2 delivery types and seven new WsEventType members. - /admin/sandbox (owner): per-role container counts, running containers, per-org limits, image mapping, stop with the id typed back (audited). A provider without the capability reports an empty list rather than an error. - /admin/domains (owner): every route with its owning app, attach/detach (host typed back), idempotent re-sync. - /projects removed entirely, with a permanent redirect to /app. Tests: 502 API (+3), 78 web (+11); ruff, mypy, tsc and lint clean. Report: docs/plan/reports/agent-3-phase-6.md
This commit is contained in:
@@ -795,7 +795,14 @@ export type WsEventType =
|
||||
| "billing.wallet"
|
||||
| "error.recorded"
|
||||
| "audit.recorded"
|
||||
| "worker.status";
|
||||
| "worker.status"
|
||||
// v2 delivery: CI/CD runs, releases and production deploys (org channel).
|
||||
| "pipeline.queued"
|
||||
| "pipeline.step"
|
||||
| "pipeline.log"
|
||||
| "pipeline.status"
|
||||
| "release.live"
|
||||
| "deploy.status";
|
||||
|
||||
/** One pushed event, as the browser receives it. */
|
||||
export interface WsEvent<T = Record<string, unknown>> {
|
||||
@@ -860,3 +867,195 @@ export interface WsSandboxCommandData {
|
||||
duration_ms: number;
|
||||
truncated: boolean;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* v2 delivery (CI/CD, demo runtime, production deploy) */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
export type PipelineRunStatus =
|
||||
| "queued"
|
||||
| "running"
|
||||
| "succeeded"
|
||||
| "failed"
|
||||
| "cancelled"
|
||||
| "superseded";
|
||||
|
||||
export type PipelineStepStatus = "pending" | "running" | "succeeded" | "failed" | "skipped";
|
||||
|
||||
/** The eight steps of a run, in the order the server executes them. */
|
||||
export const PIPELINE_STEP_NAMES = [
|
||||
"checkout",
|
||||
"setup",
|
||||
"build",
|
||||
"test",
|
||||
"package",
|
||||
"deploy_demo",
|
||||
"healthcheck",
|
||||
"route",
|
||||
] as const;
|
||||
|
||||
export interface PipelineStep {
|
||||
id: string;
|
||||
index: number;
|
||||
name: string;
|
||||
status: PipelineStepStatus;
|
||||
exit_code: number | null;
|
||||
log_tail: string;
|
||||
duration_ms: number;
|
||||
}
|
||||
|
||||
export interface PipelineRun {
|
||||
id: string;
|
||||
project_id: string;
|
||||
branch: string;
|
||||
sha: string;
|
||||
trigger: "engine" | "poll" | "manual";
|
||||
status: PipelineRunStatus;
|
||||
error_summary: string;
|
||||
started_at: string | null;
|
||||
finished_at: string | null;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
export interface PipelineRunDetail extends PipelineRun {
|
||||
steps: PipelineStep[];
|
||||
}
|
||||
|
||||
export interface Release {
|
||||
id: string;
|
||||
project_id: string;
|
||||
run_id: string;
|
||||
sha: string;
|
||||
is_demo_live: boolean;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
export interface AppRuntime {
|
||||
project_id: string;
|
||||
demo_host: string;
|
||||
demo_url: string;
|
||||
host_port: number | null;
|
||||
status: "provisioning" | "live" | "degraded" | "stopped";
|
||||
current_release_id: string | null;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export type ProductionDeployStatus =
|
||||
| "queued"
|
||||
| "running"
|
||||
| "succeeded"
|
||||
| "failed"
|
||||
| "rolled_back";
|
||||
|
||||
/** The production target as a *user* sees it: never a secret, only a hint. */
|
||||
export interface ProductionTarget {
|
||||
kind: "ssh" | "sftp" | "ftp" | "ftps";
|
||||
host: string;
|
||||
port: number;
|
||||
username: string;
|
||||
auth_type: "password" | "key";
|
||||
remote_path: string;
|
||||
has_secret: boolean;
|
||||
host_fingerprint: string | null;
|
||||
last_tested_at: string | null;
|
||||
last_test_ok: boolean | null;
|
||||
last_test_message: string | null;
|
||||
}
|
||||
|
||||
export interface ProductionDeploy {
|
||||
id: string;
|
||||
project_id: string;
|
||||
kind: string;
|
||||
host: string;
|
||||
status: ProductionDeployStatus;
|
||||
message: string;
|
||||
log_tail: string;
|
||||
release_id: string | null;
|
||||
rolled_back_from: string | null;
|
||||
started_at: string | null;
|
||||
finished_at: string | null;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
export interface ProductionOverview {
|
||||
target: ProductionTarget | null;
|
||||
deploys: ProductionDeploy[];
|
||||
}
|
||||
|
||||
/** Owner console: one managed preview route. */
|
||||
export interface DomainRoute {
|
||||
id: string;
|
||||
host: string;
|
||||
port: number;
|
||||
status: string;
|
||||
protected: boolean;
|
||||
url: string;
|
||||
organization_id: string;
|
||||
project_id: string;
|
||||
project_name: string;
|
||||
created_at: string | null;
|
||||
}
|
||||
|
||||
export interface SuggestedRoute {
|
||||
label: string;
|
||||
host: string;
|
||||
port: number;
|
||||
description: string;
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
export interface DomainSyncResult {
|
||||
ok: boolean;
|
||||
message: string;
|
||||
routes: number;
|
||||
changed: boolean;
|
||||
}
|
||||
|
||||
/* -- live event payloads (channel `org:<id>`) ------------------------------ */
|
||||
|
||||
export interface WsPipelineLogData {
|
||||
run_id: string;
|
||||
step: string;
|
||||
lines: string[];
|
||||
}
|
||||
|
||||
export interface WsPipelineStepData {
|
||||
run_id: string;
|
||||
step: string;
|
||||
index: number;
|
||||
status: PipelineStepStatus;
|
||||
}
|
||||
|
||||
export interface WsPipelineStatusData {
|
||||
run_id: string;
|
||||
project_id: string;
|
||||
status: PipelineRunStatus;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface WsPipelineQueuedData {
|
||||
run_id: string;
|
||||
project_id: string;
|
||||
sha: string;
|
||||
trigger: string;
|
||||
superseded: number;
|
||||
}
|
||||
|
||||
export interface WsReleaseLiveData {
|
||||
project_id: string;
|
||||
run_id?: string;
|
||||
release_id?: string;
|
||||
sha?: string;
|
||||
demo_host?: string;
|
||||
demo_url?: string;
|
||||
rolled_back?: boolean;
|
||||
status?: string;
|
||||
}
|
||||
|
||||
export interface WsDeployStatusData {
|
||||
project_id: string;
|
||||
deploy_id: string;
|
||||
kind: string;
|
||||
status: ProductionDeployStatus;
|
||||
message: string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user