diff --git a/codecv.yml b/codecv.yml index 5d2d44e..dc965d5 100644 --- a/codecv.yml +++ b/codecv.yml @@ -9,7 +9,10 @@ coverage: project: default: target: auto - threshold: 0.2% + threshold: 1% + patch: + default: + informational: true ignore: - "**/*__data__*/*.ts" diff --git a/src/components/ApplicationDetails/tabs/overview/visualization/hooks/useAppWorkflowData.ts b/src/components/ApplicationDetails/tabs/overview/visualization/hooks/useAppWorkflowData.ts index b768578..2c1663e 100644 --- a/src/components/ApplicationDetails/tabs/overview/visualization/hooks/useAppWorkflowData.ts +++ b/src/components/ApplicationDetails/tabs/overview/visualization/hooks/useAppWorkflowData.ts @@ -14,7 +14,6 @@ import { useAppApplicationTestNodes } from './useAppApplicationTestNodes'; import { useAppBuildNodes } from './useAppBuildNodes'; import { useAppComponentsNodes } from './useAppComponentsNodes'; import { useAppReleaseNodes } from './useAppReleaseNodes'; -import { useAppReleasePlanNodes } from './useAppReleasePlanNodes'; export const useAppWorkflowData = ( applicationName: string, @@ -63,35 +62,17 @@ export const useAppWorkflowData = ( applicationIntegrationTestNodes, ]); - const [releaseNodes, releaseGroup, releaseTasks, releasesLoaded, releasesError] = - useAppReleaseNodes( - namespace, - applicationName, - expanded ? applicationIntegrationTestTasks : [testsGroup?.id ?? ''], - expanded, - ); - - const [ - managedEnvironmentNodes, - managedEnvironmentGroup, - managedEnvironmentsLoaded, - managedEnvironmentsError, - ] = useAppReleasePlanNodes(namespace, applicationName, releaseTasks, expanded); + const [releaseNodes, releaseGroup, , releasesLoaded, releasesError] = useAppReleaseNodes( + namespace, + applicationName, + expanded ? applicationIntegrationTestTasks : [testsGroup?.id ?? ''], + expanded, + ); const allResourcesLoaded: boolean = - componentsLoaded && - buildsLoaded && - applicationTestsLoaded && - releasesLoaded && - managedEnvironmentsLoaded; + componentsLoaded && buildsLoaded && applicationTestsLoaded && releasesLoaded; - const errors = [ - ...componentsErrors, - ...buildsErrors, - ...applicationErrors, - ...releasesError, - ...managedEnvironmentsError, - ]; + const errors = [...componentsErrors, ...buildsErrors, ...applicationErrors, ...releasesError]; if (!allResourcesLoaded || errors.length > 0) { return [{ nodes: [], edges: [] }, allResourcesLoaded, errors]; @@ -103,7 +84,6 @@ export const useAppWorkflowData = ( ...(buildNodes?.length ? buildNodes : [buildGroup]), ...applicationIntegrationTestNodes, ...(releaseNodes?.length ? releaseNodes : [releaseGroup]), - ...(managedEnvironmentNodes?.length ? managedEnvironmentNodes : [managedEnvironmentGroup]), ]; const spacerNodes = getSpacerNodes(resourceNodes, NodeType.SPACER_NODE); const nodes = [ @@ -113,13 +93,12 @@ export const useAppWorkflowData = ( buildGroup, testsGroup, releaseGroup, - managedEnvironmentGroup, ]; const edges = getEdgesFromNodes(nodes, NodeType.SPACER_NODE); return [{ nodes, edges }, true, errors]; } - const nodes = [componentGroup, buildGroup, testsGroup, releaseGroup, managedEnvironmentGroup]; + const nodes = [componentGroup, buildGroup, testsGroup, releaseGroup]; const edges = getEdgesFromNodes(nodes, NodeType.SPACER_NODE); return [{ nodes, edges }, true, errors]; diff --git a/src/components/ApplicationDetails/tabs/overview/visualization/utils/node-utils.ts b/src/components/ApplicationDetails/tabs/overview/visualization/utils/node-utils.ts index 67e8096..3ae172a 100644 --- a/src/components/ApplicationDetails/tabs/overview/visualization/utils/node-utils.ts +++ b/src/components/ApplicationDetails/tabs/overview/visualization/utils/node-utils.ts @@ -114,23 +114,14 @@ export const getLinkDataForElement = ( : { tab: 'integrationtests', }; - case WorkflowNodeType.STATIC_ENVIRONMENT: - return { - tab: 'deployments', - filter: - !groupNode && !isDisabled - ? { name: 'name', value: label } - : { name: 'envType', value: 'default,static' }, - }; - case WorkflowNodeType.MANAGED_ENVIRONMENT: case WorkflowNodeType.RELEASE: - return { - tab: 'deployments', - filter: - !groupNode && !isDisabled - ? { name: 'name', value: label } - : { name: 'envType', value: 'managed' }, - }; + return !groupNode && !isDisabled + ? { + path: `/workspaces/${workspace}/applications/${ + element.getData().application + }/releases/${label}`, + } + : { tab: 'releases' }; default: return { tab: 'overview', diff --git a/src/components/Commits/CommitDetails/visualization/__tests__/CommitVisualization.spec.tsx b/src/components/Commits/CommitDetails/visualization/__tests__/CommitVisualization.spec.tsx index be8c15e..627e2fa 100644 --- a/src/components/Commits/CommitDetails/visualization/__tests__/CommitVisualization.spec.tsx +++ b/src/components/Commits/CommitDetails/visualization/__tests__/CommitVisualization.spec.tsx @@ -120,6 +120,6 @@ describe('CommitVisualization', () => { const nodes = graph.querySelectorAll('[data-kind="node"]'); - expect(nodes).toHaveLength(8); + expect(nodes).toHaveLength(6); }); }); diff --git a/src/components/Commits/CommitDetails/visualization/useCommitWorkflowData.ts b/src/components/Commits/CommitDetails/visualization/useCommitWorkflowData.ts index 78d9bcb..ba4cf78 100644 --- a/src/components/Commits/CommitDetails/visualization/useCommitWorkflowData.ts +++ b/src/components/Commits/CommitDetails/visualization/useCommitWorkflowData.ts @@ -1,22 +1,10 @@ import * as React from 'react'; -import { - PipelineRunEventType, - PipelineRunLabel, - PipelineRunType, -} from '../../../../consts/pipelinerun'; +import { PipelineRunLabel, PipelineRunType } from '../../../../consts/pipelinerun'; import { useComponents } from '../../../../hooks/useComponents'; import { useIntegrationTestScenarios } from '../../../../hooks/useIntegrationTestScenarios'; import { usePipelineRunsForCommit } from '../../../../hooks/usePipelineRuns'; -import { useReleasePlans } from '../../../../hooks/useReleasePlans'; -import { useReleases } from '../../../../hooks/useReleases'; -import { useSnapshots } from '../../../../hooks/useSnapshots'; import { Commit, ComponentKind, PipelineRunKind } from '../../../../types'; -import { ReleaseKind, ReleasePlanKind } from '../../../../types/coreBuildService'; -import { - conditionsRunStatus, - pipelineRunStatus, - runStatus, -} from '../../../../utils/pipeline-utils'; +import { pipelineRunStatus, runStatus } from '../../../../utils/pipeline-utils'; import { DEFAULT_NODE_HEIGHT } from '../../../topology/const'; import { getLabelWidth } from '../../../topology/utils'; import { useWorkspaceInfo } from '../../../Workspace/useWorkspaceInfo'; @@ -41,7 +29,6 @@ export const useCommitWorkflowData = ( commit: Commit, ): [nodes: CommitWorkflowNodeModel[], loaded: boolean, errors: unknown[]] => { const { namespace, workspace } = useWorkspaceInfo(); - const [mvpFeature] = [false]; const applicationName = commit?.application || ''; const [components, componentsLoaded] = useComponents(namespace, workspace, applicationName); @@ -50,11 +37,6 @@ export const useCommitWorkflowData = ( workspace, applicationName, ); - const [releasePlans, releasePlansLoaded, releasePlansError] = useReleasePlans( - namespace, - workspace, - ); - const [releases, releasesLoaded, releasesError] = useReleases(namespace, workspace); const [pipelines, pipelinesLoaded, pipelinesError] = usePipelineRunsForCommit( namespace, workspace, @@ -81,16 +63,8 @@ export const useCommitWorkflowData = ( [pipelines, pipelinesLoaded], ); - const [snapshots, sloaded, serror] = useSnapshots(namespace, commit.sha); - - const allResourcesLoaded: boolean = - componentsLoaded && - integrationTestsLoaded && - pipelinesLoaded && - releasesLoaded && - sloaded && - releasePlansLoaded; - const allErrors = [releasePlansError, releasesError, pipelinesError, serror].filter((e) => !!e); + const allResourcesLoaded: boolean = componentsLoaded && integrationTestsLoaded && pipelinesLoaded; + const allErrors = [pipelinesError].filter((e) => !!e); const commitComponents = React.useMemo( () => @@ -203,120 +177,6 @@ export const useCommitWorkflowData = ( nodes.push(...appTestNodes); const appTestNodesWidth = appTestNodes.reduce((max, node) => Math.max(max, node.width), 0); appTestNodes.forEach((n) => (n.width = appTestNodesWidth)); - - const currentSnapshotName = getLatestResource( - snapshots.filter( - (s) => - s.metadata.labels[PipelineRunLabel.COMPONENT] === compName && - s.metadata.labels[PipelineRunLabel.TEST_SERVICE_EVENT_TYPE_LABEL] === - PipelineRunEventType.PUSH, - ), - )?.metadata?.name; - - if (!mvpFeature) { - const latestRelease: ReleaseKind = getLatestResource( - releases.filter((r) => r.spec.snapshot === currentSnapshotName), - ); - - const releaseStatus: runStatus = - releases.length === 0 - ? undefined - : latestRelease && latestRelease?.status - ? conditionsRunStatus(latestRelease.status.conditions) - : runStatus.Succeeded; - - const releaseNodes: CommitWorkflowNodeModel[] = releases.length - ? releases.map((release) => { - const releaseName = release.metadata.name; - - const releaseNode: CommitWorkflowNodeModel = { - id: addPrefixToResourceName(compName, releaseName), - label: releaseName, - type: NodeType.WORKFLOW_NODE, - width: getLabelWidth(releaseName), - height: DEFAULT_NODE_HEIGHT, - data: { - status: releaseStatus, - workflowType: CommitWorkflowNodeType.RELEASE, - resource: release, - application: commit.application, - }, - }; - return releaseNode; - }) - : [ - { - id: `${name}-release`, - label: 'No releases set', - type: NodeType.WORKFLOW_NODE, - width: getLabelWidth('No releases set'), - height: DEFAULT_NODE_HEIGHT, - data: { - status: runStatus.Pending, - workflowType: CommitWorkflowNodeType.RELEASE, - application: commit.application, - }, - }, - ]; - nodes.push(...releaseNodes); - const releaseNodesWidth = releaseNodes.reduce((max, node) => Math.max(max, node.width), 0); - releaseNodes.forEach((n) => (n.width = releaseNodesWidth)); - const releaseNodeIds = releaseNodes.map((n) => n.id); - - const releasePlanStatus: (rp: ReleasePlanKind) => runStatus = - releasePlans.length === 0 - ? undefined - : (rp) => { - const matchedRelease = getLatestResource( - releases.filter((r) => r.spec.releasePlan === rp.metadata.name), - ); - return matchedRelease - ? pipelineRunStatus(matchedRelease as PipelineRunKind) - : runStatus.Pending; - }; - - const managedEnvNodes: CommitWorkflowNodeModel[] = releasePlans.length - ? releasePlans.map((managedEnv) => { - const managedEnvName = managedEnv.metadata.name; - - const managedEnvNode: CommitWorkflowNodeModel = { - id: addPrefixToResourceName(compName, managedEnvName), - label: managedEnvName, - type: NodeType.WORKFLOW_NODE, - width: getLabelWidth(managedEnvName), - height: DEFAULT_NODE_HEIGHT, - runAfterTasks: releaseNodeIds, - data: { - status: releasePlanStatus(managedEnv), - workflowType: CommitWorkflowNodeType.MANAGED_ENVIRONMENT, - resource: managedEnv, - application: commit.application, - }, - }; - return managedEnvNode; - }) - : [ - { - id: `${name}-managed-environments`, - label: 'No managed environments set', - type: NodeType.WORKFLOW_NODE, - width: getLabelWidth('No managed environments set'), - height: DEFAULT_NODE_HEIGHT, - runAfterTasks: releaseNodeIds, - data: { - status: runStatus.Pending, - workflowType: CommitWorkflowNodeType.MANAGED_ENVIRONMENT, - application: commit.application, - }, - }, - ]; - nodes.push(...managedEnvNodes); - const managedEnvNodesWidth = managedEnvNodes.reduce( - (max, node) => Math.max(max, node.width), - 0, - ); - managedEnvNodes.forEach((n) => (n.width = managedEnvNodesWidth)); - } }); return nodes; @@ -329,10 +189,6 @@ export const useCommitWorkflowData = ( buildPipelines, testPipelines, integrationTests, - snapshots, - mvpFeature, - releases, - releasePlans, ]); if (!allResourcesLoaded || workflowNodes.length === 0 || allErrors.length > 0) { diff --git a/src/components/Releases/ReleaseOverviewTab.tsx b/src/components/Releases/ReleaseOverviewTab.tsx index 2c2d38a..3701d62 100644 --- a/src/components/Releases/ReleaseOverviewTab.tsx +++ b/src/components/Releases/ReleaseOverviewTab.tsx @@ -1,12 +1,14 @@ import * as React from 'react'; import { Link, useParams } from 'react-router-dom'; import { + Bullseye, DescriptionList, DescriptionListDescription, DescriptionListGroup, DescriptionListTerm, Flex, FlexItem, + Spinner, Title, } from '@patternfly/react-core'; import { useReleasePlan } from '../../hooks/useReleasePlans'; @@ -36,6 +38,14 @@ const ReleaseOverviewTab: React.FC = () => { ); const status = useReleaseStatus(release); + if (!releasePlanLoaded) { + return ( + + + + ); + } + return ( <> diff --git a/src/components/Releases/__tests__/ReleaseOverviewTab.spec.tsx b/src/components/Releases/__tests__/ReleaseOverviewTab.spec.tsx index 2cecef6..1d55dab 100644 --- a/src/components/Releases/__tests__/ReleaseOverviewTab.spec.tsx +++ b/src/components/Releases/__tests__/ReleaseOverviewTab.spec.tsx @@ -19,13 +19,18 @@ jest.mock('../../../hooks/useReleases', () => ({ const watchResourceMock = createK8sWatchResourceMock(); describe('ReleaseOverviewTab', () => { - beforeEach(() => { - watchResourceMock.mockReturnValue([{ spec: { application: 'test-app' } }, true]); - }); + beforeEach(() => {}); createUseWorkspaceInfoMock({ namespace: 'test-ns', workspace: 'test-ws' }); + it('should render loading indicator', () => { + watchResourceMock.mockReturnValue([{ spec: { application: 'test-app' } }, false]); + render(<ReleaseOverviewTab />); + expect(screen.getByRole('progressbar')).toBeVisible(); + }); + it('should render correct details', () => { + watchResourceMock.mockReturnValue([{ spec: { application: 'test-app' } }, true]); render(<ReleaseOverviewTab />); expect(screen.getByText('Duration')).toBeVisible(); expect(screen.getByText('10 seconds')).toBeVisible(); diff --git a/src/components/SnapshotDetails/SnapshotDetailsView.tsx b/src/components/SnapshotDetails/SnapshotDetailsView.tsx index 585e05b..e0f531f 100644 --- a/src/components/SnapshotDetails/SnapshotDetailsView.tsx +++ b/src/components/SnapshotDetails/SnapshotDetailsView.tsx @@ -7,7 +7,6 @@ import { useSnapshot } from '../../hooks/useSnapshots'; import { HttpError } from '../../k8s/error'; import { RouterParams } from '../../routes/utils'; import ErrorEmptyState from '../../shared/components/empty-state/ErrorEmptyState'; -import { LoadingBox } from '../../shared/components/status-box/StatusBox'; import { Timestamp } from '../../shared/components/timestamp/Timestamp'; import { useApplicationBreadcrumbs } from '../../utils/breadcrumb-utils'; import { createCommitObjectFromPLR } from '../../utils/commits-utils'; @@ -50,7 +49,11 @@ const SnapshotDetailsView: React.FC = () => { } if (!plrLoadError && !plrLoaded) { - return <LoadingBox />; + return ( + <Bullseye> + <Spinner size="lg" /> + </Bullseye> + ); } if (snapshot?.metadata) { diff --git a/src/components/SnapshotDetails/__tests__/SnapshotDetailsView.spec.tsx b/src/components/SnapshotDetails/__tests__/SnapshotDetailsView.spec.tsx index 238c52a..16eba2f 100644 --- a/src/components/SnapshotDetails/__tests__/SnapshotDetailsView.spec.tsx +++ b/src/components/SnapshotDetails/__tests__/SnapshotDetailsView.spec.tsx @@ -67,10 +67,10 @@ describe('SnapshotDetailsView', () => { (useCommitStatus as jest.Mock).mockReturnValueOnce(['-', true]); }); - it('should render spinner if test data is not loaded', () => { + it('should render loading indicator', () => { watchResourceMock.mockReturnValue([[], false]); renderWithQueryClientAndRouter(<SnapshotDetails />); - expect(screen.getByTestId('loading-indicator')).toBeInTheDocument(); + screen.getByRole('progressbar'); }); it('should show error state if test cannot be loaded', () => { diff --git a/src/hooks/__tests__/useApplicationReleases.spec.ts b/src/hooks/__tests__/useApplicationReleases.spec.ts index 19e3b1f..2ef951d 100644 --- a/src/hooks/__tests__/useApplicationReleases.spec.ts +++ b/src/hooks/__tests__/useApplicationReleases.spec.ts @@ -15,6 +15,32 @@ const watchResourceMock = createK8sWatchResourceMock(); const useSnapshotsMock = useApplicationSnapshots as jest.Mock; describe('useApplicationReleases', () => { + it('should return empty array incase release are not loaded', () => { + watchResourceMock.mockReturnValue([[], false]); + useSnapshotsMock.mockReturnValue([ + [{ metadata: { name: 'my-snapshot' } }, { metadata: { name: 'my-snapshot-2' } }], + true, + ]); + + const { result } = renderHook(() => useApplicationReleases('test-app')); + const [results, loaded] = result.current; + expect(loaded).toEqual(false); + expect(results.length).toEqual(0); + }); + + it('should return empty array incase snapshots are not loaded', () => { + watchResourceMock.mockReturnValue([[], true]); + useSnapshotsMock.mockReturnValue([ + [{ metadata: { name: 'my-snapshot' } }, { metadata: { name: 'my-snapshot-2' } }], + false, + ]); + + const { result } = renderHook(() => useApplicationReleases('test-app')); + const [results, loaded] = result.current; + expect(loaded).toEqual(false); + expect(results.length).toEqual(0); + }); + it('should only return releases that are in the application', () => { watchResourceMock.mockReturnValue([ [ diff --git a/src/hooks/useApplicationReleases.ts b/src/hooks/useApplicationReleases.ts index 5af5873..92d7ef3 100644 --- a/src/hooks/useApplicationReleases.ts +++ b/src/hooks/useApplicationReleases.ts @@ -26,8 +26,11 @@ export const useApplicationReleases = ( const [snapshots, snapshotsLoaded, snapshotsError] = useApplicationSnapshots(applicationName); const releasesForApp = React.useMemo( - () => releases.filter((r) => snapshots.some((s) => s.metadata.name === r.spec.snapshot)), - [releases, snapshots], + () => + !releasesLoaded && snapshotsLoaded + ? releases.filter((r) => snapshots.some((s) => s.metadata.name === r.spec.snapshot)) + : [], + [releases, releasesLoaded, snapshots, snapshotsLoaded], ); return [releasesForApp, !releasesLoaded && snapshotsLoaded, releasesError || snapshotsError]; diff --git a/src/hooks/useReleasePlans.ts b/src/hooks/useReleasePlans.ts index 40c3966..642ad1e 100644 --- a/src/hooks/useReleasePlans.ts +++ b/src/hooks/useReleasePlans.ts @@ -30,7 +30,6 @@ export const useReleasePlan = ( namespace, workspace, name, - isList: true, }, ReleasePlanModel, );