mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-17 14:08:19 +00:00
feat(fleet): reapply Compose configuration without a version update (#1716)
* feat(fleet): reapply Compose configuration without a version update Add a distinct Fleet Reapply configuration path so Compose-managed nodes can recreate Sencho from the current on-disk project when already up to date, without pulling or rewriting the image reference. * fix(fleet): confirm remote reapply and close concurrent tracker race Require confirmation for remote compose reapply, and lock dispatch before the remote POST so a second request cannot overwrite a successful in-flight tracker. * fix(ui): icon-only Reapply control so Up to date badge can breathe Collapse the Node updates Reapply label into a tooltip so the status pill no longer wraps in the Status column. * feat(editor): Save & Reapply self-stack via fleet compose reapply (#1726) * feat(editor): Save & Reapply self-stack via fleet compose reapply Eligible admins can apply on-disk Compose edits to Sencho's own stack from the editor using the same confirm, dispatch, and reconnect path as Fleet Node Updates. * fix(editor): gate Save & Reapply label to self-stack only Ordinary stacks were labeled Save & Reapply whenever the node was reapply-eligible. Require the selected file to be the self-stack for the toolbar label and diff confirm CTA. * fix(ui): move compose diff action label helper out of dialog module Keep ComposeDiffPreviewDialog component-only so react-refresh Fast Refresh lint passes after the Save and reapply stacked merge.
This commit is contained in:
@@ -4,6 +4,8 @@ import { PreDeployScanDialog } from '../stack/PreDeployScanDialog';
|
||||
import { MissingExternalNetworksDialog } from '../stack/MissingExternalNetworksDialog';
|
||||
import { UpdateReadinessDialog } from '../stack/UpdateReadinessDialog';
|
||||
import { SelfStackProtectedDialog } from '../stack/SelfStackProtectedDialog';
|
||||
import { LocalUpdateConfirmDialog } from '../FleetView/LocalUpdateConfirmDialog';
|
||||
import { ReconnectingOverlay } from '../FleetView/ReconnectingOverlay';
|
||||
import { DeleteStackDialog } from './DeleteStackDialog';
|
||||
import { TakeDownStackDialog } from './TakeDownStackDialog';
|
||||
import { UnsavedChangesDialog } from './UnsavedChangesDialog';
|
||||
@@ -12,9 +14,11 @@ import { GitSourcePanel } from '../stack/GitSourcePanel';
|
||||
import { LogViewer } from '../LogViewer';
|
||||
import { VulnerabilityScanSheet } from '../VulnerabilityScanSheet';
|
||||
import { ComposeDiffPreviewDialog } from '@/components/ComposeDiffPreviewDialog';
|
||||
import { resolveComposeDiffActionLabel } from '@/components/resolveComposeDiffActionLabel';
|
||||
import type { OverlayState } from './hooks/useOverlayState';
|
||||
import type { StackActionsHook } from './hooks/useStackActions';
|
||||
import type { PermissionAction } from '@/context/AuthContext';
|
||||
import type { useComposeReapplyAction } from '../FleetView/hooks/useComposeReapplyAction';
|
||||
|
||||
interface ShellOverlaysProps {
|
||||
overlayState: OverlayState;
|
||||
@@ -27,6 +31,8 @@ interface ShellOverlaysProps {
|
||||
gitSourceOpen: boolean;
|
||||
setGitSourceOpen: (open: boolean) => void;
|
||||
canSelfUpdate: boolean;
|
||||
composeReapply: ReturnType<typeof useComposeReapplyAction>;
|
||||
canSaveAndReapply: boolean;
|
||||
canOfferVolumeRemoval: boolean;
|
||||
onOpenFleetNodeUpdates: () => void;
|
||||
}
|
||||
@@ -42,6 +48,8 @@ export function ShellOverlays({
|
||||
gitSourceOpen,
|
||||
setGitSourceOpen,
|
||||
canSelfUpdate,
|
||||
composeReapply,
|
||||
canSaveAndReapply,
|
||||
canOfferVolumeRemoval,
|
||||
onOpenFleetNodeUpdates,
|
||||
}: ShellOverlaysProps) {
|
||||
@@ -57,6 +65,7 @@ export function ShellOverlays({
|
||||
preDeployAdvisory,
|
||||
missingExternalNetworks, setMissingExternalNetworks,
|
||||
selfStackProtectedOpen, setSelfStackProtectedOpen,
|
||||
composeReapplyCapture, setComposeReapplyCapture,
|
||||
stackMisconfigScanId, setStackMisconfigScanId,
|
||||
diffPreview, setDiffPreview, diffPreviewConfirming, setDiffPreviewConfirming,
|
||||
} = overlayState;
|
||||
@@ -85,6 +94,32 @@ export function ShellOverlays({
|
||||
onOpenFleetUpdates={onOpenFleetNodeUpdates}
|
||||
/>
|
||||
|
||||
<LocalUpdateConfirmDialog
|
||||
open={composeReapplyCapture !== null}
|
||||
mode="reapply"
|
||||
nodeType={composeReapplyCapture?.nodeType ?? 'local'}
|
||||
onOpenChange={(open) => {
|
||||
if (!open) setComposeReapplyCapture(null);
|
||||
}}
|
||||
onConfirm={() => {
|
||||
const capture = composeReapplyCapture;
|
||||
setComposeReapplyCapture(null);
|
||||
if (!capture || composeReapply.dispatching) return;
|
||||
void composeReapply.runReapply({
|
||||
nodeId: capture.nodeId,
|
||||
type: capture.nodeType,
|
||||
name: capture.nodeName,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
|
||||
{composeReapply.reconnecting && (
|
||||
<ReconnectingOverlay
|
||||
preUpdateStartedAt={composeReapply.preUpdateStartedAt}
|
||||
mode="reapply"
|
||||
/>
|
||||
)}
|
||||
|
||||
<UnsavedChangesDialog
|
||||
open={!!pendingUnsavedLoad || !!pendingLeaveAction}
|
||||
onCancel={stackActions.cancelPendingUnsavedLoad}
|
||||
@@ -197,7 +232,7 @@ export function ShellOverlays({
|
||||
language={diffPreview?.language ?? 'yaml'}
|
||||
original={diffPreview?.original ?? ''}
|
||||
modified={diffPreview?.modified ?? ''}
|
||||
actionLabel={diffPreview?.mode === 'save-and-deploy' ? 'Save & deploy' : 'Save'}
|
||||
actionLabel={resolveComposeDiffActionLabel(diffPreview?.mode, canSaveAndReapply)}
|
||||
confirming={diffPreviewConfirming}
|
||||
isDarkMode={isDarkMode}
|
||||
onConfirm={async () => {
|
||||
|
||||
Reference in New Issue
Block a user