Skip to content

Commit 041246c

Browse files
Merge pull request finos#2549 from rocketstack-matt/fix/adr-detail-blank-without-decision
fix(calm-hub-ui): render ADR detail when decisionOutcome is absent
2 parents cbc5108 + eab9601 commit 041246c

3 files changed

Lines changed: 48 additions & 5 deletions

File tree

calm-hub-ui/src/hub/components/adr-renderer/AdrRenderer.test.tsx

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,4 +136,38 @@ describe('ADR Renderer', () => {
136136
expect(screen.getByText('30 Apr, 2025', { exact: false })).toBeInTheDocument();
137137
expect(screen.getByText('12:50', { exact: false })).toBeInTheDocument();
138138
});
139+
140+
it('should render the ADR (not a blank page) when no decision outcome is recorded', () => {
141+
// ADRs created via the API start in `draft` with no decisionOutcome — this
142+
// must not crash the renderer (regression for the blank-page bug).
143+
const draftAdr = {
144+
namespace: 'finos',
145+
id: 2,
146+
revision: 1,
147+
adr: { ...adrDetails, decisionOutcome: undefined },
148+
} as Adr;
149+
render(<AdrRenderer adrDetails={draftAdr} />);
150+
151+
expect(screen.getByText('adr title')).toBeInTheDocument();
152+
expect(screen.getByText('Decision Outcome')).toBeInTheDocument();
153+
expect(screen.getByText('No decision outcome recorded yet.')).toBeInTheDocument();
154+
// The chosen-option content from a populated decision must be absent.
155+
expect(screen.queryByText('Decision Rational:')).not.toBeInTheDocument();
156+
});
157+
158+
it('should render safely when a decision outcome is present but has no chosen option', () => {
159+
// Defensive: a malformed/partial decisionOutcome must not crash the renderer.
160+
const partialAdr = {
161+
namespace: 'finos',
162+
id: 3,
163+
revision: 1,
164+
adr: { ...adrDetails, decisionOutcome: { rationale: 'tbd' } },
165+
} as Adr;
166+
render(<AdrRenderer adrDetails={partialAdr} />);
167+
168+
expect(screen.getByText('adr title')).toBeInTheDocument();
169+
expect(screen.getByText('Decision Outcome')).toBeInTheDocument();
170+
// DisplayChosenOption renders nothing when chosenOption is missing.
171+
expect(screen.queryByText('Decision Rational:')).not.toBeInTheDocument();
172+
});
139173
});

calm-hub-ui/src/hub/components/adr-renderer/AdrRenderer.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,11 @@ export function AdrRenderer({ adrDetails }: AdrRendererProps) {
5858
<StyleTitle title="Decision Outcome" />
5959

6060
<div className="collapse-content ps-0">
61-
<DisplayChosenOption decisionOutcome={adr!.decisionOutcome} />
61+
{adr!.decisionOutcome ? (
62+
<DisplayChosenOption decisionOutcome={adr!.decisionOutcome} />
63+
) : (
64+
<p className="italic text-xs">No decision outcome recorded yet.</p>
65+
)}
6266
</div>
6367
</div>
6468

calm-hub-ui/src/hub/helper-functions/adr/adr-helper-function.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,19 +94,24 @@ export function DisplayConsideredOptions(props: { consideredOptions: Option[] })
9494
}
9595

9696
export function DisplayChosenOption(props: { decisionOutcome: Decision }) {
97+
const chosenOption = props.decisionOutcome?.chosenOption;
98+
if (!chosenOption) {
99+
return null;
100+
}
101+
97102
return (
98103
<div className="pt-2">
99-
<p className="font-bold pb-1">{props.decisionOutcome.chosenOption.name}</p>
104+
<p className="font-bold pb-1">{chosenOption.name}</p>
100105

101106
<div className=" pt-1 pb-1 pe-2 markdownParagraphSpacing">
102-
<Markdown>{props.decisionOutcome.chosenOption.description}</Markdown>
107+
<Markdown>{chosenOption.description}</Markdown>
103108
</div>
104109

105110
<p className="font-bold"> Positive Consequences:</p>
106-
{getListOfConsequences(props.decisionOutcome.chosenOption.positiveConsequences, true)}
111+
{getListOfConsequences(chosenOption.positiveConsequences, true)}
107112

108113
<p className="font-bold mt-4"> Negative Consequences:</p>
109-
{getListOfConsequences(props.decisionOutcome.chosenOption.negativeConsequences, false)}
114+
{getListOfConsequences(chosenOption.negativeConsequences, false)}
110115

111116
<p className="font-bold mt-4"> Decision Rational:</p>
112117
<div className="pe-1">

0 commit comments

Comments
 (0)