diff --git a/ui/src/features/stage/promotion-steps.tsx b/ui/src/features/stage/promotion-steps.tsx
index 1fb40d593b..9ab9016d96 100644
--- a/ui/src/features/stage/promotion-steps.tsx
+++ b/ui/src/features/stage/promotion-steps.tsx
@@ -34,22 +34,31 @@ export const PromotionSteps = (props: PromotionStepsProps) => {
const phase = getPromotionStatusPhase(props.promotion);
- const shouldShowMessage =
- isPromotionPhaseTerminal(phase) &&
- phase !== PromotionStatusPhase.SUCCEEDED &&
- phase !== PromotionStatusPhase.ERRORED && // because its already handled at individual step level
- !!props.promotion?.status?.message;
+ const message = props.promotion?.status?.message;
+
+ // A failed step's message becomes the Promotion's, so it is already on screen.
+ const hasIndividualPromotionStepTerminalMessage = (
+ props.promotion.status?.stepExecutionMetadata ?? []
+ ).some((meta, i) => isFailedStep(i, props.promotion.status) && !!meta.message);
+
+ let shouldShowMessage = false;
+
+ if (isPromotionPhaseTerminal(phase)) {
+ switch (phase) {
+ case PromotionStatusPhase.FAILED:
+ case PromotionStatusPhase.ERRORED:
+ // The failing step already shows this message, so don't repeat it.
+ shouldShowMessage = !hasIndividualPromotionStepTerminalMessage;
+ break;
+ case PromotionStatusPhase.ABORTED:
+ // An abort is not attributable to any one step.
+ shouldShowMessage = true;
+ break;
+ }
+ }
const steps = props.promotion?.spec?.steps ?? [];
- const errorItem = {
- key: 'error',
- label: ,
- showArrow: false,
- collapsible: 'disabled' as const,
- styles: { header: { paddingTop: 0 } }
- };
-
// Steps with a registered extension are interactive
const hasExtension = (step: (typeof steps)[number]) =>
promotionStepExtensions.some((ext) => ext.identifier === step.uses);
@@ -76,9 +85,26 @@ export const PromotionSteps = (props: PromotionStepsProps) => {
key
};
- return isFailedStep(i, props.promotion.status)
- ? [{ ...item, className: `${item.className || ''} !border-none` }, errorItem]
- : [item];
+ if (!isFailedStep(i, props.promotion.status)) {
+ return [item];
+ }
+
+ const stepMessage = props.promotion.status?.stepExecutionMetadata?.[i]?.message;
+
+ if (!stepMessage) {
+ return [item];
+ }
+
+ return [
+ { ...item, className: `${item.className || ''} !border-none` },
+ {
+ key: `${key}-error`,
+ label: ,
+ showArrow: false,
+ collapsible: 'disabled' as const,
+ styles: { header: { paddingTop: 0 } }
+ }
+ ];
});
useEffect(() => {
@@ -97,9 +123,7 @@ export const PromotionSteps = (props: PromotionStepsProps) => {
activeKey={activeKeys}
onChange={(keys) => setActiveKeys(typeof keys === 'string' ? [keys] : keys)}
/>
- {shouldShowMessage && (
-
- )}
+ {shouldShowMessage && !!message && }
>
);
};