/* * Copyright 2020 EPAM Systems * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import React, { useMemo } from "react"; import { Menu, Icons, Status, Stub, Table, capitalize, Cells, sendAlertEvent, } from "@drill4j/ui-kit"; import { Link, useHistory } from "react-router-dom"; import { percentFormatter, dateFormatter, timeFormatter, transformObjectsArrayToObject, } from "@drill4j/common-utils"; import tw from "twin.macro"; import { ScopeSummary } from "types/scope-summary"; import { TestTypeSummary } from "types/test-type-summary"; import { useActiveBuild, useActiveScope, useAgentRouteParams, useFilteredData, useNavigation, useTestToCodeRouteParams, } from "hooks"; import { BUILD_STATUS } from "common/constants"; import { getModalPath } from "common"; import { BuildCoverage } from "types/build-coverage"; import { PageHeader } from "components"; import { toggleScope } from "../api"; import { ScopeTimer } from "../scope-overview/scope-timer"; export const AllScopes = () => { const { agentId } = useAgentRouteParams(); const { buildVersion } = useTestToCodeRouteParams(); const { push } = useHistory(); const { buildVersion: activeBuildVersion = "", buildStatus } = useActiveBuild(agentId) || {}; const activeScope = useActiveScope(); const scopes = useFilteredData("/build/scopes/finished") || []; const { byTestType = [] } = useFilteredData("/build/coverage") || {}; const { getPagePath } = useNavigation(); scopes.sort( ({ started: firstStartedDate }, { started: secondStartedDate }) => secondStartedDate - firstStartedDate, ); const scopesData = activeScope && activeScope.name ? [activeScope, ...scopes] : scopes; const isActiveBuildVersion = (activeBuildVersion === buildVersion); const isOnlineBuild = buildStatus === BUILD_STATUS.ONLINE; const { coverage: { byTestType: activeScopeTestsType = [] } = {} } = activeScope || {}; const testsColumns = [ ...byTestType, ...activeScopeTestsType, ...Array.from(new Set(scopes.map(({ coverage: { byTestType: finishedScopeTestsType = [] } = {} }) => finishedScopeTestsType))).flat(), ].reduce((acc: string[], item) => (acc.includes(item.type) ? acc : [...acc, item.type]), []) .map((type) => ({ Header: `${capitalize(type)} tests`, accessor: `coverageByTestType.${type}`, testType: type, Cell: ({ row: { original = {} } = {} }: any) => { const coverageByTestTypes = transformObjectsArrayToObject(original?.coverage?.byTestType as TestTypeSummary[], "type"); const testTypeSummary = coverageByTestTypes[type]?.summary; if (!testTypeSummary) return null; return (
{`${percentFormatter(testTypeSummary?.coverage?.percentage || 0)}%`}
{testTypeSummary?.testCount}
); }, width: "180px", })); const data = useMemo(() => scopesData.map((value) => { const res = { ...value }; const scopeTestTypes = value?.coverage?.byTestType ?.reduce((acc, testData) => ({ [testData?.type]: testData?.summary?.coverage?.percentage }), {}) as any; res.coverageByTestType = testsColumns.reduce((acc, { testType }) => ({ ...acc, [testType]: scopeTestTypes[testType] || 0 }), {}); return res; }), [scopesData]); return ( <> All Scopes {data.length}
{scopesData.length > 0 ? ( (
Scopes List
{`Displaying ${currentCount} of ${totalCount} scopes`}
)} stub={( } title="No results found" message="Try adjusting your search or filter to find what you are looking for." /> )} columns={[ { Header: "Name", accessor: "name", filterable: true, isCustomCell: true, Cell: ({ value = "", state, row: { original: { id = "", started = 0, active = false, enabled = false, finished = 0, } = {}, }, }: any) => (
filter.value)} />
{active && Active} {!enabled && Ignored}
), textAlign: "left", width: "60%", }, { Header: "Started", accessor: "started", Cell: ({ value = 0 }: any) => ( <>
{dateFormatter(value)}
at {timeFormatter(value)}
), textAlign: "left", width: "200px", sortType: "number", }, { Header: "Coverage, %", accessor: "coverage.percentage", Cell: ({ row: { original = {} } = {} }: any) => (
{percentFormatter(original?.coverage?.percentage)}
), width: "180px", sortType: "number", }, ...testsColumns, { Header: () => null, accessor: "actions", Cell: isActiveBuildVersion ? ({ row: { original = {} } = {} }: any) => { const { active, enabled, id } = original; const title = !isOnlineBuild ? "Unavailable. Agent is offline." : undefined; const menuActions = [ active && { label: "Finish Scope", icon: "Check", onClick: () => push(getModalPath({ name: "finishScope", params: { scopeId: id } })), }, active && { label: "Sessions Management", icon: "ManageSessions", disabled: !isOnlineBuild, title, Content: isOnlineBuild ? ({ children }: { children: JSX.Element }) => ( {children} ) : undefined, }, !active && { label: `${enabled ? "Ignore" : "Include"} in stats`, icon: enabled ? "EyeCrossed" : "Eye", disabled: !isOnlineBuild, title, onClick: () => toggleScope(agentId, { onSuccess: () => { sendAlertEvent({ type: "SUCCESS", title: `Scope has been ${enabled ? "ignored" : "included"} in build stats.`, }); }, onError: () => { sendAlertEvent({ type: "ERROR", title: "There is some issue with your action. Please try again later.", }); }, })(id), }, { label: "Rename", icon: "Edit", disabled: !isOnlineBuild, title, onClick: () => push(getModalPath({ name: "renameScope", params: { scopeId: id } })), }, { label: "Delete", icon: "Delete", disabled: !isOnlineBuild, title, onClick: () => push(getModalPath({ name: "deleteScope", params: { scopeId: id } })), }, ].filter(Boolean); return (
{!active ? () : ()}
); } : () => null, width: "48px", notSortable: true, disableEllipsis: true, }, ]} /> ) : ( } title={No scopes found} message="There are no scopes with finished test sessions in this build." /> )} ); };