mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-24 08:57:25 +00:00
feat(schedules): next-24h timeline + merge auto-update into schedules (#681)
* feat(backend): add stack update-preview endpoint for readiness board Adds GET /api/stacks/:stackName/update-preview that returns per-image semver diff, bump classification, and a stack-level summary powering the Auto-Update readiness board. - New UpdatePreviewService parses compose images, inspects local digests, fetches remote digests and tag lists, and finds the highest compatible semver tag. - Major bumps are flagged blocked until human review; unknown bumps rank below real semver so they cannot mask a major. - Rollback target is reconstructed through parseImageRef to preserve registry ports and drop the Docker Hub library/ prefix. - Registry helpers (httpGet, auth token, digest, tag list, ref parse) are extracted into registry-api.ts and shared with ImageUpdateService. - 28 Vitest cases cover parse, selection, bump math, digest rebuilds, blocked policy, and rollback target construction. * feat(schedules): next-24h timeline, merge auto-update crud, add readiness board Replace the flat task table with a Timeline view as the default, showing the next 24 hours of scheduled work across four lanes (Restart, Update, Scan, Prune) with a live now rail and per-firing pills. The All tasks tab preserves the existing CRUD surface. Merge Auto-update Stack into Schedules as a first-class action and replace the standalone Auto-Update Policies view with a per-stack Readiness board that surfaces version diffs, risk tags, changelog previews, and rollback targets sourced from the stack update-preview endpoint.
This commit is contained in:
+28
-1
@@ -26,6 +26,7 @@ import { MonitorService } from './services/MonitorService';
|
||||
import { AutoHealService } from './services/AutoHealService';
|
||||
import { DockerEventManager } from './services/DockerEventManager';
|
||||
import { ImageUpdateService } from './services/ImageUpdateService';
|
||||
import { UpdatePreviewService } from './services/UpdatePreviewService';
|
||||
import { templateService } from './services/TemplateService';
|
||||
import { ErrorParser } from './utils/ErrorParser';
|
||||
import { NodeRegistry } from './services/NodeRegistry';
|
||||
@@ -5198,6 +5199,21 @@ app.post('/api/stacks/:stackName/start', async (req: Request, res: Response) =>
|
||||
}
|
||||
});
|
||||
|
||||
// Update preview: semver diff, risk tagging, rollback target for the readiness board
|
||||
app.get('/api/stacks/:stackName/update-preview', async (req: Request, res: Response) => {
|
||||
const stackName = req.params.stackName as string;
|
||||
if (!isValidStackName(stackName)) {
|
||||
return res.status(400).json({ error: 'Invalid stack name' });
|
||||
}
|
||||
try {
|
||||
const preview = await UpdatePreviewService.getInstance().getPreview(req.nodeId, stackName);
|
||||
res.json(preview);
|
||||
} catch (error) {
|
||||
console.error(`[Stacks] Update preview failed: ${stackName}`, error);
|
||||
res.status(500).json({ error: 'Failed to compute update preview' });
|
||||
}
|
||||
});
|
||||
|
||||
// Update stack: pull images and recreate containers
|
||||
app.post('/api/stacks/:stackName/update', async (req: Request, res: Response) => {
|
||||
const stackName = req.params.stackName as string;
|
||||
@@ -6428,7 +6444,18 @@ app.get('/api/scheduled-tasks', (req: Request, res: Response): void => {
|
||||
} else if (excludeAction) {
|
||||
tasks = tasks.filter(t => t.action !== excludeAction);
|
||||
}
|
||||
res.json(tasks);
|
||||
|
||||
// Timeline view needs every firing inside a rolling window, not just the next run.
|
||||
const scheduler = SchedulerService.getInstance();
|
||||
const windowHours = Math.min(Math.max(Number(req.query.window_hours) || 24, 1), 168);
|
||||
const from = Date.now();
|
||||
const to = from + windowHours * 60 * 60 * 1000;
|
||||
const enriched = tasks.map(t => ({
|
||||
...t,
|
||||
next_runs: t.enabled === 1 ? scheduler.calculateRunsWithin(t.cron_expression, from, to) : [],
|
||||
}));
|
||||
|
||||
res.json(enriched);
|
||||
} catch (error) {
|
||||
console.error('[ScheduledTasks] List error:', error);
|
||||
res.status(500).json({ error: 'Failed to fetch scheduled tasks' });
|
||||
|
||||
Reference in New Issue
Block a user