Skip to content

Commit 7bbd9b4

Browse files
feat(pipelines-output): add pipelinerun output tab component (#7)
* feat(pipelines-output): add pipelinerun output tab component * update peer deps and remove sample button component * update date format
1 parent bbe65e5 commit 7bbd9b4

File tree

98 files changed

+9174
-1525
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

98 files changed

+9174
-1525
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import '@patternfly/react-core/dist/styles/base.css';
2+
import { AdvancedClusterSecurity } from '@aonic-ui/pipelines/src';
3+
import {
4+
acsDeploymentCheck as acsDeploymentCheckResults,
5+
acsImageCheckResults,
6+
acsImageScanResult,
7+
} from '@aonic-ui/pipelines/src/components/Output/data';
8+
import type { Meta, StoryObj } from '@storybook/react';
9+
10+
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
11+
const meta = {
12+
title: 'Pipelines/Output/Cards/AdvancedClusterSecurity',
13+
component: AdvancedClusterSecurity,
14+
parameters: {
15+
// Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
16+
layout: 'padded',
17+
},
18+
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
19+
tags: ['autodocs'],
20+
// More on argTypes: https://storybook.js.org/docs/api/argtypes
21+
argTypes: {},
22+
} satisfies Meta<typeof AdvancedClusterSecurity>;
23+
export default meta;
24+
25+
type Story = StoryObj<typeof meta>;
26+
27+
export const ACSCard: Story = {
28+
args: {
29+
acsImageCheckResults,
30+
acsImageScanResult,
31+
acsDeploymentCheckResults,
32+
},
33+
parameters: {},
34+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import '@patternfly/react-core/dist/styles/base.css';
2+
import { EnterpriseContract } from '@aonic-ui/pipelines/src';
3+
import { mockEnterpriseContractUIData } from '@aonic-ui/pipelines/src/components/Output/data';
4+
import type { Meta, StoryObj } from '@storybook/react';
5+
6+
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
7+
const meta = {
8+
title: 'Pipelines/Output/Cards/EnterpriseContract',
9+
component: EnterpriseContract,
10+
parameters: {
11+
// Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
12+
layout: 'padded',
13+
},
14+
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
15+
tags: ['autodocs'],
16+
// More on argTypes: https://storybook.js.org/docs/api/argtypes
17+
argTypes: {
18+
enterpriseContractPolicies: {},
19+
},
20+
} satisfies Meta<typeof EnterpriseContract>;
21+
export default meta;
22+
23+
type Story = StoryObj<typeof meta>;
24+
25+
export const ECCard: Story = {
26+
args: {
27+
enterpriseContractPolicies: mockEnterpriseContractUIData,
28+
},
29+
parameters: {},
30+
};
+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import '@patternfly/react-core/dist/styles/base.css';
2+
import { Output } from '@aonic-ui/pipelines/src';
3+
import {
4+
acsDeploymentCheck,
5+
acsImageCheckResults,
6+
acsImageScanResult,
7+
mockEnterpriseContractUIData,
8+
} from '@aonic-ui/pipelines/src/components/Output/data';
9+
import type { Meta, StoryObj } from '@storybook/react';
10+
11+
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
12+
const meta = {
13+
title: 'Pipelines/Output',
14+
component: Output,
15+
parameters: {
16+
// Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
17+
layout: 'padded',
18+
},
19+
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
20+
tags: ['autodocs'],
21+
// More on argTypes: https://storybook.js.org/docs/api/argtypes
22+
argTypes: {
23+
pipelineRunStatus: { control: 'select', options: ['Failed', 'Succeeded'] },
24+
},
25+
} satisfies Meta<typeof Output>;
26+
export default meta;
27+
28+
type Story = StoryObj<typeof meta>;
29+
30+
export const OutputTab: Story = {
31+
args: {
32+
acsImageScanResult,
33+
acsImageCheckResults,
34+
enterpriseContractPolicies: mockEnterpriseContractUIData,
35+
acsDeploymentCheckResults: acsDeploymentCheck,
36+
results: [{ name: 'result-1', value: 'value' }],
37+
pipelineRunName: 'pipelineRunName',
38+
pipelineRunStatus: 'Succeeded',
39+
},
40+
parameters: {},
41+
};
42+
43+
export const OutputTabEC: Story = {
44+
args: {
45+
enterpriseContractPolicies: mockEnterpriseContractUIData,
46+
results: [{ name: 'result-1', value: 'value' }],
47+
pipelineRunName: 'pipelineRunName',
48+
pipelineRunStatus: 'Succeeded',
49+
},
50+
parameters: {},
51+
};
52+
53+
export const OutputTabACS: Story = {
54+
args: {
55+
acsImageScanResult,
56+
acsImageCheckResults,
57+
acsDeploymentCheckResults: acsDeploymentCheck,
58+
results: [{ name: 'result-1', value: 'value' }],
59+
pipelineRunName: 'pipelineRunName',
60+
pipelineRunStatus: 'Succeeded',
61+
},
62+
parameters: {},
63+
};
64+
65+
export const OutputTabResults: Story = {
66+
args: {
67+
results: [{ name: 'result-1', value: 'value' }],
68+
pipelineRunName: 'pipelineRunName',
69+
pipelineRunStatus: 'Succeeded',
70+
},
71+
parameters: {},
72+
};

docs/stories/pipelines/PipelinesButton/PipelinesButton.stories.tsx

-32
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import '@patternfly/react-core/dist/styles/base.css';
2+
import { ResultsList } from '@aonic-ui/pipelines/src';
3+
import { acsImageCheckResults } from '@aonic-ui/pipelines/src/components/Output/data';
4+
import type { Meta, StoryObj } from '@storybook/react';
5+
6+
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
7+
const meta = {
8+
title: 'Pipelines/Output/Cards/Others',
9+
component: ResultsList,
10+
parameters: {
11+
// Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
12+
layout: 'padded',
13+
},
14+
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
15+
tags: ['autodocs'],
16+
// More on argTypes: https://storybook.js.org/docs/api/argtypes
17+
argTypes: {},
18+
} satisfies Meta<typeof ResultsList>;
19+
export default meta;
20+
21+
type Story = StoryObj<typeof meta>;
22+
23+
export const OtherTab: Story = {
24+
args: {
25+
results: [
26+
{ name: 'result-key', value: 'results-value' },
27+
{ name: 'result-key-2', value: 'http://www.google.com' },
28+
{
29+
name: 'result-key-3',
30+
value: JSON.stringify(acsImageCheckResults),
31+
},
32+
],
33+
pipelineRunName: 'pipelinerun-name',
34+
pipelineRunStatus: 'Succeeded',
35+
},
36+
parameters: {},
37+
};

packages/jest-config/babel.config.cjs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module.exports = {
22
presets: [
33
"@babel/preset-env",
4-
"@babel/preset-react",
4+
["@babel/preset-react", { runtime: 'automatic' }],
55
"@babel/preset-typescript",
66
],
77
};

packages/pipelines/package.json

+12-1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@
3939
"@aonic-ui/rollup-config": "*",
4040
"@aonic-ui/typescript-config": "*",
4141
"@testing-library/react": "^14.1.2",
42+
"@testing-library/jest-dom": "^6.2.0",
43+
"@patternfly/react-core": "^5.1.2",
44+
"@patternfly/react-icons": "^5.1.2",
45+
"@patternfly/react-table": "^5.1.2",
46+
"@patternfly/react-tokens": "^5.1.2",
4247
"@types/jest": "^29.5.11",
4348
"@types/react": "^18.2.47",
4449
"jest": "^29.7.0",
@@ -47,7 +52,13 @@
4752
"typescript": "^5.3.3"
4853
},
4954
"peerDependencies": {
50-
"react": "^18.2.0"
55+
"react": "^18.2.0",
56+
"@testing-library/jest-dom": "^6.2.0",
57+
"@patternfly/react-core": "^5.1.2",
58+
"@patternfly/react-icons": "^5.1.2",
59+
"@patternfly/react-table": "^5.1.2",
60+
"@patternfly/react-tokens": "^5.1.2"
61+
5162
},
5263
"publishConfig": {
5364
"access": "public"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import * as React from 'react';
2+
import OutputTabCard from './OutputTabCard';
3+
import AdvancedClusterSecurity from './Tabs/AdvancedClusterSecurity/AdvancedClusterSecurity';
4+
import EnterpriseContract from './Tabs/EnterpriseContract/EnterpriseContract';
5+
import ResultsList, { ResultsListProps } from './Tabs/Others/ResultsList';
6+
import { ACSCheckResults, ACSImageScanResult, EnterpriseContractPolicy } from './types';
7+
import { getACSCheckIssues } from './utils/acs-image-check-utils';
8+
import { getImageScanIssues } from './utils/acs-image-scan-utils';
9+
import { getEnterpriseContractStatus } from './utils/ec-utils';
10+
import { isEmpty } from './utils/helper-utils';
11+
import { getACStatusLabel, getECStatusLabel } from './utils/summary-utils';
12+
13+
type OutputTabProps = {
14+
enterpriseContractPolicies?: EnterpriseContractPolicy[];
15+
acsImageScanResult?: ACSImageScanResult;
16+
acsImageCheckResults?: ACSCheckResults;
17+
acsDeploymentCheckResults?: ACSCheckResults;
18+
} & ResultsListProps;
19+
20+
const OutputTab: React.FC<OutputTabProps> = ({
21+
enterpriseContractPolicies = [],
22+
acsImageCheckResults = {} as ACSCheckResults,
23+
acsImageScanResult = {} as ACSImageScanResult,
24+
acsDeploymentCheckResults = {} as ACSCheckResults,
25+
results,
26+
pipelineRunName,
27+
pipelineRunStatus,
28+
}) => {
29+
const acsIssuesFound =
30+
getImageScanIssues(acsImageScanResult) ||
31+
getACSCheckIssues(acsImageCheckResults, acsDeploymentCheckResults);
32+
33+
const showECCard = enterpriseContractPolicies?.length > 0;
34+
const showACSCard =
35+
[acsImageScanResult, acsImageCheckResults, acsDeploymentCheckResults].filter((a) => !isEmpty(a))
36+
.length > 0;
37+
38+
const showOnlyResults = !showECCard && !showACSCard;
39+
const ResultsComponent = () => (
40+
<ResultsList
41+
results={results}
42+
pipelineRunName={pipelineRunName}
43+
pipelineRunStatus={pipelineRunStatus}
44+
/>
45+
);
46+
return (
47+
<>
48+
{showECCard && (
49+
<OutputTabCard
50+
title="Enterprise Contract"
51+
badge={getECStatusLabel(getEnterpriseContractStatus(enterpriseContractPolicies))}
52+
isOpen={true}
53+
>
54+
<EnterpriseContract enterpriseContractPolicies={enterpriseContractPolicies} />
55+
</OutputTabCard>
56+
)}
57+
{showACSCard && (
58+
<OutputTabCard
59+
title="Advanced Cluster Security"
60+
badge={getACStatusLabel(acsIssuesFound)}
61+
isOpen={!showECCard}
62+
>
63+
<AdvancedClusterSecurity
64+
acsImageScanResult={acsImageScanResult}
65+
acsImageCheckResults={acsImageCheckResults}
66+
acsDeploymentCheckResults={acsDeploymentCheckResults}
67+
/>
68+
</OutputTabCard>
69+
)}
70+
{results.length > 0 && showOnlyResults ? (
71+
<ResultsComponent data-testid="ec" />
72+
) : results.length > 0 ? (
73+
<OutputTabCard data-testid="results-card" title="Others" isOpen={showOnlyResults}>
74+
<ResultsComponent />
75+
</OutputTabCard>
76+
) : null}
77+
</>
78+
);
79+
};
80+
export default OutputTab;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import * as React from 'react';
2+
import {
3+
Card,
4+
CardBody,
5+
CardExpandableContent,
6+
CardHeader,
7+
CardTitle,
8+
Flex,
9+
FlexItem,
10+
} from '@patternfly/react-core';
11+
12+
type OutputTabCardProps = {
13+
title: string;
14+
isOpen?: boolean;
15+
badge?: React.ReactNode;
16+
children: React.ReactNode;
17+
};
18+
const OutputTabCard: React.FC<OutputTabCardProps> = ({ title, badge, isOpen, children }) => {
19+
const [tabOpen, setTabOpen] = React.useState<boolean>(isOpen ?? false);
20+
const id = title?.replace(/\//g, '-')?.toLowerCase();
21+
22+
return (
23+
<Card id={id} isExpanded={tabOpen}>
24+
<CardHeader
25+
onExpand={() => setTabOpen((open) => !open)}
26+
isToggleRightAligned={false}
27+
toggleButtonProps={{
28+
id: `${id}-toggle-button`,
29+
'aria-label': title,
30+
'aria-labelledby': `${id}-toggle-button`,
31+
'aria-expanded': tabOpen,
32+
}}
33+
>
34+
<CardTitle id={`{${id}-title}`}>
35+
<Flex gap={{ default: 'gapSm' }}>
36+
<FlexItem data-testid="card-title">{title}</FlexItem>
37+
<FlexItem data-testid="card-badge">{badge}</FlexItem>
38+
</Flex>
39+
</CardTitle>
40+
</CardHeader>
41+
<CardExpandableContent>
42+
<CardBody>{children}</CardBody>
43+
</CardExpandableContent>
44+
</Card>
45+
);
46+
};
47+
export default OutputTabCard;

0 commit comments

Comments
 (0)