Skip to content

Commit 899bdf5

Browse files
committed
Refactor TaskRunTabPanels to split components
Split TaskRunTabPanels to extract the child components to their own files. Add Storybook and unit test coverage for each.
1 parent 9e5ff37 commit 899bdf5

14 files changed

Lines changed: 1565 additions & 318 deletions

File tree

.storybook/Container.scss

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,9 @@ limitations under the License.
2828
background-color: inherit !important;
2929
}
3030
}
31+
32+
[role="main"] > .tkn--task-logs {
33+
.cds--accordion__heading {
34+
inset-block-start: 0; // demonstrate the sticky header behaviour when displayed in isolation
35+
}
36+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
Copyright 2025-2026 The Tekton Authors
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
Unless required by applicable law or agreed to in writing, software
8+
distributed under the License is distributed on an "AS IS" BASIS,
9+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
See the License for the specific language governing permissions and
11+
limitations under the License.
12+
*/
13+
14+
import { AccordionItem as CarbonAccordionItem } from '@carbon/react';
15+
16+
function AccordionItem({ children, open, ...rest }) {
17+
return (
18+
<CarbonAccordionItem open={open} {...rest}>
19+
{open ? children : null}
20+
</CarbonAccordionItem>
21+
);
22+
}
23+
24+
export default AccordionItem;
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
Copyright 2026 The Tekton Authors
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
Unless required by applicable law or agreed to in writing, software
8+
distributed under the License is distributed on an "AS IS" BASIS,
9+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
See the License for the specific language governing permissions and
11+
limitations under the License.
12+
*/
13+
14+
import { Accordion } from '@carbon/react';
15+
16+
import AccordionItem from './AccordionItem';
17+
18+
export default {
19+
component: AccordionItem,
20+
title: 'AccordionItem'
21+
};
22+
23+
export const Closed = {
24+
args: {
25+
open: false,
26+
title: 'Closed Accordion Item',
27+
children: <div>This content is not rendered when closed</div>
28+
},
29+
decorators: [
30+
Story => (
31+
<Accordion>
32+
<Story />
33+
</Accordion>
34+
)
35+
]
36+
};
37+
38+
export const Open = {
39+
args: {
40+
open: true,
41+
title: 'Open Accordion Item',
42+
children: (
43+
<div>
44+
<p>This content is rendered when open</p>
45+
<p>
46+
The AccordionItem optimizes rendering by only rendering children when
47+
open
48+
</p>
49+
</div>
50+
)
51+
},
52+
decorators: [
53+
Story => (
54+
<Accordion>
55+
<Story />
56+
</Accordion>
57+
)
58+
]
59+
};
60+
61+
export const MultipleItems = {
62+
render: () => (
63+
<Accordion>
64+
<AccordionItem open title="First Item">
65+
<p>Content of first item</p>
66+
</AccordionItem>
67+
<AccordionItem open={false} title="Second Item">
68+
<p>Content of second item (not rendered)</p>
69+
</AccordionItem>
70+
<AccordionItem open title="Third Item">
71+
<p>Content of third item</p>
72+
</AccordionItem>
73+
</Accordion>
74+
)
75+
};
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
Copyright 2026 The Tekton Authors
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
Unless required by applicable law or agreed to in writing, software
8+
distributed under the License is distributed on an "AS IS" BASIS,
9+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
See the License for the specific language governing permissions and
11+
limitations under the License.
12+
*/
13+
14+
import { render } from '../../utils/test';
15+
16+
import AccordionItem from './AccordionItem';
17+
18+
describe('AccordionItem', () => {
19+
it('should render children when open is true', () => {
20+
const { queryByText } = render(
21+
<AccordionItem open title="Test Title">
22+
<div>Test Content</div>
23+
</AccordionItem>
24+
);
25+
expect(queryByText('Test Content')).toBeTruthy();
26+
});
27+
28+
it('should not render children when open is false', () => {
29+
const { queryByText } = render(
30+
<AccordionItem open={false} title="Test Title">
31+
<div>Test Content</div>
32+
</AccordionItem>
33+
);
34+
expect(queryByText('Test Content')).toBeFalsy();
35+
});
36+
37+
it('should pass through other props to CarbonAccordionItem', () => {
38+
const { container } = render(
39+
<AccordionItem
40+
open
41+
title="Test Title"
42+
className="custom-class"
43+
data-testid="test-accordion"
44+
>
45+
<div>Test Content</div>
46+
</AccordionItem>
47+
);
48+
const accordionItem = container.querySelector('.custom-class');
49+
expect(accordionItem).toBeTruthy();
50+
});
51+
});
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/*
2+
Copyright 2026 The Tekton Authors
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
Unless required by applicable law or agreed to in writing, software
8+
distributed under the License is distributed on an "AS IS" BASIS,
9+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
See the License for the specific language governing permissions and
11+
limitations under the License.
12+
*/
13+
/* istanbul ignore file */
14+
15+
export { default } from './AccordionItem';
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
Copyright 2025-2026 The Tekton Authors
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
Unless required by applicable law or agreed to in writing, software
8+
distributed under the License is distributed on an "AS IS" BASIS,
9+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
See the License for the specific language governing permissions and
11+
limitations under the License.
12+
*/
13+
14+
import { useIntl } from 'react-intl';
15+
import { Accordion } from '@carbon/react';
16+
import { getStatus } from '@tektoncd/dashboard-utils';
17+
18+
import TaskRunStep from '../TaskRunStep';
19+
20+
function TaskRunLogs({
21+
expandedSteps,
22+
getLogContainer,
23+
ignoredSidecars,
24+
onStepSelected,
25+
selectedRetry,
26+
selectedTaskId,
27+
skippedTask,
28+
task,
29+
taskRun
30+
}) {
31+
const intl = useIntl();
32+
33+
const taskRunStatus = getStatus(taskRun);
34+
const { reason } = taskRunStatus;
35+
const { sidecars, steps } = taskRun.status || {};
36+
const sidecarsToRender =
37+
sidecars?.filter(sidecar => !ignoredSidecars[sidecar.name]) || [];
38+
39+
if (!steps) {
40+
return (
41+
<span>
42+
{intl.formatMessage({
43+
id: 'dashboard.taskRun.logs.unavailable',
44+
defaultMessage: 'No logs are available. See status for more details.'
45+
})}
46+
</span>
47+
);
48+
}
49+
if (skippedTask) {
50+
return (
51+
<span className="tkn--task-skipped">
52+
{intl.formatMessage({
53+
id: 'dashboard.taskRun.logs.skipped',
54+
defaultMessage:
55+
'This step did not run as the task was skipped. See status for more details.'
56+
})}
57+
</span>
58+
);
59+
}
60+
61+
return (
62+
<Accordion align="end" className="tkn--task-logs" ordered size="md">
63+
{steps.map(step => (
64+
<TaskRunStep
65+
expandedSteps={{
66+
...expandedSteps,
67+
// automatically expand the step when there's only one
68+
...(steps.length === 1 ? { [step.name]: true } : null)
69+
}}
70+
getLogContainer={getLogContainer}
71+
key={step.name}
72+
onStepSelected={onStepSelected}
73+
selectedRetry={selectedRetry}
74+
selectedTaskId={selectedTaskId}
75+
taskRunReason={reason}
76+
step={step}
77+
steps={steps}
78+
task={task}
79+
taskRun={taskRun}
80+
/>
81+
))}
82+
{sidecarsToRender.map(sidecar => (
83+
<TaskRunStep
84+
expandedSteps={expandedSteps}
85+
getLogContainer={getLogContainer}
86+
isSidecar
87+
key={sidecar.name}
88+
onStepSelected={onStepSelected}
89+
selectedRetry={selectedRetry}
90+
selectedTaskId={selectedTaskId}
91+
taskRunReason={reason}
92+
step={sidecar}
93+
steps={sidecars}
94+
task={task}
95+
taskRun={taskRun}
96+
/>
97+
))}
98+
</Accordion>
99+
);
100+
}
101+
102+
export default TaskRunLogs;

0 commit comments

Comments
 (0)