feat: [AH-996]: API integration for NPM package type (#3632)

* feat: [AH-996]: API integration for NPM package type
* feat: [AH-996]: API integration for NPM package type
main
Shivanand Sonnad 2025-04-04 08:45:23 +00:00 committed by Harness
parent e7d7db57b4
commit f9c9766a1e
13 changed files with 124 additions and 188 deletions

View File

@ -20,7 +20,7 @@ import { defaultTo } from 'lodash-es'
import copy from 'clipboard-copy'
import { Link } from 'react-router-dom'
import type { TableExpandedToggleProps } from 'react-table'
import { Button, ButtonProps, ButtonVariation, Layout, Text } from '@harnessio/uicore'
import { Button, ButtonProps, ButtonVariation, Layout, Text, TextProps } from '@harnessio/uicore'
import type { IconName, IconProps } from '@harnessio/icons'
import { Color, FontVariation } from '@harnessio/design-system'
@ -151,14 +151,14 @@ export const CountCell = ({ value, icon, iconProps }: CountCellProps): JSX.Eleme
)
}
interface TextCellProps {
interface TextCellProps extends TextProps {
value: string | undefined
}
export const TextCell = ({ value }: TextCellProps): JSX.Element => {
export const TextCell = ({ value, ...rest }: TextCellProps): JSX.Element => {
const { getString } = useStrings()
return (
<Text color={Color.GREY_900} lineClamp={1}>
<Text color={Color.GREY_900} lineClamp={1} {...rest}>
{defaultTo(value, getString('na'))}
</Text>
)

View File

@ -21,7 +21,7 @@ import { useParentHooks } from '@ar/hooks'
import { useStrings } from '@ar/frameworks/strings'
import { ButtonTab, ButtonTabs } from '@ar/components/ButtonTabs/ButtonTabs'
import VersionFilesProvider from '@ar/pages/version-details/context/VersionFilesProvider'
import VersionDependencyListProvider from '@ar/pages/version-details/context/VersionDependencyListProvider'
import VersionOverviewProvider from '@ar/pages/version-details/context/VersionOverviewProvider'
import NpmVersionFilesContent from './NpmVersionFilesContent'
import NpmVersionReadmeContent from './NpmVersionReadmeContent'
@ -42,38 +42,36 @@ export default function NpmVersionArtifactDetailsPage() {
)
return (
<Layout.Vertical padding="large" spacing="large">
<ButtonTabs small bold selectedTabId={detailsTab} onChange={handleTabChange}>
<ButtonTab
id={NpmArtifactDetailsTabEnum.ReadMe}
icon="document"
iconProps={{ size: 12 }}
panel={<NpmVersionReadmeContent />}
title={getString('versionDetails.artifactDetails.tabs.readme')}
/>
<ButtonTab
id={NpmArtifactDetailsTabEnum.Files}
icon="document"
iconProps={{ size: 12 }}
panel={
<VersionFilesProvider>
<NpmVersionFilesContent />
</VersionFilesProvider>
}
title={getString('versionDetails.artifactDetails.tabs.files')}
/>
<ButtonTab
id={NpmArtifactDetailsTabEnum.Dependencies}
icon="layers"
iconProps={{ size: 12 }}
panel={
<VersionDependencyListProvider>
<NpmVersionDependencyContent />
</VersionDependencyListProvider>
}
title={getString('versionDetails.artifactDetails.tabs.dependencies')}
/>
</ButtonTabs>
</Layout.Vertical>
<VersionOverviewProvider>
<Layout.Vertical padding="large" spacing="large">
<ButtonTabs small bold selectedTabId={detailsTab} onChange={handleTabChange}>
<ButtonTab
id={NpmArtifactDetailsTabEnum.ReadMe}
icon="document"
iconProps={{ size: 12 }}
panel={<NpmVersionReadmeContent />}
title={getString('versionDetails.artifactDetails.tabs.readme')}
/>
<ButtonTab
id={NpmArtifactDetailsTabEnum.Files}
icon="document"
iconProps={{ size: 12 }}
panel={
<VersionFilesProvider>
<NpmVersionFilesContent />
</VersionFilesProvider>
}
title={getString('versionDetails.artifactDetails.tabs.files')}
/>
<ButtonTab
id={NpmArtifactDetailsTabEnum.Dependencies}
icon="layers"
iconProps={{ size: 12 }}
panel={<NpmVersionDependencyContent />}
title={getString('versionDetails.artifactDetails.tabs.dependencies')}
/>
</ButtonTabs>
</Layout.Vertical>
</VersionOverviewProvider>
)
}

View File

@ -14,22 +14,23 @@
* limitations under the License.
*/
import React, { useContext } from 'react'
import React from 'react'
import { DEFAULT_PAGE_INDEX } from '@ar/constants'
import { VersionDependencyListContext } from '@ar/pages/version-details/context/VersionDependencyListProvider'
import { useVersionOverview } from '@ar/pages/version-details/context/VersionOverviewProvider'
import type { IDependencyList } from '@ar/pages/version-details/components/ArtifactDependencyListTable/types'
import ArtifactDependencyListTable from '@ar/pages/version-details/components/ArtifactDependencyListTable/ArtifactDependencyListTable'
import type { NpmVersionDetailsConfig } from '../../types'
export default function NpmVersionDependencyContent() {
const { data, updateQueryParams, sort } = useContext(VersionDependencyListContext)
return (
<ArtifactDependencyListTable
data={data}
gotoPage={pageNumber => updateQueryParams({ page: pageNumber })}
setSortBy={sortArr => {
updateQueryParams({ sort: sortArr, page: DEFAULT_PAGE_INDEX })
}}
sortBy={sort}
/>
)
const { data } = useVersionOverview<NpmVersionDetailsConfig>()
const versionMetatdata = data.metadata?.versions?.[data.version]
const dependencies = versionMetatdata?.dependencies || {}
const dependencyList: IDependencyList = Object.entries(dependencies).map(([key, value]) => ({
name: key,
version: value as string
}))
return <ArtifactDependencyListTable data={dependencyList} />
}

View File

@ -16,13 +16,21 @@
import React from 'react'
import { Container } from '@harnessio/uicore'
import { useStrings } from '@ar/frameworks/strings'
import { useVersionOverview } from '@ar/pages/version-details/context/VersionOverviewProvider'
import ReadmeFileContent from '@ar/pages/version-details/components/ReadmeFileContent/ReadmeFileContent'
import { MOCK_README_CONTENT } from './mockData'
import type { NpmVersionDetailsConfig } from '../../types'
export default function NpmVersionReadmeContent() {
const { data } = useVersionOverview<NpmVersionDetailsConfig>()
const versionMetatdata = data.metadata?.versions?.[data.version]
const { getString } = useStrings()
return (
<Container>
<ReadmeFileContent source={MOCK_README_CONTENT} />
<ReadmeFileContent source={versionMetatdata?.readme || getString('noReadme')} />
</Container>
)
}

View File

@ -14,19 +14,19 @@
* limitations under the License.
*/
import React, { useContext } from 'react'
import React from 'react'
import { defaultTo } from 'lodash-es'
import { FontVariation } from '@harnessio/design-system'
import { Card, Container, Layout, Text } from '@harnessio/uicore'
import type { ArtifactDetail, NpmArtifactDetailConfig } from '@harnessio/react-har-service-client'
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 { VersionOverviewContext } from '@ar/pages/version-details/context/VersionOverviewProvider'
import { useVersionOverview } from '@ar/pages/version-details/context/VersionOverviewProvider'
import { LabelValueContent } from '@ar/pages/version-details/components/LabelValueContent/LabelValueContent'
import type { NpmVersionDetailsConfig } from '../../types'
import css from './overview.module.scss'
interface NpmVersionGeneralInfoProps {
@ -35,8 +35,8 @@ interface NpmVersionGeneralInfoProps {
export default function NpmVersionGeneralInfo(props: NpmVersionGeneralInfoProps) {
const { className } = props
const contextValue = useContext(VersionOverviewContext)
const data = contextValue.data as ArtifactDetail & NpmArtifactDetailConfig
const { data } = useVersionOverview<NpmVersionDetailsConfig>()
const versionMetatdata = data.metadata?.versions?.[data.version]
const { getString } = useStrings()
return (
<Card
@ -64,32 +64,40 @@ export default function NpmVersionGeneralInfo(props: NpmVersionGeneralInfoProps)
value={defaultTo(data.downloadCount?.toLocaleString(), 0)}
type={LabelValueTypeEnum.Text}
/>
<LabelValueContent
label={getString('versionDetails.overview.generalInformation.repository')}
value={data.metadata?.repository}
type={LabelValueTypeEnum.Link}
/>
<LabelValueContent
label={getString('versionDetails.overview.generalInformation.homepage')}
value={data.metadata?.homepage}
type={LabelValueTypeEnum.Link}
/>
<LabelValueContent
label={getString('versionDetails.overview.generalInformation.license')}
value={data.metadata?.license}
type={LabelValueTypeEnum.Text}
/>
{versionMetatdata?.repository && (
<LabelValueContent
label={getString('versionDetails.overview.generalInformation.repository')}
value={versionMetatdata.repository?.url}
type={LabelValueTypeEnum.Link}
/>
)}
{versionMetatdata?.homepage && (
<LabelValueContent
label={getString('versionDetails.overview.generalInformation.homepage')}
value={versionMetatdata.homepage}
type={LabelValueTypeEnum.Link}
/>
)}
{versionMetatdata?.license && (
<LabelValueContent
label={getString('versionDetails.overview.generalInformation.license')}
value={versionMetatdata.license}
type={LabelValueTypeEnum.Text}
/>
)}
<LabelValueContent
label={getString('versionDetails.overview.generalInformation.uploadedBy')}
value={getReadableDateTime(Number(data.modifiedAt), DEFAULT_DATE_TIME_FORMAT)}
type={LabelValueTypeEnum.Text}
/>
<LabelValueContent
label={getString('versionDetails.overview.generalInformation.pullCommand')}
value={data.metadata?.pullCommand}
type={LabelValueTypeEnum.CommandBlock}
/>
{data.metadata?.pullCommand && (
<LabelValueContent
label={getString('versionDetails.overview.generalInformation.pullCommand')}
value={data.metadata.pullCommand}
type={LabelValueTypeEnum.CommandBlock}
/>
)}
</Container>
</Layout.Vertical>
</Card>

View File

@ -14,6 +14,7 @@
* limitations under the License.
*/
import type { ArtifactDetail, NpmArtifactDetailConfig } from '@harnessio/react-har-service-client'
import type { VersionDetailsQueryParams } from '../types'
export enum NpmArtifactDetailsTabEnum {
@ -21,7 +22,10 @@ export enum NpmArtifactDetailsTabEnum {
Files = 'files',
Dependencies = 'dependencies'
}
export interface NpmVersionDetailsQueryParams extends VersionDetailsQueryParams {
detailsTab: NpmArtifactDetailsTabEnum
digest: string
}
export type NpmVersionDetailsConfig = ArtifactDetail & NpmArtifactDetailConfig

View File

@ -14,22 +14,11 @@
* limitations under the License.
*/
import React, { useContext } from 'react'
import React from 'react'
import { DEFAULT_PAGE_INDEX } from '@ar/constants'
import { VersionDependencyListContext } from '@ar/pages/version-details/context/VersionDependencyListProvider'
import ArtifactDependencyListTable from '@ar/pages/version-details/components/ArtifactDependencyListTable/ArtifactDependencyListTable'
export default function NuGetVersionDependencyContent() {
const { data, updateQueryParams, sort } = useContext(VersionDependencyListContext)
return (
<ArtifactDependencyListTable
data={data}
gotoPage={pageNumber => updateQueryParams({ page: pageNumber })}
setSortBy={sortArr => {
updateQueryParams({ sort: sortArr, page: DEFAULT_PAGE_INDEX })
}}
sortBy={sort}
/>
)
// TODO: Implement NuGetVersionDependencyContent
return <ArtifactDependencyListTable data={[]} />
}

View File

@ -1,35 +0,0 @@
/*
* 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.
*/
.table {
--typography-size: 12px;
--typography-weight: 400;
--line-height: 20px;
padding: var(--spacing-large);
[role='cell'],
[role='columnheader'] {
width: auto !important;
padding-right: var(--spacing-large);
}
div[class*='TableV2--cells'],
div[class*='TableV2--header'] {
display: grid !important;
width: 100%; /* Ensure the container doesn't exceed 100% width */
grid-template-columns: 1fr max-content;
}
}

View File

@ -15,82 +15,40 @@
*/
import React from 'react'
import classNames from 'classnames'
import type { Column } from 'react-table'
import { type PaginationProps, TableV2 } from '@harnessio/uicore'
import type { FileDetail, FileDetailResponseResponse } from '@harnessio/react-har-service-client'
import { TableV2 } from '@harnessio/uicore'
import { useParentHooks } from '@ar/hooks'
import { useStrings } from '@ar/frameworks/strings'
import type { IDependencyItem, IDependencyList } from './types'
import { DependencyNameCell, DependencyVersionCell } from './ArtifactDependencyListTableCells'
import css from './ArtifactDependencyListTable.module.scss'
export interface DependencyListSortBy {
sort: 'name' | 'size' | 'created'
}
interface ArtifactDependencyListTableProps {
data: FileDetailResponseResponse
gotoPage: (pageNumber: number) => void
onPageSizeChange?: PaginationProps['onPageSizeChange']
setSortBy: (sortBy: string[]) => void
sortBy: string[]
data: IDependencyList
minimal?: boolean
className?: string
}
export default function ArtifactDependencyListTable(props: ArtifactDependencyListTableProps): JSX.Element {
const { data, gotoPage, onPageSizeChange, sortBy, setSortBy, className } = props
const { useDefaultPaginationProps } = useParentHooks()
const { data, className } = props
const { getString } = useStrings()
const { files, itemCount = 0, pageCount = 0, pageIndex, pageSize = 0 } = data
const paginationProps = useDefaultPaginationProps({
itemCount,
pageSize,
pageCount,
pageIndex,
gotoPage,
onPageSizeChange
})
const [currentSort, currentOrder] = sortBy
const columns: Column<FileDetail>[] = React.useMemo(() => {
const getServerSortProps = (id: string) => {
return {
enableServerSort: true,
isServerSorted: currentSort === id,
isServerSortedDesc: currentOrder === 'DESC',
getSortedColumn: ({ sort }: DependencyListSortBy) => {
setSortBy([sort, currentOrder === 'DESC' ? 'ASC' : 'DESC'])
}
}
}
const columns: Column<IDependencyItem>[] = React.useMemo(() => {
return [
{
Header: getString('versionDetails.dependencyList.table.columns.name'),
accessor: 'name',
Cell: DependencyNameCell,
serverSortProps: getServerSortProps('name')
width: '100%'
},
{
Header: getString('versionDetails.dependencyList.table.columns.version'),
accessor: 'version',
Cell: DependencyVersionCell,
serverSortProps: getServerSortProps('version')
width: '20%'
}
].filter(Boolean) as unknown as Column<FileDetail>[]
}, [currentOrder, currentSort, getString])
].filter(Boolean) as unknown as Column<IDependencyItem>[]
}, [getString])
return (
<TableV2
className={classNames(css.table, className)}
columns={columns}
data={files}
pagination={paginationProps}
sortable
/>
)
return <TableV2 className={className} columns={columns} data={data} sortable={false} />
}

View File

@ -15,6 +15,7 @@
*/
import React from 'react'
import { FontVariation } from '@harnessio/design-system'
import type { FileDetail } from '@harnessio/react-har-service-client'
import type { Cell, CellValue, ColumnInstance, Renderer, Row, TableInstance } from 'react-table'
@ -30,9 +31,9 @@ type CellTypeWithActions<D extends Record<string, any>, V = any> = TableInstance
type CellType = Renderer<CellTypeWithActions<FileDetail>>
export const DependencyNameCell: CellType = ({ value }) => {
return <TableCells.TextCell value={value} />
return <TableCells.TextCell font={{ variation: FontVariation.BODY }} value={value} />
}
export const DependencyVersionCell: CellType = ({ value }) => {
return <TableCells.TextCell value={value} />
return <TableCells.TextCell font={{ variation: FontVariation.BODY }} value={value} />
}

View File

@ -1,11 +1,11 @@
/*
* Copyright 2023 Harness, Inc.
* 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
* 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,
@ -14,6 +14,8 @@
* limitations under the License.
*/
/* eslint-disable */
// This is an auto-generated file
export declare const table: string
export type IDependencyItem = {
name: string
version: string
}
export type IDependencyList = IDependencyItem[]

View File

@ -40,6 +40,7 @@ plusNewName: + New {{name}}
enterPlaceholder: Enter {{name}}
descriptionPlaceholder: Enter Description
noDescription: No Description
noReadme: No Readme
lastUpdated: Last Updated
createdAt: Created At
modifiedAt: Modified At

View File

@ -348,6 +348,7 @@ export interface StringsMap {
new: string
noDescription: string
noMatchingFilterData: string
noReadme: string
noResultsFound: string
nonProd: string
nonProdCount: string