mirror of
https://github.com/Dvorinka/Containr.git
synced 2026-10-28 15:51:26 +00:00
feat: per-service scaling section on service detail
Exposes the existing /scaling/* API in the frontend: replica state, policy create/edit form (min/max, target CPU/memory, enable toggle), manual scale control, and disable-policy action matching the DELETE endpoint's disable-not-remove semantics. Verified live: policy CRUD, state auto-registration on policy create, replica bounds rejection, scheduler dispatch (fails cleanly with "no ready nodes" when no agents are registered). Noted in roadmap: policies are in-memory and lost on restart — tracked as Phase 4 debt. Authored By: TDvorak <[email protected]> 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
8ecc8dcea5
commit
44a1b09dad
3 files changed
+273
-5
No files matched your search
@@ -1482,3 +1482,56 @@ export async function promotePreviewEnvironment(
|
||||
body: JSON.stringify(input),
|
||||
});
|
||||
}
|
||||
|
||||
export type ScalingPolicy = components['schemas']['ScalingPolicy'];
|
||||
|
||||
export type ServiceScalingState = {
|
||||
ServiceID?: string;
|
||||
CurrentReplicas?: number;
|
||||
DesiredReplicas?: number;
|
||||
LastScaleAction?: string;
|
||||
LastScaleDirection?: string;
|
||||
};
|
||||
|
||||
export async function getScalingPolicy(serviceId: string): Promise<ScalingPolicy | null> {
|
||||
try {
|
||||
const payload = await requestJson<{ policy?: ScalingPolicy }>(
|
||||
`/scaling/policies/${encodeURIComponent(serviceId)}`,
|
||||
);
|
||||
return payload.policy ?? null;
|
||||
} catch (error) {
|
||||
if (error instanceof ApiError && error.status === 404) {
|
||||
return null;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function setScalingPolicy(policy: ScalingPolicy): Promise<void> {
|
||||
await requestJson('/scaling/policies', { method: 'POST', body: JSON.stringify(policy) });
|
||||
}
|
||||
|
||||
export async function deleteScalingPolicy(serviceId: string): Promise<void> {
|
||||
await requestJson(`/scaling/policies/${encodeURIComponent(serviceId)}`, { method: 'DELETE' });
|
||||
}
|
||||
|
||||
export async function getServiceScalingState(serviceId: string): Promise<ServiceScalingState | null> {
|
||||
try {
|
||||
const payload = await requestJson<{ state?: ServiceScalingState }>(
|
||||
`/scaling/services/${encodeURIComponent(serviceId)}`,
|
||||
);
|
||||
return payload.state ?? null;
|
||||
} catch (error) {
|
||||
if (error instanceof ApiError && error.status === 404) {
|
||||
return null;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function manualScaleService(serviceId: string, replicas: number, reason = ''): Promise<void> {
|
||||
await requestJson(`/scaling/services/${encodeURIComponent(serviceId)}/scale`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ replicas, reason }),
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user