feat: [AH-1118]: Support Showing Account/Org Level scan data in registry ui (#3574)

* feat: [AH-1118]: remove duplicate variables
* feat: [AH-1118]: update failing test config
* feat: [AH-1118]: fix issue with redirecting to tab on click of ssca and sto integration overview cards on version details page
* feat: [AH-1118]: Support showing note in configuration page
* feat: [AH-118]: Support different project, org in version details page for ssca and sto data
main
Shivanand Sonnad 2025-03-19 13:32:07 +00:00 committed by Harness
parent 642fa7e2a5
commit 7bbd5cdef1
23 changed files with 224 additions and 30 deletions

View File

@ -90,7 +90,7 @@ module.exports = {
// }
// },
transformIgnorePatterns: [
'node_modules/(?!(date-fns|lodash-es|@harnessio/uicore|@harnessio/design-system|@harnessio/react-har-service-client|@harnessio/react-ssca-manager-client)/)'
'node_modules/(?!(date-fns|lodash-es|@harnessio/uicore|@harnessio/design-system|@harnessio/react-har-service-client|@harnessio/react-ssca-manager-client|@harnessio/react-ng-manager-client)/)'
],
testPathIgnorePatterns: ['<rootDir>/dist', '<rootDir>/src/static']
}

View File

@ -52,6 +52,7 @@
"@harnessio/design-system": "^2.1.1",
"@harnessio/icons": "^2.1.9",
"@harnessio/react-har-service-client": "^0.15.0",
"@harnessio/react-ng-manager-client": "^1.40.0",
"@harnessio/react-ssca-manager-client": "^0.65.0",
"@harnessio/uicore": "^4.1.2",
"@tanstack/react-query": "4.20.4",

View File

@ -17,6 +17,7 @@
import { useRef } from 'react'
import { HARServiceAPIClient } from '@harnessio/react-har-service-client'
import { SSCAManagerAPIClient } from '@harnessio/react-ssca-manager-client'
import { NGManagerServiceAPIClient } from '@harnessio/react-ng-manager-client'
import type { CustomUtils } from '@ar/MFEAppTypes'
@ -62,4 +63,14 @@ export default function useOpenApiClient({ on401, customUtils }: useOpenApiClien
}
})
)
useRef<NGManagerServiceAPIClient>(
new NGManagerServiceAPIClient({
responseInterceptor,
requestInterceptor,
urlInterceptor: (url: string) => {
return window.getApiBaseUrl(url)
}
})
)
}

View File

@ -34,3 +34,6 @@ export enum PreferenceScope {
USER = 'USER',
MACHINE = 'MACHINE' // or workstation. This will act as default PreferenceScope
}
export const DEFAULT_ORG = 'default'
export const DEFAULT_PROJECT = 'default_project'

View File

@ -51,6 +51,15 @@ jest.mock('react-router-dom', () => ({
})
}))
jest.mock('@harnessio/react-ng-manager-client', () => ({
useGetOrgScopedProjectQuery: jest.fn().mockImplementation(() => ({
isFetching: false,
refetch: jest.fn(),
error: false,
data: { content: { data: {} } }
}))
}))
jest.mock('@harnessio/react-har-service-client', () => ({
useGetRegistryQuery: jest.fn().mockImplementation(() => ({
isFetching: false,

View File

@ -60,6 +60,15 @@ jest.mock('react-router-dom', () => ({
})
}))
jest.mock('@harnessio/react-ng-manager-client', () => ({
useGetOrgScopedProjectQuery: jest.fn().mockImplementation(() => ({
isFetching: false,
refetch: jest.fn(),
error: false,
data: { content: { data: {} } }
}))
}))
jest.mock('@harnessio/react-har-service-client', () => ({
useGetRegistryQuery: jest.fn().mockImplementation(() => ({
isFetching: false,

View File

@ -48,3 +48,9 @@
column-gap: var(--spacing-medium);
row-gap: var(--spacing-medium);
}
.helperText {
font-size: var(--font-size-small);
font-weight: 400;
color: var(--gray-900);
}

View File

@ -18,6 +18,7 @@
// This is an auto-generated file
export declare const cardContainer: string
export declare const cardHeading: string
export declare const helperText: string
export declare const includeExcludeWrapper: string
export declare const marginTopLarge: string
export declare const scannersContainer: string

View File

@ -41,7 +41,6 @@ export default function SelectContainerScannersFormSection(
}, [packageType])
if (!availableScannerOptions.length) return <></>
return (
<SelectScannerFormSection
title={getString('repositoryDetails.repositoryForm.securityScan.containerScannerSelect.cardTitle')}

View File

@ -16,14 +16,15 @@
import React from 'react'
import { useFormikContext } from 'formik'
import { FontVariation } from '@harnessio/design-system'
import { Icon } from '@harnessio/icons'
import { Color, FontVariation } from '@harnessio/design-system'
import { Checkbox, CheckboxVariant, Container, Layout, Text } from '@harnessio/uicore'
import { useLicenseStore } from '@ar/hooks'
import { String } from '@ar/frameworks/strings'
import { Scanners, type RepositoryPackageType } from '@ar/common/types'
import { LICENSE_STATE_VALUES } from '@ar/common/LicenseTypes'
import type { VirtualRegistryRequest } from '@ar/pages/repository-details/types'
import type { ScannerConfigSpec } from '@ar/pages/repository-details/constants'
import useCheckRequiredConfigForScan from '@ar/pages/repository-details/hooks/useCheckRequiredConfigForScan/useCheckRequiredConfigForScan'
import css from './FormContent.module.scss'
@ -38,11 +39,9 @@ interface SelectScannerFormSectionProps {
export default function SelectScannerFormSection(props: SelectScannerFormSectionProps) {
const { options, title, subTitle, readonly } = props
const { SSCA_LICENSE_STATE, STO_LICENSE_STATE } = useLicenseStore()
const { setFieldValue, values } = useFormikContext<VirtualRegistryRequest>()
const hasRequiredLicense =
SSCA_LICENSE_STATE === LICENSE_STATE_VALUES.ACTIVE && STO_LICENSE_STATE === LICENSE_STATE_VALUES.ACTIVE
const { hasRequiredLicense, hasRequiredProjectConfig, orgIdentifier } = useCheckRequiredConfigForScan()
const handleUpdateFormikState = (event: React.FormEvent<HTMLInputElement>) => {
const isChecked = event.currentTarget.checked
@ -55,7 +54,7 @@ export default function SelectScannerFormSection(props: SelectScannerFormSection
}
const getCheckboxState = (value: ScannerConfigSpec['value']) => {
return value === Scanners.AQUA_TRIVY
return value === Scanners.AQUA_TRIVY && hasRequiredProjectConfig
// return values.scanners?.some(each => each.name === value) || false
}
@ -81,6 +80,17 @@ export default function SelectScannerFormSection(props: SelectScannerFormSection
</Checkbox>
))}
</Container>
{!hasRequiredProjectConfig && (
<Layout.Horizontal flex={{ alignItems: 'center', justifyContent: 'flex-start' }} spacing="small">
<Icon name="main-info" color={Color.PRIMARY_7} />
<String
useRichText
vars={{ orgName: orgIdentifier }}
className={css.helperText}
stringID="repositoryDetails.repositoryForm.securityScan.containerScannerSelect.scannerNoteForRequiredConfiguration"
/>
</Layout.Horizontal>
)}
</Layout.Vertical>
)
}

View File

@ -41,6 +41,15 @@ jest.mock('@harnessio/react-har-service-client', () => ({
}))
}))
jest.mock('@harnessio/react-ng-manager-client', () => ({
useGetOrgScopedProjectQuery: jest.fn().mockImplementation(() => ({
isFetching: false,
refetch: jest.fn(),
error: false,
data: { content: { data: {} } }
}))
}))
describe('Verify repository configuration form content', () => {
beforeEach(() => {
jest.clearAllMocks()

View File

@ -28,6 +28,15 @@ import SelectContainerScannersFormSection from '../SelectContainerScannersFormSe
import '../../../RepositoryFactory'
jest.mock('@harnessio/react-ng-manager-client', () => ({
useGetOrgScopedProjectQuery: jest.fn().mockImplementation(() => ({
isFetching: false,
refetch: jest.fn(),
error: false,
data: { content: { data: {} } }
}))
}))
describe('verify SelectContainerScannersFormSection', () => {
beforeEach(() => {
jest.clearAllMocks()

View File

@ -0,0 +1,54 @@
/*
* Copyright 2024 Harness, Inc.
*
* 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 { useGetOrgScopedProjectQuery } from '@harnessio/react-ng-manager-client'
import { useAppStore, useLicenseStore } from '@ar/hooks'
import { LICENSE_STATE_VALUES } from '@ar/common/LicenseTypes'
import { DEFAULT_ORG, DEFAULT_PROJECT } from '@ar/constants'
export default function useCheckRequiredConfigForScan(): {
hasRequiredLicense: boolean
hasRequiredProjectConfig: boolean
hasRequiredConfig: boolean
orgIdentifier: string
} {
const { scope } = useAppStore()
const { orgIdentifier, projectIdentifier } = scope
const { SSCA_LICENSE_STATE, STO_LICENSE_STATE } = useLicenseStore()
const hasRequiredLicense =
SSCA_LICENSE_STATE === LICENSE_STATE_VALUES.ACTIVE && STO_LICENSE_STATE === LICENSE_STATE_VALUES.ACTIVE
const { isFetching, error } = useGetOrgScopedProjectQuery(
{
org: orgIdentifier ?? DEFAULT_ORG,
project: projectIdentifier ?? DEFAULT_PROJECT
},
{
enabled: !projectIdentifier
}
)
const hasRequiredProjectConfig = !isFetching && !error
const hasRequiredConfig = hasRequiredLicense && hasRequiredProjectConfig
return {
hasRequiredLicense,
hasRequiredProjectConfig,
hasRequiredConfig,
orgIdentifier: orgIdentifier ?? DEFAULT_ORG
}
}

View File

@ -35,6 +35,7 @@ repositoryForm:
containerScannerSelect:
cardTitle: Built-in Container Scanners
cardSubTitle: Container scanners detect vulnerabilities in your container images. Select scanner(s) below to add them in your pipeline.
scannerNoteForRequiredConfiguration: To enable scanning for account level or org level registries, please create a project with id set to <b>default_project</b> in your <b>{{orgName}}</b> org.
tabs:
configuration: Configuration
packages: '{{ $.artifactList.pageHeading }}'

View File

@ -282,25 +282,25 @@ describe('Verify DockerVersionHeader component render', () => {
const overviewTab = container.querySelector('div[data-tab-id=overview]')
await userEvent.click(overviewTab!)
expect(mockHistoryPush).toHaveBeenLastCalledWith(
'/registries/undefined/artifacts/undefined/versions/undefined/overview?digest=sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d'
'/registries/artifacts/versions/overview?digest=sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d'
)
const artifactDetailsTab = container.querySelector('div[data-tab-id=artifact_details]')
await userEvent.click(artifactDetailsTab!)
expect(mockHistoryPush).toHaveBeenLastCalledWith(
'/registries/undefined/artifacts/undefined/versions/undefined/artifact_details?digest=sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d'
'/registries/artifacts/versions/artifact_details?digest=sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d'
)
const sscaTab = container.querySelector('div[data-tab-id=supply_chain]')
await userEvent.click(sscaTab!)
expect(mockHistoryPush).toHaveBeenLastCalledWith(
'/registries/undefined/artifacts/undefined/versions/undefined/artifact-sources/67a5dccf6d75916b0c3ea1b5/artifacts/67a5dccf6d75916b0c3ea1b6/supply_chain?digest=sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d'
'/registries/undefined/artifacts/undefined/versions/undefined/orgs/default/projects/default_project/artifact-sources/67a5dccf6d75916b0c3ea1b5/artifacts/67a5dccf6d75916b0c3ea1b6/supply_chain?digest=sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d'
)
const stoTab = container.querySelector('div[data-tab-id=security_tests]')
await userEvent.click(stoTab!)
expect(mockHistoryPush).toHaveBeenLastCalledWith(
'/registries/undefined/artifacts/undefined/versions/undefined/pipelines/HARNESS_ARTIFACT_SCAN_PIPELINE/executions/Tbi7s6nETjmOMKU3Qrnm7A/security_tests?digest=sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d'
'/registries/undefined/artifacts/undefined/versions/undefined/orgs/default/projects/default_project/pipelines/HARNESS_ARTIFACT_SCAN_PIPELINE/executions/Tbi7s6nETjmOMKU3Qrnm7A/security_tests?digest=sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d'
)
})
@ -323,25 +323,25 @@ describe('Verify DockerVersionHeader component render', () => {
const overviewTab = container.querySelector('div[data-tab-id=overview]')
await userEvent.click(overviewTab!)
expect(mockHistoryPush).toHaveBeenLastCalledWith(
'/registries/undefined/artifacts/undefined/versions/undefined/overview?digest=sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d'
'/registries/artifacts/versions/overview?digest=sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d'
)
const artifactDetailsTab = container.querySelector('div[data-tab-id=artifact_details]')
await userEvent.click(artifactDetailsTab!)
expect(mockHistoryPush).toHaveBeenLastCalledWith(
'/registries/undefined/artifacts/undefined/versions/undefined/artifact_details?digest=sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d'
'/registries/artifacts/versions/artifact_details?digest=sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d'
)
const sscaTab = container.querySelector('div[data-tab-id=supply_chain]')
await userEvent.click(sscaTab!)
expect(mockHistoryPush).toHaveBeenLastCalledWith(
'/registries/undefined/artifacts/undefined/versions/undefined/supply_chain?digest=sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d'
'/registries/undefined/artifacts/undefined/versions/undefined/orgs/default/projects/default_project/supply_chain?digest=sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d'
)
const stoTab = container.querySelector('div[data-tab-id=security_tests]')
await userEvent.click(stoTab!)
expect(mockHistoryPush).toHaveBeenLastCalledWith(
'/registries/undefined/artifacts/undefined/versions/undefined/security_tests?digest=sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d'
'/registries/undefined/artifacts/undefined/versions/undefined/orgs/default/projects/default_project/security_tests?digest=sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d'
)
})
})

View File

@ -145,7 +145,7 @@ describe('Verify docker version overview page', () => {
await userEvent.click(sscaCard)
await waitFor(() => {
expect(mockHistoryPush).toHaveBeenCalledWith(
'/registries/1/artifacts/1/versions/1/artifact-sources/67a5dccf6d75916b0c3ea1b5/artifacts/67a5dccf6d75916b0c3ea1b6/supply_chain?digest=sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d'
'/registries/1/artifacts/1/versions/1/orgs/default/projects/default_project/artifact-sources/67a5dccf6d75916b0c3ea1b5/artifacts/67a5dccf6d75916b0c3ea1b6/supply_chain?digest=sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d'
)
})
@ -159,7 +159,7 @@ describe('Verify docker version overview page', () => {
await userEvent.click(securityTestsCard)
await waitFor(() => {
expect(mockHistoryPush).toHaveBeenCalledWith(
'/registries/1/artifacts/1/versions/1/pipelines/HARNESS_ARTIFACT_SCAN_PIPELINE/executions/Tbi7s6nETjmOMKU3Qrnm7A/security_tests?digest=sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d'
'/registries/1/artifacts/1/versions/1/orgs/default/projects/default_project/pipelines/HARNESS_ARTIFACT_SCAN_PIPELINE/executions/Tbi7s6nETjmOMKU3Qrnm7A/security_tests?digest=sha256:144cdab68a435424250fe06e9a4f8a5f6b6b8a8a55d257bc6ee77476a6ec520d'
)
})
})

View File

@ -23,8 +23,9 @@ import { useGetDockerArtifactIntegrationDetailsQuery } from '@harnessio/react-ha
import { encodeRef } from '@ar/hooks/useGetSpaceRef'
import { useStrings } from '@ar/frameworks/strings'
import { DEFAULT_ORG, DEFAULT_PROJECT } from '@ar/constants'
import type { VersionDetailsPathParams } from '@ar/routes/types'
import { useDecodedParams, useGetSpaceRef, useRoutes } from '@ar/hooks'
import { useAppStore, useDecodedParams, useGetSpaceRef, useRoutes } from '@ar/hooks'
import DeploymentsCard from '@ar/pages/version-details/components/DeploymentsCard/DeploymentsCard'
import SecurityTestsCard from '@ar/pages/version-details/components/SecurityTestsCard/SecurityTestsCard'
import SupplyChainCard from '@ar/pages/version-details/components/SupplyChainCard/SupplyChainCard'
@ -40,6 +41,8 @@ interface RedirectToTabOptions {
artifactId?: string
executionIdentifier?: string
pipelineIdentifier?: string
orgIdentifier?: string
projectIdentifier?: string
}
interface VersionOverviewCardsProps {
@ -51,6 +54,8 @@ export default function VersionOverviewCards(props: VersionOverviewCardsProps) {
const { digest = '', cards = [] } = props
const { getString } = useStrings()
const routes = useRoutes()
const { scope } = useAppStore()
const { orgIdentifier, projectIdentifier } = scope
const pathParams = useDecodedParams<VersionDetailsPathParams>()
const history = useHistory()
const spaceRef = useGetSpaceRef()
@ -112,7 +117,9 @@ export default function VersionOverviewCards(props: VersionOverviewCardsProps) {
onClick={() => {
handleRedirectToTab(VersionDetailsTab.SUPPLY_CHAIN, {
sourceId: responseData.sbomDetails?.artifactSourceId,
artifactId: responseData.sbomDetails?.artifactId
artifactId: responseData.sbomDetails?.artifactId,
orgIdentifier: !orgIdentifier ? DEFAULT_ORG : undefined,
projectIdentifier: !projectIdentifier ? DEFAULT_PROJECT : undefined
})
}}
orchestrationId={defaultTo(responseData.sbomDetails?.orchestrationId, '')}
@ -129,7 +136,9 @@ export default function VersionOverviewCards(props: VersionOverviewCardsProps) {
onClick={() => {
handleRedirectToTab(VersionDetailsTab.SECURITY_TESTS, {
executionIdentifier: responseData?.stoDetails?.executionId,
pipelineIdentifier: responseData?.stoDetails?.pipelineId
pipelineIdentifier: responseData?.stoDetails?.pipelineId,
orgIdentifier: !orgIdentifier ? DEFAULT_ORG : undefined,
projectIdentifier: !projectIdentifier ? DEFAULT_PROJECT : undefined
})
}}
totalCount={defaultTo(responseData.stoDetails?.total, 0)}

View File

@ -20,7 +20,8 @@ import { Container, Tab, Tabs } from '@harnessio/uicore'
import { useStrings } from '@ar/frameworks/strings'
import { useQueryParams } from '@ar/__mocks__/hooks'
import { useDecodedParams, useRoutes } from '@ar/hooks'
import { DEFAULT_ORG, DEFAULT_PROJECT } from '@ar/constants'
import { useAppStore, useDecodedParams, useRoutes } from '@ar/hooks'
import type { RepositoryPackageType } from '@ar/common/types'
import type { VersionDetailsPathParams } from '@ar/routes/types'
import versionFactory from '@ar/frameworks/Version/VersionFactory'
@ -30,7 +31,9 @@ import { VersionProviderContext } from '@ar/pages/version-details/context/Versio
import {
versionDetailsPathParams,
versionDetailsTabPathParams,
versionDetailsTabWithOrgAndProjectPathParams,
versionDetailsTabWithPipelineDetailsPathParams,
versionDetailsTabWithProjectPathParams,
versionDetailsTabWithSSCADetailsPathParams
} from '@ar/routes/RouteDestinations'
@ -42,12 +45,14 @@ export default function VersionDetailsTabs(): JSX.Element {
const [tab, setTab] = useState('')
const routes = useRoutes()
const { scope } = useAppStore()
const history = useHistory()
const { getString } = useStrings()
const routeDefinitions = useRoutes(true)
const { data } = useContext(VersionProviderContext)
const pathParams = useDecodedParams<VersionDetailsPathParams>()
const { digest } = useQueryParams<DockerVersionDetailsQueryParams>()
const { orgIdentifier, projectIdentifier } = scope
const tabList = useMemo(() => {
const versionType = versionFactory?.getVersionType(data?.packageType)
@ -65,7 +70,9 @@ export default function VersionDetailsTabs(): JSX.Element {
...pathParams,
versionTab: nextTab,
sourceId: data?.sscaArtifactSourceId,
artifactId: data?.sscaArtifactId
artifactId: data?.sscaArtifactId,
orgIdentifier: !orgIdentifier ? DEFAULT_ORG : undefined,
projectIdentifier: !projectIdentifier ? DEFAULT_PROJECT : undefined
})
break
case VersionDetailsTab.SECURITY_TESTS:
@ -73,11 +80,18 @@ export default function VersionDetailsTabs(): JSX.Element {
...pathParams,
versionTab: nextTab,
executionIdentifier: data?.stoExecutionId,
pipelineIdentifier: data?.stoPipelineId
pipelineIdentifier: data?.stoPipelineId,
orgIdentifier: !orgIdentifier ? DEFAULT_ORG : undefined,
projectIdentifier: !projectIdentifier ? DEFAULT_PROJECT : undefined
})
break
default:
newRoute = routes.toARVersionDetailsTab({ ...pathParams, versionTab: nextTab })
newRoute = routes.toARVersionDetailsTab({
versionIdentifier: pathParams.versionIdentifier,
artifactIdentifier: pathParams.artifactIdentifier,
repositoryIdentifier: pathParams.repositoryIdentifier,
versionTab: nextTab
})
break
}
if (digest) {
@ -106,8 +120,34 @@ export default function VersionDetailsTabs(): JSX.Element {
exact
path={[
routeDefinitions.toARVersionDetailsTab({ ...versionDetailsTabPathParams }),
// with project and org data
routeDefinitions.toARVersionDetailsTab({
...versionDetailsTabWithOrgAndProjectPathParams
}),
// ssca with pipeline data
routeDefinitions.toARVersionDetailsTab({ ...versionDetailsTabWithSSCADetailsPathParams }),
routeDefinitions.toARVersionDetailsTab({ ...versionDetailsTabWithPipelineDetailsPathParams })
// ssca with project and pipeline data
routeDefinitions.toARVersionDetailsTab({
...versionDetailsTabWithSSCADetailsPathParams,
...versionDetailsTabWithProjectPathParams
}),
// ssca with org, project and pipeline data
routeDefinitions.toARVersionDetailsTab({
...versionDetailsTabWithSSCADetailsPathParams,
...versionDetailsTabWithOrgAndProjectPathParams
}),
// sto with pipeline data
routeDefinitions.toARVersionDetailsTab({ ...versionDetailsTabWithPipelineDetailsPathParams }),
// sto with project and pipeline data
routeDefinitions.toARVersionDetailsTab({
...versionDetailsTabWithPipelineDetailsPathParams,
...versionDetailsTabWithProjectPathParams
}),
// sto with org, project and pipeline data
routeDefinitions.toARVersionDetailsTab({
...versionDetailsTabWithPipelineDetailsPathParams,
...versionDetailsTabWithOrgAndProjectPathParams
})
]}>
<VersionDetailsTabWidget
onInit={setTab}

View File

@ -63,13 +63,17 @@ export const routeDefinitions: ARRouteDefinitionsReturn = {
toARVersionDetails: params =>
`/registries/${params?.repositoryIdentifier}/artifacts/${params?.artifactIdentifier}/versions/${params?.versionIdentifier}`,
toARVersionDetailsTab: params => {
let route = `/registries/${params?.repositoryIdentifier}/artifacts/${params?.artifactIdentifier}/versions/${params?.versionIdentifier}`
if (params.orgIdentifier) route += `/orgs/${params.orgIdentifier}`
if (params.projectIdentifier) route += `/projects/${params.projectIdentifier}`
if (params.sourceId && params.artifactId) {
return `/registries/${params?.repositoryIdentifier}/artifacts/${params?.artifactIdentifier}/versions/${params?.versionIdentifier}/artifact-sources/${params.sourceId}/artifacts/${params.artifactId}/${params.versionTab}`
route += `/artifact-sources/${params.sourceId}/artifacts/${params.artifactId}`
}
if (params.pipelineIdentifier && params.executionIdentifier) {
return `/registries/${params?.repositoryIdentifier}/artifacts/${params?.artifactIdentifier}/versions/${params?.versionIdentifier}/pipelines/${params.pipelineIdentifier}/executions/${params.executionIdentifier}/${params.versionTab}`
route += `/pipelines/${params.pipelineIdentifier}/executions/${params.executionIdentifier}`
}
return `/registries/${params?.repositoryIdentifier}/artifacts/${params?.artifactIdentifier}/versions/${params?.versionIdentifier}/${params.versionTab}`
route += `/${params.versionTab}`
return route
},
toARRepositoryWebhookDetails: params =>
`/registries/${params?.repositoryIdentifier}/webhooks/${params?.webhookIdentifier}`,

View File

@ -66,6 +66,17 @@ export const versionDetailsTabPathParams: VersionDetailsTabPathParams = {
versionTab: ':versionTab'
}
export const versionDetailsTabWithProjectPathParams: VersionDetailsTabPathParams = {
...versionDetailsTabPathParams,
projectIdentifier: ':projectIdentifier'
}
export const versionDetailsTabWithOrgAndProjectPathParams: VersionDetailsTabPathParams = {
...versionDetailsTabPathParams,
orgIdentifier: ':orgIdentifier',
projectIdentifier: ':projectIdentifier'
}
export const versionDetailsTabWithPipelineDetailsPathParams: VersionDetailsTabPathParams = {
...versionDetailsTabPathParams,
pipelineIdentifier: ':pipelineIdentifier',

View File

@ -41,6 +41,8 @@ export interface VersionDetailsTabPathParams extends VersionDetailsPathParams {
executionIdentifier?: string
artifactId?: string
sourceId?: string
orgIdentifier?: string
projectIdentifier?: string
}
export interface RedirectPageQueryParams {

View File

@ -87,6 +87,7 @@ export interface StringsMap {
'repositoryDetails.repositoryForm.repositoryUpdated': string
'repositoryDetails.repositoryForm.securityScan.containerScannerSelect.cardSubTitle': string
'repositoryDetails.repositoryForm.securityScan.containerScannerSelect.cardTitle': string
'repositoryDetails.repositoryForm.securityScan.containerScannerSelect.scannerNoteForRequiredConfiguration': string
'repositoryDetails.repositoryForm.securityScan.title': string
'repositoryDetails.repositoryForm.selectRepoType': string
'repositoryDetails.repositoryForm.title': string

View File

@ -1952,6 +1952,11 @@
dependencies:
"@harnessio/oats-cli" "^3.0.0"
"@harnessio/react-ng-manager-client@^1.40.0":
version "1.40.0"
resolved "https://registry.yarnpkg.com/@harnessio/react-ng-manager-client/-/react-ng-manager-client-1.40.0.tgz#e874e9afe1b2358d85364d5e23aabe9f6157bae8"
integrity sha512-PETKrA+4TmFs3e+Ok99zPi0ngvGwVJqX5HKczxTWtaDrfXiu/ktZYX5pDN9GBBibShadT0ONbRe4xN6ILFPIuA==
"@harnessio/react-ssca-manager-client@^0.65.0":
version "0.65.0"
resolved "https://registry.yarnpkg.com/@harnessio/react-ssca-manager-client/-/react-ssca-manager-client-0.65.0.tgz#8088869e282c5268bf1fefb9715652e0fc1a8940"