f7cb0f3241
Add a discoverable per-container "Update now" action, shown only when the
image status is `outdated`, plus a bulk "Update selected" action in the
containers list.
Both manual paths share ONE apply primitive (applyContainerUpdate /
useUpdateContainerImage) that also backs the future M4 auto-update job:
- standalone container -> recreate-with-pull (existing recreate endpoint)
- stack-managed -> stack redeploy-with-pull (existing git/file stack
update mutations), so the container stays in its
stack and is never recreated out-of-band
- externally-managed -> refused; the details button is disabled with an
compose explanatory tooltip and the bulk action skips it
Decision logic lives in the pure, unit-tested resolveContainerUpdatePath /
groupContainersForUpdate helpers. The bulk action filters to outdated
containers and redeploys each owning stack exactly once even when several of
its containers are selected, reporting per-item success/failure.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
57 lines
1.8 KiB
TypeScript
57 lines
1.8 KiB
TypeScript
import { QueryClient, useMutation, useQueryClient } from '@tanstack/react-query';
|
|
|
|
import { withError } from '@/react-tools/react-query';
|
|
import { Stack } from '@/react/common/stacks/types';
|
|
import { queryKeys as stacksQueryKeys } from '@/react/common/stacks/queries/query-keys';
|
|
|
|
import { queryKeys as containerQueryKeys } from '../queries/query-keys';
|
|
|
|
import { applyContainerUpdate } from './applyContainerUpdate';
|
|
import { ContainerUpdateContext } from './types';
|
|
|
|
/**
|
|
* Refresh the data affected by a container image update: the container itself,
|
|
* its image-status badge (so it flips away from "outdated") and the stacks
|
|
* list (a stack redeploy bumps its deployment info).
|
|
*/
|
|
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
|
|
)
|
|
);
|
|
queryClient.invalidateQueries(stacksQueryKeys.base());
|
|
}
|
|
|
|
interface UpdateContainerImageParams {
|
|
context: ContainerUpdateContext;
|
|
stacks: Stack[];
|
|
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, stacks, pullImage }: UpdateContainerImageParams) =>
|
|
applyContainerUpdate(context, stacks, { pullImage }),
|
|
onSuccess: (_kind, { context }) => {
|
|
invalidateContainerUpdateQueries(queryClient, context);
|
|
},
|
|
...withError('Unable to update container image'),
|
|
});
|
|
}
|