mirror of
https://github.com/Dvorinka/Containr.git
synced 2026-10-28 15:51:26 +00:00
feat(environments): env CRUD, workspace switcher, CLI + MCP parity (#68)
Environment lanes existed as seeded rows (production/preview/development) with a per-service environment label, but there was no way to list, create, or delete them. Adds the management surface and the switcher: - GET /projects/:id/environments with live service counts (sqlc) - POST /projects/:id/environments — lowercase dns-label names, 1-50 chars, unique per project (409 on dupe) - DELETE /environments/:id — refuses while it holds services (409) - Workspace service list gains env filter chips with counts plus an inline "+ env" creator - CLI: containr environments list|create|delete (--yes on delete); MCP: containr_environments_list/create/delete (delete needs confirm) - OpenAPI: new Environments tag + ProjectEnvironment schema Live-verified: list counts, name validation, dupe 409, empty delete, non-empty 409, CLI list. Generated with [Devin](https://devin.ai) Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
dd7b735b38
commit
60145f7b21
13 files changed
+727
-6
No files matched your search
@@ -1321,6 +1321,34 @@ export async function listServicesByProject(projectId: string): Promise<ServiceE
|
||||
return normalizeServiceArray(rows);
|
||||
}
|
||||
|
||||
export interface ProjectEnvironment {
|
||||
id: string;
|
||||
name: string;
|
||||
project_id: string;
|
||||
service_count: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export async function listProjectEnvironments(projectId: string): Promise<ProjectEnvironment[]> {
|
||||
const payload = await requestJson<{ environments?: ProjectEnvironment[] }>(
|
||||
`/projects/${projectId}/environments`,
|
||||
);
|
||||
return payload.environments ?? [];
|
||||
}
|
||||
|
||||
export async function createProjectEnvironment(projectId: string, name: string): Promise<ProjectEnvironment> {
|
||||
const payload = await requestJson<{ environment: ProjectEnvironment }>(
|
||||
`/projects/${projectId}/environments`,
|
||||
{ method: 'POST', body: JSON.stringify({ name }) },
|
||||
);
|
||||
return payload.environment;
|
||||
}
|
||||
|
||||
export async function deleteProjectEnvironment(environmentId: string): Promise<void> {
|
||||
await requestJson(`/environments/${encodeURIComponent(environmentId)}`, { method: 'DELETE' });
|
||||
}
|
||||
|
||||
export async function getServiceById(serviceId: string): Promise<ServiceEntity> {
|
||||
const payload = await requestJson<RawService | { service?: RawService }>(`/services/${serviceId}`);
|
||||
const row = (payload as { service?: RawService }).service ?? (payload as RawService);
|
||||
|
||||
Reference in new issue
Block a user