Commit c6158f0a authored by Illya Klymov's avatar Illya Klymov

Merge branch '36422-add-nuget-metadata-to-package-details' into 'master'

Add NuGet project and license urls to package details

See merge request gitlab-org/gitlab!33268
parents 552fbbaf ff29d467
<script> <script>
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import { GlLink } from '@gitlab/ui';
import { InformationType } from '../constants';
export default { export default {
name: 'PackageInformation', name: 'PackageInformation',
components: { components: {
ClipboardButton, ClipboardButton,
GlLink,
}, },
props: { props: {
heading: { heading: {
...@@ -24,6 +27,7 @@ export default { ...@@ -24,6 +27,7 @@ export default {
default: false, default: false,
}, },
}, },
informationType: InformationType,
}; };
</script> </script>
...@@ -36,8 +40,17 @@ export default { ...@@ -36,8 +40,17 @@ export default {
<ul class="content-list"> <ul class="content-list">
<li v-for="(item, index) in information" :key="index"> <li v-for="(item, index) in information" :key="index">
<span class="text-secondary">{{ item.label }}</span> <span class="text-secondary">{{ item.label }}</span>
<div class="pull-right"> <div class="pull-right w-75 gl-text-right">
<span>{{ item.value }}</span> <gl-link
v-if="item.type === $options.informationType.LINK"
:href="item.value"
target="_blank"
>
{{ item.value }}
</gl-link>
<span v-else>{{ item.value }}</span>
<clipboard-button <clipboard-button
v-if="showCopy" v-if="showCopy"
:text="item.value" :text="item.value"
......
...@@ -41,3 +41,7 @@ export const NpmManager = { ...@@ -41,3 +41,7 @@ export const NpmManager = {
export const FETCH_PACKAGE_VERSIONS_ERROR = s__( export const FETCH_PACKAGE_VERSIONS_ERROR = s__(
'PackageRegistry|Unable to fetch package version information.', 'PackageRegistry|Unable to fetch package version information.',
); );
export const InformationType = {
LINK: 'link',
};
import { __ } from '~/locale'; import { __ } from '~/locale';
import { formatDate } from '~/lib/utils/datetime_utility'; import { formatDate } from '~/lib/utils/datetime_utility';
import { TrackingActions } from './constants'; import { TrackingActions, InformationType } from './constants';
import { PackageType } from '../shared/constants'; import { PackageType } from '../shared/constants';
import { orderBy } from 'lodash';
export const trackInstallationTabChange = { export const trackInstallationTabChange = {
methods: { methods: {
...@@ -30,29 +31,61 @@ export function generatePackageInfo(packageEntity = {}) { ...@@ -30,29 +31,61 @@ export function generatePackageInfo(packageEntity = {}) {
if (packageEntity.package_type === PackageType.CONAN) { if (packageEntity.package_type === PackageType.CONAN) {
information.push({ information.push({
order: 1,
label: __('Recipe'), label: __('Recipe'),
value: generateConanRecipe(packageEntity), value: generateConanRecipe(packageEntity),
}); });
} else { } else {
information.push({ information.push({
order: 1,
label: __('Name'), label: __('Name'),
value: packageEntity.name || '', value: packageEntity.name || '',
}); });
} }
return [ if (packageEntity.package_type === PackageType.NUGET) {
const {
nuget_metadatum: { project_url: projectUrl, license_url: licenseUrl } = {},
} = packageEntity;
if (projectUrl) {
information.push({
order: 3,
label: __('Project URL'),
value: projectUrl,
type: InformationType.LINK,
});
}
if (licenseUrl) {
information.push({
order: 4,
label: __('License URL'),
value: licenseUrl,
type: InformationType.LINK,
});
}
}
return orderBy(
[
...information, ...information,
{ {
order: 2,
label: __('Version'), label: __('Version'),
value: packageEntity.version || '', value: packageEntity.version || '',
}, },
{ {
order: 5,
label: __('Created on'), label: __('Created on'),
value: formatDate(packageEntity.created_at), value: formatDate(packageEntity.created_at),
}, },
{ {
order: 6,
label: __('Updated at'), label: __('Updated at'),
value: formatDate(packageEntity.updated_at), value: formatDate(packageEntity.updated_at),
}, },
]; ],
['order'],
);
} }
---
title: Adds NuGet project and license URL to the package details page
merge_request: 33268
author:
type: added
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import PackageInformation from 'ee/packages/details/components/information.vue'; import PackageInformation from 'ee/packages/details/components/information.vue';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import { GlLink } from '@gitlab/ui';
describe('PackageInformation', () => { describe('PackageInformation', () => {
let wrapper; let wrapper;
const defaultProps = { const gitlabLink = 'https://gitlab.com';
information: [ const testInformation = [
{ {
label: 'Information one', label: 'Information one',
value: 'Information value one', value: 'Information value one',
...@@ -19,12 +20,11 @@ describe('PackageInformation', () => { ...@@ -19,12 +20,11 @@ describe('PackageInformation', () => {
label: 'Information three', label: 'Information three',
value: 'Information value three', value: 'Information value three',
}, },
], ];
};
function createComponent(props = {}) { function createComponent(props = {}) {
const propsData = { const propsData = {
...defaultProps, information: testInformation,
...props, ...props,
}; };
...@@ -40,6 +40,7 @@ describe('PackageInformation', () => { ...@@ -40,6 +40,7 @@ describe('PackageInformation', () => {
informationSelector() informationSelector()
.at(index) .at(index)
.text(); .text();
const informationLink = () => wrapper.find(GlLink);
afterEach(() => { afterEach(() => {
if (wrapper) wrapper.destroy(); if (wrapper) wrapper.destroy();
...@@ -66,10 +67,28 @@ describe('PackageInformation', () => { ...@@ -66,10 +67,28 @@ describe('PackageInformation', () => {
it('renders the supplied information', () => { it('renders the supplied information', () => {
createComponent(); createComponent();
expect(informationSelector()).toHaveLength(3); expect(informationSelector()).toHaveLength(testInformation.length);
expect(informationRowText(0)).toContain('one'); expect(informationRowText(0)).toContain(testInformation[0].value);
expect(informationRowText(1)).toContain('two'); expect(informationRowText(1)).toContain(testInformation[1].value);
expect(informationRowText(2)).toContain('three'); expect(informationRowText(2)).toContain(testInformation[2].value);
});
it('renders a link when the information is of type link', () => {
createComponent({
information: [
{
label: 'Information link',
value: gitlabLink,
type: 'link',
},
],
});
const link = informationLink();
expect(link.exists()).toBe(true);
expect(link.text()).toBe(gitlabLink);
expect(link.attributes('href')).toBe(gitlabLink);
}); });
describe('copy button', () => { describe('copy button', () => {
...@@ -82,10 +101,10 @@ describe('PackageInformation', () => { ...@@ -82,10 +101,10 @@ describe('PackageInformation', () => {
it('does render when the prop is set and has correct text set', () => { it('does render when the prop is set and has correct text set', () => {
createComponent({ showCopy: true }); createComponent({ showCopy: true });
expect(copyButton()).toHaveLength(3); expect(copyButton()).toHaveLength(testInformation.length);
expect(copyButton().at(0).vm.text).toBe(defaultProps.information[0].value); expect(copyButton().at(0).vm.text).toBe(testInformation[0].value);
expect(copyButton().at(1).vm.text).toBe(defaultProps.information[1].value); expect(copyButton().at(1).vm.text).toBe(testInformation[1].value);
expect(copyButton().at(2).vm.text).toBe(defaultProps.information[2].value); expect(copyButton().at(2).vm.text).toBe(testInformation[2].value);
}); });
}); });
}); });
import { formatDate } from '~/lib/utils/datetime_utility'; import { formatDate } from '~/lib/utils/datetime_utility';
import { orderBy } from 'lodash';
export const registryUrl = 'foo/registry'; export const registryUrl = 'foo/registry';
...@@ -43,18 +44,21 @@ export const generateMavenSetupXml = () => `<repositories> ...@@ -43,18 +44,21 @@ export const generateMavenSetupXml = () => `<repositories>
</snapshotRepository> </snapshotRepository>
</distributionManagement>`; </distributionManagement>`;
export const generateCommonPackageInformation = packageEntity => [ const generateCommonPackageInformation = packageEntity => [
{ {
label: 'Version', label: 'Version',
value: packageEntity.version, value: packageEntity.version,
order: 2,
}, },
{ {
label: 'Created on', label: 'Created on',
value: formatDate(packageEntity.created_at), value: formatDate(packageEntity.created_at),
order: 5,
}, },
{ {
label: 'Updated at', label: 'Updated at',
value: formatDate(packageEntity.updated_at), value: formatDate(packageEntity.updated_at),
order: 6,
}, },
]; ];
...@@ -62,6 +66,7 @@ export const generateStandardPackageInformation = packageEntity => [ ...@@ -62,6 +66,7 @@ export const generateStandardPackageInformation = packageEntity => [
{ {
label: 'Name', label: 'Name',
value: packageEntity.name, value: packageEntity.name,
order: 1,
}, },
...generateCommonPackageInformation(packageEntity), ...generateCommonPackageInformation(packageEntity),
]; ];
...@@ -70,10 +75,36 @@ export const generateConanInformation = conanPackage => [ ...@@ -70,10 +75,36 @@ export const generateConanInformation = conanPackage => [
{ {
label: 'Recipe', label: 'Recipe',
value: conanPackage.recipe, value: conanPackage.recipe,
order: 1,
}, },
...generateCommonPackageInformation(conanPackage), ...generateCommonPackageInformation(conanPackage),
]; ];
export const generateNugetInformation = nugetPackage =>
orderBy(
[
...generateCommonPackageInformation(nugetPackage),
{
label: 'Name',
value: nugetPackage.name,
order: 1,
},
{
label: 'Project URL',
value: nugetPackage.nuget_metadatum.project_url,
order: 3,
type: 'link',
},
{
label: 'License URL',
value: nugetPackage.nuget_metadatum.license_url,
order: 4,
type: 'link',
},
],
['order'],
);
export const pypiSetupCommandStr = `[gitlab] export const pypiSetupCommandStr = `[gitlab]
repository = foo repository = foo
username = __token__ username = __token__
......
import { generateConanRecipe, generatePackageInfo } from 'ee/packages/details/utils'; import { generateConanRecipe, generatePackageInfo } from 'ee/packages/details/utils';
import { conanPackage, mavenPackage, npmPackage } from '../mock_data'; import { conanPackage, mavenPackage, npmPackage, nugetPackage } from '../mock_data';
import { generateConanInformation, generateStandardPackageInformation } from './mock_data'; import {
generateConanInformation,
generateStandardPackageInformation,
generateNugetInformation,
} from './mock_data';
describe('Package detail utils', () => { describe('Package detail utils', () => {
describe('generating information', () => { describe('generating information', () => {
...@@ -53,5 +57,15 @@ describe('Package detail utils', () => { ...@@ -53,5 +57,15 @@ describe('Package detail utils', () => {
expect(info).toEqual(mavenInformation); expect(info).toEqual(mavenInformation);
}); });
}); });
describe('nuget packages', () => {
const nugetInformation = generateNugetInformation(nugetPackage);
it('correctly generates the nuget information', () => {
const info = generatePackageInfo(nugetPackage);
expect(info).toEqual(nugetInformation);
});
});
}); });
}); });
...@@ -120,6 +120,8 @@ export const nugetPackage = { ...@@ -120,6 +120,8 @@ export const nugetPackage = {
dependency_links: Object.values(dependencyLinks), dependency_links: Object.values(dependencyLinks),
nuget_metadatum: { nuget_metadatum: {
icon_url: 'fake-icon', icon_url: 'fake-icon',
project_url: 'project-foo-url',
license_url: 'license-foo-url',
}, },
}; };
......
...@@ -13012,6 +13012,9 @@ msgstr "" ...@@ -13012,6 +13012,9 @@ msgstr ""
msgid "License History" msgid "License History"
msgstr "" msgstr ""
msgid "License URL"
msgstr ""
msgid "License-Check" msgid "License-Check"
msgstr "" msgstr ""
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment