diff --git a/src/Pages/Lightwell/Packages/PackageDetails.test.tsx b/src/Pages/Lightwell/Packages/PackageDetails.test.tsx index 31a032cbe..226ed15b2 100644 --- a/src/Pages/Lightwell/Packages/PackageDetails.test.tsx +++ b/src/Pages/Lightwell/Packages/PackageDetails.test.tsx @@ -3,14 +3,12 @@ import userEvent from '@testing-library/user-event'; import PackageDetails from './PackageDetails'; import { - useLightwellRepositoryPackagesQuery, useMavenPackageVersionsListQuery, usePythonPackageVersionsQuery, } from 'services/Content/ContentQueries'; import { defaultLightwellContentItem, defaultLightwellRepositoryPackageItem, - defaultLightwellRepositoryPackageResponse, defaultPythonRemediatedContentItem, defaultPythonPackageVersions, defaultPythonRemediatedRepositoryPackageItem, @@ -22,23 +20,16 @@ import { javaRemediatedCopyCommand, mavenRemediatedDependencySnippet, mavenValidatedDependencySnippet, - pipConfRemediatedInstallSnippet, pipConfValidatedInstallSnippet, - pipRemediatedInstallSnippet, pipValidatedInstallSnippet, - pythonRemediatedPipCommand, ReactQueryTestWrapper, - requirementsRemediatedInstallSnippet, requirementsValidatedInstallSnippet, - otherPythonRemediatedPipCommand, otherJavaRemediatedCopyCommand, } from 'testingHelpers'; -import { RepositoryPackageItem } from 'services/Content/ContentApi'; import { getRepositoryPathSlug } from '../helpers'; import useLightwellRepository from '../useLightwellRepository'; jest.mock('services/Content/ContentQueries', () => ({ - useLightwellRepositoryPackagesQuery: jest.fn(), useMavenPackageVersionsListQuery: jest.fn(), usePythonPackageVersionsQuery: jest.fn(), })); @@ -70,59 +61,9 @@ jest.mock('../../../Hooks/useLightwellNavigate', () => ({ })); const defaultBuilds = [ - { version: '3.14.0.rhlw-00001', release: 'rhlw-00001', created_at: '2026-07-01T00:00:00Z' }, + { version: '3.14.0', release: 'rhlw-00001', created_at: '2026-07-01T00:00:00Z' }, ]; -const multiVersionReleasePackage: RepositoryPackageItem = { - group: 'org.json.test', - name: 'json-test', - versions: ['3.14.0', '2.12.0'], - latest_releases: [ - { version: '3.14.0', release: 'rhlw-00001', created_at: '2026-07-01T00:00:00Z' }, - { version: '2.12.0', release: 'rhlw-00002', created_at: '2026-06-18T00:00:00Z' }, - ], -}; - -const multiVersionReleasePackageWithFullVersions: RepositoryPackageItem = { - ...multiVersionReleasePackage, - latest_releases: [ - { version: '3.14.0.rhlw-00001', release: 'rhlw-00001', created_at: '2026-07-01T00:00:00Z' }, - { version: '2.12.0.rhlw-00002', release: 'rhlw-00002', created_at: '2026-06-18T00:00:00Z' }, - ], -}; - -const multipleReleasesPerVersionPackage: RepositoryPackageItem = { - group: 'org.json.test', - name: 'json-test', - versions: [ - '3.14.0.rhlw-00003', - '3.14.0.rhlw-00002', - '3.14.0.rhlw-00001', - '2.12.0.rhlw-00002', - '2.12.0.rhlw-00001', - ], - latest_releases: [ - { version: '3.14.0.rhlw-00003', release: 'rhlw-00003', created_at: '2026-07-03T00:00:00Z' }, - { version: '3.14.0.rhlw-00002', release: 'rhlw-00002', created_at: '2026-07-02T00:00:00Z' }, - { version: '3.14.0.rhlw-00001', release: 'rhlw-00001', created_at: '2026-07-01T00:00:00Z' }, - { version: '2.12.0.rhlw-00002', release: 'rhlw-00002', created_at: '2026-06-18T00:00:00Z' }, - { version: '2.12.0.rhlw-00001', release: 'rhlw-00001', created_at: '2026-06-17T00:00:00Z' }, - ], -}; - -const multiVersionNoReleasePackage: RepositoryPackageItem = { - group: 'org.json.test', - name: 'json-test', - versions: ['2.21.2', '2.20.0', '2.19.1'], - latest_releases: [ - { version: '2.21.2', release: '', created_at: '2026-07-01T00:00:00Z' }, - { version: '2.20.0', release: '', created_at: '2026-06-15T00:00:00Z' }, - { version: '2.19.1', release: '', created_at: '2026-06-01T00:00:00Z' }, - ], -}; - -const noReleaseBuilds = [{ version: '2.21.2', release: '', created_at: '2026-07-01T00:00:00Z' }]; - type PackageMetadata = { summary?: string; license?: string; @@ -151,16 +92,6 @@ const mockVersionsListQuery = ( }, }); -const mockPackagesQuery = () => ({ - isLoading: false, - isFetching: false, - data: { - ...defaultLightwellRepositoryPackageResponse, - results: [defaultLightwellRepositoryPackageItem], - total: 1, - }, -}); - const renderPackageDetails = () => render( @@ -181,7 +112,6 @@ beforeEach(() => { isError: false, error: undefined, }); - (useLightwellRepositoryPackagesQuery as jest.Mock).mockImplementation(mockPackagesQuery); (useMavenPackageVersionsListQuery as jest.Mock).mockImplementation(() => mockVersionsListQuery()); (usePythonPackageVersionsQuery as jest.Mock).mockImplementation(() => ({ isLoading: false, @@ -191,9 +121,14 @@ beforeEach(() => { }); it('shows empty state when the package has no builds', async () => { - (useMavenPackageVersionsListQuery as jest.Mock).mockImplementation(() => - mockVersionsListQuery([]), - ); + (useMavenPackageVersionsListQuery as jest.Mock).mockImplementation(() => ({ + isLoading: false, + data: { + group: defaultLightwellRepositoryPackageItem.group, + name: defaultLightwellRepositoryPackageItem.name, + versions: [], + }, + })); renderPackageDetails(); @@ -201,18 +136,33 @@ it('shows empty state when the package has no builds', async () => { }); const setupNoReleasePackage = () => { - (useLightwellRepositoryPackagesQuery as jest.Mock).mockImplementation(() => ({ + (useMavenPackageVersionsListQuery as jest.Mock).mockImplementation(() => ({ isLoading: false, - isFetching: false, data: { - ...defaultLightwellRepositoryPackageResponse, - results: [multiVersionNoReleasePackage], - total: 1, + group: 'org.json.test', + name: 'json-test', + versions: [ + { + group: 'org.json.test', + name: 'json-test', + version: '2.21.2', + builds: [{ version: '2.21.2', release: '', created_at: '2026-07-01T00:00:00Z' }], + }, + { + group: 'org.json.test', + name: 'json-test', + version: '2.20.0', + builds: [{ version: '2.20.0', release: '', created_at: '2026-06-15T00:00:00Z' }], + }, + { + group: 'org.json.test', + name: 'json-test', + version: '2.19.1', + builds: [{ version: '2.19.1', release: '', created_at: '2026-06-01T00:00:00Z' }], + }, + ], }, })); - (useMavenPackageVersionsListQuery as jest.Mock).mockImplementation(() => - mockVersionsListQuery(noReleaseBuilds, {}, '2.21.2'), - ); }; const setupPythonRemediatedPackage = () => { @@ -227,15 +177,6 @@ const setupPythonRemediatedPackage = () => { isError: false, error: undefined, }); - (useLightwellRepositoryPackagesQuery as jest.Mock).mockImplementation(() => ({ - isLoading: false, - isFetching: false, - data: { - ...defaultLightwellRepositoryPackageResponse, - results: [defaultPythonRemediatedRepositoryPackageItem], - total: 1, - }, - })); (usePythonPackageVersionsQuery as jest.Mock).mockImplementation(() => ({ isLoading: false, isFetching: false, @@ -349,16 +290,31 @@ it('shows upstream versions list in sidebar for non-release packages', async () }); const setupMultiVersionReleasePackage = () => { - (useLightwellRepositoryPackagesQuery as jest.Mock).mockImplementation(() => ({ + (useMavenPackageVersionsListQuery as jest.Mock).mockImplementation(() => ({ isLoading: false, - isFetching: false, data: { - ...defaultLightwellRepositoryPackageResponse, - results: [multiVersionReleasePackage], - total: 1, + group: 'org.json.test', + name: 'json-test', + versions: [ + { + group: 'org.json.test', + name: 'json-test', + version: '3.14.0', + builds: [ + { version: '3.14.0', release: 'rhlw-00001', created_at: '2026-07-01T00:00:00Z' }, + ], + }, + { + group: 'org.json.test', + name: 'json-test', + version: '2.12.0', + builds: [ + { version: '2.12.0', release: 'rhlw-00002', created_at: '2026-06-18T00:00:00Z' }, + ], + }, + ], }, })); - (useMavenPackageVersionsListQuery as jest.Mock).mockImplementation(() => mockVersionsListQuery()); }; it('shows "Available versions" on Releases tab for multi-version release packages', async () => { @@ -381,22 +337,34 @@ it('shows "Available versions" on Releases tab for multi-version release package }); it('deduplicates "Available versions" rows when multiple releases share the same base version', async () => { - (useLightwellRepositoryPackagesQuery as jest.Mock).mockImplementation(() => ({ + (useMavenPackageVersionsListQuery as jest.Mock).mockImplementation(() => ({ isLoading: false, - isFetching: false, data: { - ...defaultLightwellRepositoryPackageResponse, - results: [multipleReleasesPerVersionPackage], - total: 1, + group: 'org.json.test', + name: 'json-test', + versions: [ + { + group: 'org.json.test', + name: 'json-test', + version: '3.14.0', + builds: [ + { version: '3.14.0', release: 'rhlw-00003', created_at: '2026-07-03T00:00:00Z' }, + { version: '3.14.0', release: 'rhlw-00002', created_at: '2026-07-02T00:00:00Z' }, + { version: '3.14.0', release: 'rhlw-00001', created_at: '2026-07-01T00:00:00Z' }, + ], + }, + { + group: 'org.json.test', + name: 'json-test', + version: '2.12.0', + builds: [ + { version: '2.12.0', release: 'rhlw-00002', created_at: '2026-06-18T00:00:00Z' }, + { version: '2.12.0', release: 'rhlw-00001', created_at: '2026-06-17T00:00:00Z' }, + ], + }, + ], }, })); - (useMavenPackageVersionsListQuery as jest.Mock).mockImplementation(() => - mockVersionsListQuery( - [{ version: '3.14.0.rhlw-00003', release: 'rhlw-00003', created_at: '2026-07-03T00:00:00Z' }], - {}, - '3.14.0.rhlw-00003', - ), - ); renderPackageDetails(); @@ -410,28 +378,6 @@ it('deduplicates "Available versions" rows when multiple releases share the same expect(versionRows[1]).toHaveTextContent('2.12.0'); }); -it('shows release metadata when latest_releases use full version strings', async () => { - (useLightwellRepositoryPackagesQuery as jest.Mock).mockImplementation(() => ({ - isLoading: false, - isFetching: false, - data: { - ...defaultLightwellRepositoryPackageResponse, - results: [multiVersionReleasePackageWithFullVersions], - total: 1, - }, - })); - (useMavenPackageVersionsListQuery as jest.Mock).mockImplementation(() => mockVersionsListQuery()); - - renderPackageDetails(); - - const releasesTab = await screen.findByRole('tab', { name: 'Releases' }); - await userEvent.click(releasesTab); - - expect(await screen.findByText('2.12.0.rhlw-00002')).toBeInTheDocument(); - expect(await screen.findByText('2026-06-18')).toBeInTheDocument(); - expect(await screen.findByRole('button', { name: '2.12.0' })).toBeInTheDocument(); -}); - it('shows version dropdown for multi-version release packages', async () => { setupMultiVersionReleasePackage(); @@ -478,62 +424,6 @@ const assertClipboardCopy = async ( expect(writeText).toHaveBeenCalledWith(expected); }; -it('copies pip command to clipboard for remediated python package', async () => { - const writeText = mockClipboard(); - - setupPythonRemediatedPackage(); - renderPackageDetails(); - - // pip tab in "How to use" section of Overview tab - await assertClipboardCopy( - writeText, - async () => { - await userEvent.click(await screen.findByRole('button', { name: 'Copy' })); - }, - pipRemediatedInstallSnippet, - ); - - // requirements.txt tab in "How to use" section of Overview tab - await assertClipboardCopy( - writeText, - async () => { - await userEvent.click(await screen.findByRole('tab', { name: 'requirements.txt' })); - await userEvent.click(await screen.findByRole('button', { name: 'Copy' })); - }, - requirementsRemediatedInstallSnippet, - ); - - // pip.conf tab in "How to use" section of Overview tab - await assertClipboardCopy( - writeText, - async () => { - await userEvent.click(await screen.findByRole('tab', { name: 'pip.conf' })); - await userEvent.click(await screen.findByRole('button', { name: 'Copy' })); - }, - pipConfRemediatedInstallSnippet, - ); - - // "Releases for version x.x.x" section of Releases tab - await assertClipboardCopy( - writeText, - async () => { - await userEvent.click(await screen.findByRole('tab', { name: 'Releases' })); - const buttons = await screen.findAllByRole('button', { name: '2.32.0.rhlw-0002' }); - await userEvent.click(buttons[0]); - }, - pythonRemediatedPipCommand, - ); - - // "Available versions" section of Releases tab - await assertClipboardCopy( - writeText, - async () => { - await userEvent.click(await screen.findByRole('button', { name: '2.31.0.rhlw-0001' })); - }, - otherPythonRemediatedPipCommand, - ); -}); - it('copies maven coordinate to clipboard for remediated java package', async () => { const writeText = mockClipboard(); @@ -592,15 +482,6 @@ const setupPythonValidatedPackage = () => { isError: false, error: undefined, }); - (useLightwellRepositoryPackagesQuery as jest.Mock).mockImplementation(() => ({ - isLoading: false, - isFetching: false, - data: { - ...defaultLightwellRepositoryPackageResponse, - results: [defaultPythonValidatedPackageItem], - total: 1, - }, - })); (usePythonPackageVersionsQuery as jest.Mock).mockImplementation(() => ({ isLoading: false, isFetching: false, diff --git a/src/Pages/Lightwell/Packages/PackageDetails.tsx b/src/Pages/Lightwell/Packages/PackageDetails.tsx index 12f134434..725841aa9 100644 --- a/src/Pages/Lightwell/Packages/PackageDetails.tsx +++ b/src/Pages/Lightwell/Packages/PackageDetails.tsx @@ -32,14 +32,12 @@ import { useNavigate, useParams } from 'react-router-dom'; import EmptyTableState from 'components/EmptyTableState/EmptyTableState'; import Loader from 'components/Loader'; import { - useLightwellRepositoryPackagesQuery, useMavenPackageVersionsListQuery, usePythonPackageVersionsQuery, } from 'services/Content/ContentQueries'; import { LIGHTWELL_USE_MOCK } from '../constants'; import { useLightwellDemo } from '../LightwellDemoContext'; import { - compareVersionsDesc, formatDistributionUrl, formatRepositoryName, lightwellReleaseNum, @@ -104,29 +102,9 @@ const PackageDetails = () => { error, } = useLightwellRepository(repoSlug); - const apiPackagesQuery = useLightwellRepositoryPackagesQuery( - repoUUID, - 1, - 20, - packageName, - !!repoUUID && !!packageName && !useMock, - ); - - const packageItem = useMemo(() => { - if (useMock) { - return getMockLightwellPackages(repoUUID).find((pkg) => pkg.name === packageName); - } - - return (apiPackagesQuery.data?.results ?? []).find((pkg) => pkg.name === packageName); - }, [useMock, repoUUID, packageName, apiPackagesQuery.data?.results]); - - const packageVersion = packageItem?.versions[0] ?? ''; - const hasRelease = (packageItem?.latest_releases ?? []).some((r) => !!r.release); const isMaven = repository?.content_type === 'maven'; const isPython = repository?.content_type === 'python'; - const activeVersion = selectedVersion || packageVersion; - const mavenVersionsListQuery = useMavenPackageVersionsListQuery( repoUUID, packageGroup, @@ -153,49 +131,23 @@ const PackageDetails = () => { [useMock, isPython, repoUUID, packageName], ); - const mavenDetail = ( - useMock ? mockMavenVersionsList : mavenVersionsListQuery.data - )?.versions.find( - (v) => stripLightwellVersionSuffix(v.version) === stripLightwellVersionSuffix(activeVersion), - ); - const mavenVersionsData = useMock ? mockMavenVersionsList : mavenVersionsListQuery.data; + const pythonVersionsData = useMock ? mockPythonVersions : pythonPackageVersionsQuery.data; - const mavenBuilds = useMemo(() => { - if (!isMaven || !hasRelease || !mavenVersionsData?.versions) return []; - - const upstream = stripLightwellVersionSuffix(activeVersion); - - return mavenVersionsData.versions - .filter((v) => stripLightwellVersionSuffix(v.version) === upstream) - .flatMap((v) => v.builds) - .sort((a, b) => lightwellReleaseNum(b.release) - lightwellReleaseNum(a.release)); - }, [isMaven, hasRelease, mavenVersionsData?.versions, activeVersion]); - - const mavenDeduplicatedVersions = useMemo(() => { - const versions = packageItem?.versions ?? []; - - if (!isMaven || !hasRelease) { - return sortVersionsDesc(versions.map(stripLightwellVersionSuffix)); - } + const mavenVersions = useMemo(() => { + if (!isMaven || !mavenVersionsData?.versions) return []; + return sortVersionsDesc(mavenVersionsData.versions.map((v) => v.version)); + }, [isMaven, mavenVersionsData?.versions]); - const seen = new Set(); - - return [...(packageItem?.versions ?? [])] - .sort((a, b) => lightwellReleaseNum(b) - lightwellReleaseNum(a)) - .filter((v) => { - const upstream = stripLightwellVersionSuffix(v); - if (seen.has(upstream)) { - return false; - } - seen.add(upstream); - return true; - }) - .map(stripLightwellVersionSuffix) - .sort(compareVersionsDesc); - }, [isMaven, hasRelease, packageItem?.versions]); + const mavenAllReleases = useMemo(() => { + if (!isMaven || !mavenVersionsData?.versions) return []; + return mavenVersionsData.versions.flatMap((v) => v.builds); + }, [isMaven, mavenVersionsData?.versions]); - const pythonVersionsData = useMock ? mockPythonVersions : pythonPackageVersionsQuery.data; + const mavenHasRelease = useMemo( + () => mavenAllReleases.some((r) => !!r.release), + [mavenAllReleases], + ); const pythonVersionsFromApi = useMemo( () => pythonVersionsData?.versions?.map((version) => version.version) ?? [], @@ -203,58 +155,53 @@ const PackageDetails = () => { ); const pythonVersions = useMemo(() => { - const versions = - useMock && !pythonVersionsData ? (packageItem?.versions ?? []) : pythonVersionsFromApi; + const versions = useMock + ? (getMockLightwellPackages(repoUUID).find((pkg) => pkg.name === packageName)?.versions ?? []) + : pythonVersionsFromApi; return sortVersionsDesc(versions.map(stripLightwellVersionSuffix)); - }, [useMock, pythonVersionsData, packageItem?.versions, pythonVersionsFromApi]); + }, [useMock, repoUUID, packageName, pythonVersionsFromApi]); + + // TODO: Derive Python hasRelease from its versions API when remediated support is added + const hasRelease = isMaven ? mavenHasRelease : false; + + const packageVersion = isMaven ? (mavenVersions[0] ?? '') : (pythonVersions[0] ?? ''); + + const activeVersion = selectedVersion || packageVersion; + + const mavenDetail = mavenVersionsData?.versions.find((v) => v.version === activeVersion); + + const mavenBuilds = useMemo(() => { + if (!isMaven || !hasRelease || !mavenVersionsData?.versions) return []; + + return mavenVersionsData.versions + .filter((v) => v.version === activeVersion) + .flatMap((v) => v.builds) + .sort((a, b) => lightwellReleaseNum(b.release) - lightwellReleaseNum(a.release)); + }, [isMaven, hasRelease, mavenVersionsData?.versions, activeVersion]); const pythonDetail = useMemo( () => pythonVersionsData?.versions.find((version) => version.version === activeVersion), [pythonVersionsData?.versions, activeVersion], ); - const pythonVersionReleases = useMemo(() => { - if (pythonVersionsData?.versions) { - return pythonVersionsData.versions.map((version) => ({ + const pythonVersionReleases = useMemo( + () => + (pythonVersionsData?.versions ?? []).map((version) => ({ version: version.version, release: '', created_at: version.last_updated, - })); - } + })), + [pythonVersionsData?.versions], + ); - return (packageItem?.latest_releases ?? []).map((release) => ({ - version: release.version, - release: release.release, - created_at: release.created_at, - })); - }, [pythonVersionsData?.versions, packageItem?.latest_releases]); - - const pythonBuilds = useMemo(() => { - if (!isPython || !packageItem) return []; - - const upstream = stripLightwellVersionSuffix(activeVersion); - return (packageItem.latest_releases ?? []) - .filter( - (release) => !!release.release && stripLightwellVersionSuffix(release.version) === upstream, - ) - .map((release) => ({ - version: buildVersionFromRelease(release), - release: release.release, - created_at: release.created_at, - })); - }, [isPython, packageItem, activeVersion]); - - const versionOptions = isPython ? pythonVersions : mavenDeduplicatedVersions; + const versionOptions = isPython ? pythonVersions : mavenVersions; useEffect(() => { if (!versionOptions.length) { return; } - if ( - !selectedVersion || - !versionOptions.includes(stripLightwellVersionSuffix(selectedVersion)) - ) { + if (!selectedVersion || !versionOptions.includes(selectedVersion)) { setSelectedVersion(versionOptions[0]); } }, [versionOptions, selectedVersion]); @@ -279,7 +226,6 @@ const PackageDetails = () => { } if (!repoUUID || isError) throw error; - if (!useMock && apiPackagesQuery.isError) throw apiPackagesQuery.error; const repositoryName = formatRepositoryName( repository.content_type, @@ -290,17 +236,13 @@ const PackageDetails = () => { const builds = isMaven && hasRelease ? mavenBuilds : (mavenDetail?.builds ?? []); const latestBuild = builds[0]; - const latestVersion = isMaven ? (latestBuild?.version ?? activeVersion) : activeVersion; - const upstreamVersion = stripLightwellVersionSuffix(isMaven ? latestVersion : activeVersion); - const pythonBuildVersion = pythonBuilds[0]?.version; + const upstreamVersion = isMaven ? (latestBuild?.version ?? activeVersion) : activeVersion; const displayVersion = isMaven - ? hasRelease - ? latestVersion - : selectedVersion || packageVersion - : hasRelease && pythonBuildVersion - ? pythonBuildVersion - : activeVersion; + ? hasRelease && latestBuild + ? buildVersionFromRelease(latestBuild) + : activeVersion + : activeVersion; const formatReleaseCopyText = (version: string) => isMaven @@ -314,20 +256,16 @@ const PackageDetails = () => { .at(-1) ?? '') : (pythonDetail?.last_updated ?? ''); - const packagesReady = useMock || (!apiPackagesQuery.isLoading && !!apiPackagesQuery.data); const detailReady = !isLoadingDetail; - const doneLoading = !!packageItem && packagesReady && detailReady; + const doneLoading = detailReady && (isMaven ? !!mavenVersionsData : !!pythonVersionsData); const hasDetail = - !!packageItem && detailReady && (isMaven - ? builds.length > 0 || (!hasRelease && !!packageItem.versions.length) - : hasRelease - ? pythonBuilds.length > 0 - : pythonVersions.length > 0); + ? builds.length > 0 || (!hasRelease && mavenVersions.length > 0) + : pythonVersions.length > 0); - const showEmpty = packagesReady && detailReady && !hasDetail; + const showEmpty = doneLoading && !hasDetail; const showVersionsTab = isMaven ? !hasRelease @@ -401,9 +339,7 @@ const PackageDetails = () => { isExpanded={versionDropdownOpen} ouiaId='lightwell-version-selector' > - {isMaven && hasRelease - ? stripLightwellVersionSuffix(selectedVersion) - : selectedVersion || activeVersion} + {selectedVersion || activeVersion} )} onOpenChange={(isOpen) => setVersionDropdownOpen(isOpen)} @@ -412,7 +348,7 @@ const PackageDetails = () => { {versionOptions.map((v) => ( - {isMaven && hasRelease ? stripLightwellVersionSuffix(v) : v} + {v} ))} @@ -528,9 +464,9 @@ const PackageDetails = () => { @@ -549,9 +485,7 @@ const PackageDetails = () => { @@ -565,7 +499,7 @@ const PackageDetails = () => { upstreamVersion={upstreamVersion} allVersions={ isMaven && !hasRelease - ? packageItem?.versions + ? mavenVersions : isPython && pythonVersions.length > 1 ? pythonVersions : undefined diff --git a/src/Pages/Lightwell/Packages/PackagesTable.test.tsx b/src/Pages/Lightwell/Packages/PackagesTable.test.tsx index 704440ceb..31ddf0c18 100644 --- a/src/Pages/Lightwell/Packages/PackagesTable.test.tsx +++ b/src/Pages/Lightwell/Packages/PackagesTable.test.tsx @@ -250,10 +250,10 @@ it('shows one version row per upstream version with its latest release only', as name: 'my-lib', versions: ['2.0.0', '1.0.0'], latest_releases: [ - { version: '2.0.0.rhlw-2', release: 'rhlw-2', created_at: '2026-07-02T00:00:00Z' }, - { version: '2.0.0.rhlw-1', release: 'rhlw-1', created_at: '2026-07-01T00:00:00Z' }, - { version: '1.0.0.rhlw-3', release: 'rhlw-3', created_at: '2026-06-15T00:00:00Z' }, - { version: '1.0.0.rhlw-1', release: 'rhlw-1', created_at: '2026-06-13T00:00:00Z' }, + { version: '2.0.0', release: 'rhlw-2', created_at: '2026-07-02T00:00:00Z' }, + { version: '2.0.0', release: 'rhlw-1', created_at: '2026-07-01T00:00:00Z' }, + { version: '1.0.0', release: 'rhlw-3', created_at: '2026-06-15T00:00:00Z' }, + { version: '1.0.0', release: 'rhlw-1', created_at: '2026-06-13T00:00:00Z' }, ], }; diff --git a/src/Pages/Lightwell/Packages/PackagesTable.tsx b/src/Pages/Lightwell/Packages/PackagesTable.tsx index ad5b1e8a0..9d6e117ca 100644 --- a/src/Pages/Lightwell/Packages/PackagesTable.tsx +++ b/src/Pages/Lightwell/Packages/PackagesTable.tsx @@ -50,7 +50,6 @@ import { formatRepositoryName, getRepositoryDescription, sortVersionsDesc, - stripLightwellVersionSuffix, } from '../helpers'; import Hide from 'components/Hide/Hide'; import { LIGHTWELL_USE_MOCK, lightwellPkgsPerPageKey } from '../constants'; @@ -105,26 +104,24 @@ const mapRepositoryPackage = (pkg: RepositoryPackageItem): MappedPackage => { const sortedReleases = [...pkg.latest_releases].sort(compareReleasesDesc); - // Deduplicate: keep only the latest release per upstream version const seenVersions = new Set(); const latestReleasePerVersion = sortedReleases.filter((release) => { - const v = stripLightwellVersionSuffix(release.version); - if (seenVersions.has(v)) return false; - seenVersions.add(v); + if (seenVersions.has(release.version)) return false; + seenVersions.add(release.version); return true; }); const sortedVersions = latestReleasePerVersion.length > 0 - ? latestReleasePerVersion.map((release) => stripLightwellVersionSuffix(release.version)) - : sortVersionsDesc(pkg.versions.map(stripLightwellVersionSuffix)); + ? latestReleasePerVersion.map((release) => release.version) + : sortVersionsDesc(pkg.versions); return { group_id: pkg.group, name: pkg.name, versions: sortedVersions, latest_releases: latestReleasePerVersion.map((release) => ({ - version: stripLightwellVersionSuffix(release.version), + version: release.version, release: release.release, })), last_updated: latestCreatedAt ?? '', diff --git a/src/Pages/Lightwell/Packages/components/PackageReleasesTab.tsx b/src/Pages/Lightwell/Packages/components/PackageReleasesTab.tsx index 876f6bc31..54a6e2494 100644 --- a/src/Pages/Lightwell/Packages/components/PackageReleasesTab.tsx +++ b/src/Pages/Lightwell/Packages/components/PackageReleasesTab.tsx @@ -4,7 +4,7 @@ import { useMemo } from 'react'; import { RepositoryPackageReleaseInfo } from 'services/Content/ContentApi'; import CopyLabel from './CopyLabel'; -import { compareReleasesDesc, sortVersionsDesc, stripLightwellVersionSuffix } from '../../helpers'; +import { compareReleasesDesc, sortVersionsDesc } from '../../helpers'; type PackageReleasesTabProps = { version: string; @@ -17,10 +17,7 @@ type PackageReleasesTabProps = { export const buildVersionFromRelease = ( release: Pick, -) => - release.version.includes('.rhlw-') - ? release.version - : `${stripLightwellVersionSuffix(release.version)}.${release.release}`; +) => `${release.version}.${release.release}`; const PackageReleasesTab = ({ version, @@ -37,10 +34,9 @@ const PackageReleasesTab = ({ for (const r of sorted) { if (!r.release) continue; - const upstream = stripLightwellVersionSuffix(r.version); - if (!map[upstream]) { - map[upstream] = r; - versions.push(upstream); + if (!map[r.version]) { + map[r.version] = r; + versions.push(r.version); } } @@ -48,8 +44,7 @@ const PackageReleasesTab = ({ return { releaseMap: map, sortedVersions: versions }; } - const stripped = allVersions.map(stripLightwellVersionSuffix); - return { releaseMap: map, sortedVersions: sortVersionsDesc([...new Set(stripped)]) }; + return { releaseMap: map, sortedVersions: sortVersionsDesc([...new Set(allVersions)]) }; }, [allVersions, latestReleases]); return ( @@ -65,14 +60,17 @@ const PackageReleasesTab = ({ - {builds.map((build) => ( - - - {build.version} - - {build.created_at?.split('T')[0] ?? '—'} - - ))} + {builds.map((build) => { + const fullVersion = buildVersionFromRelease(build); + return ( + + + {fullVersion} + + {build.created_at?.split('T')[0] ?? '—'} + + ); + })} diff --git a/src/Pages/Lightwell/mockPackages.ts b/src/Pages/Lightwell/mockPackages.ts index ab3ac03aa..fb7f5f56e 100644 --- a/src/Pages/Lightwell/mockPackages.ts +++ b/src/Pages/Lightwell/mockPackages.ts @@ -337,9 +337,7 @@ const mavenRemediatedDetail = ( group, name, version: v.version, - builds: [ - { version: `${v.version}.rhlw-00001`, release: 'rhlw-00001', created_at: v.created_at }, - ], + builds: [{ version: v.version, release: 'rhlw-00001', created_at: v.created_at }], summary, license, project_url: projectUrl, @@ -487,17 +485,17 @@ const mockMavenVersionsListByRepo: Record< version: '2.24.1', builds: [ { - version: '2.24.1.rhlw-00003', + version: '2.24.1', release: 'rhlw-00003', created_at: '2026-07-10T00:00:00Z', }, { - version: '2.24.1.rhlw-00002', + version: '2.24.1', release: 'rhlw-00002', created_at: '2026-06-28T00:00:00Z', }, { - version: '2.24.1.rhlw-00001', + version: '2.24.1', release: 'rhlw-00001', created_at: '2026-06-15T00:00:00Z', }, @@ -530,12 +528,12 @@ const mockMavenVersionsListByRepo: Record< version: '6.2.1', builds: [ { - version: '6.2.1.rhlw-00002', + version: '6.2.1', release: 'rhlw-00002', created_at: '2026-07-05T00:00:00Z', }, { - version: '6.2.1.rhlw-00001', + version: '6.2.1', release: 'rhlw-00001', created_at: '2026-06-22T00:00:00Z', }, @@ -590,12 +588,12 @@ const mockMavenVersionsListByRepo: Record< version: '4.1.115', builds: [ { - version: '4.1.115.rhlw-00002', + version: '4.1.115', release: 'rhlw-00002', created_at: '2026-07-12T00:00:00Z', }, { - version: '4.1.115.rhlw-00001', + version: '4.1.115', release: 'rhlw-00001', created_at: '2026-07-03T00:00:00Z', }, @@ -612,12 +610,12 @@ const mockMavenVersionsListByRepo: Record< version: '4.1.114', builds: [ { - version: '4.1.114.rhlw-00002', + version: '4.1.114', release: 'rhlw-00002', created_at: '2026-06-15T00:00:00Z', }, { - version: '4.1.114.rhlw-00001', + version: '4.1.114', release: 'rhlw-00001', created_at: '2026-06-01T00:00:00Z', },