mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-24 08:57:25 +00:00
77d5ff58d3
* feat(fleet): add Fleet Actions tab for cross-node bulk operations Introduces a new "Actions" sub-tab in Fleet view with two Skipper+ cards that fill gaps in the existing surface: - Stop fleet by label: matches a label name across every node and stops every stack assigned to it, reporting per-node and per-stack results. - Bulk label assign: applies the same label set to many stacks on one node in a single round trip. Other bulk operations stay in their existing homes (sidebar bulk mode, Schedules, NodeUpdatesSheet) to avoid duplicate surfaces. Backend: - POST /api/fleet/labels/fleet-stop (gateway-orchestrated, multi-node) - POST /api/fleet-actions/labels/bulk-assign (per-node, capped at 1000) - Tightens /api/fleet proxy-exempt prefix to /api/fleet/ so /api/fleet-actions/* is routed through the proxy for per-node calls. - Exports activeBulkActions from labels.ts so fleet-stop and label-action share the per-node lock and cannot double-stop the same containers. - Extracts containerActionForStack helper from stacks.ts for reuse. * chore(fleet): rename Actions tab to Fleet Actions and reorder Fleet sub-tabs - Tab label "Actions" -> "Fleet Actions" so the surface is unambiguous alongside Schedules and the sidebar bulk bar. - Reorder Fleet sub-tabs as Overview / Snapshots / Status | Deployments / Traffic / Fleet Actions, with the separator after Status. - Rename "Traffic · Routing" -> "Traffic" and update Sencho Mesh docs to match the shorter label. - Update Fleet Actions docs to the new tab name and placement.
50 lines
1.6 KiB
TypeScript
50 lines
1.6 KiB
TypeScript
import { Square, Tags } from 'lucide-react';
|
|
import { useLicense } from '@/context/LicenseContext';
|
|
import type { FleetNode } from '@/components/FleetView/types';
|
|
import { LabelFleetStopCard } from './cards/LabelFleetStopCard';
|
|
import { BulkLabelAssignCard } from './cards/BulkLabelAssignCard';
|
|
|
|
interface Props {
|
|
nodes: FleetNode[];
|
|
}
|
|
|
|
export function FleetActionsTab({ nodes }: Props) {
|
|
const { isPaid } = useLicense();
|
|
|
|
if (nodes.length === 0) {
|
|
return (
|
|
<div className="text-sm text-stat-subtitle">Add a node to the fleet to use bulk actions.</div>
|
|
);
|
|
}
|
|
|
|
if (!isPaid) {
|
|
// Both actions are Skipper+. Community users see a calm empty state with
|
|
// upgrade context rather than a stripped-down launcher.
|
|
return (
|
|
<EmptyState />
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
|
<LabelFleetStopCard nodes={nodes} accentTone="rose" icon={Square} />
|
|
<BulkLabelAssignCard nodes={nodes} accentTone="purple" icon={Tags} />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function EmptyState() {
|
|
return (
|
|
<div className="rounded-lg border border-card-border/60 bg-card p-8 text-center">
|
|
<div className="mx-auto mb-3 inline-flex h-10 w-10 items-center justify-center rounded-md bg-glass-highlight">
|
|
<Tags className="h-5 w-5 text-stat-subtitle" strokeWidth={1.5} />
|
|
</div>
|
|
<h3 className="text-sm font-medium text-stat-value mb-1">Fleet-wide bulk actions</h3>
|
|
<p className="text-xs text-stat-subtitle max-w-md mx-auto">
|
|
Stop stacks across every node by label name, and assign labels to many
|
|
stacks in one shot. Available on Skipper and Admiral.
|
|
</p>
|
|
</div>
|
|
);
|
|
}
|