Files
portainer/app/react/docker/containers/update/useUpdateContainerImage.ts
T
vvzvlad e63d2ffe9b fix(automation): update a single container instead of redeploying its stack
Clicking "Update" on a stack member (and the native auto-update daemon
updating one) redeployed the whole compose stack instead of updating just
that container. Match Watchtower behaviour: always recreate the single
container with a re-pull. The recreate endpoint preserves config + compose
labels, so the container stays part of its project.

Collapse all update surfaces to a single-container recreate and drop the
now-dead stack-aware routing:
- frontend: "Update now" button, list badge and bulk "Update selected" now
  recreate each container individually; remove standalone/stack/external
  routing, the external refusal, the PortainerStackUpdate gate and the
  stack-update confirm dialog.
- daemon: route every outdated candidate through updateStandalone; remove
  updateStack, the stack/external grouping and the stackDeployer dependency.
- add a regression test asserting a Portainer-managed compose-stack member is
  recreated individually, not stack-redeployed.

Behavioural notes: git/external compose containers are now auto-updated too
(were detect-only), and updating a stack member no longer requires
PortainerStackUpdate (same auth as the normal Recreate action).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 15:21:29 +03:00

54 lines
1.7 KiB
TypeScript

import { QueryClient, useMutation, useQueryClient } from '@tanstack/react-query';
import { withError } from '@/react-tools/react-query';
import { queryKeys as containerQueryKeys } from '../queries/query-keys';
import { applyContainerUpdate } from './applyContainerUpdate';
import { ContainerUpdateContext } from './types';
/**
* Refresh the data affected by a single-container image update: the container
* itself and its image-status badge (so it flips away from "outdated"). A
* single-container recreate doesn't change the stacks list, so that isn't
* invalidated here.
*/
export function invalidateContainerUpdateQueries(
queryClient: QueryClient,
context: ContainerUpdateContext
) {
queryClient.invalidateQueries(
containerQueryKeys.container(context.environmentId, context.id)
);
queryClient.invalidateQueries(
containerQueryKeys.imageStatus(
context.environmentId,
context.id,
context.nodeName
)
);
}
interface UpdateContainerImageParams {
context: ContainerUpdateContext;
pullImage?: boolean;
}
/**
* Single-container image-update mutation built on the shared apply primitive.
* Used by the details-view "Update now" button; the bulk action drives the same
* primitive directly (see useBulkUpdateContainerImages).
*/
export function useUpdateContainerImage() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ context, pullImage }: UpdateContainerImageParams) =>
applyContainerUpdate(context, { pullImage }),
onSuccess: (_result, { context }) => {
invalidateContainerUpdateQueries(queryClient, context);
},
...withError('Unable to update container image'),
});
}