diff --git a/dashboard/src/components/Accordion/Accordion.stories.tsx b/dashboard/src/components/Accordion/Accordion.stories.tsx deleted file mode 100644 index ef8ebec..0000000 --- a/dashboard/src/components/Accordion/Accordion.stories.tsx +++ /dev/null @@ -1,98 +0,0 @@ -import type { Meta, StoryObj } from '@storybook/react'; - -import Accordion, { IAccordionItems } from './Accordion'; - -const meta = { - title: 'Accordion', - component: Accordion, - parameters: { - layout: 'centered', - }, - tags: ['autodocs'], -} satisfies Meta; - -export default meta; -type Story = StoryObj; - -const itemsBuild: IAccordionItems[] = [ - { - trigger: { - config: 'config', - compiler: 'compiler', - date: 'dd/mm/yyyy', - buildErrors: 5, - buildTime: '500 seconds', - status: 'valid', - }, - content: AAAAa, - }, - { - trigger: { - config: 'config', - compiler: 'compiler', - date: 'dd/mm/yyyy', - buildErrors: 5, - buildTime: '500 seconds', - status: 'valid', - }, - content: AAAAa, - }, - { - trigger: { - config: 'config', - compiler: 'compiler', - date: 'dd/mm/yyyy', - buildErrors: 5, - buildTime: '500 seconds', - status: 'valid', - }, - content: AAAAa, - }, -]; - -const headersBuild = [ - 'config', - 'compiler', - 'date', - 'build errors', - 'build time', - 'status', -]; - -const itemsTest: IAccordionItems[] = [ - { - trigger: { - testPlans: 'aaaaaaa', - testErrors: 5, - testSuccessfull: 12, - status: 'invalid', - }, - content: AAAAa, - }, - { - trigger: { - testPlans: 'aaaaaaasdkjmla', - testErrors: 5, - testSuccessfull: 12, - status: 'valid', - }, - content: BBB, - }, -]; -const headersTest = ['test plan', 'test results', 'status']; - -export const Builds: Story = { - args: { - items: itemsBuild, - headers: headersBuild, - type: 'build', - }, -}; - -export const Tests: Story = { - args: { - items: itemsTest, - headers: headersTest, - type: 'test', - }, -}; diff --git a/dashboard/src/components/Accordion/Accordion.tsx b/dashboard/src/components/Accordion/Accordion.tsx index 1193964..6114ecc 100644 --- a/dashboard/src/components/Accordion/Accordion.tsx +++ b/dashboard/src/components/Accordion/Accordion.tsx @@ -1,7 +1,9 @@ -import { ReactNode, useMemo } from 'react'; +import { ReactElement, ReactNode, useMemo } from 'react'; import { MdCheck, MdClose } from 'react-icons/md'; +import { FormattedMessage } from 'react-intl'; + import { TableBody, TableCell, TableRow } from '../ui/table'; import BaseTable from '../Table/BaseTable'; import { @@ -13,7 +15,7 @@ import ColoredCircle from '../ColoredCircle/ColoredCircle'; import { ItemType } from '../ListingItem/ListingItem'; export interface IAccordion { - headers: string[]; + headers?: ReactElement[]; items: IAccordionItems[]; type: 'build' | 'test'; } @@ -44,11 +46,20 @@ export type AccordionItemTestsTrigger = { status?: 'valid' | 'invalid'; }; -const Accordion = ({ headers, items, type }: IAccordion): JSX.Element => { - const accordionTableHeader = useMemo( - () => headers.map(header => {header}), - [headers], - ); +const headersBuilds = [ + , + , + , + , + , + , +]; + +const Accordion = ({ items, type }: IAccordion): JSX.Element => { + const accordionTableHeader = type === 'build' ? headersBuilds : []; return ( void; + onClickBack: () => void; +} + +export const TableInfo = ({ + startIndex, + endIndex, + totalTrees, + itemsPerPage, + onClickForward, + onClickBack, +}: ITableInformation): JSX.Element => { + const buttonsClassName = 'text-lightBlue font-bold'; + const groupsClassName = 'flex flex-row items-center gap-2'; + return ( +
+
+ + + {startIndex} - {endIndex} + + + {totalTrees} + +
+
+ + {itemsPerPage} + +
+
+ + +
+
+ ); +}; diff --git a/dashboard/src/components/Tabs/TreeDetails/TreeDetailsBuildTab.tsx b/dashboard/src/components/Tabs/TreeDetails/TreeDetailsBuildTab.tsx index 612659c..6459b0c 100644 --- a/dashboard/src/components/Tabs/TreeDetails/TreeDetailsBuildTab.tsx +++ b/dashboard/src/components/Tabs/TreeDetails/TreeDetailsBuildTab.tsx @@ -1,12 +1,16 @@ import { FormattedMessage } from 'react-intl'; -import { useMemo } from 'react'; +import { useCallback, useMemo, useState } from 'react'; import CardsGroup from '@/components/CardsGroup/CardsGroup'; import { Colors, IStatusChart } from '@/components/StatusChart/StatusCharts'; import { ITreeDetails } from '@/routes/TreeDetails/TreeDetails'; -import { ISummary } from '@/components/Summary/Summary'; +import { TableInfo } from '@/components/Table/TableInfo'; +import { usePagination } from '@/hooks/usePagination'; +import Accordion from '@/components/Accordion/Accordion'; +import { Button } from '@/components/ui/button'; import { IListingContent } from '@/components/ListingContent/ListingContent'; +import { ISummary } from '@/components/Summary/Summary'; interface ITreeDetailsBuildTab { treeDetailsData?: ITreeDetails; @@ -15,30 +19,66 @@ interface ITreeDetailsBuildTab { const TreeDetailsBuildTab = ({ treeDetailsData, }: ITreeDetailsBuildTab): JSX.Element => { + const [filterBy, setFilterBy] = useState<'error' | 'success' | 'all'>('all'); + const accordionContent = useMemo(() => { + return treeDetailsData?.builds.map(row => ({ + trigger: { + ...row, + config: row.config ?? '-', + compiler: row.compiler ?? '-', + buildTime: row.buildTime ? ( + + {typeof row.buildTime === 'number' + ? Math.floor(row.buildTime) + ' ' + : row.buildTime} + + + ) : ( + '-' + ), + date: row.date?.split('T')[0], + }, + content: <>, + })); + }, [treeDetailsData?.builds]); + + const filteredContent = + filterBy === 'error' + ? accordionContent?.filter( + row => row.trigger.buildErrors && row.trigger.buildErrors > 0, + ) + : filterBy === 'success' + ? accordionContent?.filter( + row => row.trigger.status && row.trigger.status === 'valid', + ) + : accordionContent; + + const { startIndex, endIndex, onClickGoForward, onClickGoBack } = + usePagination(filteredContent?.length ?? 0, ITEMS_PER_PAGE); const cards = useMemo( () => [ { title: , type: 'chart', pieCentralLabel: `${ - (treeDetailsData?.builds.invalid ?? 0) + - (treeDetailsData?.builds.valid ?? 0) + - (treeDetailsData?.builds.null ?? 0) + (treeDetailsData?.buildsSummary.invalid ?? 0) + + (treeDetailsData?.buildsSummary.valid ?? 0) + + (treeDetailsData?.buildsSummary.null ?? 0) }`, pieCentralDescription: , elements: [ { - value: treeDetailsData?.builds.valid ?? 0, + value: treeDetailsData?.buildsSummary.valid ?? 0, label: 'Valid', color: Colors.Green, }, { - value: treeDetailsData?.builds.invalid ?? 0, + value: treeDetailsData?.buildsSummary.invalid ?? 0, label: 'Invalid', color: Colors.Red, }, { - value: treeDetailsData?.builds.null ?? 0, + value: treeDetailsData?.buildsSummary.null ?? 0, label: 'Null', color: Colors.Gray, }, @@ -64,17 +104,78 @@ const TreeDetailsBuildTab = ({ ], [ treeDetailsData?.archs, - treeDetailsData?.builds.invalid, - treeDetailsData?.builds.null, - treeDetailsData?.builds.valid, + treeDetailsData?.buildsSummary.invalid, + treeDetailsData?.buildsSummary.null, + treeDetailsData?.buildsSummary.valid, treeDetailsData?.configs, ], ); + + const onClickFilter = useCallback((type: 'error' | 'success' | 'all') => { + setFilterBy(type); + }, []); + return ( -
+
+ {filteredContent && ( +
+
+ +
+
+
+ + + +
+ +
+ +
+ +
+
+ )}
); }; +const ITEMS_PER_PAGE = 10; + export default TreeDetailsBuildTab; diff --git a/dashboard/src/components/TreeListingPage/TreeListingPage.tsx b/dashboard/src/components/TreeListingPage/TreeListingPage.tsx index a7fba81..882a406 100644 --- a/dashboard/src/components/TreeListingPage/TreeListingPage.tsx +++ b/dashboard/src/components/TreeListingPage/TreeListingPage.tsx @@ -1,77 +1,21 @@ import { FormattedMessage } from 'react-intl'; -import { - MdArrowBackIos, - MdArrowForwardIos, - MdExpandMore, -} from 'react-icons/md'; +import { MdExpandMore } from 'react-icons/md'; -import { useCallback, useEffect, useMemo, useState } from 'react'; +import { useMemo } from 'react'; + +import { usePagination } from '@/hooks/usePagination'; import TreeTable from '../Table/TreeTable'; import { Button } from '../ui/button'; import { Tree, TreeTableBody } from '../../types/tree/Tree'; import { useTreeTable } from '../../api/Tree'; - -interface ITableInformation { - startIndex: number; - endIndex: number; - totalTrees: number; - itemsPerPage: number; - onClickForward: () => void; - onClickBack: () => void; -} +import { TableInfo } from '../Table/TableInfo'; interface ITreeListingPage { inputFilter: string; } -const TableInfo = ({ - startIndex, - endIndex, - totalTrees, - itemsPerPage, - onClickForward, - onClickBack, -}: ITableInformation): JSX.Element => { - const buttonsClassName = 'text-lightBlue font-bold'; - const groupsClassName = 'flex flex-row items-center gap-2'; - return ( -
-
- - - {startIndex} - {endIndex} - - - {totalTrees} - -
-
- - {itemsPerPage} - -
-
- - -
-
- ); -}; - const FilterButton = (): JSX.Element => { return (