mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-13 04:06:59 +00:00
feat(auto-update): add auto-update policies and fix image update detection (#297)
* feat(auto-update): add auto-update policies and fix image update detection Auto-Update Policies (Skipper+ tier): - New scheduled task action type 'update' for check-then-update flow - Dedicated AutoUpdatePoliciesView with CRUD, cron presets, and run history - Conditional tier gating: Skipper gets auto-update, Admiral gets full scheduled ops - Backend executeUpdate: checks digests, pulls only if newer, atomic redeploy Image Update Detection fixes (all tiers): - Fix stack name key mismatch: use working_dir label instead of project label - Add 5-minute periodic frontend polling for background check results - Replace fixed 3s timeout with polling-based manual refresh via /api/image-updates/status - Clear update status after successful stack update * fix(ui): remove Skipper tier badge from Auto-Update Policies header * fix(ui): remove auto-update action from Scheduled Operations view Admiral users have a dedicated Auto-Update view — showing update tasks in Scheduled Operations too was confusing duplication. Each view now owns a distinct, non-overlapping set of action types. * fix(auto-update): fix node-stack linking and add All Stacks option - Stack dropdown now re-fetches when node selection changes using fetchForNode, and resets the selected stack - Node selector moved above stack selector with stack disabled until a node is picked - Added "All Stacks" wildcard option that checks and updates every stack on the selected node - Backend executeUpdate refactored to iterate over all stacks when target_id is "*", with per-stack error isolation * refactor(ui): replace Select dropdowns with searchable Combobox component Add a reusable Combobox component with inline search and use it for Node/Stack selectors in both Auto-Update Policies and Scheduled Operations dialogs. Also fixes node-stack linking bug where changing node didn't update the stack list. * fix(ui): resolve CI TypeScript errors in Combobox and ScheduledOperationsView Add missing searchPlaceholder prop to ComboboxProps interface and remove dead 'update' action filter that conflicted with the narrowed type union. * fix(ui): use Geist Sans font in toast component The toast renders via React portal on document.body, bypassing the app's font inheritance. Add explicit font-family declaration using var(--font-sans) to match Sencho's design system.
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
import https from 'https';
|
||||
import http from 'http';
|
||||
import path from 'path';
|
||||
import DockerController from './DockerController';
|
||||
import { DatabaseService } from './DatabaseService';
|
||||
import { RegistryService } from './RegistryService';
|
||||
import { NodeRegistry } from './NodeRegistry';
|
||||
|
||||
// ─── Image ref parsing ────────────────────────────────────────────────────────
|
||||
|
||||
@@ -230,14 +232,22 @@ export class ImageUpdateService {
|
||||
private async checkNode(nodeId: number, db: DatabaseService) {
|
||||
const docker = DockerController.getInstance(nodeId);
|
||||
const containers = await docker.getAllContainers();
|
||||
const composeDir = path.resolve(NodeRegistry.getInstance().getComposeDir(nodeId));
|
||||
|
||||
// stackName → set of image refs used by that stack
|
||||
// Key by directory name (matching FileSystemService.getStacks()) rather than
|
||||
// com.docker.compose.project label, which diverges when compose files set `name:`.
|
||||
const stackImages = new Map<string, Set<string>>();
|
||||
|
||||
for (const c of containers) {
|
||||
const stackName: string | undefined = c.Labels?.['com.docker.compose.project'];
|
||||
if (!stackName) continue;
|
||||
const workingDir: string | undefined = c.Labels?.['com.docker.compose.project.working_dir'];
|
||||
if (!workingDir) continue;
|
||||
|
||||
// Only consider containers managed under COMPOSE_DIR
|
||||
const resolved = path.resolve(workingDir);
|
||||
if (resolved !== composeDir && !resolved.startsWith(composeDir + path.sep)) continue;
|
||||
|
||||
const stackName = path.basename(resolved);
|
||||
const imageRef: string = c.Image ?? '';
|
||||
if (!imageRef || imageRef.startsWith('sha256:')) continue;
|
||||
|
||||
@@ -270,7 +280,7 @@ export class ImageUpdateService {
|
||||
}
|
||||
}
|
||||
|
||||
private async checkImage(docker: DockerController, imageRef: string): Promise<boolean> {
|
||||
public async checkImage(docker: DockerController, imageRef: string): Promise<boolean> {
|
||||
const parsed = parseImageRef(imageRef);
|
||||
if (!parsed) return false;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user