mirror of
https://github.com/harness/drone.git
synced 2025-05-05 15:32:56 +00:00
feat: [AH-1192]: Tree view implementation (#3736)
* feat: [AH-1192]: fix failing PR checks * feat: [AH-1192]: rebase with main and fix bugs * feat: [AH-1192]: Implement digest list view in tree view (#3733) * feat: [AH-1192]: do not encode query params * feat: [AH-1192]: Implement digest list view in tree view * feat: [AH-1192]: Support version list and details in tree view (#3727) * feat: [AH-1192]: resolve PR comments * feat: [AH-1192]: Support version list and details in tree view * feat: [AH-1192]: Implement artifact list tree view and artifact tree node details view (#3694) * feat: [AH-1192]: add factory implementation for artifact details node view * feat: [AH-1192]: Implement artifact list tree view and artifact tree node details view * feat: [AH-1192]: implement a repository list and details route in tree view (#3685) * feat: [AH-1192]: refactor refetch logic * feat: [AH-1192]: fix failing unit tests * feat: [AH-1192]: implement a repository list and details route in tree view * feat: [AH-1192]: Implement landing page for
This commit is contained in:
parent
92f986122f
commit
38e2ec8308
@ -77,6 +77,7 @@ module.exports = {
|
||||
'monaco-editor': '<rootDir>/node_modules/react-monaco-editor',
|
||||
'\\.(jpg|jpeg|png|gif|svg|eot|otf|webp|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
|
||||
'<rootDir>/scripts/jest/file-mock.js',
|
||||
'\\.svg?.url': '<rootDir>/scripts/jest/file-mock.js',
|
||||
'@uiw/react-markdown-preview': '<rootDir>/node_modules/@uiw/react-markdown-preview/dist/markdown.min.js',
|
||||
...pathsToModuleNameMapper(compilerOptions.paths)
|
||||
},
|
||||
|
@ -135,5 +135,6 @@ export interface MFEAppProps {
|
||||
export enum FeatureFlags {
|
||||
HAR_TRIGGERS = 'HAR_TRIGGERS',
|
||||
HAR_NUGET_PACKAGE_TYPE_ENABLED = 'HAR_NUGET_PACKAGE_TYPE_ENABLED',
|
||||
HAR_RPM_PACKAGE_TYPE_ENABLED = 'HAR_RPM_PACKAGE_TYPE_ENABLED'
|
||||
HAR_RPM_PACKAGE_TYPE_ENABLED = 'HAR_RPM_PACKAGE_TYPE_ENABLED',
|
||||
HAR_TREE_VIEW_ENABLED = 'HAR_TREE_VIEW_ENABLED'
|
||||
}
|
||||
|
@ -19,13 +19,14 @@ import { Page } from '@harnessio/uicore'
|
||||
import { QueryClientProvider } from '@tanstack/react-query'
|
||||
|
||||
import { StringsContextProvider } from '@ar/frameworks/strings/StringsContextProvider'
|
||||
import { AppStoreContext } from '@ar/contexts/AppStoreContext'
|
||||
import { AppStoreContext, RepositoryListViewTypeEnum } from '@ar/contexts/AppStoreContext'
|
||||
import ParentProvider from '@ar/contexts/ParentProvider'
|
||||
import type { ParentProviderProps } from '@ar/contexts/ParentProvider'
|
||||
import { queryClient } from '@ar/utils/queryClient'
|
||||
|
||||
import { Parent } from '@ar/common/types'
|
||||
import strings from '@ar/strings/strings.en.yaml'
|
||||
import { PreferenceScope } from '@ar/constants'
|
||||
import type { MFEAppProps } from '@ar/MFEAppTypes'
|
||||
import DefaultNavComponent from '@ar/__mocks__/components/DefaultNavComponent'
|
||||
import AppErrorBoundary from '@ar/components/AppErrorBoundary/AppErrorBoundary'
|
||||
@ -60,6 +61,10 @@ export default function ChildApp(props: PropsWithChildren<MFEAppProps>): React.R
|
||||
|
||||
const { ModalProvider } = customComponents
|
||||
const appStoreData = React.useContext(parentContextObj.appStoreContext)
|
||||
const { usePreferenceStore } = customHooks
|
||||
const { preference: repositoryListViewType, setPreference: setRepositoryListViewType } = usePreferenceStore<
|
||||
RepositoryListViewTypeEnum | undefined
|
||||
>(PreferenceScope.USER, 'RepositoryListViewType')
|
||||
|
||||
useOpenApiClient({ on401, customUtils })
|
||||
|
||||
@ -81,6 +86,8 @@ export default function ChildApp(props: PropsWithChildren<MFEAppProps>): React.R
|
||||
matchPath,
|
||||
baseUrl: renderUrl,
|
||||
scope: { ...scope, ...customScope },
|
||||
repositoryListViewType: repositoryListViewType || RepositoryListViewTypeEnum.LIST,
|
||||
setRepositoryListViewType,
|
||||
parent
|
||||
}}>
|
||||
<StringsContextProvider initialStrings={strings}>
|
||||
|
@ -20,11 +20,18 @@ import type { PropsWithChildren } from 'react'
|
||||
import { Parent } from '@ar/common/types'
|
||||
import { useAppStore, useDecodedParams, useDeepCompareEffect } from '@ar/hooks'
|
||||
|
||||
export default function ParentSyncProvider(props: PropsWithChildren<unknown>) {
|
||||
const pathParams = useDecodedParams<Record<string, unknown>>()
|
||||
interface ParentSyncProviderProps {
|
||||
onLoad?: (pathParams: Record<string, string>) => void
|
||||
}
|
||||
|
||||
export default function ParentSyncProvider(props: PropsWithChildren<ParentSyncProviderProps>) {
|
||||
const pathParams = useDecodedParams<Record<string, string>>()
|
||||
const { updateAppStore, parent } = useAppStore()
|
||||
|
||||
useDeepCompareEffect(() => {
|
||||
if (typeof props.onLoad === 'function') {
|
||||
props.onLoad(pathParams)
|
||||
}
|
||||
if (typeof updateAppStore === 'function' && parent !== Parent.Enterprise) {
|
||||
updateAppStore({
|
||||
repositoryIdentifier: pathParams?.repositoryIdentifier as string,
|
||||
|
@ -24,15 +24,16 @@ import ParentSyncProvider from './ParentSyncProvider'
|
||||
|
||||
interface RouteProviderProps extends RouteProps {
|
||||
enabled?: boolean
|
||||
onLoad?: (pathParams: Record<string, string>) => void
|
||||
}
|
||||
|
||||
function RouteProvider(props: PropsWithChildren<RouteProviderProps>) {
|
||||
const { children, enabled = true, ...rest } = props
|
||||
const { children, enabled = true, onLoad, ...rest } = props
|
||||
const { ModalProvider } = useParentComponents()
|
||||
if (!enabled) return <></>
|
||||
return (
|
||||
<Route {...rest}>
|
||||
<ParentSyncProvider>
|
||||
<ParentSyncProvider onLoad={onLoad}>
|
||||
<ModalProvider>{children}</ModalProvider>
|
||||
</ParentSyncProvider>
|
||||
</Route>
|
||||
|
48
web/src/ar/components/TreeView/TreeBody.tsx
Normal file
48
web/src/ar/components/TreeView/TreeBody.tsx
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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 React, { type PropsWithChildren } from 'react'
|
||||
import { Spinner } from '@blueprintjs/core'
|
||||
import { PageError, Text } from '@harnessio/uicore'
|
||||
|
||||
import { useStrings } from '@ar/frameworks/strings'
|
||||
|
||||
import TreeNode from './TreeNode'
|
||||
|
||||
interface TreeBodyProps {
|
||||
loading?: boolean
|
||||
error?: string
|
||||
retryOnError?: () => void
|
||||
isEmpty?: boolean
|
||||
emptyDataMessage?: string
|
||||
}
|
||||
|
||||
export default function TreeBody(props: PropsWithChildren<TreeBodyProps>) {
|
||||
const { loading, error, retryOnError, emptyDataMessage, isEmpty } = props
|
||||
const { getString } = useStrings()
|
||||
if (loading) return <Spinner size={Spinner.SIZE_SMALL} />
|
||||
if (error) return <PageError message={error} onClick={retryOnError} />
|
||||
if (isEmpty)
|
||||
return (
|
||||
<TreeNode
|
||||
disabled
|
||||
level={1}
|
||||
isLastChild
|
||||
heading={<Text>{emptyDataMessage ?? getString('noResultsFound')}</Text>}
|
||||
/>
|
||||
)
|
||||
return <>{props.children}</>
|
||||
}
|
42
web/src/ar/components/TreeView/TreeLoadMoreNode.tsx
Normal file
42
web/src/ar/components/TreeView/TreeLoadMoreNode.tsx
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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 React from 'react'
|
||||
import { Button, ButtonSize, ButtonVariation } from '@harnessio/uicore'
|
||||
|
||||
import { useStrings } from '@ar/frameworks/strings'
|
||||
|
||||
import TreeNode, { TreeNodeProps } from './TreeNode'
|
||||
|
||||
export default function TreeLoadMoreNode(props: Omit<TreeNodeProps, 'heading'>) {
|
||||
const { getString } = useStrings()
|
||||
return (
|
||||
<TreeNode
|
||||
disabled
|
||||
level={props.level}
|
||||
heading={
|
||||
<Button
|
||||
variation={ButtonVariation.LINK}
|
||||
size={ButtonSize.SMALL}
|
||||
minimal
|
||||
onClick={props.onClick}
|
||||
disabled={props.disabled}>
|
||||
{getString('loadMore')}
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
115
web/src/ar/components/TreeView/TreeNode.tsx
Normal file
115
web/src/ar/components/TreeView/TreeNode.tsx
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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 React, { useEffect, useRef, useState, type PropsWithChildren } from 'react'
|
||||
import classNames from 'classnames'
|
||||
import { Icon } from '@harnessio/icons'
|
||||
import { Container } from '@harnessio/uicore'
|
||||
|
||||
import childImage from './images/child.svg?url'
|
||||
import lastChildImage from './images/last-child.svg?url'
|
||||
import lineImage from './images/line.svg?url'
|
||||
|
||||
import type { NodeSpec } from './TreeViewContext'
|
||||
|
||||
import css from './TreeView.module.scss'
|
||||
|
||||
export enum NodeTypeEnum {
|
||||
File = 'File',
|
||||
Folder = 'Folder'
|
||||
}
|
||||
|
||||
export interface TreeNodeProps<T = unknown> extends React.HTMLAttributes<HTMLLIElement> {
|
||||
heading: string | React.ReactNode
|
||||
isActive?: boolean
|
||||
isOpen?: boolean
|
||||
nodeType?: NodeTypeEnum
|
||||
level?: number
|
||||
compact?: boolean
|
||||
disabled?: boolean
|
||||
onClick?: () => void
|
||||
actionElement?: React.ReactNode
|
||||
alwaysShowAction?: boolean
|
||||
isLastChild?: boolean
|
||||
parentNodeLevels?: Array<NodeSpec<T>>
|
||||
}
|
||||
|
||||
export default function TreeNode<T>(props: PropsWithChildren<TreeNodeProps<T>>) {
|
||||
const {
|
||||
isOpen,
|
||||
nodeType = NodeTypeEnum.File,
|
||||
level = 0,
|
||||
onClick,
|
||||
compact = true,
|
||||
disabled,
|
||||
isActive,
|
||||
actionElement,
|
||||
alwaysShowAction,
|
||||
parentNodeLevels = [],
|
||||
isLastChild = false,
|
||||
className,
|
||||
...rest
|
||||
} = props
|
||||
const ref = useRef<HTMLLIElement>(null)
|
||||
const [open, setOpen] = useState(isOpen)
|
||||
const [isMounted, setIsMounted] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
if (open && ref.current) {
|
||||
ref.current.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'center' })
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<li
|
||||
data-level={2}
|
||||
data-last-child={isLastChild}
|
||||
ref={ref}
|
||||
className={classNames(css.treeNode, className)}
|
||||
{...rest}>
|
||||
<Container
|
||||
tabIndex={0}
|
||||
onMouseEnter={() => setIsMounted(true)}
|
||||
onMouseLeave={() => setIsMounted(false)}
|
||||
className={classNames(css.header, {
|
||||
[css.active]: isActive,
|
||||
[css.disabled]: disabled
|
||||
})}
|
||||
onClick={() => {
|
||||
if (disabled) return
|
||||
if (nodeType === NodeTypeEnum.Folder) setOpen(!open)
|
||||
onClick?.()
|
||||
}}>
|
||||
{parentNodeLevels.slice(1).map((_each, indx) => {
|
||||
const img = _each.isLastChild ? undefined : lineImage
|
||||
return <div key={indx} className={css.levelImg} style={{ backgroundImage: `url(${img})` }}></div>
|
||||
})}
|
||||
{level > 0 && (
|
||||
<div
|
||||
className={css.levelImg}
|
||||
style={{ backgroundImage: `url(${isLastChild ? lastChildImage : childImage})` }}></div>
|
||||
)}
|
||||
|
||||
{nodeType === NodeTypeEnum.Folder && <Icon name={open ? 'chevron-down' : 'chevron-right'} />}
|
||||
<Container padding={compact ? 'xsmall' : 'small'} className={css.headingContent}>
|
||||
{props.heading}
|
||||
</Container>
|
||||
{actionElement && (isMounted || alwaysShowAction || isActive) && <Container>{actionElement}</Container>}
|
||||
</Container>
|
||||
{open && <Container>{props.children}</Container>}
|
||||
</li>
|
||||
)
|
||||
}
|
99
web/src/ar/components/TreeView/TreeNodeContent.tsx
Normal file
99
web/src/ar/components/TreeView/TreeNodeContent.tsx
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* 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 React from 'react'
|
||||
import { Layout, Text } from '@harnessio/uicore'
|
||||
import { Icon, type IconName } from '@harnessio/icons'
|
||||
import { Color, FontVariation } from '@harnessio/design-system'
|
||||
|
||||
import { useStrings } from '@ar/frameworks/strings'
|
||||
import { RepositoryConfigType } from '@ar/common/types'
|
||||
|
||||
import css from './TreeView.module.scss'
|
||||
|
||||
interface TreeNodeContentProps {
|
||||
icon?: IconName
|
||||
iconSize?: number
|
||||
label: string
|
||||
downloads?: number
|
||||
size?: string
|
||||
artifacts?: number
|
||||
type?: RepositoryConfigType
|
||||
compact?: boolean
|
||||
}
|
||||
|
||||
export default function TreeNodeContent(props: TreeNodeContentProps) {
|
||||
const { icon, iconSize, label, type, downloads, artifacts, size, compact } = props
|
||||
const { getString } = useStrings()
|
||||
return (
|
||||
<Layout.Horizontal className={css.treeNodeContent} flex={{ alignItems: 'center', justifyContent: 'flex-start' }}>
|
||||
{icon && <Icon name={icon} size={iconSize} />}
|
||||
<Layout.Vertical className={css.labelContainer} spacing="xsmall">
|
||||
<Text font={{ variation: FontVariation.BODY }} lineClamp={1}>
|
||||
{label}
|
||||
</Text>
|
||||
{!compact && (
|
||||
<Layout.Horizontal flex={{ alignItems: 'center', justifyContent: 'flex-start' }} spacing="xsmall">
|
||||
{type && (
|
||||
<>
|
||||
<Text font={{ variation: FontVariation.SMALL }} color={Color.GREY_400} lineClamp={1}>
|
||||
{type === RepositoryConfigType.VIRTUAL
|
||||
? getString('badges.artifactRegistry')
|
||||
: getString('badges.upstreamProxy')}
|
||||
</Text>
|
||||
</>
|
||||
)}
|
||||
|
||||
{size !== undefined && (
|
||||
<Text
|
||||
icon="dot"
|
||||
iconProps={{ size: 8, color: Color.GREY_400 }}
|
||||
font={{ variation: FontVariation.SMALL }}
|
||||
color={Color.GREY_400}
|
||||
lineClamp={1}>
|
||||
{size}
|
||||
</Text>
|
||||
)}
|
||||
{artifacts !== undefined && (
|
||||
<Text
|
||||
icon="dot"
|
||||
iconProps={{ size: 8, color: Color.GREY_400 }}
|
||||
rightIcon="store-artifact-bundle"
|
||||
rightIconProps={{ size: 12 }}
|
||||
color={Color.GREY_400}
|
||||
font={{ variation: FontVariation.SMALL }}
|
||||
lineClamp={1}>
|
||||
{artifacts}
|
||||
</Text>
|
||||
)}
|
||||
{downloads !== undefined && (
|
||||
<Text
|
||||
icon="dot"
|
||||
iconProps={{ size: 8, color: Color.GREY_400 }}
|
||||
rightIcon="download-box"
|
||||
rightIconProps={{ size: 12 }}
|
||||
color={Color.GREY_400}
|
||||
font={{ variation: FontVariation.SMALL }}
|
||||
lineClamp={1}>
|
||||
{downloads.toLocaleString()}
|
||||
</Text>
|
||||
)}
|
||||
</Layout.Horizontal>
|
||||
)}
|
||||
</Layout.Vertical>
|
||||
</Layout.Horizontal>
|
||||
)
|
||||
}
|
30
web/src/ar/components/TreeView/TreeNodeList.tsx
Normal file
30
web/src/ar/components/TreeView/TreeNodeList.tsx
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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 React, { type PropsWithChildren } from 'react'
|
||||
import classNames from 'classnames'
|
||||
|
||||
import css from './TreeView.module.scss'
|
||||
|
||||
export default function TreeNodeList(
|
||||
props: PropsWithChildren<React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>>
|
||||
) {
|
||||
return (
|
||||
<ul {...props} className={classNames(props.className, css.treeList)}>
|
||||
{props.children}
|
||||
</ul>
|
||||
)
|
||||
}
|
42
web/src/ar/components/TreeView/TreeNodeSearchInput.tsx
Normal file
42
web/src/ar/components/TreeView/TreeNodeSearchInput.tsx
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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 React from 'react'
|
||||
import classNames from 'classnames'
|
||||
import { ExpandingSearchInput, ExpandingSearchInputProps } from '@harnessio/uicore'
|
||||
import { useStrings } from '@ar/frameworks/strings'
|
||||
import TreeNode, { TreeNodeProps } from './TreeNode'
|
||||
|
||||
import css from './TreeView.module.scss'
|
||||
|
||||
interface TreeNodeSearchInputProps extends ExpandingSearchInputProps {
|
||||
level?: number
|
||||
treeNodeProps?: Omit<TreeNodeProps, 'heading'>
|
||||
}
|
||||
|
||||
export default function TreeNodeSearchInput(props: TreeNodeSearchInputProps) {
|
||||
const { level = 0, treeNodeProps, className, ...rest } = props
|
||||
const { getString } = useStrings()
|
||||
return (
|
||||
<TreeNode
|
||||
className={classNames(className, css.stickyNode)}
|
||||
disabled
|
||||
level={level}
|
||||
heading={<ExpandingSearchInput alwaysExpanded placeholder={getString('search')} width="100%" {...rest} />}
|
||||
{...treeNodeProps}
|
||||
/>
|
||||
)
|
||||
}
|
85
web/src/ar/components/TreeView/TreeView.module.scss
Normal file
85
web/src/ar/components/TreeView/TreeView.module.scss
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
.treeList {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.treeNodeCollapseContainer {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.headingContent {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.actionElement {
|
||||
display: none;
|
||||
&.alwaysShowAction {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.treeNode {
|
||||
& > :first-child {
|
||||
padding-left: var(--spacing-large) !important;
|
||||
padding-right: var(--spacing-small) !important;
|
||||
}
|
||||
& .header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-xsmall);
|
||||
|
||||
&:hover,
|
||||
&.active {
|
||||
background-color: var(--primary-2);
|
||||
cursor: pointer;
|
||||
|
||||
& .actionElement {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
cursor: auto;
|
||||
&:hover {
|
||||
background-color: var(--grey-100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
& .levelImg {
|
||||
width: var(--spacing-large);
|
||||
align-self: stretch;
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.treeNodeContent {
|
||||
.labelContainer {
|
||||
margin-left: var(--spacing-small) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.stickyNode {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background-color: var(--white);
|
||||
}
|
31
web/src/ar/components/TreeView/TreeView.module.scss.d.ts
vendored
Normal file
31
web/src/ar/components/TreeView/TreeView.module.scss.d.ts
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2023 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.
|
||||
*/
|
||||
|
||||
/* eslint-disable */
|
||||
// This is an auto-generated file
|
||||
export declare const actionElement: string
|
||||
export declare const active: string
|
||||
export declare const alwaysShowAction: string
|
||||
export declare const disabled: string
|
||||
export declare const header: string
|
||||
export declare const headingContent: string
|
||||
export declare const labelContainer: string
|
||||
export declare const levelImg: string
|
||||
export declare const stickyNode: string
|
||||
export declare const treeList: string
|
||||
export declare const treeNode: string
|
||||
export declare const treeNodeCollapseContainer: string
|
||||
export declare const treeNodeContent: string
|
35
web/src/ar/components/TreeView/TreeViewContext.tsx
Normal file
35
web/src/ar/components/TreeView/TreeViewContext.tsx
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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 { createContext } from 'react'
|
||||
import { noop } from 'lodash-es'
|
||||
|
||||
export interface NodeSpec<T = unknown> {
|
||||
data: T
|
||||
isLastChild?: boolean
|
||||
}
|
||||
|
||||
interface TreeViewContextValue {
|
||||
activePath: string
|
||||
setActivePath: (path: string) => void
|
||||
compact?: boolean
|
||||
}
|
||||
|
||||
export const TreeViewContext = createContext<TreeViewContextValue>({
|
||||
activePath: '',
|
||||
setActivePath: noop,
|
||||
compact: false
|
||||
})
|
4
web/src/ar/components/TreeView/images/child.svg
Normal file
4
web/src/ar/components/TreeView/images/child.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg height="100%" width="100%" xmlns="http://www.w3.org/2000/svg">
|
||||
<line x1="50%" y1="0" x2="50%" y2="100%" stroke="#d9dae5" stroke-width="1"/>
|
||||
<line x1="50%" y1="50%" x2="100%" y2="50%" stroke="#d9dae5" stroke-width="1"/>
|
||||
</svg>
|
After Width: | Height: | Size: 234 B |
4
web/src/ar/components/TreeView/images/last-child.svg
Normal file
4
web/src/ar/components/TreeView/images/last-child.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg height="100%" width="100%" xmlns="http://www.w3.org/2000/svg">
|
||||
<line x1="50%" y1="0" x2="50%" y2="50%" stroke="#d9dae5" stroke-width="1"/>
|
||||
<line x1="50%" y1="50%" x2="100%" y2="50%" stroke="#d9dae5" stroke-width="1"/>
|
||||
</svg>
|
After Width: | Height: | Size: 233 B |
3
web/src/ar/components/TreeView/images/line.svg
Normal file
3
web/src/ar/components/TreeView/images/line.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg height="100%" width="100%" xmlns="http://www.w3.org/2000/svg">
|
||||
<line x1="50%" y1="0" x2="50%" y2="100%" stroke="#d9dae5" stroke-width="1"/>
|
||||
</svg>
|
After Width: | Height: | Size: 153 B |
@ -15,14 +15,22 @@
|
||||
*/
|
||||
|
||||
import { createContext } from 'react'
|
||||
import { noop } from 'lodash-es'
|
||||
import type { AppstoreContext, Scope } from '@ar/MFEAppTypes'
|
||||
import { Parent } from '@ar/common/types'
|
||||
|
||||
export enum RepositoryListViewTypeEnum {
|
||||
LIST = 'list',
|
||||
DIRECTORY = 'directory'
|
||||
}
|
||||
|
||||
export interface ModuleAppStoreContextProps extends AppstoreContext, Record<string, unknown> {
|
||||
baseUrl: string
|
||||
matchPath: string
|
||||
scope: Scope & Record<string, string>
|
||||
parent: Parent
|
||||
repositoryListViewType: RepositoryListViewTypeEnum
|
||||
setRepositoryListViewType: (type: RepositoryListViewTypeEnum) => void
|
||||
}
|
||||
|
||||
export const AppStoreContext = createContext<ModuleAppStoreContextProps>({
|
||||
@ -33,5 +41,7 @@ export const AppStoreContext = createContext<ModuleAppStoreContextProps>({
|
||||
matchPath: '',
|
||||
scope: {},
|
||||
accountInfo: {},
|
||||
parent: Parent.OSS
|
||||
parent: Parent.OSS,
|
||||
repositoryListViewType: RepositoryListViewTypeEnum.LIST,
|
||||
setRepositoryListViewType: noop
|
||||
})
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
import type { IconName } from '@harnessio/icons'
|
||||
import type { RegistryMetadata } from '@harnessio/react-har-service-client'
|
||||
import type { UpstreamRepositoryURLInputSource } from '@ar/pages/upstream-proxy-details/types'
|
||||
import type { FormikFowardRef, RepositoryPackageType, RepositoryConfigType, PageType, Scanners } from '@ar/common/types'
|
||||
import type { StringKeys } from '../strings'
|
||||
@ -48,6 +49,11 @@ export interface RepositoryDetailsHeaderProps<T> {
|
||||
type: RepositoryConfigType
|
||||
}
|
||||
|
||||
export interface RepositoryTreeNodeProps {
|
||||
data: RegistryMetadata
|
||||
isLastChild?: boolean
|
||||
}
|
||||
|
||||
export abstract class RepositoryStep<T, U = unknown> {
|
||||
protected abstract packageType: RepositoryPackageType
|
||||
protected abstract repositoryName: string
|
||||
@ -132,4 +138,8 @@ export abstract class RepositoryStep<T, U = unknown> {
|
||||
abstract renderRepositoryDetailsHeader(props: RepositoryDetailsHeaderProps<U>): JSX.Element
|
||||
|
||||
abstract renderRedirectPage(): JSX.Element
|
||||
|
||||
abstract renderTreeNodeView(props: RepositoryTreeNodeProps): JSX.Element
|
||||
|
||||
abstract renderTreeNodeDetails(): JSX.Element
|
||||
}
|
||||
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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 React from 'react'
|
||||
import { Text } from '@harnessio/uicore'
|
||||
|
||||
import { useStrings } from '@ar/frameworks/strings'
|
||||
import type { RepositoryPackageType } from '@ar/common/types'
|
||||
|
||||
import repositoryFactory from './RepositoryFactory'
|
||||
import type { RepositoryAbstractFactory } from './RepositoryAbstractFactory'
|
||||
|
||||
interface RepositoryTreeNodeDetailsWidgetProps {
|
||||
packageType: RepositoryPackageType
|
||||
factory?: RepositoryAbstractFactory
|
||||
}
|
||||
|
||||
export default function RepositoryTreeNodeDetailsWidget(props: RepositoryTreeNodeDetailsWidgetProps): JSX.Element {
|
||||
const { packageType, factory = repositoryFactory } = props
|
||||
const { getString } = useStrings()
|
||||
const repositoryType = factory?.getRepositoryType(packageType as RepositoryPackageType)
|
||||
if (!repositoryType) {
|
||||
return <Text intent="warning">{getString('stepNotFound')}</Text>
|
||||
}
|
||||
return repositoryType.renderTreeNodeDetails()
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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 React from 'react'
|
||||
import { Text } from '@harnessio/uicore'
|
||||
|
||||
import { useStrings } from '@ar/frameworks/strings'
|
||||
import type { RepositoryPackageType } from '@ar/common/types'
|
||||
|
||||
import repositoryFactory from './RepositoryFactory'
|
||||
import type { RepositoryTreeNodeProps } from './Repository'
|
||||
import type { RepositoryAbstractFactory } from './RepositoryAbstractFactory'
|
||||
|
||||
interface RepositoryTreeNodeViewWidgetProps extends RepositoryTreeNodeProps {
|
||||
packageType: RepositoryPackageType
|
||||
factory?: RepositoryAbstractFactory
|
||||
}
|
||||
|
||||
export default function RepositoryTreeNodeViewWidget(props: RepositoryTreeNodeViewWidgetProps): JSX.Element {
|
||||
const { packageType, factory = repositoryFactory, ...rest } = props
|
||||
const { getString } = useStrings()
|
||||
const repositoryType = factory?.getRepositoryType(packageType as RepositoryPackageType)
|
||||
if (!repositoryType) {
|
||||
return <Text intent="warning">{getString('stepNotFound')}</Text>
|
||||
}
|
||||
return repositoryType.renderTreeNodeView({ ...rest })
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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 React from 'react'
|
||||
import { Text } from '@harnessio/uicore'
|
||||
|
||||
import { useStrings } from '@ar/frameworks/strings'
|
||||
import type { RepositoryPackageType } from '@ar/common/types'
|
||||
|
||||
import versionFactory from './VersionFactory'
|
||||
import type { VersionAbstractFactory } from './VersionAbstractFactory'
|
||||
|
||||
interface ArtifactTreeNodeDetailsWidgetProps {
|
||||
packageType: RepositoryPackageType
|
||||
factory?: VersionAbstractFactory
|
||||
}
|
||||
|
||||
export default function ArtifactTreeNodeDetailsWidget(props: ArtifactTreeNodeDetailsWidgetProps): JSX.Element {
|
||||
const { packageType, factory = versionFactory } = props
|
||||
const { getString } = useStrings()
|
||||
const repositoryType = factory?.getVersionType(packageType as RepositoryPackageType)
|
||||
if (!repositoryType) {
|
||||
return <Text intent="warning">{getString('stepNotFound')}</Text>
|
||||
}
|
||||
return repositoryType.renderArtifactTreeNodeDetails()
|
||||
}
|
40
web/src/ar/frameworks/Version/ArtifactTreeNodeViewWidget.tsx
Normal file
40
web/src/ar/frameworks/Version/ArtifactTreeNodeViewWidget.tsx
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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 React from 'react'
|
||||
import { Text } from '@harnessio/uicore'
|
||||
|
||||
import { useStrings } from '@ar/frameworks/strings'
|
||||
import type { RepositoryPackageType } from '@ar/common/types'
|
||||
|
||||
import versionFactory from './VersionFactory'
|
||||
import type { ArtifactTreeNodeViewProps } from './Version'
|
||||
import type { VersionAbstractFactory } from './VersionAbstractFactory'
|
||||
|
||||
interface ArtifactTreeNodeViewWidgetProps extends ArtifactTreeNodeViewProps {
|
||||
packageType: RepositoryPackageType
|
||||
factory?: VersionAbstractFactory
|
||||
}
|
||||
|
||||
export default function ArtifactTreeNodeViewWidget(props: ArtifactTreeNodeViewWidgetProps): JSX.Element {
|
||||
const { packageType, factory = versionFactory, ...rest } = props
|
||||
const { getString } = useStrings()
|
||||
const repositoryType = factory?.getVersionType(packageType as RepositoryPackageType)
|
||||
if (!repositoryType) {
|
||||
return <Text intent="warning">{getString('stepNotFound')}</Text>
|
||||
}
|
||||
return repositoryType.renderArtifactTreeNodeView({ ...rest })
|
||||
}
|
@ -21,10 +21,12 @@ import type {
|
||||
ArtifactVersionMetadata,
|
||||
ArtifactVersionSummary,
|
||||
ListArtifactVersion,
|
||||
RegistryArtifactMetadata
|
||||
RegistryArtifactMetadata,
|
||||
RegistryMetadata
|
||||
} from '@harnessio/react-har-service-client'
|
||||
import type { VersionDetailsTab } from '@ar/pages/version-details/components/VersionDetailsTabs/constants'
|
||||
import type { NodeSpec } from '@ar/components/TreeView/TreeViewContext'
|
||||
import type { PageType, Parent, RepositoryPackageType } from '@ar/common/types'
|
||||
import type { VersionDetailsTab } from '@ar/pages/version-details/components/VersionDetailsTabs/constants'
|
||||
|
||||
export interface VersionDetailsHeaderProps<T> {
|
||||
data: T
|
||||
@ -69,6 +71,23 @@ export interface ArtifactRowSubComponentProps {
|
||||
data: ArtifactMetadata
|
||||
}
|
||||
|
||||
export interface ArtifactTreeNodeViewProps {
|
||||
data: RegistryArtifactMetadata
|
||||
parentNodeLevels: Array<NodeSpec<RegistryMetadata>>
|
||||
isLastChild?: boolean
|
||||
}
|
||||
|
||||
export interface VersionTreeNodeViewProps {
|
||||
data: ArtifactVersionMetadata
|
||||
artifactIdentifier: string
|
||||
parentNodeLevels: Array<NodeSpec<RegistryMetadata | RegistryArtifactMetadata>>
|
||||
isLastChild?: boolean
|
||||
}
|
||||
|
||||
export interface VersionTreeNodeDetailsProps {
|
||||
data: ArtifactVersionSummary
|
||||
}
|
||||
|
||||
export abstract class VersionStep<T> {
|
||||
protected abstract packageType: RepositoryPackageType
|
||||
protected abstract allowedVersionDetailsTabs: VersionDetailsTab[]
|
||||
@ -97,4 +116,12 @@ export abstract class VersionStep<T> {
|
||||
abstract renderVersionActions(props: VersionActionProps): JSX.Element
|
||||
|
||||
abstract renderArtifactRowSubComponent(props: ArtifactRowSubComponentProps): JSX.Element
|
||||
|
||||
abstract renderArtifactTreeNodeView(props: ArtifactTreeNodeViewProps): JSX.Element
|
||||
|
||||
abstract renderArtifactTreeNodeDetails(): JSX.Element
|
||||
|
||||
abstract renderVersionTreeNodeView(props: VersionTreeNodeViewProps): JSX.Element
|
||||
|
||||
abstract renderVersionTreeNodeDetails(props: VersionTreeNodeDetailsProps): JSX.Element
|
||||
}
|
||||
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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 React from 'react'
|
||||
import { Text } from '@harnessio/uicore'
|
||||
|
||||
import { useStrings } from '@ar/frameworks/strings'
|
||||
import type { RepositoryPackageType } from '@ar/common/types'
|
||||
|
||||
import versionFactory from './VersionFactory'
|
||||
import type { VersionTreeNodeDetailsProps } from './Version'
|
||||
import type { VersionAbstractFactory } from './VersionAbstractFactory'
|
||||
|
||||
interface VersionTreeNodeDetailsWidgetProps extends VersionTreeNodeDetailsProps {
|
||||
packageType: RepositoryPackageType
|
||||
factory?: VersionAbstractFactory
|
||||
}
|
||||
|
||||
export default function VersionTreeNodeDetailsWidget(props: VersionTreeNodeDetailsWidgetProps): JSX.Element {
|
||||
const { packageType, factory = versionFactory, ...rest } = props
|
||||
const { getString } = useStrings()
|
||||
const repositoryType = factory?.getVersionType(packageType as RepositoryPackageType)
|
||||
if (!repositoryType) {
|
||||
return <Text intent="warning">{getString('stepNotFound')}</Text>
|
||||
}
|
||||
return repositoryType.renderVersionTreeNodeDetails({ ...rest })
|
||||
}
|
40
web/src/ar/frameworks/Version/VersionTreeNodeViewWidget.tsx
Normal file
40
web/src/ar/frameworks/Version/VersionTreeNodeViewWidget.tsx
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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 React from 'react'
|
||||
import { Text } from '@harnessio/uicore'
|
||||
|
||||
import { useStrings } from '@ar/frameworks/strings'
|
||||
import type { RepositoryPackageType } from '@ar/common/types'
|
||||
|
||||
import versionFactory from './VersionFactory'
|
||||
import type { VersionTreeNodeViewProps } from './Version'
|
||||
import type { VersionAbstractFactory } from './VersionAbstractFactory'
|
||||
|
||||
interface VersionTreeNodeViewWidgetProps extends VersionTreeNodeViewProps {
|
||||
packageType: RepositoryPackageType
|
||||
factory?: VersionAbstractFactory
|
||||
}
|
||||
|
||||
export default function VersionTreeNodeViewWidget(props: VersionTreeNodeViewWidgetProps): JSX.Element {
|
||||
const { packageType, factory = versionFactory, ...rest } = props
|
||||
const { getString } = useStrings()
|
||||
const repositoryType = factory?.getVersionType(packageType as RepositoryPackageType)
|
||||
if (!repositoryType) {
|
||||
return <Text intent="warning">{getString('stepNotFound')}</Text>
|
||||
}
|
||||
return repositoryType.renderVersionTreeNodeView({ ...rest })
|
||||
}
|
@ -15,6 +15,8 @@
|
||||
*/
|
||||
|
||||
import { defaultTo, isEmpty } from 'lodash-es'
|
||||
|
||||
import { routeDefinitionWithMode } from '@ar/routes/utils'
|
||||
import type { ARRouteDefinitionsReturn } from '@ar/routes/RouteDefinitions'
|
||||
|
||||
export default function getARRouteDefinitions(routeParams: Record<string, string>): ARRouteDefinitionsReturn {
|
||||
@ -34,17 +36,34 @@ export default function getARRouteDefinitions(routeParams: Record<string, string
|
||||
}
|
||||
return '/redirect'
|
||||
},
|
||||
toARRepositories: () => '/',
|
||||
toARRepositoryDetails: params => `/${params?.repositoryIdentifier}`,
|
||||
toARRepositoryDetailsTab: params => `/${params?.repositoryIdentifier}/${params?.tab}`,
|
||||
toARRepositoryWebhookDetails: params => `/${params?.repositoryIdentifier}/webhooks/${params?.webhookIdentifier}`,
|
||||
toARArtifacts: () => `/${routeParams?.repositoryIdentifier}/packages`,
|
||||
toARArtifactDetails: params => `/${params?.repositoryIdentifier}/artifacts/${params?.artifactIdentifier}`,
|
||||
toARVersionDetails: params =>
|
||||
`/${params?.repositoryIdentifier}/artifacts/${params?.artifactIdentifier}/versions/${params?.versionIdentifier}`,
|
||||
toARRepositories: routeDefinitionWithMode(() => '/'),
|
||||
toARRepositoryDetails: routeDefinitionWithMode(params => `/${params?.repositoryIdentifier}`),
|
||||
toARRepositoryDetailsTab: routeDefinitionWithMode(params => `/${params?.repositoryIdentifier}/${params?.tab}`),
|
||||
toARArtifacts: routeDefinitionWithMode(() => `/${routeParams?.repositoryIdentifier}/packages`),
|
||||
toARArtifactDetails: routeDefinitionWithMode(
|
||||
params => `/${params?.repositoryIdentifier}/artifacts/${params?.artifactIdentifier}`
|
||||
),
|
||||
toARVersionDetails: routeDefinitionWithMode(
|
||||
params =>
|
||||
`/${params?.repositoryIdentifier}/artifacts/${params?.artifactIdentifier}/versions/${params?.versionIdentifier}`
|
||||
),
|
||||
// anything random, as this route will not be used in gitness
|
||||
toARVersionDetailsTab: params =>
|
||||
`/${params?.repositoryIdentifier}/artifacts/${params?.artifactIdentifier}/versions/${params?.versionIdentifier}`,
|
||||
toARVersionDetailsTab: routeDefinitionWithMode(params => {
|
||||
let route = `/${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) {
|
||||
route += `/artifact-sources/${params.sourceId}/artifacts/${params.artifactId}`
|
||||
}
|
||||
if (params.pipelineIdentifier && params.executionIdentifier) {
|
||||
route += `/pipelines/${params.pipelineIdentifier}/executions/${params.executionIdentifier}`
|
||||
}
|
||||
route += `/${params.versionTab}`
|
||||
return route
|
||||
}),
|
||||
toARRepositoryWebhookDetails: routeDefinitionWithMode(
|
||||
params => `/${params?.repositoryIdentifier}/webhooks/${params?.webhookIdentifier}`
|
||||
),
|
||||
toARRepositoryWebhookDetailsTab: params =>
|
||||
`/${params?.repositoryIdentifier}/webhooks/${params?.webhookIdentifier}/${params?.tab}`
|
||||
}
|
||||
|
@ -26,3 +26,4 @@ export { useParentContextObj } from './useParentContextObj'
|
||||
export { useLicenseStore } from './useLicenseStore'
|
||||
export { useFeatureFlags, useFeatureFlag } from './useFeatureFlag'
|
||||
export { useGetUpstreamRepositoryPackageTypes } from './useGetUpstreamRepositoryPackageTypes'
|
||||
export { useGetRepositoryListViewType } from './useGetRepositoryListViewType'
|
||||
|
29
web/src/ar/hooks/useGetRepositoryListViewType.ts
Normal file
29
web/src/ar/hooks/useGetRepositoryListViewType.ts
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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 { RepositoryListViewTypeEnum } from '@ar/contexts/AppStoreContext'
|
||||
|
||||
import { useAppStore } from './useAppStore'
|
||||
import { useFeatureFlags } from './useFeatureFlag'
|
||||
|
||||
export function useGetRepositoryListViewType() {
|
||||
const { repositoryListViewType } = useAppStore()
|
||||
const { HAR_TREE_VIEW_ENABLED } = useFeatureFlags()
|
||||
if (!HAR_TREE_VIEW_ENABLED) {
|
||||
return RepositoryListViewTypeEnum.LIST
|
||||
}
|
||||
return repositoryListViewType || RepositoryListViewTypeEnum.LIST
|
||||
}
|
@ -17,7 +17,7 @@
|
||||
import { useMemo } from 'react'
|
||||
import { mapValues } from 'lodash-es'
|
||||
|
||||
import { encodePathParams, normalizePath } from '@ar/routes/utils'
|
||||
import { encodePathParams, IRouteOptions, normalizePath } from '@ar/routes/utils'
|
||||
import { ARRouteDefinitionsReturn, routeDefinitions } from '@ar/routes/RouteDefinitions'
|
||||
|
||||
import { useAppStore } from './useAppStore'
|
||||
@ -32,11 +32,11 @@ export function useRoutes(isRouteDestinationRendering = false): ARRouteDefinitio
|
||||
const transformedRouteDefinitions: ARRouteDefinitionsReturn = useMemo(() => {
|
||||
const finalRouteDefinitions =
|
||||
typeof getRouteDefinitions === 'function' ? getRouteDefinitions(routeParams) : routeDefinitions
|
||||
return mapValues(finalRouteDefinitions, route => (params: any = {}) => {
|
||||
return mapValues(finalRouteDefinitions, route => (params: any = {}, options?: IRouteOptions) => {
|
||||
const transformedParams: any = Object.keys(params).reduce((acc, curr) => {
|
||||
return { ...acc, [curr]: encodePathParams(params[curr]) }
|
||||
}, {})
|
||||
return normalizePath(`${prefixUrl}/${route(transformedParams)}`)
|
||||
return normalizePath(`${prefixUrl}/${route(transformedParams, options)}`)
|
||||
})
|
||||
}, [prefixUrl])
|
||||
|
||||
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
.cardContainer {
|
||||
width: 60% !important;
|
||||
min-width: 1040px;
|
||||
padding: var(--spacing-7) !important;
|
||||
background-color: var(--white);
|
||||
}
|
||||
|
||||
.gridContainer {
|
||||
align-items: center;
|
||||
display: grid;
|
||||
grid-template-columns: max-content auto;
|
||||
row-gap: var(--spacing-medium);
|
||||
column-gap: 30px;
|
||||
}
|
20
web/src/ar/pages/artifact-details/components/ArtifactTreeNode/ArtifactTreeNode.module.scss.d.ts
vendored
Normal file
20
web/src/ar/pages/artifact-details/components/ArtifactTreeNode/ArtifactTreeNode.module.scss.d.ts
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2023 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.
|
||||
*/
|
||||
|
||||
/* eslint-disable */
|
||||
// This is an auto-generated file
|
||||
export declare const cardContainer: string
|
||||
export declare const gridContainer: string
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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 React, { useContext } from 'react'
|
||||
import { omit } from 'lodash-es'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
import type { IconName } from '@harnessio/icons'
|
||||
import type { RegistryArtifactMetadata, RegistryMetadata } from '@harnessio/react-har-service-client'
|
||||
|
||||
import { useParentHooks, useRoutes } from '@ar/hooks'
|
||||
import TreeNode, { NodeTypeEnum } from '@ar/components/TreeView/TreeNode'
|
||||
import TreeNodeContent from '@ar/components/TreeView/TreeNodeContent'
|
||||
import { PageType, type RepositoryPackageType } from '@ar/common/types'
|
||||
import { TreeViewContext } from '@ar/components/TreeView/TreeViewContext'
|
||||
import type { ArtifactTreeNodeViewProps } from '@ar/frameworks/Version/Version'
|
||||
import ArtifactActionsWidget from '@ar/frameworks/Version/ArtifactActionsWidget'
|
||||
import VersionListTreeView from '@ar/pages/version-list/components/VersionListTreeView/VersionListTreeView'
|
||||
|
||||
interface IArtifactTreeNode extends ArtifactTreeNodeViewProps {
|
||||
icon: IconName
|
||||
iconSize?: number
|
||||
level?: number
|
||||
}
|
||||
|
||||
export default function ArtifactTreeNode(props: IArtifactTreeNode) {
|
||||
const { data, icon, iconSize = 24, level = 1, isLastChild, parentNodeLevels } = props
|
||||
const { setActivePath, activePath, compact } = useContext(TreeViewContext)
|
||||
const { useQueryParams } = useParentHooks()
|
||||
const queryParams = useQueryParams<Record<string, string>>()
|
||||
const routes = useRoutes()
|
||||
const history = useHistory()
|
||||
const path = `${data.registryIdentifier}/${data.name}`
|
||||
return (
|
||||
<TreeNode<RegistryMetadata | RegistryArtifactMetadata>
|
||||
key={path}
|
||||
id={path}
|
||||
level={level}
|
||||
nodeType={NodeTypeEnum.Folder}
|
||||
compact={compact}
|
||||
isLastChild={isLastChild}
|
||||
parentNodeLevels={parentNodeLevels}
|
||||
isOpen={activePath.includes(path)}
|
||||
isActive={activePath === path}
|
||||
onClick={() => {
|
||||
setActivePath(path)
|
||||
history.push(
|
||||
routes.toARArtifactDetails(
|
||||
{
|
||||
repositoryIdentifier: data.registryIdentifier,
|
||||
artifactIdentifier: data.name
|
||||
},
|
||||
{ queryParams: omit(queryParams, 'digest') }
|
||||
)
|
||||
)
|
||||
}}
|
||||
heading={
|
||||
<TreeNodeContent
|
||||
icon={icon}
|
||||
iconSize={iconSize}
|
||||
label={data.name}
|
||||
downloads={data.downloadsCount}
|
||||
compact={compact}
|
||||
/>
|
||||
}
|
||||
actionElement={
|
||||
<ArtifactActionsWidget
|
||||
packageType={data.packageType as RepositoryPackageType}
|
||||
data={data}
|
||||
repoKey={data.registryIdentifier}
|
||||
artifactKey={data.name}
|
||||
pageType={PageType.Table}
|
||||
/>
|
||||
}>
|
||||
<VersionListTreeView
|
||||
parentNodeLevels={[...parentNodeLevels, { data, isLastChild }]}
|
||||
registryIdentifier={data.registryIdentifier}
|
||||
artifactIdentifier={data.name}
|
||||
/>
|
||||
</TreeNode>
|
||||
)
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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 React, { useContext } from 'react'
|
||||
import type { RepositoryPackageType } from '@ar/common/types'
|
||||
import ArtifactTreeNodeDetailsWidget from '@ar/frameworks/Version/ArtifactTreeNodeDetailsWidget'
|
||||
import { ArtifactProviderContext } from '../../context/ArtifactProvider'
|
||||
|
||||
export default function ArtifactTreeNodeDetails() {
|
||||
const { data } = useContext(ArtifactProviderContext)
|
||||
if (!data) return null
|
||||
const { packageType } = data
|
||||
return <ArtifactTreeNodeDetailsWidget packageType={packageType as RepositoryPackageType} />
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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 React, { useContext } from 'react'
|
||||
import { FontVariation } from '@harnessio/design-system'
|
||||
import { Card, Container, Layout, Text } from '@harnessio/uicore'
|
||||
|
||||
import { useStrings } from '@ar/frameworks/strings'
|
||||
import { DEFAULT_DATE_TIME_FORMAT } from '@ar/constants'
|
||||
import { getReadableDateTime } from '@ar/common/dateUtils'
|
||||
import { LabelValueTypeEnum } from '@ar/pages/version-details/components/LabelValueContent/type'
|
||||
import { LabelValueContent } from '@ar/pages/version-details/components/LabelValueContent/LabelValueContent'
|
||||
|
||||
import { ArtifactProviderContext } from '../../context/ArtifactProvider'
|
||||
import css from './ArtifactTreeNode.module.scss'
|
||||
|
||||
export default function ArtifactTreeNodeDetailsContent(): JSX.Element {
|
||||
const { data } = useContext(ArtifactProviderContext)
|
||||
const { getString } = useStrings()
|
||||
|
||||
if (!data) return <></>
|
||||
return (
|
||||
<Layout.Vertical spacing="small" padding="large">
|
||||
<Text font={{ variation: FontVariation.CARD_TITLE }}>{getString('details')}</Text>
|
||||
<Card className={css.cardContainer}>
|
||||
<Container className={css.gridContainer}>
|
||||
<LabelValueContent
|
||||
label={getString('versionDetails.overview.generalInformation.name')}
|
||||
value={data.imageName}
|
||||
type={LabelValueTypeEnum.Text}
|
||||
/>
|
||||
<LabelValueContent
|
||||
label={getString('versionDetails.overview.generalInformation.downloads')}
|
||||
value={data.downloadsCount}
|
||||
type={LabelValueTypeEnum.Text}
|
||||
/>
|
||||
<LabelValueContent
|
||||
label={getString('versionDetails.overview.generalInformation.createdAt')}
|
||||
value={getReadableDateTime(Number(data.createdAt), DEFAULT_DATE_TIME_FORMAT)}
|
||||
type={LabelValueTypeEnum.Text}
|
||||
/>
|
||||
<LabelValueContent
|
||||
label={getString('versionDetails.overview.generalInformation.modifiedAt')}
|
||||
value={getReadableDateTime(Number(data.modifiedAt), DEFAULT_DATE_TIME_FORMAT)}
|
||||
type={LabelValueTypeEnum.Text}
|
||||
/>
|
||||
</Container>
|
||||
</Card>
|
||||
</Layout.Vertical>
|
||||
)
|
||||
}
|
@ -18,8 +18,9 @@ import React, { createContext, type FC, type PropsWithChildren } from 'react'
|
||||
import { ArtifactSummary, useGetArtifactSummaryQuery } from '@harnessio/react-har-service-client'
|
||||
import { PageError, PageSpinner } from '@harnessio/uicore'
|
||||
|
||||
import { useGetSpaceRef } from '@ar/hooks'
|
||||
import { encodeRef } from '@ar/hooks/useGetSpaceRef'
|
||||
import { useDecodedParams, useGetSpaceRef } from '@ar/hooks'
|
||||
import type { ArtifactDetailsPathParams } from '@ar/routes/types'
|
||||
|
||||
export interface ArtifactProviderProps {
|
||||
data: ArtifactSummary | undefined
|
||||
@ -29,12 +30,13 @@ export interface ArtifactProviderProps {
|
||||
|
||||
export const ArtifactProviderContext = createContext<ArtifactProviderProps>({} as ArtifactProviderProps)
|
||||
|
||||
const ArtifactProvider: FC<PropsWithChildren<{ repoKey: string; artifact: string }>> = ({
|
||||
const ArtifactProvider: FC<PropsWithChildren<{ repoKey?: string; artifact?: string }>> = ({
|
||||
children,
|
||||
repoKey,
|
||||
artifact
|
||||
}): JSX.Element => {
|
||||
const spaceRef = useGetSpaceRef(repoKey)
|
||||
const { repositoryIdentifier, artifactIdentifier } = useDecodedParams<ArtifactDetailsPathParams>()
|
||||
const spaceRef = useGetSpaceRef(repoKey ?? repositoryIdentifier)
|
||||
const {
|
||||
data,
|
||||
isFetching: loading,
|
||||
@ -42,7 +44,7 @@ const ArtifactProvider: FC<PropsWithChildren<{ repoKey: string; artifact: string
|
||||
refetch
|
||||
} = useGetArtifactSummaryQuery({
|
||||
registry_ref: spaceRef,
|
||||
artifact: encodeRef(artifact)
|
||||
artifact: encodeRef(artifact ?? artifactIdentifier)
|
||||
})
|
||||
|
||||
const responseData = data?.content?.data
|
||||
|
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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 React, { useMemo } from 'react'
|
||||
import { useInfiniteQuery } from '@tanstack/react-query'
|
||||
import {
|
||||
type Error,
|
||||
getAllArtifactsByRegistry,
|
||||
type GetAllArtifactsByRegistryOkResponse,
|
||||
type RegistryMetadata
|
||||
} from '@harnessio/react-har-service-client'
|
||||
|
||||
import { DEFAULT_PAGE_SIZE } from '@ar/constants'
|
||||
import { useStrings } from '@ar/frameworks/strings'
|
||||
import TreeBody from '@ar/components/TreeView/TreeBody'
|
||||
import { useGetSpaceRef, useParentHooks } from '@ar/hooks'
|
||||
import type { RepositoryPackageType } from '@ar/common/types'
|
||||
import TreeNodeList from '@ar/components/TreeView/TreeNodeList'
|
||||
import TreeLoadMoreNode from '@ar/components/TreeView/TreeLoadMoreNode'
|
||||
import type { NodeSpec } from '@ar/components/TreeView/TreeViewContext'
|
||||
import TreeNodeSearchInput from '@ar/components/TreeView/TreeNodeSearchInput'
|
||||
import ArtifactTreeNodeViewWidget from '@ar/frameworks/Version/ArtifactTreeNodeViewWidget'
|
||||
|
||||
import {
|
||||
type RegistryArtifactListPageQueryParams,
|
||||
useRegistryArtifactListQueryParamOptions
|
||||
} from '../RegistryArtifactListTable/utils'
|
||||
|
||||
interface ArtifactListTreeViewProps {
|
||||
registryIdentifier: string
|
||||
parentNodeLevels: Array<NodeSpec<RegistryMetadata>>
|
||||
}
|
||||
|
||||
export default function ArtifactListTreeView(props: ArtifactListTreeViewProps) {
|
||||
const { registryIdentifier } = props
|
||||
const { useQueryParams, useUpdateQueryParams } = useParentHooks()
|
||||
const { updateQueryParams } = useUpdateQueryParams<Partial<RegistryArtifactListPageQueryParams>>()
|
||||
const queryParams = useQueryParams<RegistryArtifactListPageQueryParams>(useRegistryArtifactListQueryParamOptions())
|
||||
const { artifactSearchTerm } = queryParams
|
||||
const { getString } = useStrings()
|
||||
|
||||
const registryRef = useGetSpaceRef(registryIdentifier)
|
||||
const { data, isLoading, error, hasNextPage, fetchNextPage, refetch, isFetchingNextPage } = useInfiniteQuery<
|
||||
GetAllArtifactsByRegistryOkResponse,
|
||||
Error,
|
||||
GetAllArtifactsByRegistryOkResponse,
|
||||
Array<string | undefined>
|
||||
>({
|
||||
queryKey: ['artifactList', registryIdentifier, artifactSearchTerm],
|
||||
queryFn: ({ pageParam = 0 }) =>
|
||||
getAllArtifactsByRegistry({
|
||||
registry_ref: registryRef,
|
||||
queryParams: {
|
||||
page: pageParam,
|
||||
size: DEFAULT_PAGE_SIZE,
|
||||
search_term: artifactSearchTerm
|
||||
},
|
||||
stringifyQueryParamsOptions: {
|
||||
arrayFormat: 'repeat'
|
||||
}
|
||||
}),
|
||||
getNextPageParam: lastPage => {
|
||||
const totalPages = lastPage.content.data.pageCount ?? 0
|
||||
const lastPageNumber = lastPage.content.data.pageIndex ?? -1
|
||||
const nextPage = lastPageNumber + 1
|
||||
return nextPage < totalPages ? nextPage : undefined
|
||||
}
|
||||
})
|
||||
|
||||
const { list: artifactList, count: totalArtifacts } = useMemo(() => {
|
||||
const list = data?.pages.flatMap(page => page.content.data.artifacts) || []
|
||||
const count = data?.pages[0].content.data.itemCount || 0
|
||||
return { list, count }
|
||||
}, [data])
|
||||
|
||||
return (
|
||||
<TreeNodeList>
|
||||
{totalArtifacts > DEFAULT_PAGE_SIZE && (
|
||||
<TreeNodeSearchInput
|
||||
level={1}
|
||||
defaultValue={artifactSearchTerm}
|
||||
onChange={val => {
|
||||
updateQueryParams({ artifactSearchTerm: val })
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<TreeBody
|
||||
loading={isLoading}
|
||||
error={error?.message}
|
||||
retryOnError={refetch}
|
||||
isEmpty={!artifactList.length}
|
||||
emptyDataMessage={getString('artifactList.table.noArtifactsTitle')}>
|
||||
{artifactList.map((each, indx) => (
|
||||
<ArtifactTreeNodeViewWidget
|
||||
key={each.name}
|
||||
packageType={each.packageType as RepositoryPackageType}
|
||||
data={each}
|
||||
isLastChild={indx === artifactList.length - 1}
|
||||
parentNodeLevels={props.parentNodeLevels}
|
||||
/>
|
||||
))}
|
||||
{hasNextPage && <TreeLoadMoreNode level={1} onClick={() => fetchNextPage()} disabled={isFetchingNextPage} />}
|
||||
</TreeBody>
|
||||
</TreeNodeList>
|
||||
)
|
||||
}
|
@ -26,6 +26,7 @@ export type RegistryArtifactListPageQueryParams = {
|
||||
size: number
|
||||
sort: string[]
|
||||
searchTerm?: string
|
||||
artifactSearchTerm?: string
|
||||
isDeployedArtifacts: boolean
|
||||
packageTypes: RepositoryPackageType[]
|
||||
repositoryKey?: string
|
||||
|
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* 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 React, { useContext, useState } from 'react'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
import {
|
||||
type ArtifactVersionMetadata,
|
||||
type DockerManifestDetails,
|
||||
type RegistryArtifactMetadata,
|
||||
type RegistryMetadata,
|
||||
useGetDockerArtifactManifestsQuery
|
||||
} from '@harnessio/react-har-service-client'
|
||||
|
||||
import { useGetSpaceRef, useParentHooks, useRoutes } from '@ar/hooks'
|
||||
import { encodeRef } from '@ar/hooks/useGetSpaceRef'
|
||||
import TreeNode, { NodeTypeEnum } from '@ar/components/TreeView/TreeNode'
|
||||
import TreeBody from '@ar/components/TreeView/TreeBody'
|
||||
import TreeNodeList from '@ar/components/TreeView/TreeNodeList'
|
||||
import TreeNodeContent from '@ar/components/TreeView/TreeNodeContent'
|
||||
import { type NodeSpec, TreeViewContext } from '@ar/components/TreeView/TreeViewContext'
|
||||
import { VersionDetailsTab } from '@ar/pages/version-details/components/VersionDetailsTabs/constants'
|
||||
|
||||
import { getShortDigest } from '../../utils'
|
||||
|
||||
interface DigestListTreeViewProps {
|
||||
registryIdentifier: string
|
||||
artifactIdentifier: string
|
||||
versionIdentifier: string
|
||||
parentNodeLevels: Array<NodeSpec<RegistryMetadata | RegistryArtifactMetadata | ArtifactVersionMetadata>>
|
||||
}
|
||||
|
||||
export default function DigestListTreeView(props: DigestListTreeViewProps) {
|
||||
const { registryIdentifier, artifactIdentifier, versionIdentifier, parentNodeLevels } = props
|
||||
const [page] = useState(0)
|
||||
const [searchTerm] = useState('')
|
||||
const routes = useRoutes()
|
||||
const history = useHistory()
|
||||
const { setActivePath, activePath, compact } = useContext(TreeViewContext)
|
||||
const { useQueryParams } = useParentHooks()
|
||||
const queryParams = useQueryParams<Record<string, string>>()
|
||||
|
||||
const registryRef = useGetSpaceRef(registryIdentifier)
|
||||
const {
|
||||
data,
|
||||
refetch,
|
||||
isFetching: loading,
|
||||
error
|
||||
} = useGetDockerArtifactManifestsQuery({
|
||||
registry_ref: registryRef,
|
||||
artifact: encodeRef(artifactIdentifier),
|
||||
version: versionIdentifier,
|
||||
queryParams: {
|
||||
page,
|
||||
size: 100,
|
||||
search_term: searchTerm
|
||||
},
|
||||
stringifyQueryParamsOptions: {
|
||||
arrayFormat: 'repeat'
|
||||
}
|
||||
})
|
||||
const manifestList = data?.content.data.manifests || []
|
||||
return (
|
||||
<TreeNodeList>
|
||||
<TreeBody
|
||||
loading={loading}
|
||||
error={error?.message}
|
||||
retryOnError={refetch}
|
||||
isEmpty={!manifestList.length}
|
||||
emptyDataMessage="digestList.table.noDigestTitle">
|
||||
{manifestList.map((each, idx) => {
|
||||
const path = `${registryIdentifier}/${artifactIdentifier}/${versionIdentifier}/${each.digest}`
|
||||
const isLastChild = idx === manifestList.length - 1
|
||||
return (
|
||||
<TreeNode<
|
||||
| RegistryMetadata
|
||||
| RegistryArtifactMetadata
|
||||
| ArtifactVersionMetadata
|
||||
| ArtifactVersionMetadata
|
||||
| DockerManifestDetails
|
||||
>
|
||||
key={path}
|
||||
id={path}
|
||||
level={3}
|
||||
compact={compact}
|
||||
nodeType={NodeTypeEnum.File}
|
||||
isOpen={activePath.includes(path)}
|
||||
isActive={activePath === path}
|
||||
isLastChild={isLastChild}
|
||||
parentNodeLevels={parentNodeLevels}
|
||||
onClick={() => {
|
||||
setActivePath(path)
|
||||
history.push(
|
||||
routes.toARVersionDetailsTab(
|
||||
{
|
||||
repositoryIdentifier: registryIdentifier,
|
||||
artifactIdentifier,
|
||||
versionIdentifier,
|
||||
versionTab: VersionDetailsTab.OVERVIEW
|
||||
},
|
||||
{
|
||||
queryParams: {
|
||||
...queryParams,
|
||||
digest: each.digest
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
}}
|
||||
heading={
|
||||
<TreeNodeContent
|
||||
icon="file"
|
||||
iconSize={20}
|
||||
size={each.size}
|
||||
compact={compact}
|
||||
label={getShortDigest(each.digest)}
|
||||
downloads={each.downloadsCount}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</TreeBody>
|
||||
</TreeNodeList>
|
||||
)
|
||||
}
|
@ -23,6 +23,7 @@ import type {
|
||||
RepositoryActionsProps,
|
||||
RepositoryConfigurationFormProps,
|
||||
RepositoryDetailsHeaderProps,
|
||||
RepositoryTreeNodeProps,
|
||||
RepositoySetupClientProps
|
||||
} from '@ar/frameworks/RepositoryStep/Repository'
|
||||
|
||||
@ -38,12 +39,14 @@ import {
|
||||
} from '@ar/pages/upstream-proxy-details/types'
|
||||
import type { Repository, VirtualRegistryRequest } from '@ar/pages/repository-details/types'
|
||||
|
||||
import RepositoryDetails from '../RepositoryDetails'
|
||||
import RepositoryActions from '../components/Actions/RepositoryActions'
|
||||
import RepositoryConfigurationForm from '../components/Forms/RepositoryConfigurationForm'
|
||||
import DockerRedirectPage from './DockerRedirectPage/DockerRedirectPage'
|
||||
import SetupClientContent from '../components/SetupClientContent/SetupClientContent'
|
||||
import RepositoryTreeNode from '../components/RepositoryTreeNode/RepositoryTreeNode'
|
||||
import RepositoryConfigurationForm from '../components/Forms/RepositoryConfigurationForm'
|
||||
import RepositoryCreateFormContent from '../components/FormContent/RepositoryCreateFormContent'
|
||||
import RepositoryDetailsHeader from '../components/RepositoryDetailsHeader/RepositoryDetailsHeader'
|
||||
import DockerRedirectPage from './DockerRedirectPage/DockerRedirectPage'
|
||||
|
||||
export class DockerRepositoryType extends RepositoryStep<VirtualRegistryRequest> {
|
||||
protected packageType = RepositoryPackageType.DOCKER
|
||||
@ -131,4 +134,12 @@ export class DockerRepositoryType extends RepositoryStep<VirtualRegistryRequest>
|
||||
renderRedirectPage(): JSX.Element {
|
||||
return <DockerRedirectPage />
|
||||
}
|
||||
|
||||
renderTreeNodeView(props: RepositoryTreeNodeProps): JSX.Element {
|
||||
return <RepositoryTreeNode {...props} icon={this.repositoryIcon} />
|
||||
}
|
||||
|
||||
renderTreeNodeDetails(): JSX.Element {
|
||||
return <RepositoryDetails />
|
||||
}
|
||||
}
|
||||
|
@ -24,15 +24,19 @@ import {
|
||||
RepositoryConfigurationFormProps,
|
||||
RepositoryDetailsHeaderProps,
|
||||
RepositoryStep,
|
||||
RepositoryTreeNodeProps,
|
||||
RepositoySetupClientProps
|
||||
} from '@ar/frameworks/RepositoryStep/Repository'
|
||||
import RepositoryActions from '../components/Actions/RepositoryActions'
|
||||
|
||||
import RepositoryDetails from '../RepositoryDetails'
|
||||
import type { Repository, VirtualRegistryRequest } from '../types'
|
||||
import RepositoryCreateFormContent from '../components/FormContent/RepositoryCreateFormContent'
|
||||
import RepositoryConfigurationForm from '../components/Forms/RepositoryConfigurationForm'
|
||||
import RepositoryDetailsHeader from '../components/RepositoryDetailsHeader/RepositoryDetailsHeader'
|
||||
import SetupClientContent from '../components/SetupClientContent/SetupClientContent'
|
||||
import RepositoryActions from '../components/Actions/RepositoryActions'
|
||||
import RedirectPageView from '../components/RedirectPageView/RedirectPageView'
|
||||
import RepositoryTreeNode from '../components/RepositoryTreeNode/RepositoryTreeNode'
|
||||
import SetupClientContent from '../components/SetupClientContent/SetupClientContent'
|
||||
import RepositoryConfigurationForm from '../components/Forms/RepositoryConfigurationForm'
|
||||
import RepositoryCreateFormContent from '../components/FormContent/RepositoryCreateFormContent'
|
||||
import RepositoryDetailsHeader from '../components/RepositoryDetailsHeader/RepositoryDetailsHeader'
|
||||
|
||||
export class GenericRepositoryType extends RepositoryStep<VirtualRegistryRequest> {
|
||||
protected packageType = RepositoryPackageType.GENERIC
|
||||
@ -89,4 +93,12 @@ export class GenericRepositoryType extends RepositoryStep<VirtualRegistryRequest
|
||||
renderRedirectPage(): JSX.Element {
|
||||
return <RedirectPageView />
|
||||
}
|
||||
|
||||
renderTreeNodeView(props: RepositoryTreeNodeProps): JSX.Element {
|
||||
return <RepositoryTreeNode {...props} icon={this.repositoryIcon} iconSize={20} />
|
||||
}
|
||||
|
||||
renderTreeNodeDetails(): JSX.Element {
|
||||
return <RepositoryDetails />
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ import type {
|
||||
RepositoryActionsProps,
|
||||
RepositoryConfigurationFormProps,
|
||||
RepositoryDetailsHeaderProps,
|
||||
RepositoryTreeNodeProps,
|
||||
RepositoySetupClientProps
|
||||
} from '@ar/frameworks/RepositoryStep/Repository'
|
||||
|
||||
@ -38,12 +39,14 @@ import {
|
||||
} from '@ar/pages/upstream-proxy-details/types'
|
||||
import type { Repository, VirtualRegistryRequest } from '@ar/pages/repository-details/types'
|
||||
|
||||
import RepositoryDetails from '../RepositoryDetails'
|
||||
import RepositoryActions from '../components/Actions/RepositoryActions'
|
||||
import RedirectPageView from '../components/RedirectPageView/RedirectPageView'
|
||||
import SetupClientContent from '../components/SetupClientContent/SetupClientContent'
|
||||
import RepositoryTreeNode from '../components/RepositoryTreeNode/RepositoryTreeNode'
|
||||
import RepositoryConfigurationForm from '../components/Forms/RepositoryConfigurationForm'
|
||||
import RepositoryCreateFormContent from '../components/FormContent/RepositoryCreateFormContent'
|
||||
import RepositoryDetailsHeader from '../components/RepositoryDetailsHeader/RepositoryDetailsHeader'
|
||||
import RepositoryConfigurationForm from '../components/Forms/RepositoryConfigurationForm'
|
||||
import RedirectPageView from '../components/RedirectPageView/RedirectPageView'
|
||||
|
||||
export class HelmRepositoryType extends RepositoryStep<VirtualRegistryRequest> {
|
||||
protected packageType = RepositoryPackageType.HELM
|
||||
@ -128,4 +131,12 @@ export class HelmRepositoryType extends RepositoryStep<VirtualRegistryRequest> {
|
||||
renderRedirectPage(): JSX.Element {
|
||||
return <RedirectPageView />
|
||||
}
|
||||
|
||||
renderTreeNodeView(props: RepositoryTreeNodeProps): JSX.Element {
|
||||
return <RepositoryTreeNode {...props} icon={this.repositoryIcon} />
|
||||
}
|
||||
|
||||
renderTreeNodeDetails(): JSX.Element {
|
||||
return <RepositoryDetails />
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ import {
|
||||
type RepositoryConfigurationFormProps,
|
||||
type RepositoryDetailsHeaderProps,
|
||||
RepositoryStep,
|
||||
type RepositoryTreeNodeProps,
|
||||
type RepositoySetupClientProps
|
||||
} from '@ar/frameworks/RepositoryStep/Repository'
|
||||
import {
|
||||
@ -36,10 +37,12 @@ import {
|
||||
UpstreamRepositoryURLInputSource
|
||||
} from '@ar/pages/upstream-proxy-details/types'
|
||||
|
||||
import RepositoryDetails from '../RepositoryDetails'
|
||||
import type { Repository, VirtualRegistryRequest } from '../types'
|
||||
import RepositoryActions from '../components/Actions/RepositoryActions'
|
||||
import RedirectPageView from '../components/RedirectPageView/RedirectPageView'
|
||||
import SetupClientContent from '../components/SetupClientContent/SetupClientContent'
|
||||
import RepositoryTreeNode from '../components/RepositoryTreeNode/RepositoryTreeNode'
|
||||
import RepositoryConfigurationForm from '../components/Forms/RepositoryConfigurationForm'
|
||||
import RepositoryCreateFormContent from '../components/FormContent/RepositoryCreateFormContent'
|
||||
import RepositoryDetailsHeader from '../components/RepositoryDetailsHeader/RepositoryDetailsHeader'
|
||||
@ -127,4 +130,12 @@ export class MavenRepositoryType extends RepositoryStep<VirtualRegistryRequest>
|
||||
renderRedirectPage(): JSX.Element {
|
||||
return <RedirectPageView />
|
||||
}
|
||||
|
||||
renderTreeNodeView(props: RepositoryTreeNodeProps): JSX.Element {
|
||||
return <RepositoryTreeNode {...props} icon={this.repositoryIcon} />
|
||||
}
|
||||
|
||||
renderTreeNodeDetails(): JSX.Element {
|
||||
return <RepositoryDetails />
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ import {
|
||||
type RepositoryConfigurationFormProps,
|
||||
type RepositoryDetailsHeaderProps,
|
||||
RepositoryStep,
|
||||
type RepositoryTreeNodeProps,
|
||||
type RepositoySetupClientProps
|
||||
} from '@ar/frameworks/RepositoryStep/Repository'
|
||||
import {
|
||||
@ -36,10 +37,12 @@ import {
|
||||
UpstreamRepositoryURLInputSource
|
||||
} from '@ar/pages/upstream-proxy-details/types'
|
||||
|
||||
import RepositoryDetails from '../RepositoryDetails'
|
||||
import type { Repository, VirtualRegistryRequest } from '../types'
|
||||
import RepositoryActions from '../components/Actions/RepositoryActions'
|
||||
import RedirectPageView from '../components/RedirectPageView/RedirectPageView'
|
||||
import SetupClientContent from '../components/SetupClientContent/SetupClientContent'
|
||||
import RepositoryTreeNode from '../components/RepositoryTreeNode/RepositoryTreeNode'
|
||||
import RepositoryConfigurationForm from '../components/Forms/RepositoryConfigurationForm'
|
||||
import RepositoryCreateFormContent from '../components/FormContent/RepositoryCreateFormContent'
|
||||
import RepositoryDetailsHeader from '../components/RepositoryDetailsHeader/RepositoryDetailsHeader'
|
||||
@ -127,4 +130,12 @@ export class NpmRepositoryType extends RepositoryStep<VirtualRegistryRequest> {
|
||||
renderRedirectPage(): JSX.Element {
|
||||
return <RedirectPageView />
|
||||
}
|
||||
|
||||
renderTreeNodeView(props: RepositoryTreeNodeProps): JSX.Element {
|
||||
return <RepositoryTreeNode {...props} icon={this.repositoryIcon} />
|
||||
}
|
||||
|
||||
renderTreeNodeDetails(): JSX.Element {
|
||||
return <RepositoryDetails />
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ import {
|
||||
type RepositoryConfigurationFormProps,
|
||||
type RepositoryDetailsHeaderProps,
|
||||
RepositoryStep,
|
||||
type RepositoryTreeNodeProps,
|
||||
type RepositoySetupClientProps
|
||||
} from '@ar/frameworks/RepositoryStep/Repository'
|
||||
import {
|
||||
@ -36,10 +37,12 @@ import {
|
||||
UpstreamRepositoryURLInputSource
|
||||
} from '@ar/pages/upstream-proxy-details/types'
|
||||
|
||||
import RepositoryDetails from '../RepositoryDetails'
|
||||
import type { Repository, VirtualRegistryRequest } from '../types'
|
||||
import RepositoryActions from '../components/Actions/RepositoryActions'
|
||||
import RedirectPageView from '../components/RedirectPageView/RedirectPageView'
|
||||
import SetupClientContent from '../components/SetupClientContent/SetupClientContent'
|
||||
import RepositoryTreeNode from '../components/RepositoryTreeNode/RepositoryTreeNode'
|
||||
import RepositoryConfigurationForm from '../components/Forms/RepositoryConfigurationForm'
|
||||
import RepositoryCreateFormContent from '../components/FormContent/RepositoryCreateFormContent'
|
||||
import RepositoryDetailsHeader from '../components/RepositoryDetailsHeader/RepositoryDetailsHeader'
|
||||
@ -127,4 +130,12 @@ export class NuGetRepositoryType extends RepositoryStep<VirtualRegistryRequest>
|
||||
renderRedirectPage(): JSX.Element {
|
||||
return <RedirectPageView />
|
||||
}
|
||||
|
||||
renderTreeNodeView(props: RepositoryTreeNodeProps): JSX.Element {
|
||||
return <RepositoryTreeNode {...props} icon={this.repositoryIcon} />
|
||||
}
|
||||
|
||||
renderTreeNodeDetails(): JSX.Element {
|
||||
return <RepositoryDetails />
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ import {
|
||||
type RepositoryConfigurationFormProps,
|
||||
type RepositoryDetailsHeaderProps,
|
||||
RepositoryStep,
|
||||
type RepositoryTreeNodeProps,
|
||||
type RepositoySetupClientProps
|
||||
} from '@ar/frameworks/RepositoryStep/Repository'
|
||||
import {
|
||||
@ -36,10 +37,12 @@ import {
|
||||
UpstreamRepositoryURLInputSource
|
||||
} from '@ar/pages/upstream-proxy-details/types'
|
||||
|
||||
import RepositoryDetails from '../RepositoryDetails'
|
||||
import type { Repository, VirtualRegistryRequest } from '../types'
|
||||
import RepositoryActions from '../components/Actions/RepositoryActions'
|
||||
import RedirectPageView from '../components/RedirectPageView/RedirectPageView'
|
||||
import SetupClientContent from '../components/SetupClientContent/SetupClientContent'
|
||||
import RepositoryTreeNode from '../components/RepositoryTreeNode/RepositoryTreeNode'
|
||||
import RepositoryConfigurationForm from '../components/Forms/RepositoryConfigurationForm'
|
||||
import RepositoryCreateFormContent from '../components/FormContent/RepositoryCreateFormContent'
|
||||
import RepositoryDetailsHeader from '../components/RepositoryDetailsHeader/RepositoryDetailsHeader'
|
||||
@ -127,4 +130,12 @@ export class PythonRepositoryType extends RepositoryStep<VirtualRegistryRequest>
|
||||
renderRedirectPage(): JSX.Element {
|
||||
return <RedirectPageView />
|
||||
}
|
||||
|
||||
renderTreeNodeView(props: RepositoryTreeNodeProps): JSX.Element {
|
||||
return <RepositoryTreeNode {...props} icon={this.repositoryIcon} />
|
||||
}
|
||||
|
||||
renderTreeNodeDetails(): JSX.Element {
|
||||
return <RepositoryDetails />
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ import {
|
||||
type RepositoryConfigurationFormProps,
|
||||
type RepositoryDetailsHeaderProps,
|
||||
RepositoryStep,
|
||||
type RepositoryTreeNodeProps,
|
||||
type RepositoySetupClientProps
|
||||
} from '@ar/frameworks/RepositoryStep/Repository'
|
||||
import {
|
||||
@ -36,10 +37,12 @@ import {
|
||||
UpstreamRepositoryURLInputSource
|
||||
} from '@ar/pages/upstream-proxy-details/types'
|
||||
|
||||
import RepositoryDetails from '../RepositoryDetails'
|
||||
import type { Repository, VirtualRegistryRequest } from '../types'
|
||||
import RepositoryActions from '../components/Actions/RepositoryActions'
|
||||
import RedirectPageView from '../components/RedirectPageView/RedirectPageView'
|
||||
import SetupClientContent from '../components/SetupClientContent/SetupClientContent'
|
||||
import RepositoryTreeNode from '../components/RepositoryTreeNode/RepositoryTreeNode'
|
||||
import RepositoryConfigurationForm from '../components/Forms/RepositoryConfigurationForm'
|
||||
import RepositoryCreateFormContent from '../components/FormContent/RepositoryCreateFormContent'
|
||||
import RepositoryDetailsHeader from '../components/RepositoryDetailsHeader/RepositoryDetailsHeader'
|
||||
@ -124,4 +127,12 @@ export class RPMRepositoryType extends RepositoryStep<VirtualRegistryRequest> {
|
||||
renderRedirectPage(): JSX.Element {
|
||||
return <RedirectPageView />
|
||||
}
|
||||
|
||||
renderTreeNodeView(props: RepositoryTreeNodeProps): JSX.Element {
|
||||
return <RepositoryTreeNode {...props} icon={this.repositoryIcon} />
|
||||
}
|
||||
|
||||
renderTreeNodeDetails(): JSX.Element {
|
||||
return <RepositoryDetails />
|
||||
}
|
||||
}
|
||||
|
@ -23,13 +23,17 @@ import { Button, ButtonVariation, Container, Layout, Tab, Tabs } from '@harnessi
|
||||
import { useStrings } from '@ar/frameworks/strings'
|
||||
import type { RepositoryDetailsPathParams } from '@ar/routes/types'
|
||||
import RouteProvider from '@ar/components/RouteProvider/RouteProvider'
|
||||
import { useDecodedParams, useFeatureFlags, useParentComponents, useRoutes } from '@ar/hooks'
|
||||
import {
|
||||
useDecodedParams,
|
||||
useFeatureFlags,
|
||||
useGetRepositoryListViewType,
|
||||
useParentComponents,
|
||||
useRoutes
|
||||
} from '@ar/hooks'
|
||||
import { PermissionIdentifier, ResourceType } from '@ar/common/permissionTypes'
|
||||
import { RepositoryConfigType, RepositoryPackageType } from '@ar/common/types'
|
||||
import RepositoryDetailsHeaderWidget from '@ar/frameworks/RepositoryStep/RepositoryDetailsHeaderWidget'
|
||||
import { repositoryDetailsPathProps, repositoryDetailsTabPathProps } from '@ar/routes/RouteDestinations'
|
||||
|
||||
import { RepositoryDetailsTab } from './constants'
|
||||
import { RepositoryDetailsTab, RepositoryDetailsTabs } from './constants'
|
||||
import RepositoryDetailsTabPage from './RepositoryDetailsTabPage'
|
||||
import { RepositoryProviderContext } from './context/RepositoryProvider'
|
||||
import css from './RepositoryDetailsPage.module.scss'
|
||||
@ -37,7 +41,7 @@ import css from './RepositoryDetailsPage.module.scss'
|
||||
export default function RepositoryDetails(): JSX.Element | null {
|
||||
const { RbacButton } = useParentComponents()
|
||||
const { getString } = useStrings()
|
||||
const { HAR_TRIGGERS } = useFeatureFlags()
|
||||
const featureFlags = useFeatureFlags()
|
||||
const pathParams = useDecodedParams<RepositoryDetailsPathParams>()
|
||||
const { repositoryIdentifier } = pathParams
|
||||
const [activeTab, setActiveTab] = useState('')
|
||||
@ -46,6 +50,7 @@ export default function RepositoryDetails(): JSX.Element | null {
|
||||
const routeDefinitions = useRoutes(true)
|
||||
const history = useHistory()
|
||||
const routes = useRoutes()
|
||||
const repositoryListViewType = useGetRepositoryListViewType()
|
||||
|
||||
const { isDirty, data, isUpdating } = useContext(RepositoryProviderContext)
|
||||
|
||||
@ -90,22 +95,17 @@ export default function RepositoryDetails(): JSX.Element | null {
|
||||
|
||||
if (!data) return null
|
||||
|
||||
const isNotUpstreamRegistry = data.config.type !== RepositoryConfigType.UPSTREAM
|
||||
|
||||
return (
|
||||
<>
|
||||
<RepositoryDetailsHeaderWidget
|
||||
data={data}
|
||||
packageType={data.packageType as RepositoryPackageType}
|
||||
type={data.config.type as RepositoryConfigType}
|
||||
/>
|
||||
<Container className={css.tabsContainer}>
|
||||
<Tabs id="repositoryTabDetails" selectedTabId={activeTab} onChange={handleTabChange}>
|
||||
<Tab id={RepositoryDetailsTab.PACKAGES} title={getString('repositoryDetails.tabs.packages')} />
|
||||
<Tab id={RepositoryDetailsTab.CONFIGURATION} title={getString('repositoryDetails.tabs.configuration')} />
|
||||
{HAR_TRIGGERS && isNotUpstreamRegistry && (
|
||||
<Tab id={RepositoryDetailsTab.WEBHOOKS} title={getString('repositoryDetails.tabs.webhooks')} />
|
||||
)}
|
||||
{RepositoryDetailsTabs.filter(each => !each.featureFlag || featureFlags[each.featureFlag])
|
||||
.filter(each => !each.packageType || each.packageType === data.packageType)
|
||||
.filter(each => !each.type || each.type === data.config.type)
|
||||
.filter(each => !each.mode || each.mode === repositoryListViewType)
|
||||
.map(each => (
|
||||
<Tab key={each.value} id={each.value} title={getString(each.label)} />
|
||||
))}
|
||||
<Expander />
|
||||
{activeTab === RepositoryDetailsTab.CONFIGURATION && renderActionBtns()}
|
||||
</Tabs>
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
import React from 'react'
|
||||
import RepositoryHeader from './RepositoryHeader'
|
||||
import RepositoryDetails from './RepositoryDetails'
|
||||
import RepositoryProvider from './context/RepositoryProvider'
|
||||
|
||||
@ -23,6 +24,7 @@ import './RepositoryFactory'
|
||||
export default function RepositoryDetailsPage(): JSX.Element {
|
||||
return (
|
||||
<RepositoryProvider>
|
||||
<RepositoryHeader />
|
||||
<RepositoryDetails />
|
||||
</RepositoryProvider>
|
||||
)
|
||||
|
34
web/src/ar/pages/repository-details/RepositoryHeader.tsx
Normal file
34
web/src/ar/pages/repository-details/RepositoryHeader.tsx
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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 React, { useContext } from 'react'
|
||||
|
||||
import type { RepositoryConfigType, RepositoryPackageType } from '@ar/common/types'
|
||||
import RepositoryDetailsHeaderWidget from '@ar/frameworks/RepositoryStep/RepositoryDetailsHeaderWidget'
|
||||
|
||||
import { RepositoryProviderContext } from './context/RepositoryProvider'
|
||||
|
||||
export default function RepositoryHeader() {
|
||||
const { data } = useContext(RepositoryProviderContext)
|
||||
if (!data) return null
|
||||
return (
|
||||
<RepositoryDetailsHeaderWidget
|
||||
data={data}
|
||||
packageType={data.packageType as RepositoryPackageType}
|
||||
type={data.config.type as RepositoryConfigType}
|
||||
/>
|
||||
)
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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 React, { useContext } from 'react'
|
||||
import { defaultTo, omit } from 'lodash-es'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
import type { IconName } from '@harnessio/icons'
|
||||
|
||||
import { useParentHooks, useRoutes } from '@ar/hooks'
|
||||
import TreeNode, { NodeTypeEnum } from '@ar/components/TreeView/TreeNode'
|
||||
import TreeNodeContent from '@ar/components/TreeView/TreeNodeContent'
|
||||
import { TreeViewContext } from '@ar/components/TreeView/TreeViewContext'
|
||||
import type { RepositoryTreeNodeProps } from '@ar/frameworks/RepositoryStep/Repository'
|
||||
import RepositoryActionsWidget from '@ar/frameworks/RepositoryStep/RepositoryActionsWidget'
|
||||
import { PageType, type RepositoryConfigType, type RepositoryPackageType } from '@ar/common/types'
|
||||
import ArtifactListTreeView from '@ar/pages/artifact-list/components/ArtifactListTreeView/ArtifactListTreeView'
|
||||
|
||||
import { RepositoryDetailsTab } from '../../constants'
|
||||
|
||||
interface IRepositoryTreeNode extends RepositoryTreeNodeProps {
|
||||
icon: IconName
|
||||
iconSize?: number
|
||||
level?: number
|
||||
}
|
||||
export default function RepositoryTreeNode(props: IRepositoryTreeNode) {
|
||||
const { data, icon, iconSize = 24, level = 0, isLastChild } = props
|
||||
const { setActivePath, activePath, compact } = useContext(TreeViewContext)
|
||||
const { useQueryParams } = useParentHooks()
|
||||
const queryParams = useQueryParams<Record<string, string>>()
|
||||
const routes = useRoutes()
|
||||
const history = useHistory()
|
||||
const path = data.identifier
|
||||
return (
|
||||
<TreeNode
|
||||
key={path}
|
||||
id={path}
|
||||
level={level}
|
||||
compact={compact}
|
||||
parentNodeLevels={[]}
|
||||
nodeType={NodeTypeEnum.Folder}
|
||||
isOpen={activePath.includes(path)}
|
||||
isActive={activePath === path}
|
||||
isLastChild={isLastChild}
|
||||
onClick={() => {
|
||||
setActivePath(path)
|
||||
history.push(
|
||||
routes.toARRepositoryDetailsTab(
|
||||
{
|
||||
repositoryIdentifier: data.identifier,
|
||||
tab: RepositoryDetailsTab.CONFIGURATION
|
||||
},
|
||||
{ queryParams: omit(queryParams, 'digest') }
|
||||
)
|
||||
)
|
||||
}}
|
||||
heading={
|
||||
<TreeNodeContent
|
||||
icon={icon}
|
||||
iconSize={iconSize}
|
||||
label={data.identifier}
|
||||
type={data.type as RepositoryConfigType}
|
||||
artifacts={defaultTo(data.artifactsCount, 0)}
|
||||
downloads={defaultTo(data.downloadsCount, 0)}
|
||||
size={data.registrySize}
|
||||
compact={compact}
|
||||
/>
|
||||
}
|
||||
actionElement={
|
||||
<RepositoryActionsWidget
|
||||
packageType={data.packageType as RepositoryPackageType}
|
||||
readonly={false}
|
||||
data={data}
|
||||
type={data.type as RepositoryConfigType}
|
||||
pageType={PageType.Table}
|
||||
/>
|
||||
}>
|
||||
<ArtifactListTreeView registryIdentifier={data.identifier} parentNodeLevels={[{ data, isLastChild }]} />
|
||||
</TreeNode>
|
||||
)
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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 React, { useContext } from 'react'
|
||||
|
||||
import type { RepositoryPackageType } from '@ar/common/types'
|
||||
import RepositoryTreeNodeDetailsWidget from '@ar/frameworks/RepositoryStep/RepositoryTreeNodeDetailsWidget'
|
||||
|
||||
import { RepositoryProviderContext } from '../../context/RepositoryProvider'
|
||||
|
||||
export default function RepositoryTreeNodeDetails() {
|
||||
const { data } = useContext(RepositoryProviderContext)
|
||||
if (!data) return null
|
||||
const { packageType } = data
|
||||
return <RepositoryTreeNodeDetailsWidget packageType={packageType as RepositoryPackageType} />
|
||||
}
|
@ -17,7 +17,10 @@
|
||||
import type { IconName } from '@harnessio/icons'
|
||||
import type { Scanner } from '@harnessio/react-har-service-client'
|
||||
|
||||
import type { Scanners } from '@ar/common/types'
|
||||
import { FeatureFlags } from '@ar/MFEAppTypes'
|
||||
import type { StringKeys } from '@ar/frameworks/strings'
|
||||
import { RepositoryListViewTypeEnum } from '@ar/contexts/AppStoreContext'
|
||||
import { RepositoryConfigType, RepositoryPackageType, Scanners } from '@ar/common/types'
|
||||
|
||||
export enum RepositoryDetailsTab {
|
||||
PACKAGES = 'packages',
|
||||
@ -44,3 +47,30 @@ export const ContainerScannerConfig: Record<Scanners, ScannerConfigSpec> = {
|
||||
value: 'GRYPE'
|
||||
}
|
||||
}
|
||||
|
||||
interface RepositoryDetailsTabSpec {
|
||||
label: StringKeys
|
||||
value: RepositoryDetailsTab
|
||||
packageType?: RepositoryPackageType
|
||||
type?: RepositoryConfigType
|
||||
mode?: RepositoryListViewTypeEnum
|
||||
featureFlag?: FeatureFlags
|
||||
}
|
||||
|
||||
export const RepositoryDetailsTabs: RepositoryDetailsTabSpec[] = [
|
||||
{
|
||||
label: 'repositoryDetails.tabs.packages',
|
||||
value: RepositoryDetailsTab.PACKAGES,
|
||||
mode: RepositoryListViewTypeEnum.LIST
|
||||
},
|
||||
{
|
||||
label: 'repositoryDetails.tabs.configuration',
|
||||
value: RepositoryDetailsTab.CONFIGURATION
|
||||
},
|
||||
{
|
||||
label: 'repositoryDetails.tabs.webhooks',
|
||||
value: RepositoryDetailsTab.WEBHOOKS,
|
||||
featureFlag: FeatureFlags.HAR_TRIGGERS,
|
||||
type: RepositoryConfigType.VIRTUAL
|
||||
}
|
||||
]
|
||||
|
@ -19,6 +19,11 @@
|
||||
background-color: var(--primary-bg) !important;
|
||||
}
|
||||
|
||||
.treeViewPageBody {
|
||||
--page-header-height: 145px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.pageHeader {
|
||||
height: var(--har-repository-list-page-header-height) !important;
|
||||
background-color: var(--white) !important;
|
||||
|
@ -20,3 +20,4 @@ export declare const pageBody: string
|
||||
export declare const pageHeader: string
|
||||
export declare const subHeader: string
|
||||
export declare const subHeaderItems: string
|
||||
export declare const treeViewPageBody: string
|
||||
|
@ -17,13 +17,29 @@
|
||||
import React, { useMemo, useRef } from 'react'
|
||||
import { flushSync } from 'react-dom'
|
||||
import { Expander } from '@blueprintjs/core'
|
||||
import { ExpandingSearchInput, HarnessDocTooltip, Page, Button, ButtonVariation } from '@harnessio/uicore'
|
||||
import {
|
||||
ExpandingSearchInput,
|
||||
HarnessDocTooltip,
|
||||
Page,
|
||||
Button,
|
||||
ButtonVariation,
|
||||
GridListToggle,
|
||||
Views
|
||||
} from '@harnessio/uicore'
|
||||
import type { ExpandingSearchInputHandle } from '@harnessio/uicore'
|
||||
import { useGetAllRegistriesQuery } from '@harnessio/react-har-service-client'
|
||||
|
||||
import { useStrings } from '@ar/frameworks/strings'
|
||||
import { DEFAULT_PAGE_INDEX, PreferenceScope } from '@ar/constants'
|
||||
import { useParentComponents, useParentHooks, useGetSpaceRef } from '@ar/hooks'
|
||||
import { RepositoryListViewTypeEnum } from '@ar/contexts/AppStoreContext'
|
||||
import {
|
||||
useParentComponents,
|
||||
useParentHooks,
|
||||
useGetSpaceRef,
|
||||
useFeatureFlags,
|
||||
useAppStore,
|
||||
useGetRepositoryListViewType
|
||||
} from '@ar/hooks'
|
||||
import PackageTypeSelector from '@ar/components/PackageTypeSelector/PackageTypeSelector'
|
||||
|
||||
import { CreateRepository } from './components/CreateRepository/CreateRepository'
|
||||
@ -39,7 +55,10 @@ function RepositoryListPage(): JSX.Element {
|
||||
const { getString } = useStrings()
|
||||
const { NGBreadcrumbs } = useParentComponents()
|
||||
const { useQueryParams, useUpdateQueryParams, usePreferenceStore } = useParentHooks()
|
||||
const { HAR_TREE_VIEW_ENABLED } = useFeatureFlags()
|
||||
const { updateQueryParams } = useUpdateQueryParams<Partial<ArtifactRepositoryListPageQueryParams>>()
|
||||
const { setRepositoryListViewType } = useAppStore()
|
||||
const repositoryListViewType = useGetRepositoryListViewType()
|
||||
|
||||
const spaceRef = useGetSpaceRef()
|
||||
const queryParamOptions = useArtifactRepositoriesQueryParamOptions()
|
||||
@ -130,6 +149,16 @@ function RepositoryListPage(): JSX.Element {
|
||||
defaultValue={searchTerm}
|
||||
ref={searchRef}
|
||||
/>
|
||||
{HAR_TREE_VIEW_ENABLED && (
|
||||
<GridListToggle
|
||||
initialSelectedView={repositoryListViewType === RepositoryListViewTypeEnum.LIST ? Views.LIST : Views.GRID}
|
||||
icons={{ left: 'SplitView' }}
|
||||
onViewToggle={newView => {
|
||||
if (newView === Views.LIST) return
|
||||
setRepositoryListViewType(RepositoryListViewTypeEnum.DIRECTORY)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</Page.SubHeader>
|
||||
<Page.Body
|
||||
|
101
web/src/ar/pages/repository-list/RepositoryListTreeViewPage.tsx
Normal file
101
web/src/ar/pages/repository-list/RepositoryListTreeViewPage.tsx
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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 React from 'react'
|
||||
import { Expander } from '@blueprintjs/core'
|
||||
import { HarnessDocTooltip, Page, GridListToggle, Views } from '@harnessio/uicore'
|
||||
|
||||
import { useStrings } from '@ar/frameworks/strings'
|
||||
import { DEFAULT_PAGE_INDEX } from '@ar/constants'
|
||||
import { RepositoryListViewTypeEnum } from '@ar/contexts/AppStoreContext'
|
||||
import { useAppStore, useGetRepositoryListViewType, useParentComponents, useParentHooks } from '@ar/hooks'
|
||||
import PackageTypeSelector from '@ar/components/PackageTypeSelector/PackageTypeSelector'
|
||||
import TableFilterCheckbox from '@ar/components/TableFilterCheckbox/TableFilterCheckbox'
|
||||
|
||||
import { useArtifactRepositoriesQueryParamOptions } from './utils'
|
||||
import type { ArtifactRepositoryListPageQueryParams } from './utils'
|
||||
import { CreateRepository } from './components/CreateRepository/CreateRepository'
|
||||
import RepositoryTypeSelector from './components/RepositoryTypeSelector/RepositoryTypeSelector'
|
||||
import RepositoryListTreeView from './components/RepositoryListTreeView/RepositoryListTreeView'
|
||||
|
||||
import css from './RepositoryListPage.module.scss'
|
||||
|
||||
function RepositoryListTreeViewPage(): JSX.Element {
|
||||
const { getString } = useStrings()
|
||||
const { NGBreadcrumbs } = useParentComponents()
|
||||
const { useQueryParams, useUpdateQueryParams } = useParentHooks()
|
||||
const { updateQueryParams } = useUpdateQueryParams<Partial<ArtifactRepositoryListPageQueryParams>>()
|
||||
const { setRepositoryListViewType } = useAppStore()
|
||||
const repositoryListViewType = useGetRepositoryListViewType()
|
||||
|
||||
const queryParamOptions = useArtifactRepositoriesQueryParamOptions()
|
||||
const queryParams = useQueryParams<ArtifactRepositoryListPageQueryParams>(queryParamOptions)
|
||||
const { repositoryTypes, configType, compact } = queryParams
|
||||
|
||||
return (
|
||||
<>
|
||||
<Page.Header
|
||||
className={css.pageHeader}
|
||||
title={
|
||||
<div className="ng-tooltip-native">
|
||||
<h2 data-tooltip-id="artifactRepositoriesPageHeading">{getString('repositoryList.pageHeading')}</h2>
|
||||
<HarnessDocTooltip tooltipId="artifactRepositoriesPageHeading" useStandAlone={true} />
|
||||
</div>
|
||||
}
|
||||
breadcrumbs={<NGBreadcrumbs links={[]} />}
|
||||
/>
|
||||
<Page.SubHeader className={css.subHeader}>
|
||||
<div className={css.subHeaderItems}>
|
||||
<CreateRepository />
|
||||
<RepositoryTypeSelector
|
||||
value={configType}
|
||||
onChange={val => {
|
||||
updateQueryParams({ configType: val, page: DEFAULT_PAGE_INDEX })
|
||||
}}
|
||||
/>
|
||||
<PackageTypeSelector
|
||||
value={repositoryTypes}
|
||||
onChange={val => {
|
||||
updateQueryParams({ repositoryTypes: val, page: DEFAULT_PAGE_INDEX })
|
||||
}}
|
||||
/>
|
||||
<Expander />
|
||||
<TableFilterCheckbox
|
||||
value={compact}
|
||||
label={getString('repositoryList.compact')}
|
||||
disabled={false}
|
||||
onChange={val => {
|
||||
updateQueryParams({ compact: val })
|
||||
}}
|
||||
/>
|
||||
<GridListToggle
|
||||
initialSelectedView={repositoryListViewType === RepositoryListViewTypeEnum.LIST ? Views.LIST : Views.GRID}
|
||||
icons={{ left: 'SplitView' }}
|
||||
onViewToggle={newView => {
|
||||
if (newView === Views.GRID) return
|
||||
setRepositoryListViewType(RepositoryListViewTypeEnum.LIST)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Page.SubHeader>
|
||||
<Page.Body className={css.treeViewPageBody}>
|
||||
<RepositoryListTreeView />
|
||||
</Page.Body>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default RepositoryListTreeViewPage
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
.treeViewPageContainer {
|
||||
--tree-view-page-content-height: calc(var(--page-height, var(--page-min-height)) - var(--page-header-height, 64px));
|
||||
--tree-view-width: 25%;
|
||||
--har-repository-details-page-header-height: 0px;
|
||||
--har-version-details-page-header-height: 0px;
|
||||
width: 100% !important;
|
||||
height: var(--tree-view-page-content-height);
|
||||
}
|
||||
|
||||
.treeViewContainer {
|
||||
width: var(--tree-view-width);
|
||||
height: var(--tree-view-page-content-height);
|
||||
overflow: auto;
|
||||
border-right: 1px solid var(--grey-200);
|
||||
background-color: var(--white) !important;
|
||||
padding: var(--spacing-0) var(--spacing-0) var(--spacing-small) !important;
|
||||
}
|
||||
|
||||
.treeViewPageContentContainer {
|
||||
position: relative;
|
||||
background-color: var(--primary-bg) !important;
|
||||
width: calc(100% - var(--tree-view-width));
|
||||
height: var(--tree-view-page-content-height);
|
||||
overflow: auto;
|
||||
padding: var(--spacing-0);
|
||||
border-top: 1px solid var(--grey-200);
|
||||
}
|
||||
|
||||
.sortingDropDown {
|
||||
cursor: pointer;
|
||||
|
||||
& :global([class*='DropDown--dropdownButton--']) {
|
||||
column-gap: var(--spacing-small) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.searchInput {
|
||||
padding: var(--spacing-xsmall) !important;
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2023 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.
|
||||
*/
|
||||
|
||||
/* eslint-disable */
|
||||
// This is an auto-generated file
|
||||
export declare const searchInput: string
|
||||
export declare const sortingDropDown: string
|
||||
export declare const treeViewContainer: string
|
||||
export declare const treeViewPageContainer: string
|
||||
export declare const treeViewPageContentContainer: string
|
@ -0,0 +1,222 @@
|
||||
/*
|
||||
* 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 React, { useMemo, useState } from 'react'
|
||||
import { compact as lodashCompact } from 'lodash-es'
|
||||
import { Switch } from 'react-router-dom'
|
||||
import { useInfiniteQuery } from '@tanstack/react-query'
|
||||
import { FontVariation } from '@harnessio/design-system'
|
||||
import { Container, DropDown, Layout, Text } from '@harnessio/uicore'
|
||||
import { type Error, getAllRegistries, type GetAllRegistriesOkResponse } from '@harnessio/react-har-service-client'
|
||||
|
||||
import { useStrings } from '@ar/frameworks/strings'
|
||||
import { useGetSpaceRef, useParentHooks, useRoutes } from '@ar/hooks'
|
||||
import TreeBody from '@ar/components/TreeView/TreeBody'
|
||||
import TreeNode from '@ar/components/TreeView/TreeNode'
|
||||
import type { RepositoryPackageType } from '@ar/common/types'
|
||||
import TreeNodeList from '@ar/components/TreeView/TreeNodeList'
|
||||
import RouteProvider from '@ar/components/RouteProvider/RouteProvider'
|
||||
import TreeLoadMoreNode from '@ar/components/TreeView/TreeLoadMoreNode'
|
||||
import RepositoryProvider from '@ar/pages/repository-details/context/RepositoryProvider'
|
||||
import {
|
||||
artifactDetailsPathProps,
|
||||
repositoryDetailsPathProps,
|
||||
versionDetailsPathParams
|
||||
} from '@ar/routes/RouteDestinations'
|
||||
import TreeNodeSearchInput from '@ar/components/TreeView/TreeNodeSearchInput'
|
||||
import { TreeViewContext } from '@ar/components/TreeView/TreeViewContext'
|
||||
import VersionProvider from '@ar/pages/version-details/context/VersionProvider'
|
||||
import ArtifactProvider from '@ar/pages/artifact-details/context/ArtifactProvider'
|
||||
import type { DockerVersionDetailsQueryParams } from '@ar/pages/version-details/DockerVersion/types'
|
||||
import RepositoryTreeNodeViewWidget from '@ar/frameworks/RepositoryStep/RepositoryTreeNodeViewWidget'
|
||||
import VersionTreeNodeDetails from '@ar/pages/version-details/components/VersionTreeNode/VersionTreeNodeDetails'
|
||||
|
||||
import ArtifactTreeNodeDetails from '@ar/pages/artifact-details/components/ArtifactTreeNode/ArtifactTreeNodeDetails'
|
||||
import RepositoryTreeNodeDetails from '@ar/pages/repository-details/components/RepositoryTreeNode/RepositoryTreeNodeDetails'
|
||||
|
||||
import { TreeViewSortingOptions } from '../../constants'
|
||||
import { useArtifactRepositoriesQueryParamOptions, type ArtifactRepositoryListPageQueryParams } from '../../utils'
|
||||
|
||||
import css from './RepositoryListTreeView.module.scss'
|
||||
|
||||
export default function RepositoryListTreeView() {
|
||||
const routeDefinitions = useRoutes(true)
|
||||
const { getString } = useStrings()
|
||||
const spaceRef = useGetSpaceRef()
|
||||
const [initialised, setInitialised] = useState(false)
|
||||
|
||||
const { useQueryParams, useUpdateQueryParams } = useParentHooks()
|
||||
const { digest } = useQueryParams<DockerVersionDetailsQueryParams>()
|
||||
const [activePath, setActivePath] = useState('')
|
||||
|
||||
const queryParamOptions = useArtifactRepositoriesQueryParamOptions()
|
||||
const { updateQueryParams } = useUpdateQueryParams<Partial<ArtifactRepositoryListPageQueryParams>>()
|
||||
const { registrySearchTerm, compact, repositoryTypes, configType, treeSort } =
|
||||
useQueryParams<ArtifactRepositoryListPageQueryParams>(queryParamOptions)
|
||||
|
||||
const [sortField, sortOrder] = treeSort?.split(',') || []
|
||||
|
||||
const { data, isFetching, error, hasNextPage, fetchNextPage, refetch, isFetchingNextPage } = useInfiniteQuery<
|
||||
GetAllRegistriesOkResponse,
|
||||
Error,
|
||||
GetAllRegistriesOkResponse,
|
||||
Array<string | Record<string, unknown>>
|
||||
>({
|
||||
queryKey: [
|
||||
'registryList',
|
||||
{
|
||||
sortField,
|
||||
sortOrder,
|
||||
registrySearchTerm,
|
||||
configType,
|
||||
repositoryTypes
|
||||
}
|
||||
],
|
||||
queryFn: ({ pageParam = 0 }) =>
|
||||
getAllRegistries({
|
||||
space_ref: spaceRef,
|
||||
queryParams: {
|
||||
page: pageParam,
|
||||
size: 20,
|
||||
sort_field: sortField,
|
||||
sort_order: sortOrder,
|
||||
package_type: repositoryTypes,
|
||||
search_term: registrySearchTerm,
|
||||
type: configType
|
||||
},
|
||||
stringifyQueryParamsOptions: {
|
||||
arrayFormat: 'repeat'
|
||||
}
|
||||
}),
|
||||
getNextPageParam: lastPage => {
|
||||
const totalPages = lastPage.content.data.pageCount ?? 0
|
||||
const lastPageNumber = lastPage.content.data.pageIndex ?? -1
|
||||
const nextPage = lastPageNumber + 1
|
||||
return nextPage < totalPages ? nextPage : undefined
|
||||
}
|
||||
})
|
||||
|
||||
const handleUpdateActivePath = (values: Record<string, string>) => {
|
||||
const initialActivePath = lodashCompact([
|
||||
values.repositoryIdentifier,
|
||||
values.artifactIdentifier,
|
||||
values.versionIdentifier,
|
||||
digest
|
||||
]).join('/')
|
||||
setActivePath(initialActivePath)
|
||||
setInitialised(true)
|
||||
}
|
||||
|
||||
const { list: repositoryList, count: repositoryCount } = useMemo(() => {
|
||||
const list = data?.pages.flatMap(page => page.content.data.registries) || []
|
||||
const count = data?.pages[0].content.data.itemCount || 0
|
||||
return { list, count }
|
||||
}, [data])
|
||||
|
||||
return (
|
||||
<TreeViewContext.Provider value={{ activePath, setActivePath, compact }}>
|
||||
<Layout.Horizontal className={css.treeViewPageContainer}>
|
||||
<Container className={css.treeViewContainer}>
|
||||
<TreeNodeList>
|
||||
<TreeNodeSearchInput
|
||||
className={css.searchInput}
|
||||
defaultValue={registrySearchTerm}
|
||||
onChange={val => {
|
||||
updateQueryParams({ registrySearchTerm: val })
|
||||
}}
|
||||
treeNodeProps={{
|
||||
alwaysShowAction: true,
|
||||
actionElement: (
|
||||
<DropDown
|
||||
icon="main-sort"
|
||||
className={css.sortingDropDown}
|
||||
items={TreeViewSortingOptions}
|
||||
value={treeSort}
|
||||
onChange={option => {
|
||||
const selectedOption = TreeViewSortingOptions.find(each => each.label === option.label)
|
||||
if (!selectedOption) return
|
||||
const val = selectedOption.key
|
||||
const dir = selectedOption.dir
|
||||
updateQueryParams({ treeSort: [val, dir].join(',') })
|
||||
}}
|
||||
usePortal
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
{!!repositoryCount && (
|
||||
<TreeNode
|
||||
disabled
|
||||
alwaysShowAction
|
||||
compact={compact}
|
||||
heading={
|
||||
<Text font={{ variation: FontVariation.BODY, weight: 'semi-bold' }}>
|
||||
{getString('repositoryList.registryCount', { count: repositoryCount })}
|
||||
</Text>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<TreeBody
|
||||
loading={isFetching || !initialised}
|
||||
error={error?.message}
|
||||
retryOnError={refetch}
|
||||
isEmpty={!repositoryList.length}>
|
||||
{repositoryList.map((registry, idx) => (
|
||||
<RepositoryTreeNodeViewWidget
|
||||
key={registry.identifier}
|
||||
data={registry}
|
||||
packageType={registry.packageType as RepositoryPackageType}
|
||||
isLastChild={idx === repositoryList.length - 1}
|
||||
/>
|
||||
))}
|
||||
{hasNextPage && <TreeLoadMoreNode onClick={() => fetchNextPage()} disabled={isFetchingNextPage} />}
|
||||
</TreeBody>
|
||||
</TreeNodeList>
|
||||
</Container>
|
||||
<Container className={css.treeViewPageContentContainer}>
|
||||
<Switch>
|
||||
<RouteProvider exact onLoad={handleUpdateActivePath} path={[routeDefinitions.toARRepositories()]}>
|
||||
{/* TODO: Implement a default page for this path */}
|
||||
<></>
|
||||
</RouteProvider>
|
||||
<RouteProvider
|
||||
exact
|
||||
onLoad={handleUpdateActivePath}
|
||||
path={[routeDefinitions.toARArtifactDetails({ ...artifactDetailsPathProps })]}>
|
||||
<ArtifactProvider>
|
||||
<ArtifactTreeNodeDetails />
|
||||
</ArtifactProvider>
|
||||
</RouteProvider>
|
||||
<RouteProvider
|
||||
onLoad={handleUpdateActivePath}
|
||||
path={[routeDefinitions.toARVersionDetails({ ...versionDetailsPathParams })]}>
|
||||
<VersionProvider>
|
||||
<VersionTreeNodeDetails />
|
||||
</VersionProvider>
|
||||
</RouteProvider>
|
||||
<RouteProvider
|
||||
onLoad={handleUpdateActivePath}
|
||||
path={[routeDefinitions.toARRepositoryDetails({ ...repositoryDetailsPathProps })]}>
|
||||
<RepositoryProvider>
|
||||
<RepositoryTreeNodeDetails />
|
||||
</RepositoryProvider>
|
||||
</RouteProvider>
|
||||
</Switch>
|
||||
</Container>
|
||||
</Layout.Horizontal>
|
||||
</TreeViewContext.Provider>
|
||||
)
|
||||
}
|
@ -31,6 +31,7 @@ export default function RepositoryTypeSelector(props: RepositoryTypeSelectorProp
|
||||
return (
|
||||
<DropDown
|
||||
width={180}
|
||||
usePortal
|
||||
buttonTestId="registry-type-select"
|
||||
items={RepositoryConfigTypes.filter(each => !each.disabled).map(each => ({
|
||||
...each,
|
||||
|
28
web/src/ar/pages/repository-list/constants.ts
Normal file
28
web/src/ar/pages/repository-list/constants.ts
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export interface TreeViewSortingOption {
|
||||
value: string
|
||||
label: string
|
||||
dir?: string
|
||||
}
|
||||
|
||||
export const TreeViewSortingOptions = [
|
||||
{ value: 'lastModified,DESC', label: 'Newest', key: 'lastModified', dir: 'DESC' },
|
||||
{ value: 'lastModified,ASC', label: 'Oldest', key: 'lastModified', dir: 'ASC' },
|
||||
{ value: 'identifier,ASC', label: 'Name (A->Z, 0->9)', key: 'identifier', dir: 'ASC' },
|
||||
{ value: 'identifier,DESC', label: 'Name (Z->A, 9->0)', key: 'identifier', dir: 'DESC' }
|
||||
]
|
@ -1,6 +1,7 @@
|
||||
pageHeading: Artifact Registries
|
||||
newRepository: New Artifact Registry
|
||||
newRegistry: New Registry
|
||||
registryCount: 'Total {{count}} Registries'
|
||||
artifactRegistry:
|
||||
label: Artifact Registry
|
||||
subLabel: Manage internal packages and external dependencies through a unified registry.
|
||||
@ -11,6 +12,7 @@ selectEnvironments: Environments
|
||||
selectPackageTypes: Package Types
|
||||
selectRegistryType: Registry Type
|
||||
selectLabels: '{{ $.artifactList.table.columns.tags }}'
|
||||
compact: Compact View
|
||||
deleteModal:
|
||||
title: '{{ $.artifactList.table.actions.deleteRepository }}'
|
||||
contentText: Are you sure you want to delete the registry?
|
||||
|
@ -29,8 +29,11 @@ type GetArtifactRepositoryQueryParams = {
|
||||
size: number
|
||||
sort: string[]
|
||||
searchTerm?: string
|
||||
registrySearchTerm?: string
|
||||
compact: boolean
|
||||
repositoryTypes: RepositoryPackageType[]
|
||||
configType?: RepositoryConfigType
|
||||
treeSort?: string
|
||||
}
|
||||
|
||||
export type ArtifactRepositoryListPageQueryParams = Omit<
|
||||
@ -46,7 +49,8 @@ export const useArtifactRepositoriesQueryParamOptions =
|
||||
page: DEFAULT_PAGE_INDEX,
|
||||
size: DEFAULT_PAGE_SIZE,
|
||||
sort: DEFAULT_PIPELINE_LIST_TABLE_SORT,
|
||||
repositoryTypes: []
|
||||
repositoryTypes: [],
|
||||
compact: false
|
||||
},
|
||||
{ ignoreEmptyString: false }
|
||||
)
|
||||
|
@ -19,12 +19,13 @@ import { FontVariation } from '@harnessio/design-system'
|
||||
import { Card, Container, Layout, Page, Text } from '@harnessio/uicore'
|
||||
import { useGetDockerArtifactDetailsQuery } from '@harnessio/react-har-service-client'
|
||||
|
||||
import { Parent } from '@ar/common/types'
|
||||
import { useStrings } from '@ar/frameworks/strings'
|
||||
import { encodeRef } from '@ar/hooks/useGetSpaceRef'
|
||||
import { DEFAULT_DATE_TIME_FORMAT } from '@ar/constants'
|
||||
import type { VersionDetailsPathParams } from '@ar/routes/types'
|
||||
import { getReadableDateTime } from '@ar/common/dateUtils'
|
||||
import { useDecodedParams, useGetSpaceRef, useParentHooks } from '@ar/hooks'
|
||||
import { useAppStore, useDecodedParams, useGetSpaceRef, useParentHooks } from '@ar/hooks'
|
||||
|
||||
import type { DockerVersionDetailsQueryParams } from './types'
|
||||
import { VersionOverviewCard } from '../components/OverviewCards/types'
|
||||
@ -40,6 +41,7 @@ export default function DockerVersionOverviewContent(): JSX.Element {
|
||||
const { useQueryParams } = useParentHooks()
|
||||
const { digest } = useQueryParams<DockerVersionDetailsQueryParams>()
|
||||
const spaceRef = useGetSpaceRef()
|
||||
const { parent } = useAppStore()
|
||||
|
||||
const {
|
||||
data,
|
||||
@ -70,15 +72,17 @@ export default function DockerVersionOverviewContent(): JSX.Element {
|
||||
retryOnError={() => refetch()}>
|
||||
{response && (
|
||||
<Layout.Vertical className={css.cardContainer} spacing="medium" flex={{ alignItems: 'flex-start' }}>
|
||||
<VersionOverviewCards
|
||||
cards={[
|
||||
VersionOverviewCard.DEPLOYMENT,
|
||||
VersionOverviewCard.BUILD,
|
||||
VersionOverviewCard.SECURITY_TESTS,
|
||||
VersionOverviewCard.SUPPLY_CHAIN
|
||||
]}
|
||||
digest={digest}
|
||||
/>
|
||||
{parent === Parent.Enterprise && (
|
||||
<VersionOverviewCards
|
||||
cards={[
|
||||
VersionOverviewCard.DEPLOYMENT,
|
||||
VersionOverviewCard.BUILD,
|
||||
VersionOverviewCard.SECURITY_TESTS,
|
||||
VersionOverviewCard.SUPPLY_CHAIN
|
||||
]}
|
||||
digest={digest}
|
||||
/>
|
||||
)}
|
||||
<Card
|
||||
data-testid="general-information-card"
|
||||
title={getString('versionDetails.overview.generalInformation.title')}
|
||||
|
@ -18,30 +18,38 @@ import React from 'react'
|
||||
import type { ArtifactVersionSummary } from '@harnessio/react-har-service-client'
|
||||
|
||||
import { String } from '@ar/frameworks/strings'
|
||||
import { PageType, RepositoryPackageType } from '@ar/common/types'
|
||||
import { NodeTypeEnum } from '@ar/components/TreeView/TreeNode'
|
||||
import DigestListPage from '@ar/pages/digest-list/DigestListPage'
|
||||
import { PageType, RepositoryPackageType } from '@ar/common/types'
|
||||
import ArtifactActions from '@ar/pages/artifact-details/components/ArtifactActions/ArtifactActions'
|
||||
import ArtifactTreeNode from '@ar/pages/artifact-details/components/ArtifactTreeNode/ArtifactTreeNode'
|
||||
import DigestListTreeView from '@ar/pages/digest-list/components/DigestListTreeView/DigestListTreeView'
|
||||
import DockerVersionListTable from '@ar/pages/version-list/DockerVersion/VersionListTable/DockerVersionListTable'
|
||||
import ArtifactTreeNodeDetailsContent from '@ar/pages/artifact-details/components/ArtifactTreeNode/ArtifactTreeNodeDetailsContent'
|
||||
import {
|
||||
type ArtifactActionProps,
|
||||
ArtifactRowSubComponentProps,
|
||||
type VersionActionProps,
|
||||
type ArtifactTreeNodeViewProps,
|
||||
type VersionDetailsHeaderProps,
|
||||
type VersionDetailsTabProps,
|
||||
type VersionListTableProps,
|
||||
VersionStep
|
||||
VersionStep,
|
||||
type VersionTreeNodeViewProps
|
||||
} from '@ar/frameworks/Version/Version'
|
||||
|
||||
import DockerVersionHeader from './DockerVersionHeader'
|
||||
import { VersionAction } from '../components/VersionActions/types'
|
||||
import DockerArtifactSSCAContent from './DockerArtifactSSCAContent'
|
||||
import VersionActions from '../components/VersionActions/VersionActions'
|
||||
import DockerVersionOverviewContent from './DockerVersionOverviewContent'
|
||||
import DockerArtifactDetailsContent from './DockerArtifactDetailsContent'
|
||||
import VersionTreeNode from '../components/VersionTreeNode/VersionTreeNode'
|
||||
import { VersionDetailsTab } from '../components/VersionDetailsTabs/constants'
|
||||
import DockerArtifactSecurityTestsContent from './DockerArtifactSecurityTestsContent'
|
||||
import DockerVersionOSSContent from './DockerVersionOSSContent/DockerVersionOSSContent'
|
||||
import DockerDeploymentsContent from './DockerDeploymentsContent/DockerDeploymentsContent'
|
||||
import VersionActions from '../components/VersionActions/VersionActions'
|
||||
import { VersionAction } from '../components/VersionActions/types'
|
||||
import DockerVersionTreeNodeDetailsContent from './components/DockerVersionTreeNodeDetailsContent/DockerVersionTreeNodeDetailsContent'
|
||||
|
||||
export class DockerVersionType extends VersionStep<ArtifactVersionSummary> {
|
||||
protected packageType = RepositoryPackageType.DOCKER
|
||||
@ -111,4 +119,30 @@ export class DockerVersionType extends VersionStep<ArtifactVersionSummary> {
|
||||
<DigestListPage repoKey={props.data.registryIdentifier} artifact={props.data.name} version={props.data.version} />
|
||||
)
|
||||
}
|
||||
|
||||
renderArtifactTreeNodeView(props: ArtifactTreeNodeViewProps): JSX.Element {
|
||||
return <ArtifactTreeNode {...props} icon="store-artifact-bundle" />
|
||||
}
|
||||
|
||||
renderArtifactTreeNodeDetails(): JSX.Element {
|
||||
return <ArtifactTreeNodeDetailsContent />
|
||||
}
|
||||
|
||||
renderVersionTreeNodeView(props: VersionTreeNodeViewProps): JSX.Element {
|
||||
const { data, parentNodeLevels, isLastChild } = props
|
||||
return (
|
||||
<VersionTreeNode {...props} icon="container" nodeType={NodeTypeEnum.Folder}>
|
||||
<DigestListTreeView
|
||||
registryIdentifier={props.data.registryIdentifier}
|
||||
artifactIdentifier={props.artifactIdentifier}
|
||||
versionIdentifier={props.data.name}
|
||||
parentNodeLevels={[...parentNodeLevels, { data, isLastChild }]}
|
||||
/>
|
||||
</VersionTreeNode>
|
||||
)
|
||||
}
|
||||
|
||||
renderVersionTreeNodeDetails(): JSX.Element {
|
||||
return <DockerVersionTreeNodeDetailsContent />
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
.cardContainer {
|
||||
width: 60% !important;
|
||||
min-width: 1040px;
|
||||
padding: var(--spacing-7) !important;
|
||||
background-color: var(--white);
|
||||
}
|
||||
|
||||
.gridContainer {
|
||||
align-items: center;
|
||||
display: grid;
|
||||
grid-template-columns: max-content auto;
|
||||
row-gap: var(--spacing-medium);
|
||||
column-gap: 30px;
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2023 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.
|
||||
*/
|
||||
|
||||
/* eslint-disable */
|
||||
// This is an auto-generated file
|
||||
export declare const cardContainer: string
|
||||
export declare const gridContainer: string
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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 React, { useContext } from 'react'
|
||||
import { FontVariation } from '@harnessio/design-system'
|
||||
import { Card, Container, Layout, Text } from '@harnessio/uicore'
|
||||
|
||||
import { useParentHooks } from '@ar/hooks'
|
||||
import { useStrings } from '@ar/frameworks/strings'
|
||||
import { VersionProviderContext } from '@ar/pages/version-details/context/VersionProvider'
|
||||
import { LabelValueTypeEnum } from '@ar/pages/version-details/components/LabelValueContent/type'
|
||||
import VersionDetailsTabs from '@ar/pages/version-details/components/VersionDetailsTabs/VersionDetailsTabs'
|
||||
import { LabelValueContent } from '@ar/pages/version-details/components/LabelValueContent/LabelValueContent'
|
||||
|
||||
import type { DockerVersionDetailsQueryParams } from '../../types'
|
||||
|
||||
import css from './DockerVersionTreeNodeDetailsContent.module.scss'
|
||||
|
||||
export default function DockerVersionTreeNodeDetailsContent(): JSX.Element {
|
||||
const { useQueryParams } = useParentHooks()
|
||||
const { getString } = useStrings()
|
||||
const { data } = useContext(VersionProviderContext)
|
||||
const { digest } = useQueryParams<DockerVersionDetailsQueryParams>()
|
||||
if (!data) return <></>
|
||||
if (!digest) {
|
||||
return (
|
||||
<Layout.Vertical spacing="small" padding="large">
|
||||
<Text font={{ variation: FontVariation.CARD_TITLE }}>{getString('details')}</Text>
|
||||
<Card className={css.cardContainer}>
|
||||
<Container className={css.gridContainer}>
|
||||
<LabelValueContent
|
||||
label={getString('versionDetails.overview.generalInformation.name')}
|
||||
value={data.imageName}
|
||||
type={LabelValueTypeEnum.Text}
|
||||
/>
|
||||
<LabelValueContent
|
||||
label={getString('versionDetails.overview.generalInformation.version')}
|
||||
value={data.version}
|
||||
type={LabelValueTypeEnum.Text}
|
||||
/>
|
||||
<LabelValueContent
|
||||
label={getString('versionDetails.overview.generalInformation.packageType')}
|
||||
value={getString('packageTypes.dockerPackage')}
|
||||
type={LabelValueTypeEnum.PackageType}
|
||||
icon="docker-step"
|
||||
/>
|
||||
</Container>
|
||||
</Card>
|
||||
</Layout.Vertical>
|
||||
)
|
||||
}
|
||||
return <VersionDetailsTabs />
|
||||
}
|
@ -20,10 +20,12 @@ import {
|
||||
type ArtifactActionProps,
|
||||
ArtifactRowSubComponentProps,
|
||||
type VersionActionProps,
|
||||
type ArtifactTreeNodeViewProps,
|
||||
type VersionDetailsHeaderProps,
|
||||
type VersionDetailsTabProps,
|
||||
type VersionListTableProps,
|
||||
VersionStep
|
||||
VersionStep,
|
||||
type VersionTreeNodeViewProps
|
||||
} from '@ar/frameworks/Version/Version'
|
||||
import { String } from '@ar/frameworks/strings'
|
||||
import { PageType, RepositoryPackageType } from '@ar/common/types'
|
||||
@ -32,9 +34,13 @@ import VersionListTable, {
|
||||
} from '@ar/pages/version-list/components/VersionListTable/VersionListTable'
|
||||
import { VersionListColumnEnum } from '@ar/pages/version-list/components/VersionListTable/types'
|
||||
import ArtifactActions from '@ar/pages/artifact-details/components/ArtifactActions/ArtifactActions'
|
||||
import ArtifactTreeNode from '@ar/pages/artifact-details/components/ArtifactTreeNode/ArtifactTreeNode'
|
||||
import ArtifactTreeNodeDetailsContent from '@ar/pages/artifact-details/components/ArtifactTreeNode/ArtifactTreeNodeDetailsContent'
|
||||
import { VersionDetailsTab } from '../components/VersionDetailsTabs/constants'
|
||||
import GenericOverviewPage from './pages/overview/OverviewPage'
|
||||
import OSSContentPage from './pages/oss-details/OSSContentPage'
|
||||
import VersionTreeNode from '../components/VersionTreeNode/VersionTreeNode'
|
||||
import VersionDetailsTabs from '../components/VersionDetailsTabs/VersionDetailsTabs'
|
||||
import GenericArtifactDetailsPage from './pages/artifact-details/GenericArtifactDetailsPage'
|
||||
import VersionDetailsHeaderContent from '../components/VersionDetailsHeaderContent/VersionDetailsHeaderContent'
|
||||
import VersionFilesProvider from '../context/VersionFilesProvider'
|
||||
@ -113,4 +119,20 @@ export class GenericVersionType extends VersionStep<ArtifactVersionSummary> {
|
||||
</VersionFilesProvider>
|
||||
)
|
||||
}
|
||||
|
||||
renderArtifactTreeNodeView(props: ArtifactTreeNodeViewProps): JSX.Element {
|
||||
return <ArtifactTreeNode {...props} icon="store-artifact-bundle" />
|
||||
}
|
||||
|
||||
renderArtifactTreeNodeDetails(): JSX.Element {
|
||||
return <ArtifactTreeNodeDetailsContent />
|
||||
}
|
||||
|
||||
renderVersionTreeNodeView(props: VersionTreeNodeViewProps): JSX.Element {
|
||||
return <VersionTreeNode {...props} icon="container" />
|
||||
}
|
||||
|
||||
renderVersionTreeNodeDetails(): JSX.Element {
|
||||
return <VersionDetailsTabs />
|
||||
}
|
||||
}
|
||||
|
@ -24,19 +24,26 @@ import VersionListTable, {
|
||||
CommonVersionListTableProps
|
||||
} from '@ar/pages/version-list/components/VersionListTable/VersionListTable'
|
||||
import ArtifactActions from '@ar/pages/artifact-details/components/ArtifactActions/ArtifactActions'
|
||||
import ArtifactTreeNode from '@ar/pages/artifact-details/components/ArtifactTreeNode/ArtifactTreeNode'
|
||||
import ArtifactTreeNodeDetailsContent from '@ar/pages/artifact-details/components/ArtifactTreeNode/ArtifactTreeNodeDetailsContent'
|
||||
import {
|
||||
type ArtifactActionProps,
|
||||
type VersionActionProps,
|
||||
type ArtifactTreeNodeViewProps,
|
||||
type VersionDetailsHeaderProps,
|
||||
type VersionDetailsTabProps,
|
||||
type VersionListTableProps,
|
||||
VersionStep
|
||||
VersionStep,
|
||||
type VersionTreeNodeViewProps
|
||||
} from '@ar/frameworks/Version/Version'
|
||||
import { VersionDetailsTab } from '../components/VersionDetailsTabs/constants'
|
||||
|
||||
import HelmVersionOverviewContent from './HelmVersionOverviewContent'
|
||||
import HelmArtifactDetailsContent from './HelmArtifactDetailsContent'
|
||||
import VersionActions from '../components/VersionActions/VersionActions'
|
||||
import VersionTreeNode from '../components/VersionTreeNode/VersionTreeNode'
|
||||
import { VersionDetailsTab } from '../components/VersionDetailsTabs/constants'
|
||||
import HelmVersionOSSContent from './HelmVersionOSSContent/HelmVersionOSSContent'
|
||||
import VersionDetailsTabs from '../components/VersionDetailsTabs/VersionDetailsTabs'
|
||||
import VersionDetailsHeaderContent from '../components/VersionDetailsHeaderContent/VersionDetailsHeaderContent'
|
||||
import { VersionAction } from '../components/VersionActions/types'
|
||||
|
||||
@ -105,4 +112,20 @@ export class HelmVersionType extends VersionStep<ArtifactVersionSummary> {
|
||||
renderArtifactRowSubComponent(): JSX.Element {
|
||||
return <></>
|
||||
}
|
||||
|
||||
renderArtifactTreeNodeView(props: ArtifactTreeNodeViewProps): JSX.Element {
|
||||
return <ArtifactTreeNode {...props} icon="store-artifact-bundle" />
|
||||
}
|
||||
|
||||
renderArtifactTreeNodeDetails(): JSX.Element {
|
||||
return <ArtifactTreeNodeDetailsContent />
|
||||
}
|
||||
|
||||
renderVersionTreeNodeView(props: VersionTreeNodeViewProps): JSX.Element {
|
||||
return <VersionTreeNode {...props} icon="container" />
|
||||
}
|
||||
|
||||
renderVersionTreeNodeDetails(): JSX.Element {
|
||||
return <VersionDetailsTabs />
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,8 @@ import type { ArtifactVersionSummary } from '@harnessio/react-har-service-client
|
||||
import { String } from '@ar/frameworks/strings'
|
||||
import { PageType, RepositoryPackageType } from '@ar/common/types'
|
||||
import { VersionListColumnEnum } from '@ar/pages/version-list/components/VersionListTable/types'
|
||||
import ArtifactTreeNode from '@ar/pages/artifact-details/components/ArtifactTreeNode/ArtifactTreeNode'
|
||||
import ArtifactTreeNodeDetailsContent from '@ar/pages/artifact-details/components/ArtifactTreeNode/ArtifactTreeNodeDetailsContent'
|
||||
import VersionListTable, {
|
||||
type CommonVersionListTableProps
|
||||
} from '@ar/pages/version-list/components/VersionListTable/VersionListTable'
|
||||
@ -27,17 +29,21 @@ import {
|
||||
type ArtifactActionProps,
|
||||
ArtifactRowSubComponentProps,
|
||||
type VersionActionProps,
|
||||
type ArtifactTreeNodeViewProps,
|
||||
type VersionDetailsHeaderProps,
|
||||
type VersionDetailsTabProps,
|
||||
type VersionListTableProps,
|
||||
VersionStep
|
||||
VersionStep,
|
||||
type VersionTreeNodeViewProps
|
||||
} from '@ar/frameworks/Version/Version'
|
||||
import ArtifactActions from '@ar/pages/artifact-details/components/ArtifactActions/ArtifactActions'
|
||||
|
||||
import OSSContentPage from './pages/oss-details/OSSContentPage'
|
||||
import VersionFilesProvider from '../context/VersionFilesProvider'
|
||||
import VersionTreeNode from '../components/VersionTreeNode/VersionTreeNode'
|
||||
import { VersionDetailsTab } from '../components/VersionDetailsTabs/constants'
|
||||
import MavenArtifactOverviewPage from './pages/overview/MavenArtifactOverviewPage'
|
||||
import VersionDetailsTabs from '../components/VersionDetailsTabs/VersionDetailsTabs'
|
||||
import MavenArtifactDetailsPage from './pages/artifact-details/MavenArtifactDetailsPage'
|
||||
import ArtifactFilesContent from '../components/ArtifactFileListTable/ArtifactFilesContent'
|
||||
import VersionDetailsHeaderContent from '../components/VersionDetailsHeaderContent/VersionDetailsHeaderContent'
|
||||
@ -115,4 +121,20 @@ export class MavenVersionType extends VersionStep<ArtifactVersionSummary> {
|
||||
</VersionFilesProvider>
|
||||
)
|
||||
}
|
||||
|
||||
renderArtifactTreeNodeView(props: ArtifactTreeNodeViewProps): JSX.Element {
|
||||
return <ArtifactTreeNode {...props} icon="store-artifact-bundle" />
|
||||
}
|
||||
|
||||
renderArtifactTreeNodeDetails(): JSX.Element {
|
||||
return <ArtifactTreeNodeDetailsContent />
|
||||
}
|
||||
|
||||
renderVersionTreeNodeView(props: VersionTreeNodeViewProps): JSX.Element {
|
||||
return <VersionTreeNode {...props} icon="container" />
|
||||
}
|
||||
|
||||
renderVersionTreeNodeDetails(): JSX.Element {
|
||||
return <VersionDetailsTabs />
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,8 @@ import { String } from '@ar/frameworks/strings'
|
||||
import { PageType, RepositoryPackageType } from '@ar/common/types'
|
||||
import { VersionListColumnEnum } from '@ar/pages/version-list/components/VersionListTable/types'
|
||||
import ArtifactActions from '@ar/pages/artifact-details/components/ArtifactActions/ArtifactActions'
|
||||
import ArtifactTreeNode from '@ar/pages/artifact-details/components/ArtifactTreeNode/ArtifactTreeNode'
|
||||
import ArtifactTreeNodeDetailsContent from '@ar/pages/artifact-details/components/ArtifactTreeNode/ArtifactTreeNodeDetailsContent'
|
||||
import VersionListTable, {
|
||||
type CommonVersionListTableProps
|
||||
} from '@ar/pages/version-list/components/VersionListTable/VersionListTable'
|
||||
@ -29,15 +31,19 @@ import {
|
||||
type ArtifactActionProps,
|
||||
ArtifactRowSubComponentProps,
|
||||
type VersionActionProps,
|
||||
type ArtifactTreeNodeViewProps,
|
||||
type VersionDetailsHeaderProps,
|
||||
type VersionDetailsTabProps,
|
||||
type VersionListTableProps,
|
||||
VersionStep
|
||||
VersionStep,
|
||||
type VersionTreeNodeViewProps
|
||||
} from '@ar/frameworks/Version/Version'
|
||||
|
||||
import VersionActions from '../components/VersionActions/VersionActions'
|
||||
import VersionTreeNode from '../components/VersionTreeNode/VersionTreeNode'
|
||||
import NpmVersionOverviewPage from './pages/overview/NpmVersionOverviewPage'
|
||||
import { VersionDetailsTab } from '../components/VersionDetailsTabs/constants'
|
||||
import VersionDetailsTabs from '../components/VersionDetailsTabs/VersionDetailsTabs'
|
||||
import NpmVersionArtifactDetailsPage from './pages/artifact-dertails/NpmVersionArtifactDetailsPage'
|
||||
import VersionDetailsHeaderContent from '../components/VersionDetailsHeaderContent/VersionDetailsHeaderContent'
|
||||
import VersionFilesProvider from '../context/VersionFilesProvider'
|
||||
@ -123,4 +129,20 @@ export class NpmVersionType extends VersionStep<ArtifactVersionSummary> {
|
||||
</VersionFilesProvider>
|
||||
)
|
||||
}
|
||||
|
||||
renderArtifactTreeNodeView(props: ArtifactTreeNodeViewProps): JSX.Element {
|
||||
return <ArtifactTreeNode {...props} icon="store-artifact-bundle" />
|
||||
}
|
||||
|
||||
renderArtifactTreeNodeDetails(): JSX.Element {
|
||||
return <ArtifactTreeNodeDetailsContent />
|
||||
}
|
||||
|
||||
renderVersionTreeNodeView(props: VersionTreeNodeViewProps): JSX.Element {
|
||||
return <VersionTreeNode {...props} icon="container" />
|
||||
}
|
||||
|
||||
renderVersionTreeNodeDetails(): JSX.Element {
|
||||
return <VersionDetailsTabs />
|
||||
}
|
||||
}
|
||||
|
@ -22,22 +22,28 @@ import { String } from '@ar/frameworks/strings'
|
||||
import { PageType, RepositoryPackageType } from '@ar/common/types'
|
||||
import { VersionListColumnEnum } from '@ar/pages/version-list/components/VersionListTable/types'
|
||||
import ArtifactActions from '@ar/pages/artifact-details/components/ArtifactActions/ArtifactActions'
|
||||
import ArtifactTreeNode from '@ar/pages/artifact-details/components/ArtifactTreeNode/ArtifactTreeNode'
|
||||
import ArtifactTreeNodeDetailsContent from '@ar/pages/artifact-details/components/ArtifactTreeNode/ArtifactTreeNodeDetailsContent'
|
||||
import VersionListTable, {
|
||||
type CommonVersionListTableProps
|
||||
} from '@ar/pages/version-list/components/VersionListTable/VersionListTable'
|
||||
import {
|
||||
type ArtifactActionProps,
|
||||
ArtifactRowSubComponentProps,
|
||||
type ArtifactRowSubComponentProps,
|
||||
type ArtifactTreeNodeViewProps,
|
||||
type VersionActionProps,
|
||||
type VersionDetailsHeaderProps,
|
||||
type VersionDetailsTabProps,
|
||||
type VersionListTableProps,
|
||||
VersionStep
|
||||
VersionStep,
|
||||
type VersionTreeNodeViewProps
|
||||
} from '@ar/frameworks/Version/Version'
|
||||
|
||||
import VersionActions from '../components/VersionActions/VersionActions'
|
||||
import NuGetVersionOverviewPage from './pages/overview/NuGetVersionOverviewPage'
|
||||
import VersionTreeNode from '../components/VersionTreeNode/VersionTreeNode'
|
||||
import { VersionDetailsTab } from '../components/VersionDetailsTabs/constants'
|
||||
import NuGetVersionOverviewPage from './pages/overview/NuGetVersionOverviewPage'
|
||||
import VersionDetailsTabs from '../components/VersionDetailsTabs/VersionDetailsTabs'
|
||||
import NuGetVersionArtifactDetailsPage from './pages/artifact-dertails/NuGetVersionArtifactDetailsPage'
|
||||
import VersionDetailsHeaderContent from '../components/VersionDetailsHeaderContent/VersionDetailsHeaderContent'
|
||||
import VersionFilesProvider from '../context/VersionFilesProvider'
|
||||
@ -123,4 +129,20 @@ export class NuGetVersionType extends VersionStep<ArtifactVersionSummary> {
|
||||
</VersionFilesProvider>
|
||||
)
|
||||
}
|
||||
|
||||
renderArtifactTreeNodeView(props: ArtifactTreeNodeViewProps): JSX.Element {
|
||||
return <ArtifactTreeNode {...props} icon="store-artifact-bundle" />
|
||||
}
|
||||
|
||||
renderArtifactTreeNodeDetails(): JSX.Element {
|
||||
return <ArtifactTreeNodeDetailsContent />
|
||||
}
|
||||
|
||||
renderVersionTreeNodeView(props: VersionTreeNodeViewProps): JSX.Element {
|
||||
return <VersionTreeNode {...props} icon="container" />
|
||||
}
|
||||
|
||||
renderVersionTreeNodeDetails(): JSX.Element {
|
||||
return <VersionDetailsTabs />
|
||||
}
|
||||
}
|
||||
|
@ -22,22 +22,28 @@ import { String } from '@ar/frameworks/strings'
|
||||
import { PageType, RepositoryPackageType } from '@ar/common/types'
|
||||
import { VersionListColumnEnum } from '@ar/pages/version-list/components/VersionListTable/types'
|
||||
import ArtifactActions from '@ar/pages/artifact-details/components/ArtifactActions/ArtifactActions'
|
||||
import ArtifactTreeNode from '@ar/pages/artifact-details/components/ArtifactTreeNode/ArtifactTreeNode'
|
||||
import ArtifactTreeNodeDetailsContent from '@ar/pages/artifact-details/components/ArtifactTreeNode/ArtifactTreeNodeDetailsContent'
|
||||
import VersionListTable, {
|
||||
type CommonVersionListTableProps
|
||||
} from '@ar/pages/version-list/components/VersionListTable/VersionListTable'
|
||||
import {
|
||||
type ArtifactActionProps,
|
||||
ArtifactRowSubComponentProps,
|
||||
type ArtifactRowSubComponentProps,
|
||||
type ArtifactTreeNodeViewProps,
|
||||
type VersionActionProps,
|
||||
type VersionDetailsHeaderProps,
|
||||
type VersionDetailsTabProps,
|
||||
type VersionListTableProps,
|
||||
VersionStep
|
||||
VersionStep,
|
||||
type VersionTreeNodeViewProps
|
||||
} from '@ar/frameworks/Version/Version'
|
||||
|
||||
import VersionActions from '../components/VersionActions/VersionActions'
|
||||
import VersionTreeNode from '../components/VersionTreeNode/VersionTreeNode'
|
||||
import { VersionDetailsTab } from '../components/VersionDetailsTabs/constants'
|
||||
import PythonVersionOverviewPage from './pages/overview/PythonVersionOverviewPage'
|
||||
import VersionDetailsTabs from '../components/VersionDetailsTabs/VersionDetailsTabs'
|
||||
import PythonVersionArtifactDetailsPage from './pages/artifact-dertails/PythonVersionArtifactDetailsPage'
|
||||
import VersionDetailsHeaderContent from '../components/VersionDetailsHeaderContent/VersionDetailsHeaderContent'
|
||||
import VersionFilesProvider from '../context/VersionFilesProvider'
|
||||
@ -124,4 +130,20 @@ export class PythonVersionType extends VersionStep<ArtifactVersionSummary> {
|
||||
</VersionFilesProvider>
|
||||
)
|
||||
}
|
||||
|
||||
renderArtifactTreeNodeView(props: ArtifactTreeNodeViewProps): JSX.Element {
|
||||
return <ArtifactTreeNode {...props} icon="store-artifact-bundle" />
|
||||
}
|
||||
|
||||
renderArtifactTreeNodeDetails(): JSX.Element {
|
||||
return <ArtifactTreeNodeDetailsContent />
|
||||
}
|
||||
|
||||
renderVersionTreeNodeView(props: VersionTreeNodeViewProps): JSX.Element {
|
||||
return <VersionTreeNode {...props} icon="container" />
|
||||
}
|
||||
|
||||
renderVersionTreeNodeDetails(): JSX.Element {
|
||||
return <VersionDetailsTabs />
|
||||
}
|
||||
}
|
||||
|
@ -22,17 +22,21 @@ import { String } from '@ar/frameworks/strings'
|
||||
import { PageType, RepositoryPackageType } from '@ar/common/types'
|
||||
import { VersionListColumnEnum } from '@ar/pages/version-list/components/VersionListTable/types'
|
||||
import ArtifactActions from '@ar/pages/artifact-details/components/ArtifactActions/ArtifactActions'
|
||||
import ArtifactTreeNode from '@ar/pages/artifact-details/components/ArtifactTreeNode/ArtifactTreeNode'
|
||||
import ArtifactTreeNodeDetailsContent from '@ar/pages/artifact-details/components/ArtifactTreeNode/ArtifactTreeNodeDetailsContent'
|
||||
import VersionListTable, {
|
||||
type CommonVersionListTableProps
|
||||
} from '@ar/pages/version-list/components/VersionListTable/VersionListTable'
|
||||
import {
|
||||
type ArtifactActionProps,
|
||||
ArtifactRowSubComponentProps,
|
||||
type ArtifactRowSubComponentProps,
|
||||
type ArtifactTreeNodeViewProps,
|
||||
type VersionActionProps,
|
||||
type VersionDetailsHeaderProps,
|
||||
type VersionDetailsTabProps,
|
||||
type VersionListTableProps,
|
||||
VersionStep
|
||||
VersionStep,
|
||||
VersionTreeNodeViewProps
|
||||
} from '@ar/frameworks/Version/Version'
|
||||
|
||||
import VersionFilesProvider from '../context/VersionFilesProvider'
|
||||
@ -44,6 +48,8 @@ import { VersionDetailsTab } from '../components/VersionDetailsTabs/constants'
|
||||
import ArtifactFilesContent from '../components/ArtifactFileListTable/ArtifactFilesContent'
|
||||
import RPMVersionArtifactDetailsPage from './pages/artifact-dertails/RPMVersionArtifactDetailsPage'
|
||||
import VersionDetailsHeaderContent from '../components/VersionDetailsHeaderContent/VersionDetailsHeaderContent'
|
||||
import VersionTreeNode from '../components/VersionTreeNode/VersionTreeNode'
|
||||
import VersionDetailsTabs from '../components/VersionDetailsTabs/VersionDetailsTabs'
|
||||
|
||||
export class RPMVersionType extends VersionStep<ArtifactVersionSummary> {
|
||||
protected packageType = RepositoryPackageType.RPM
|
||||
@ -133,4 +139,20 @@ export class RPMVersionType extends VersionStep<ArtifactVersionSummary> {
|
||||
</VersionFilesProvider>
|
||||
)
|
||||
}
|
||||
|
||||
renderArtifactTreeNodeView(props: ArtifactTreeNodeViewProps): JSX.Element {
|
||||
return <ArtifactTreeNode {...props} icon="store-artifact-bundle" />
|
||||
}
|
||||
|
||||
renderArtifactTreeNodeDetails(): JSX.Element {
|
||||
return <ArtifactTreeNodeDetailsContent />
|
||||
}
|
||||
|
||||
renderVersionTreeNodeView(props: VersionTreeNodeViewProps): JSX.Element {
|
||||
return <VersionTreeNode {...props} icon="container" />
|
||||
}
|
||||
|
||||
renderVersionTreeNodeDetails(): JSX.Element {
|
||||
return <VersionDetailsTabs />
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,6 @@ import {
|
||||
} from '@ar/routes/RouteDestinations'
|
||||
|
||||
import { VersionDetailsTab, VersionDetailsTabList } from './constants'
|
||||
import type { DockerVersionDetailsQueryParams } from '../../DockerVersion/types'
|
||||
import css from './VersionDetailsTab.module.scss'
|
||||
|
||||
export default function VersionDetailsTabs(): JSX.Element {
|
||||
@ -49,15 +48,18 @@ export default function VersionDetailsTabs(): JSX.Element {
|
||||
const history = useHistory()
|
||||
const { getString } = useStrings()
|
||||
const routeDefinitions = useRoutes(true)
|
||||
const { parent } = useAppStore()
|
||||
const { data } = useContext(VersionProviderContext)
|
||||
const pathParams = useDecodedParams<VersionDetailsPathParams>()
|
||||
const { digest } = useQueryParams<DockerVersionDetailsQueryParams>()
|
||||
const queryParams = useQueryParams<Record<string, string>>()
|
||||
const { orgIdentifier, projectIdentifier } = scope
|
||||
|
||||
const tabList = useMemo(() => {
|
||||
const versionType = versionFactory?.getVersionType(data?.packageType)
|
||||
if (!versionType) return []
|
||||
return VersionDetailsTabList.filter(each => versionType.getAllowedVersionDetailsTab().includes(each.value))
|
||||
return VersionDetailsTabList.filter(each => !each.parent || each.parent === parent).filter(each =>
|
||||
versionType.getAllowedVersionDetailsTab().includes(each.value)
|
||||
)
|
||||
}, [data])
|
||||
|
||||
const handleTabChange = useCallback(
|
||||
@ -66,44 +68,50 @@ export default function VersionDetailsTabs(): JSX.Element {
|
||||
let newRoute
|
||||
switch (nextTab) {
|
||||
case VersionDetailsTab.SUPPLY_CHAIN:
|
||||
newRoute = routes.toARVersionDetailsTab({
|
||||
versionIdentifier: pathParams.versionIdentifier,
|
||||
artifactIdentifier: pathParams.artifactIdentifier,
|
||||
repositoryIdentifier: pathParams.repositoryIdentifier,
|
||||
versionTab: nextTab,
|
||||
sourceId: data?.sscaArtifactSourceId,
|
||||
artifactId: data?.sscaArtifactId,
|
||||
orgIdentifier: !orgIdentifier ? DEFAULT_ORG : undefined,
|
||||
projectIdentifier: !projectIdentifier ? DEFAULT_PROJECT : undefined
|
||||
})
|
||||
newRoute = routes.toARVersionDetailsTab(
|
||||
{
|
||||
versionIdentifier: pathParams.versionIdentifier,
|
||||
artifactIdentifier: pathParams.artifactIdentifier,
|
||||
repositoryIdentifier: pathParams.repositoryIdentifier,
|
||||
versionTab: nextTab,
|
||||
sourceId: data?.sscaArtifactSourceId,
|
||||
artifactId: data?.sscaArtifactId,
|
||||
orgIdentifier: !orgIdentifier ? DEFAULT_ORG : undefined,
|
||||
projectIdentifier: !projectIdentifier ? DEFAULT_PROJECT : undefined
|
||||
},
|
||||
{ queryParams }
|
||||
)
|
||||
break
|
||||
case VersionDetailsTab.SECURITY_TESTS:
|
||||
newRoute = routes.toARVersionDetailsTab({
|
||||
versionIdentifier: pathParams.versionIdentifier,
|
||||
artifactIdentifier: pathParams.artifactIdentifier,
|
||||
repositoryIdentifier: pathParams.repositoryIdentifier,
|
||||
versionTab: nextTab,
|
||||
executionIdentifier: data?.stoExecutionId,
|
||||
pipelineIdentifier: data?.stoPipelineId,
|
||||
orgIdentifier: !orgIdentifier ? DEFAULT_ORG : undefined,
|
||||
projectIdentifier: !projectIdentifier ? DEFAULT_PROJECT : undefined
|
||||
})
|
||||
newRoute = routes.toARVersionDetailsTab(
|
||||
{
|
||||
versionIdentifier: pathParams.versionIdentifier,
|
||||
artifactIdentifier: pathParams.artifactIdentifier,
|
||||
repositoryIdentifier: pathParams.repositoryIdentifier,
|
||||
versionTab: nextTab,
|
||||
executionIdentifier: data?.stoExecutionId,
|
||||
pipelineIdentifier: data?.stoPipelineId,
|
||||
orgIdentifier: !orgIdentifier ? DEFAULT_ORG : undefined,
|
||||
projectIdentifier: !projectIdentifier ? DEFAULT_PROJECT : undefined
|
||||
},
|
||||
{ queryParams }
|
||||
)
|
||||
break
|
||||
default:
|
||||
newRoute = routes.toARVersionDetailsTab({
|
||||
versionIdentifier: pathParams.versionIdentifier,
|
||||
artifactIdentifier: pathParams.artifactIdentifier,
|
||||
repositoryIdentifier: pathParams.repositoryIdentifier,
|
||||
versionTab: nextTab
|
||||
})
|
||||
newRoute = routes.toARVersionDetailsTab(
|
||||
{
|
||||
versionIdentifier: pathParams.versionIdentifier,
|
||||
artifactIdentifier: pathParams.artifactIdentifier,
|
||||
repositoryIdentifier: pathParams.repositoryIdentifier,
|
||||
versionTab: nextTab
|
||||
},
|
||||
{ queryParams }
|
||||
)
|
||||
break
|
||||
}
|
||||
if (digest) {
|
||||
newRoute = `${newRoute}?digest=${digest}`
|
||||
}
|
||||
history.push(newRoute)
|
||||
},
|
||||
[digest]
|
||||
[queryParams]
|
||||
)
|
||||
|
||||
if (!data) return <></>
|
||||
|
@ -14,6 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Parent } from '@ar/common/types'
|
||||
import type { StringsMap } from '@ar/frameworks/strings'
|
||||
|
||||
export enum VersionDetailsTab {
|
||||
@ -30,6 +31,7 @@ interface VersionDetailsTabListItem {
|
||||
label: keyof StringsMap
|
||||
value: VersionDetailsTab
|
||||
disabled?: boolean
|
||||
parent?: Parent
|
||||
}
|
||||
|
||||
export const VersionDetailsTabList: VersionDetailsTabListItem[] = [
|
||||
@ -43,19 +45,23 @@ export const VersionDetailsTabList: VersionDetailsTabListItem[] = [
|
||||
},
|
||||
{
|
||||
label: 'versionDetails.tabs.supplyChain',
|
||||
value: VersionDetailsTab.SUPPLY_CHAIN
|
||||
value: VersionDetailsTab.SUPPLY_CHAIN,
|
||||
parent: Parent.Enterprise
|
||||
},
|
||||
{
|
||||
label: 'versionDetails.tabs.securityTests',
|
||||
value: VersionDetailsTab.SECURITY_TESTS
|
||||
value: VersionDetailsTab.SECURITY_TESTS,
|
||||
parent: Parent.Enterprise
|
||||
},
|
||||
{
|
||||
label: 'versionDetails.tabs.deployments',
|
||||
value: VersionDetailsTab.DEPLOYMENTS
|
||||
value: VersionDetailsTab.DEPLOYMENTS,
|
||||
parent: Parent.Enterprise
|
||||
},
|
||||
{
|
||||
label: 'versionDetails.tabs.code',
|
||||
value: VersionDetailsTab.CODE,
|
||||
disabled: true
|
||||
disabled: true,
|
||||
parent: Parent.Enterprise
|
||||
}
|
||||
]
|
||||
|
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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 React, { PropsWithChildren, useContext } from 'react'
|
||||
import { omit } from 'lodash-es'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
import type { IconName } from '@harnessio/icons'
|
||||
import type {
|
||||
ArtifactVersionMetadata,
|
||||
RegistryArtifactMetadata,
|
||||
RegistryMetadata
|
||||
} from '@harnessio/react-har-service-client'
|
||||
|
||||
import { useParentHooks, useRoutes } from '@ar/hooks'
|
||||
import TreeNode, { NodeTypeEnum } from '@ar/components/TreeView/TreeNode'
|
||||
import TreeNodeContent from '@ar/components/TreeView/TreeNodeContent'
|
||||
import { PageType, type RepositoryPackageType } from '@ar/common/types'
|
||||
import { TreeViewContext } from '@ar/components/TreeView/TreeViewContext'
|
||||
import VersionActionsWidget from '@ar/frameworks/Version/VersionActionsWidget'
|
||||
import type { VersionTreeNodeViewProps } from '@ar/frameworks/Version/Version'
|
||||
import { VersionDetailsTab } from '../VersionDetailsTabs/constants'
|
||||
|
||||
interface IVersionTreeNode extends VersionTreeNodeViewProps {
|
||||
icon: IconName
|
||||
iconSize?: number
|
||||
level?: number
|
||||
nodeType?: NodeTypeEnum
|
||||
}
|
||||
|
||||
export default function VersionTreeNode(props: PropsWithChildren<IVersionTreeNode>) {
|
||||
const {
|
||||
data,
|
||||
icon,
|
||||
iconSize = 24,
|
||||
level = 2,
|
||||
nodeType = NodeTypeEnum.File,
|
||||
artifactIdentifier,
|
||||
isLastChild,
|
||||
parentNodeLevels
|
||||
} = props
|
||||
const { setActivePath, activePath, compact } = useContext(TreeViewContext)
|
||||
const routes = useRoutes()
|
||||
const history = useHistory()
|
||||
const { useQueryParams } = useParentHooks()
|
||||
const queryParams = useQueryParams<Record<string, string>>()
|
||||
const path = `${data.registryIdentifier}/${artifactIdentifier}/${data.name}`
|
||||
return (
|
||||
<TreeNode<RegistryMetadata | RegistryArtifactMetadata | ArtifactVersionMetadata>
|
||||
key={path}
|
||||
id={path}
|
||||
level={level}
|
||||
nodeType={nodeType}
|
||||
compact={compact}
|
||||
isOpen={activePath.includes(path)}
|
||||
isActive={activePath === path}
|
||||
isLastChild={isLastChild}
|
||||
parentNodeLevels={parentNodeLevels}
|
||||
onClick={() => {
|
||||
setActivePath(path)
|
||||
history.push(
|
||||
routes.toARVersionDetailsTab(
|
||||
{
|
||||
repositoryIdentifier: data.registryIdentifier,
|
||||
artifactIdentifier: artifactIdentifier,
|
||||
versionIdentifier: data.name,
|
||||
versionTab: VersionDetailsTab.OVERVIEW
|
||||
},
|
||||
{ queryParams: omit(queryParams, 'digest') }
|
||||
)
|
||||
)
|
||||
}}
|
||||
heading={
|
||||
<TreeNodeContent
|
||||
icon={icon}
|
||||
iconSize={iconSize}
|
||||
label={data.name}
|
||||
size={data.size}
|
||||
downloads={data.downloadsCount}
|
||||
compact={compact}
|
||||
/>
|
||||
}
|
||||
actionElement={
|
||||
<VersionActionsWidget
|
||||
pageType={PageType.Table}
|
||||
data={data}
|
||||
repoKey={data.registryIdentifier}
|
||||
artifactKey={artifactIdentifier}
|
||||
versionKey={data.name}
|
||||
packageType={data.packageType as RepositoryPackageType}
|
||||
/>
|
||||
}>
|
||||
{nodeType === NodeTypeEnum.Folder && props.children}
|
||||
</TreeNode>
|
||||
)
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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 React, { useContext } from 'react'
|
||||
|
||||
import type { RepositoryPackageType } from '@ar/common/types'
|
||||
import VersionTreeNodeDetailsWidget from '@ar/frameworks/Version/VersionTreeNodeDetailsWidget'
|
||||
|
||||
import { VersionProviderContext } from '../../context/VersionProvider'
|
||||
|
||||
export default function VersionTreeNodeDetails() {
|
||||
const { data } = useContext(VersionProviderContext)
|
||||
if (!data) return <></>
|
||||
const { packageType } = data
|
||||
return <VersionTreeNodeDetailsWidget packageType={packageType as RepositoryPackageType} data={data} />
|
||||
}
|
@ -19,7 +19,8 @@ import { PageError, PageSpinner } from '@harnessio/uicore'
|
||||
import { ArtifactVersionSummary, useGetArtifactVersionSummaryQuery } from '@harnessio/react-har-service-client'
|
||||
|
||||
import { encodeRef } from '@ar/hooks/useGetSpaceRef'
|
||||
import { useGetSpaceRef, useParentHooks } from '@ar/hooks'
|
||||
import type { VersionDetailsPathParams } from '@ar/routes/types'
|
||||
import { useDecodedParams, useGetSpaceRef, useParentHooks } from '@ar/hooks'
|
||||
|
||||
import type { DockerVersionDetailsQueryParams } from '../DockerVersion/types'
|
||||
|
||||
@ -32,9 +33,9 @@ interface VersionProviderProps {
|
||||
export const VersionProviderContext = createContext<VersionProviderProps>({} as VersionProviderProps)
|
||||
|
||||
interface VersionProviderSpcs {
|
||||
repoKey: string
|
||||
artifactKey: string
|
||||
versionKey: string
|
||||
repoKey?: string
|
||||
artifactKey?: string
|
||||
versionKey?: string
|
||||
}
|
||||
|
||||
const VersionProvider: FC<PropsWithChildren<VersionProviderSpcs>> = ({
|
||||
@ -43,10 +44,11 @@ const VersionProvider: FC<PropsWithChildren<VersionProviderSpcs>> = ({
|
||||
artifactKey,
|
||||
versionKey
|
||||
}): JSX.Element => {
|
||||
const spaceRef = useGetSpaceRef(repoKey)
|
||||
const { useQueryParams } = useParentHooks()
|
||||
const { digest } = useQueryParams<DockerVersionDetailsQueryParams>()
|
||||
const { repositoryIdentifier, artifactIdentifier, versionIdentifier } = useDecodedParams<VersionDetailsPathParams>()
|
||||
|
||||
const spaceRef = useGetSpaceRef(repoKey ?? repositoryIdentifier)
|
||||
const {
|
||||
data,
|
||||
isFetching: loading,
|
||||
@ -54,8 +56,8 @@ const VersionProvider: FC<PropsWithChildren<VersionProviderSpcs>> = ({
|
||||
refetch
|
||||
} = useGetArtifactVersionSummaryQuery({
|
||||
registry_ref: spaceRef,
|
||||
artifact: encodeRef(artifactKey),
|
||||
version: versionKey,
|
||||
artifact: encodeRef(artifactKey ?? artifactIdentifier),
|
||||
version: versionKey ?? versionIdentifier,
|
||||
queryParams: {
|
||||
digest
|
||||
}
|
||||
|
@ -50,6 +50,8 @@ overview:
|
||||
downloads: '{{ $.repositoryList.table.columns.downloads }}'
|
||||
uploadedBy: Uploaded At
|
||||
createdAndLastModifiedAt: Created | Last modified
|
||||
createdAt: Created At
|
||||
modifiedAt: Modified At
|
||||
description: Description
|
||||
pullCommand: Pull command
|
||||
repository: Repository
|
||||
|
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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 React, { useMemo } from 'react'
|
||||
import { useInfiniteQuery } from '@tanstack/react-query'
|
||||
import {
|
||||
type Error,
|
||||
getAllArtifactVersions,
|
||||
type GetAllArtifactVersionsOkResponse,
|
||||
type RegistryArtifactMetadata,
|
||||
type RegistryMetadata
|
||||
} from '@harnessio/react-har-service-client'
|
||||
|
||||
import { DEFAULT_PAGE_SIZE } from '@ar/constants'
|
||||
import { useStrings } from '@ar/frameworks/strings'
|
||||
import { encodeRef } from '@ar/hooks/useGetSpaceRef'
|
||||
import TreeBody from '@ar/components/TreeView/TreeBody'
|
||||
import { useGetSpaceRef, useParentHooks } from '@ar/hooks'
|
||||
import type { RepositoryPackageType } from '@ar/common/types'
|
||||
import TreeNodeList from '@ar/components/TreeView/TreeNodeList'
|
||||
import type { NodeSpec } from '@ar/components/TreeView/TreeViewContext'
|
||||
import TreeLoadMoreNode from '@ar/components/TreeView/TreeLoadMoreNode'
|
||||
import TreeNodeSearchInput from '@ar/components/TreeView/TreeNodeSearchInput'
|
||||
import VersionTreeNodeViewWidget from '@ar/frameworks/Version/VersionTreeNodeViewWidget'
|
||||
import { useVersionListQueryParamOptions, VersionListPageQueryParams } from '../../utils'
|
||||
|
||||
interface VersiontListTreeViewProps {
|
||||
registryIdentifier: string
|
||||
artifactIdentifier: string
|
||||
parentNodeLevels: Array<NodeSpec<RegistryMetadata | RegistryArtifactMetadata>>
|
||||
}
|
||||
|
||||
export default function VersionListTreeView(props: VersiontListTreeViewProps) {
|
||||
const { registryIdentifier, artifactIdentifier, parentNodeLevels } = props
|
||||
|
||||
const { useQueryParams, useUpdateQueryParams } = useParentHooks()
|
||||
const { updateQueryParams } = useUpdateQueryParams<Partial<VersionListPageQueryParams>>()
|
||||
const queryParams = useQueryParams<VersionListPageQueryParams>(useVersionListQueryParamOptions())
|
||||
const { versionSearchTerm } = queryParams
|
||||
|
||||
const { getString } = useStrings()
|
||||
const registryRef = useGetSpaceRef(registryIdentifier)
|
||||
|
||||
const { data, isLoading, error, hasNextPage, fetchNextPage, refetch, isFetchingNextPage } = useInfiniteQuery<
|
||||
GetAllArtifactVersionsOkResponse,
|
||||
Error,
|
||||
GetAllArtifactVersionsOkResponse,
|
||||
Array<string | undefined>
|
||||
>({
|
||||
queryKey: ['versionList', registryIdentifier, artifactIdentifier, versionSearchTerm],
|
||||
queryFn: ({ pageParam = 0 }) =>
|
||||
getAllArtifactVersions({
|
||||
registry_ref: registryRef,
|
||||
artifact: encodeRef(artifactIdentifier),
|
||||
queryParams: {
|
||||
page: pageParam,
|
||||
size: DEFAULT_PAGE_SIZE,
|
||||
search_term: versionSearchTerm
|
||||
},
|
||||
stringifyQueryParamsOptions: {
|
||||
arrayFormat: 'repeat'
|
||||
}
|
||||
}),
|
||||
getNextPageParam: lastPage => {
|
||||
const totalPages = lastPage.content.data.pageCount ?? 0
|
||||
const lastPageNumber = lastPage.content.data.pageIndex ?? -1
|
||||
return lastPageNumber < totalPages - 1 ? lastPageNumber + 1 : undefined
|
||||
}
|
||||
})
|
||||
|
||||
const { list: versionList, count: totalVersions } = useMemo(() => {
|
||||
const list = data?.pages.flatMap(page => page.content.data.artifactVersions ?? []) || []
|
||||
const count = data?.pages[0].content.data.itemCount || 0
|
||||
return { list, count }
|
||||
}, [data])
|
||||
|
||||
return (
|
||||
<TreeNodeList>
|
||||
{totalVersions > DEFAULT_PAGE_SIZE && (
|
||||
<TreeNodeSearchInput
|
||||
level={2}
|
||||
defaultValue={versionSearchTerm}
|
||||
onChange={val => {
|
||||
updateQueryParams({ versionSearchTerm: val })
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<TreeBody
|
||||
loading={isLoading}
|
||||
error={error?.message}
|
||||
retryOnError={refetch}
|
||||
isEmpty={!versionList.length}
|
||||
emptyDataMessage={getString('versionList.table.noVersionsTitle')}>
|
||||
{versionList.map((each, idx) => (
|
||||
<VersionTreeNodeViewWidget
|
||||
key={each.name}
|
||||
packageType={each.packageType as RepositoryPackageType}
|
||||
artifactIdentifier={artifactIdentifier}
|
||||
data={{
|
||||
...each,
|
||||
registryIdentifier
|
||||
}}
|
||||
parentNodeLevels={parentNodeLevels}
|
||||
isLastChild={idx === versionList.length - 1}
|
||||
/>
|
||||
))}
|
||||
{hasNextPage && <TreeLoadMoreNode level={2} onClick={() => fetchNextPage()} disabled={isFetchingNextPage} />}
|
||||
</TreeBody>
|
||||
</TreeNodeList>
|
||||
)
|
||||
}
|
@ -30,6 +30,7 @@ type GetVersionListQueryParams = {
|
||||
size: number
|
||||
sort: string[]
|
||||
searchTerm: string
|
||||
versionSearchTerm?: string
|
||||
isDeployedArtifacts: boolean
|
||||
packageTypes: RepositoryPackageType[]
|
||||
repositoryKey: string
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
import { defaultTo, isEmpty } from 'lodash-es'
|
||||
|
||||
import type {
|
||||
ArtifactDetailsPathParams,
|
||||
RedirectPageQueryParams,
|
||||
@ -25,19 +26,20 @@ import type {
|
||||
VersionDetailsPathParams,
|
||||
VersionDetailsTabPathParams
|
||||
} from './types'
|
||||
import { IRouteOptions, routeDefinitionWithMode } from './utils'
|
||||
|
||||
export interface ARRouteDefinitionsReturn {
|
||||
toAR: () => string
|
||||
toARRedirect: (params?: RedirectPageQueryParams) => string
|
||||
toARRepositories: () => string
|
||||
toARRepositoryDetails: (params: RepositoryDetailsPathParams) => string
|
||||
toARRepositoryDetailsTab: (params: RepositoryDetailsTabPathParams) => string
|
||||
toARArtifacts: () => string
|
||||
toARArtifactDetails: (params: ArtifactDetailsPathParams) => string
|
||||
toARVersionDetails: (params: VersionDetailsPathParams) => string
|
||||
toARVersionDetailsTab: (params: VersionDetailsTabPathParams) => string
|
||||
toARRepositoryWebhookDetails: (params: RepositoryWebhookDetailsPathParams) => string
|
||||
toARRepositoryWebhookDetailsTab: (params: RepositoryWebhookDetailsTabPathParams) => string
|
||||
toARRedirect: (params?: RedirectPageQueryParams, options?: IRouteOptions) => string
|
||||
toARRepositories: (_?: unknown, options?: IRouteOptions) => string
|
||||
toARRepositoryDetails: (params: RepositoryDetailsPathParams, options?: IRouteOptions) => string
|
||||
toARRepositoryDetailsTab: (params: RepositoryDetailsTabPathParams, options?: IRouteOptions) => string
|
||||
toARArtifacts: (_?: unknown, options?: IRouteOptions) => string
|
||||
toARArtifactDetails: (params: ArtifactDetailsPathParams, options?: IRouteOptions) => string
|
||||
toARVersionDetails: (params: VersionDetailsPathParams, options?: IRouteOptions) => string
|
||||
toARVersionDetailsTab: (params: VersionDetailsTabPathParams, options?: IRouteOptions) => string
|
||||
toARRepositoryWebhookDetails: (params: RepositoryWebhookDetailsPathParams, options?: IRouteOptions) => string
|
||||
toARRepositoryWebhookDetailsTab: (params: RepositoryWebhookDetailsTabPathParams, options?: IRouteOptions) => string
|
||||
}
|
||||
|
||||
export const routeDefinitions: ARRouteDefinitionsReturn = {
|
||||
@ -55,14 +57,20 @@ export const routeDefinitions: ARRouteDefinitionsReturn = {
|
||||
}
|
||||
return '/redirect'
|
||||
},
|
||||
toARRepositories: () => '/registries',
|
||||
toARRepositoryDetails: params => `/registries/${params?.repositoryIdentifier}`,
|
||||
toARRepositoryDetailsTab: params => `/registries/${params?.repositoryIdentifier}/${params?.tab}`,
|
||||
toARArtifacts: () => '/artifacts',
|
||||
toARArtifactDetails: params => `/registries/${params?.repositoryIdentifier}/artifacts/${params?.artifactIdentifier}`,
|
||||
toARVersionDetails: params =>
|
||||
`/registries/${params?.repositoryIdentifier}/artifacts/${params?.artifactIdentifier}/versions/${params?.versionIdentifier}`,
|
||||
toARVersionDetailsTab: params => {
|
||||
toARRepositories: routeDefinitionWithMode(() => '/registries'),
|
||||
toARRepositoryDetails: routeDefinitionWithMode(params => `/registries/${params?.repositoryIdentifier}`),
|
||||
toARRepositoryDetailsTab: routeDefinitionWithMode(
|
||||
params => `/registries/${params?.repositoryIdentifier}/${params.tab}`
|
||||
),
|
||||
toARArtifacts: routeDefinitionWithMode(() => '/artifacts'),
|
||||
toARArtifactDetails: routeDefinitionWithMode(
|
||||
params => `/registries/${params?.repositoryIdentifier}/artifacts/${params?.artifactIdentifier}`
|
||||
),
|
||||
toARVersionDetails: routeDefinitionWithMode(
|
||||
params =>
|
||||
`/registries/${params?.repositoryIdentifier}/artifacts/${params?.artifactIdentifier}/versions/${params?.versionIdentifier}`
|
||||
),
|
||||
toARVersionDetailsTab: routeDefinitionWithMode(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}`
|
||||
@ -74,7 +82,7 @@ export const routeDefinitions: ARRouteDefinitionsReturn = {
|
||||
}
|
||||
route += `/${params.versionTab}`
|
||||
return route
|
||||
},
|
||||
}),
|
||||
toARRepositoryWebhookDetails: params =>
|
||||
`/registries/${params?.repositoryIdentifier}/webhooks/${params?.webhookIdentifier}`,
|
||||
toARRepositoryWebhookDetailsTab: params =>
|
||||
|
@ -18,8 +18,9 @@ import React from 'react'
|
||||
import { Redirect, Switch } from 'react-router-dom'
|
||||
|
||||
import { Parent } from '@ar/common/types'
|
||||
import { useAppStore, useRoutes } from '@ar/hooks'
|
||||
import { useAppStore, useGetRepositoryListViewType, useRoutes } from '@ar/hooks'
|
||||
import RedirectPage from '@ar/pages/redirect-page/RedirectPage'
|
||||
import { RepositoryListViewTypeEnum } from '@ar/contexts/AppStoreContext'
|
||||
import type { WebhookDetailsTab } from '@ar/pages/webhook-details/constants'
|
||||
import type { RepositoryDetailsTab } from '@ar/pages/repository-details/constants'
|
||||
|
||||
@ -34,6 +35,7 @@ import type {
|
||||
} from './types'
|
||||
|
||||
const RepositoryListPage = React.lazy(() => import('@ar/pages/repository-list/RepositoryListPage'))
|
||||
const RepositoryListTreeViewPage = React.lazy(() => import('@ar/pages/repository-list/RepositoryListTreeViewPage'))
|
||||
const RepositoryDetailsPage = React.lazy(() => import('@ar/pages/repository-details/RepositoryDetailsPage'))
|
||||
const ArtifactListPage = React.lazy(() => import('@ar/pages/artifact-list/ArtifactListPage'))
|
||||
const ArtifactDetailsPage = React.lazy(() => import('@ar/pages/artifact-details/ArtifactDetailsPage'))
|
||||
@ -51,7 +53,7 @@ export const repositoryDetailsTabPathProps: RepositoryDetailsTabPathParams = {
|
||||
tab: ':tab' as RepositoryDetailsTab
|
||||
}
|
||||
|
||||
const artifactDetailsPathProps: ArtifactDetailsPathParams = {
|
||||
export const artifactDetailsPathProps: ArtifactDetailsPathParams = {
|
||||
...repositoryDetailsPathProps,
|
||||
artifactIdentifier: ':artifactIdentifier'
|
||||
}
|
||||
@ -102,6 +104,9 @@ export const repositoryWebhookDetailsTabPathParams: RepositoryWebhookDetailsTabP
|
||||
const RouteDestinations = (): JSX.Element => {
|
||||
const routes = useRoutes(true)
|
||||
const { parent } = useAppStore()
|
||||
const repositoryListViewType = useGetRepositoryListViewType()
|
||||
const shouldUseSeperateVersionDetailsRoute =
|
||||
parent === Parent.Enterprise || repositoryListViewType === RepositoryListViewTypeEnum.DIRECTORY
|
||||
return (
|
||||
<Switch>
|
||||
<RouteProvider exact path={routes.toAR()}>
|
||||
@ -110,27 +115,38 @@ const RouteDestinations = (): JSX.Element => {
|
||||
<RouteProvider exact path={routes.toARRedirect()}>
|
||||
<RedirectPage />
|
||||
</RouteProvider>
|
||||
<RouteProvider exact path={routes.toARRepositories()}>
|
||||
<RepositoryListPage />
|
||||
</RouteProvider>
|
||||
<RouteProvider exact path={routes.toARArtifacts()}>
|
||||
<ArtifactListPage />
|
||||
</RouteProvider>
|
||||
{repositoryListViewType === RepositoryListViewTypeEnum.DIRECTORY && (
|
||||
<RouteProvider path={routes.toARRepositories()}>
|
||||
<RepositoryListTreeViewPage />
|
||||
</RouteProvider>
|
||||
)}
|
||||
{repositoryListViewType === RepositoryListViewTypeEnum.LIST && (
|
||||
<RouteProvider exact path={routes.toARRepositories()}>
|
||||
<RepositoryListPage />
|
||||
</RouteProvider>
|
||||
)}
|
||||
{/* IF Enterprise then will use different route for version details page
|
||||
* IF repositoryListViewType = DIRECTORY then will use different route for version details page
|
||||
* IF OSS then will use version details as sub route for artifact details page
|
||||
*/}
|
||||
<RouteProvider
|
||||
exact={parent === Parent.Enterprise}
|
||||
exact={shouldUseSeperateVersionDetailsRoute}
|
||||
path={routes.toARArtifactDetails({ ...artifactDetailsPathProps })}>
|
||||
<>
|
||||
<ArtifactDetailsPage />
|
||||
{parent === Parent.OSS && (
|
||||
<Switch>
|
||||
<RouteProvider exact path={routes.toARVersionDetails({ ...versionDetailsPathParams })}>
|
||||
<RouteProvider path={routes.toARVersionDetails({ ...versionDetailsPathParams })}>
|
||||
<OSSVersionDetailsPage />
|
||||
</RouteProvider>
|
||||
</Switch>
|
||||
)}
|
||||
</>
|
||||
</RouteProvider>
|
||||
{parent === Parent.Enterprise && (
|
||||
{shouldUseSeperateVersionDetailsRoute && (
|
||||
<RouteProvider path={routes.toARVersionDetails({ ...versionDetailsPathParams })}>
|
||||
<VersionDetailsPage />
|
||||
</RouteProvider>
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
import { defaultTo } from 'lodash-es'
|
||||
import QueryString from 'qs'
|
||||
|
||||
export function normalizePath(url: string): string {
|
||||
return url.replace(/\/{2,}/g, '/')
|
||||
@ -24,3 +25,19 @@ export const encodePathParams = (val?: string): string => {
|
||||
if (typeof val === 'string' && val.startsWith(':')) return val
|
||||
return encodeURIComponent(defaultTo(val, ''))
|
||||
}
|
||||
|
||||
export interface IRouteOptions {
|
||||
queryParams?: Record<string, string>
|
||||
}
|
||||
|
||||
export function routeDefinitionWithMode<T>(fn: (params: T) => string) {
|
||||
return (params: T, options?: IRouteOptions) => {
|
||||
const { queryParams } = options || {}
|
||||
let route = fn(params)
|
||||
if (queryParams) {
|
||||
const queryString = QueryString.stringify(queryParams, { encode: false })
|
||||
route = `${route}?${queryString}`
|
||||
}
|
||||
return route
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ prodCount: '{{count}} Prod'
|
||||
nonProdCount: '{{count}} Non-Prod'
|
||||
copy: Copy
|
||||
view: View
|
||||
loadMore: Load More
|
||||
noMatchingFilterData: No results found matching the filter criteria
|
||||
stepNotFound: Step not found
|
||||
tabNotFound: Tab not found
|
||||
@ -48,6 +49,7 @@ createdAt: Created At
|
||||
modifiedAt: Modified At
|
||||
plaintext: Plain Text
|
||||
encrypted: Encrypted
|
||||
details: Details
|
||||
tags:
|
||||
latest: LATEST
|
||||
latestVersion: LATEST VERSION
|
||||
|
@ -107,11 +107,13 @@ export interface StringsMap {
|
||||
'repositoryDetails.upstreamProxiesSelectList.selectedList.note.message': string
|
||||
'repositoryList.artifactRegistry.label': string
|
||||
'repositoryList.artifactRegistry.subLabel': string
|
||||
'repositoryList.compact': string
|
||||
'repositoryList.deleteModal.contentText': string
|
||||
'repositoryList.deleteModal.title': string
|
||||
'repositoryList.newRegistry': string
|
||||
'repositoryList.newRepository': string
|
||||
'repositoryList.pageHeading': string
|
||||
'repositoryList.registryCount': string
|
||||
'repositoryList.selectEnvironments': string
|
||||
'repositoryList.selectLabels': string
|
||||
'repositoryList.selectPackageTypes': string
|
||||
@ -219,11 +221,13 @@ export interface StringsMap {
|
||||
'versionDetails.overview.generalInformation.buildHost': string
|
||||
'versionDetails.overview.generalInformation.buildTime': string
|
||||
'versionDetails.overview.generalInformation.createdAndLastModifiedAt': string
|
||||
'versionDetails.overview.generalInformation.createdAt': string
|
||||
'versionDetails.overview.generalInformation.description': string
|
||||
'versionDetails.overview.generalInformation.digest': string
|
||||
'versionDetails.overview.generalInformation.downloads': string
|
||||
'versionDetails.overview.generalInformation.homepage': string
|
||||
'versionDetails.overview.generalInformation.license': string
|
||||
'versionDetails.overview.generalInformation.modifiedAt': string
|
||||
'versionDetails.overview.generalInformation.name': string
|
||||
'versionDetails.overview.generalInformation.packageType': string
|
||||
'versionDetails.overview.generalInformation.packager': string
|
||||
@ -342,6 +346,7 @@ export interface StringsMap {
|
||||
delete: string
|
||||
description: string
|
||||
descriptionPlaceholder: string
|
||||
details: string
|
||||
discard: string
|
||||
download: string
|
||||
encrypted: string
|
||||
@ -352,6 +357,7 @@ export interface StringsMap {
|
||||
harnessAI: string
|
||||
id: string
|
||||
lastUpdated: string
|
||||
loadMore: string
|
||||
loading: string
|
||||
modifiedAt: string
|
||||
moduleName: string
|
||||
|
@ -26,7 +26,7 @@ import type { FeatureFlags, Scope } from '@ar/MFEAppTypes'
|
||||
import { Parent } from '@ar/common/types'
|
||||
import { ModalProvider } from '@ar/__mocks__/hooks'
|
||||
import type { UseStringsReturn } from '@ar/frameworks/strings'
|
||||
import { AppStoreContext } from '@ar/contexts/AppStoreContext'
|
||||
import { AppStoreContext, RepositoryListViewTypeEnum } from '@ar/contexts/AppStoreContext'
|
||||
import ParentProvider from '@ar/contexts/ParentProvider'
|
||||
import type { ParentProviderProps } from '@ar/contexts/ParentProvider'
|
||||
import { StringsContextProvider } from '@ar/frameworks/strings/StringsContextProvider'
|
||||
@ -82,7 +82,9 @@ export default function ArTestWrapper(props: PropsWithChildren<TestWrapperProps>
|
||||
matchPath,
|
||||
scope,
|
||||
parent,
|
||||
updateAppStore: noop
|
||||
updateAppStore: noop,
|
||||
repositoryListViewType: RepositoryListViewTypeEnum.LIST,
|
||||
setRepositoryListViewType: noop
|
||||
}}>
|
||||
<StringsContextProvider initialStrings={stringsData} getString={getString}>
|
||||
<ParentProvider
|
||||
|
Loading…
x
Reference in New Issue
Block a user