Commit 93d7f2ac authored by Natalia Tepluhina's avatar Natalia Tepluhina

Merge branch '330847-convert-package-details-page-to-use-graphql-3' into 'master'

Finalise package details refactor

See merge request gitlab-org/gitlab!67991
parents 742e2b29 2d453ec8
...@@ -29,8 +29,10 @@ export default { ...@@ -29,8 +29,10 @@ export default {
}, },
computed: { computed: {
showMetadata() { showMetadata() {
return [PACKAGE_TYPE_NUGET, PACKAGE_TYPE_CONAN, PACKAGE_TYPE_MAVEN].includes( return (
[PACKAGE_TYPE_NUGET, PACKAGE_TYPE_CONAN, PACKAGE_TYPE_MAVEN].includes(
this.packageEntity.packageType, this.packageEntity.packageType,
) && this.packageEntity.metadata
); );
}, },
showNugetMetadata() { showNugetMetadata() {
......
<script> <script>
/*
* The commented part of this component needs to be re-enabled in the refactor process,
* See here for more info: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/64939
*/
import { import {
GlBadge, GlBadge,
GlButton, GlButton,
...@@ -19,10 +15,9 @@ import { convertToGraphQLId } from '~/graphql_shared/utils'; ...@@ -19,10 +15,9 @@ import { convertToGraphQLId } from '~/graphql_shared/utils';
import { numberToHumanSize } from '~/lib/utils/number_utils'; import { numberToHumanSize } from '~/lib/utils/number_utils';
import { objectToQuery } from '~/lib/utils/url_utility'; import { objectToQuery } from '~/lib/utils/url_utility';
import { s__, __ } from '~/locale'; import { s__, __ } from '~/locale';
// import DependencyRow from '~/packages/details/components/dependency_row.vue';
import PackagesListLoader from '~/packages/shared/components/packages_list_loader.vue';
import { packageTypeToTrackCategory } from '~/packages/shared/utils'; import { packageTypeToTrackCategory } from '~/packages/shared/utils';
import AdditionalMetadata from '~/packages_and_registries/package_registry/components/details/additional_metadata.vue'; import AdditionalMetadata from '~/packages_and_registries/package_registry/components/details/additional_metadata.vue';
import DependencyRow from '~/packages_and_registries/package_registry/components/details/dependency_row.vue';
import InstallationCommands from '~/packages_and_registries/package_registry/components/details/installation_commands.vue'; import InstallationCommands from '~/packages_and_registries/package_registry/components/details/installation_commands.vue';
import PackageFiles from '~/packages_and_registries/package_registry/components/details/package_files.vue'; import PackageFiles from '~/packages_and_registries/package_registry/components/details/package_files.vue';
import PackageHistory from '~/packages_and_registries/package_registry/components/details/package_history.vue'; import PackageHistory from '~/packages_and_registries/package_registry/components/details/package_history.vue';
...@@ -61,9 +56,8 @@ export default { ...@@ -61,9 +56,8 @@ export default {
GlTabs, GlTabs,
GlSprintf, GlSprintf,
PackageTitle, PackageTitle,
PackagesListLoader,
VersionRow, VersionRow,
// DependencyRow, DependencyRow,
PackageHistory, PackageHistory,
AdditionalMetadata, AdditionalMetadata,
InstallationCommands, InstallationCommands,
...@@ -141,7 +135,7 @@ export default { ...@@ -141,7 +135,7 @@ export default {
return this.packageEntity.versions?.nodes?.length > 0; return this.packageEntity.versions?.nodes?.length > 0;
}, },
packageDependencies() { packageDependencies() {
return this.packageEntity.dependency_links || []; return this.packageEntity.dependencyLinks?.nodes || [];
}, },
showDependencies() { showDependencies() {
return this.packageEntity.packageType === PACKAGE_TYPE_NUGET; return this.packageEntity.packageType === PACKAGE_TYPE_NUGET;
...@@ -268,8 +262,7 @@ export default { ...@@ -268,8 +262,7 @@ export default {
:description="s__('PackageRegistry|There was a problem fetching the details for this package.')" :description="s__('PackageRegistry|There was a problem fetching the details for this package.')"
:svg-path="svgPath" :svg-path="svgPath"
/> />
<div v-else-if="!isLoading" class="packages-app">
<div v-else class="packages-app">
<package-title :package-entity="packageEntity"> <package-title :package-entity="packageEntity">
<template #delete-button> <template #delete-button>
<gl-button <gl-button
...@@ -303,20 +296,14 @@ export default { ...@@ -303,20 +296,14 @@ export default {
/> />
</gl-tab> </gl-tab>
<gl-tab v-if="showDependencies" title-item-class="js-dependencies-tab"> <gl-tab v-if="showDependencies">
<template #title> <template #title>
<span>{{ __('Dependencies') }}</span> <span>{{ __('Dependencies') }}</span>
<gl-badge size="sm" data-testid="dependencies-badge">{{ <gl-badge size="sm">{{ packageDependencies.length }}</gl-badge>
packageDependencies.length
}}</gl-badge>
</template> </template>
<template v-if="packageDependencies.length > 0"> <template v-if="packageDependencies.length > 0">
<!-- <dependency-row <dependency-row v-for="dep in packageDependencies" :key="dep.id" :dependency-link="dep" />
v-for="(dep, index) in packageDependencies"
:key="index"
:dependency="dep"
/> -->
</template> </template>
<p v-else class="gl-mt-3" data-testid="no-dependencies-message"> <p v-else class="gl-mt-3" data-testid="no-dependencies-message">
...@@ -325,11 +312,7 @@ export default { ...@@ -325,11 +312,7 @@ export default {
</gl-tab> </gl-tab>
<gl-tab :title="__('Other versions')" title-item-class="js-versions-tab"> <gl-tab :title="__('Other versions')" title-item-class="js-versions-tab">
<template v-if="isLoading && !hasVersions"> <template v-if="hasVersions">
<packages-list-loader />
</template>
<template v-else-if="hasVersions">
<version-row v-for="v in packageEntity.versions.nodes" :key="v.id" :package-entity="v" /> <version-row v-for="v in packageEntity.versions.nodes" :key="v.id" :package-entity="v" />
</template> </template>
......
...@@ -2,14 +2,17 @@ ...@@ -2,14 +2,17 @@
export default { export default {
name: 'DependencyRow', name: 'DependencyRow',
props: { props: {
dependency: { dependencyLink: {
type: Object, type: Object,
required: true, required: true,
}, },
}, },
computed: { computed: {
showVersion() { showVersion() {
return Boolean(this.dependency.version_pattern); return Boolean(this.dependencyLink.dependency?.versionPattern);
},
showTargetFramework() {
return Boolean(this.dependencyLink.metadata?.targetFramework);
}, },
}, },
}; };
...@@ -18,10 +21,10 @@ export default { ...@@ -18,10 +21,10 @@ export default {
<template> <template>
<div class="gl-responsive-table-row"> <div class="gl-responsive-table-row">
<div class="table-section section-50"> <div class="table-section section-50">
<strong class="gl-text-body">{{ dependency.name }}</strong> <strong class="gl-text-body">{{ dependencyLink.dependency.name }}</strong>
<span v-if="dependency.target_framework" data-testid="target-framework" <span v-if="showTargetFramework" data-testid="target-framework">
>({{ dependency.target_framework }})</span ({{ dependencyLink.metadata.targetFramework }})
> </span>
</div> </div>
<div <div
...@@ -29,7 +32,7 @@ export default { ...@@ -29,7 +32,7 @@ export default {
class="table-section section-50 gl-display-flex gl-md-justify-content-end" class="table-section section-50 gl-display-flex gl-md-justify-content-end"
data-testid="version-pattern" data-testid="version-pattern"
> >
<span class="gl-text-body">{{ dependency.version_pattern }}</span> <span class="gl-text-body">{{ dependencyLink.dependency.versionPattern }}</span>
</div> </div>
</div> </div>
</template> </template>
...@@ -16,7 +16,7 @@ query getPackageDetails($id: ID!) { ...@@ -16,7 +16,7 @@ query getPackageDetails($id: ID!) {
name name
} }
} }
pipelines(first: 3) { pipelines(first: 10) {
nodes { nodes {
ref ref
id id
...@@ -60,6 +60,23 @@ query getPackageDetails($id: ID!) { ...@@ -60,6 +60,23 @@ query getPackageDetails($id: ID!) {
} }
} }
} }
dependencyLinks {
nodes {
id
dependency {
id
name
versionPattern
}
dependencyType
metadata {
... on NugetDependencyLinkMetadata {
id
targetFramework
}
}
}
}
metadata { metadata {
... on ComposerMetadata { ... on ComposerMetadata {
targetSha targetSha
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
.row .row
.col-12 .col-12
- if Feature.enabled?(:package_details_apollo) - if Feature.enabled?(:package_details_apollo, default_enabled: :yaml)
#js-vue-packages-detail-new{ data: package_details_data(@project, @package) } #js-vue-packages-detail-new{ data: package_details_data(@project, @package) }
- else - else
#js-vue-packages-detail{ data: package_details_data(@project, @package, true) } #js-vue-packages-detail{ data: package_details_data(@project, @package, true) }
...@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/334786 ...@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/334786
milestone: '14.1' milestone: '14.1'
type: development type: development
group: group::package group: group::package
default_enabled: false default_enabled: true
...@@ -52,6 +52,8 @@ RSpec.describe 'Group Packages' do ...@@ -52,6 +52,8 @@ RSpec.describe 'Group Packages' do
it_behaves_like 'package details link' it_behaves_like 'package details link'
end end
it_behaves_like 'package details link'
it 'allows you to navigate to the project page' do it 'allows you to navigate to the project page' do
find('[data-testid="root-link"]', text: project.name).click find('[data-testid="root-link"]', text: project.name).click
......
...@@ -45,6 +45,8 @@ RSpec.describe 'Packages' do ...@@ -45,6 +45,8 @@ RSpec.describe 'Packages' do
it_behaves_like 'package details link' it_behaves_like 'package details link'
end end
it_behaves_like 'package details link'
context 'deleting a package' do context 'deleting a package' do
let_it_be(:project) { create(:project) } let_it_be(:project) { create(:project) }
let_it_be(:package) { create(:package, project: project) } let_it_be(:package) { create(:package, project: project) }
......
...@@ -10,13 +10,15 @@ exports[`DependencyRow renders full dependency 1`] = ` ...@@ -10,13 +10,15 @@ exports[`DependencyRow renders full dependency 1`] = `
<strong <strong
class="gl-text-body" class="gl-text-body"
> >
Test.Dependency Ninject.Extensions.Factory
</strong> </strong>
<span <span
data-testid="target-framework" data-testid="target-framework"
> >
(.NETStandard2.0)
(.NETCoreApp3.1)
</span> </span>
</div> </div>
...@@ -27,7 +29,7 @@ exports[`DependencyRow renders full dependency 1`] = ` ...@@ -27,7 +29,7 @@ exports[`DependencyRow renders full dependency 1`] = `
<span <span
class="gl-text-body" class="gl-text-body"
> >
2.3.7 3.3.2
</span> </span>
</div> </div>
</div> </div>
......
import { GlEmptyState } from '@gitlab/ui'; import { GlEmptyState, GlBadge, GlTabs, GlTab } from '@gitlab/ui';
import { createLocalVue } from '@vue/test-utils'; import { createLocalVue } from '@vue/test-utils';
import { nextTick } from 'vue'; import { nextTick } from 'vue';
import VueApollo from 'vue-apollo'; import VueApollo from 'vue-apollo';
...@@ -10,6 +10,7 @@ import createFlash from '~/flash'; ...@@ -10,6 +10,7 @@ import createFlash from '~/flash';
import AdditionalMetadata from '~/packages_and_registries/package_registry/components/details/additional_metadata.vue'; import AdditionalMetadata from '~/packages_and_registries/package_registry/components/details/additional_metadata.vue';
import PackagesApp from '~/packages_and_registries/package_registry/components/details/app.vue'; import PackagesApp from '~/packages_and_registries/package_registry/components/details/app.vue';
import DependencyRow from '~/packages_and_registries/package_registry/components/details/dependency_row.vue';
import InstallationCommands from '~/packages_and_registries/package_registry/components/details/installation_commands.vue'; import InstallationCommands from '~/packages_and_registries/package_registry/components/details/installation_commands.vue';
import PackageFiles from '~/packages_and_registries/package_registry/components/details/package_files.vue'; import PackageFiles from '~/packages_and_registries/package_registry/components/details/package_files.vue';
import PackageHistory from '~/packages_and_registries/package_registry/components/details/package_history.vue'; import PackageHistory from '~/packages_and_registries/package_registry/components/details/package_history.vue';
...@@ -21,6 +22,7 @@ import { ...@@ -21,6 +22,7 @@ import {
PACKAGE_TYPE_COMPOSER, PACKAGE_TYPE_COMPOSER,
DELETE_PACKAGE_FILE_SUCCESS_MESSAGE, DELETE_PACKAGE_FILE_SUCCESS_MESSAGE,
DELETE_PACKAGE_FILE_ERROR_MESSAGE, DELETE_PACKAGE_FILE_ERROR_MESSAGE,
PACKAGE_TYPE_NUGET,
} from '~/packages_and_registries/package_registry/constants'; } from '~/packages_and_registries/package_registry/constants';
import destroyPackageMutation from '~/packages_and_registries/package_registry/graphql/mutations/destroy_package.mutation.graphql'; import destroyPackageMutation from '~/packages_and_registries/package_registry/graphql/mutations/destroy_package.mutation.graphql';
...@@ -30,6 +32,7 @@ import { ...@@ -30,6 +32,7 @@ import {
packageDetailsQuery, packageDetailsQuery,
packageData, packageData,
packageVersions, packageVersions,
dependencyLinks,
emptyPackageDetailsQuery, emptyPackageDetailsQuery,
packageDestroyMutation, packageDestroyMutation,
packageDestroyMutationError, packageDestroyMutationError,
...@@ -85,6 +88,8 @@ describe('PackagesApp', () => { ...@@ -85,6 +88,8 @@ describe('PackagesApp', () => {
show: jest.fn(), show: jest.fn(),
}, },
}, },
GlTabs,
GlTab,
}, },
}); });
} }
...@@ -100,6 +105,9 @@ describe('PackagesApp', () => { ...@@ -100,6 +105,9 @@ describe('PackagesApp', () => {
const findDeleteFileModal = () => wrapper.findByTestId('delete-file-modal'); const findDeleteFileModal = () => wrapper.findByTestId('delete-file-modal');
const findVersionRows = () => wrapper.findAllComponents(VersionRow); const findVersionRows = () => wrapper.findAllComponents(VersionRow);
const noVersionsMessage = () => wrapper.findByTestId('no-versions-message'); const noVersionsMessage = () => wrapper.findByTestId('no-versions-message');
const findDependenciesCountBadge = () => wrapper.findComponent(GlBadge);
const findNoDependenciesMessage = () => wrapper.findByTestId('no-dependencies-message');
const findDependencyRows = () => wrapper.findAllComponents(DependencyRow);
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
...@@ -401,4 +409,43 @@ describe('PackagesApp', () => { ...@@ -401,4 +409,43 @@ describe('PackagesApp', () => {
expect(noVersionsMessage().exists()).toBe(true); expect(noVersionsMessage().exists()).toBe(true);
}); });
}); });
describe('dependency links', () => {
it('does not show the dependency links for a non nuget package', async () => {
createComponent();
expect(findDependenciesCountBadge().exists()).toBe(false);
});
it('shows the dependencies tab with 0 count when a nuget package with no dependencies', async () => {
createComponent({
resolver: jest.fn().mockResolvedValue(
packageDetailsQuery({
packageType: PACKAGE_TYPE_NUGET,
dependencyLinks: { nodes: [] },
}),
),
});
await waitForPromises();
expect(findDependenciesCountBadge().exists()).toBe(true);
expect(findDependenciesCountBadge().text()).toBe('0');
expect(findNoDependenciesMessage().exists()).toBe(true);
});
it('renders the correct number of dependency rows for a nuget package', async () => {
createComponent({
resolver: jest.fn().mockResolvedValue(
packageDetailsQuery({
packageType: PACKAGE_TYPE_NUGET,
}),
),
});
await waitForPromises();
expect(findDependenciesCountBadge().exists()).toBe(true);
expect(findDependenciesCountBadge().text()).toBe(dependencyLinks().length.toString());
expect(findDependencyRows()).toHaveLength(dependencyLinks().length);
});
});
}); });
import { shallowMount } from '@vue/test-utils'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { dependencyLinks } from 'jest/packages/mock_data';
import DependencyRow from '~/packages_and_registries/package_registry/components/details/dependency_row.vue'; import DependencyRow from '~/packages_and_registries/package_registry/components/details/dependency_row.vue';
import { dependencyLinks } from '../../mock_data';
describe('DependencyRow', () => { describe('DependencyRow', () => {
let wrapper; let wrapper;
const { withoutFramework, withoutVersion, fullLink } = dependencyLinks; const [fullDependencyLink] = dependencyLinks();
const { dependency, metadata } = fullDependencyLink;
function createComponent({ dependencyLink = fullLink } = {}) { function createComponent(dependencyLink = fullDependencyLink) {
wrapper = shallowMount(DependencyRow, { wrapper = shallowMountExtended(DependencyRow, {
propsData: { propsData: {
dependency: dependencyLink, dependencyLink,
}, },
}); });
} }
const dependencyVersion = () => wrapper.find('[data-testid="version-pattern"]'); const dependencyVersion = () => wrapper.findByTestId('version-pattern');
const dependencyFramework = () => wrapper.find('[data-testid="target-framework"]'); const dependencyFramework = () => wrapper.findByTestId('target-framework');
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
...@@ -32,7 +33,10 @@ describe('DependencyRow', () => { ...@@ -32,7 +33,10 @@ describe('DependencyRow', () => {
describe('version', () => { describe('version', () => {
it('does not render any version information when not supplied', () => { it('does not render any version information when not supplied', () => {
createComponent({ dependencyLink: withoutVersion }); createComponent({
...fullDependencyLink,
dependency: { ...dependency, versionPattern: undefined },
});
expect(dependencyVersion().exists()).toBe(false); expect(dependencyVersion().exists()).toBe(false);
}); });
...@@ -41,13 +45,16 @@ describe('DependencyRow', () => { ...@@ -41,13 +45,16 @@ describe('DependencyRow', () => {
createComponent(); createComponent();
expect(dependencyVersion().exists()).toBe(true); expect(dependencyVersion().exists()).toBe(true);
expect(dependencyVersion().text()).toBe(fullLink.version_pattern); expect(dependencyVersion().text()).toBe(dependency.versionPattern);
}); });
}); });
describe('target framework', () => { describe('target framework', () => {
it('does not render any framework information when not supplied', () => { it('does not render any framework information when not supplied', () => {
createComponent({ dependencyLink: withoutFramework }); createComponent({
...fullDependencyLink,
metadata: { ...metadata, targetFramework: undefined },
});
expect(dependencyFramework().exists()).toBe(false); expect(dependencyFramework().exists()).toBe(false);
}); });
...@@ -56,7 +63,7 @@ describe('DependencyRow', () => { ...@@ -56,7 +63,7 @@ describe('DependencyRow', () => {
createComponent(); createComponent();
expect(dependencyFramework().exists()).toBe(true); expect(dependencyFramework().exists()).toBe(true);
expect(dependencyFramework().text()).toBe(`(${fullLink.target_framework})`); expect(dependencyFramework().text()).toBe(`(${metadata.targetFramework})`);
}); });
}); });
}); });
...@@ -51,6 +51,41 @@ export const packageFiles = () => [ ...@@ -51,6 +51,41 @@ export const packageFiles = () => [
}, },
]; ];
export const dependencyLinks = () => [
{
dependencyType: 'DEPENDENCIES',
id: 'gid://gitlab/Packages::DependencyLink/77',
__typename: 'PackageDependencyLink',
dependency: {
id: 'gid://gitlab/Packages::Dependency/3',
name: 'Ninject.Extensions.Factory',
versionPattern: '3.3.2',
__typename: 'PackageDependency',
},
metadata: {
id: 'gid://gitlab/Packages::Nuget::DependencyLinkMetadatum/77',
targetFramework: '.NETCoreApp3.1',
__typename: 'NugetDependencyLinkMetadata',
},
},
{
dependencyType: 'DEPENDENCIES',
id: 'gid://gitlab/Packages::DependencyLink/78',
__typename: 'PackageDependencyLink',
dependency: {
id: 'gid://gitlab/Packages::Dependency/4',
name: 'Ninject.Extensions.Factory',
versionPattern: '3.3.2',
__typename: 'PackageDependency',
},
metadata: {
id: 'gid://gitlab/Packages::Nuget::DependencyLinkMetadatum/78',
targetFramework: '.NETCoreApp3.1',
__typename: 'NugetDependencyLinkMetadata',
},
},
];
export const packageVersions = () => [ export const packageVersions = () => [
{ {
createdAt: '2021-08-10T09:33:54Z', createdAt: '2021-08-10T09:33:54Z',
...@@ -145,6 +180,9 @@ export const packageDetailsQuery = (extendPackage) => ({ ...@@ -145,6 +180,9 @@ export const packageDetailsQuery = (extendPackage) => ({
nodes: packageVersions(), nodes: packageVersions(),
__typename: 'PackageConnection', __typename: 'PackageConnection',
}, },
dependencyLinks: {
nodes: dependencyLinks(),
},
__typename: 'PackageDetailsType', __typename: 'PackageDetailsType',
...extendPackage, ...extendPackage,
}, },
......
...@@ -34,11 +34,9 @@ RSpec.shared_examples 'package details link' do |property| ...@@ -34,11 +34,9 @@ RSpec.shared_examples 'package details link' do |property|
expect(page).to have_css('.packages-app h1[data-testid="title"]', text: package.name) expect(page).to have_css('.packages-app h1[data-testid="title"]', text: package.name)
page.within(%Q([name="#{package.name}"])) do
expect(page).to have_content('Installation') expect(page).to have_content('Installation')
expect(page).to have_content('Registry setup') expect(page).to have_content('Registry setup')
end end
end
end end
RSpec.shared_examples 'when there are no packages' do RSpec.shared_examples 'when there are no packages' do
......
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