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 {
},
computed: {
showMetadata() {
return [PACKAGE_TYPE_NUGET, PACKAGE_TYPE_CONAN, PACKAGE_TYPE_MAVEN].includes(
this.packageEntity.packageType,
return (
[PACKAGE_TYPE_NUGET, PACKAGE_TYPE_CONAN, PACKAGE_TYPE_MAVEN].includes(
this.packageEntity.packageType,
) && this.packageEntity.metadata
);
},
showNugetMetadata() {
......
<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 {
GlBadge,
GlButton,
......@@ -19,10 +15,9 @@ import { convertToGraphQLId } from '~/graphql_shared/utils';
import { numberToHumanSize } from '~/lib/utils/number_utils';
import { objectToQuery } from '~/lib/utils/url_utility';
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 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 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';
......@@ -61,9 +56,8 @@ export default {
GlTabs,
GlSprintf,
PackageTitle,
PackagesListLoader,
VersionRow,
// DependencyRow,
DependencyRow,
PackageHistory,
AdditionalMetadata,
InstallationCommands,
......@@ -141,7 +135,7 @@ export default {
return this.packageEntity.versions?.nodes?.length > 0;
},
packageDependencies() {
return this.packageEntity.dependency_links || [];
return this.packageEntity.dependencyLinks?.nodes || [];
},
showDependencies() {
return this.packageEntity.packageType === PACKAGE_TYPE_NUGET;
......@@ -268,8 +262,7 @@ export default {
:description="s__('PackageRegistry|There was a problem fetching the details for this package.')"
:svg-path="svgPath"
/>
<div v-else class="packages-app">
<div v-else-if="!isLoading" class="packages-app">
<package-title :package-entity="packageEntity">
<template #delete-button>
<gl-button
......@@ -303,20 +296,14 @@ export default {
/>
</gl-tab>
<gl-tab v-if="showDependencies" title-item-class="js-dependencies-tab">
<gl-tab v-if="showDependencies">
<template #title>
<span>{{ __('Dependencies') }}</span>
<gl-badge size="sm" data-testid="dependencies-badge">{{
packageDependencies.length
}}</gl-badge>
<gl-badge size="sm">{{ packageDependencies.length }}</gl-badge>
</template>
<template v-if="packageDependencies.length > 0">
<!-- <dependency-row
v-for="(dep, index) in packageDependencies"
:key="index"
:dependency="dep"
/> -->
<dependency-row v-for="dep in packageDependencies" :key="dep.id" :dependency-link="dep" />
</template>
<p v-else class="gl-mt-3" data-testid="no-dependencies-message">
......@@ -325,11 +312,7 @@ export default {
</gl-tab>
<gl-tab :title="__('Other versions')" title-item-class="js-versions-tab">
<template v-if="isLoading && !hasVersions">
<packages-list-loader />
</template>
<template v-else-if="hasVersions">
<template v-if="hasVersions">
<version-row v-for="v in packageEntity.versions.nodes" :key="v.id" :package-entity="v" />
</template>
......
......@@ -2,14 +2,17 @@
export default {
name: 'DependencyRow',
props: {
dependency: {
dependencyLink: {
type: Object,
required: true,
},
},
computed: {
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 {
<template>
<div class="gl-responsive-table-row">
<div class="table-section section-50">
<strong class="gl-text-body">{{ dependency.name }}</strong>
<span v-if="dependency.target_framework" data-testid="target-framework"
>({{ dependency.target_framework }})</span
>
<strong class="gl-text-body">{{ dependencyLink.dependency.name }}</strong>
<span v-if="showTargetFramework" data-testid="target-framework">
({{ dependencyLink.metadata.targetFramework }})
</span>
</div>
<div
......@@ -29,7 +32,7 @@ export default {
class="table-section section-50 gl-display-flex gl-md-justify-content-end"
data-testid="version-pattern"
>
<span class="gl-text-body">{{ dependency.version_pattern }}</span>
<span class="gl-text-body">{{ dependencyLink.dependency.versionPattern }}</span>
</div>
</div>
</template>
......@@ -16,7 +16,7 @@ query getPackageDetails($id: ID!) {
name
}
}
pipelines(first: 3) {
pipelines(first: 10) {
nodes {
ref
id
......@@ -60,6 +60,23 @@ query getPackageDetails($id: ID!) {
}
}
}
dependencyLinks {
nodes {
id
dependency {
id
name
versionPattern
}
dependencyType
metadata {
... on NugetDependencyLinkMetadata {
id
targetFramework
}
}
}
}
metadata {
... on ComposerMetadata {
targetSha
......
......@@ -6,7 +6,7 @@
.row
.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) }
- else
#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
milestone: '14.1'
type: development
group: group::package
default_enabled: false
default_enabled: true
......@@ -52,6 +52,8 @@ RSpec.describe 'Group Packages' do
it_behaves_like 'package details link'
end
it_behaves_like 'package details link'
it 'allows you to navigate to the project page' do
find('[data-testid="root-link"]', text: project.name).click
......
......@@ -45,6 +45,8 @@ RSpec.describe 'Packages' do
it_behaves_like 'package details link'
end
it_behaves_like 'package details link'
context 'deleting a package' do
let_it_be(:project) { create(:project) }
let_it_be(:package) { create(:package, project: project) }
......
......@@ -10,13 +10,15 @@ exports[`DependencyRow renders full dependency 1`] = `
<strong
class="gl-text-body"
>
Test.Dependency
Ninject.Extensions.Factory
</strong>
<span
data-testid="target-framework"
>
(.NETStandard2.0)
(.NETCoreApp3.1)
</span>
</div>
......@@ -27,7 +29,7 @@ exports[`DependencyRow renders full dependency 1`] = `
<span
class="gl-text-body"
>
2.3.7
3.3.2
</span>
</div>
</div>
......
import { GlEmptyState } from '@gitlab/ui';
import { GlEmptyState, GlBadge, GlTabs, GlTab } from '@gitlab/ui';
import { createLocalVue } from '@vue/test-utils';
import { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
......@@ -10,6 +10,7 @@ import createFlash from '~/flash';
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 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 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';
......@@ -21,6 +22,7 @@ import {
PACKAGE_TYPE_COMPOSER,
DELETE_PACKAGE_FILE_SUCCESS_MESSAGE,
DELETE_PACKAGE_FILE_ERROR_MESSAGE,
PACKAGE_TYPE_NUGET,
} from '~/packages_and_registries/package_registry/constants';
import destroyPackageMutation from '~/packages_and_registries/package_registry/graphql/mutations/destroy_package.mutation.graphql';
......@@ -30,6 +32,7 @@ import {
packageDetailsQuery,
packageData,
packageVersions,
dependencyLinks,
emptyPackageDetailsQuery,
packageDestroyMutation,
packageDestroyMutationError,
......@@ -85,6 +88,8 @@ describe('PackagesApp', () => {
show: jest.fn(),
},
},
GlTabs,
GlTab,
},
});
}
......@@ -100,6 +105,9 @@ describe('PackagesApp', () => {
const findDeleteFileModal = () => wrapper.findByTestId('delete-file-modal');
const findVersionRows = () => wrapper.findAllComponents(VersionRow);
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(() => {
wrapper.destroy();
......@@ -401,4 +409,43 @@ describe('PackagesApp', () => {
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 { dependencyLinks } from 'jest/packages/mock_data';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import DependencyRow from '~/packages_and_registries/package_registry/components/details/dependency_row.vue';
import { dependencyLinks } from '../../mock_data';
describe('DependencyRow', () => {
let wrapper;
const { withoutFramework, withoutVersion, fullLink } = dependencyLinks;
const [fullDependencyLink] = dependencyLinks();
const { dependency, metadata } = fullDependencyLink;
function createComponent({ dependencyLink = fullLink } = {}) {
wrapper = shallowMount(DependencyRow, {
function createComponent(dependencyLink = fullDependencyLink) {
wrapper = shallowMountExtended(DependencyRow, {
propsData: {
dependency: dependencyLink,
dependencyLink,
},
});
}
const dependencyVersion = () => wrapper.find('[data-testid="version-pattern"]');
const dependencyFramework = () => wrapper.find('[data-testid="target-framework"]');
const dependencyVersion = () => wrapper.findByTestId('version-pattern');
const dependencyFramework = () => wrapper.findByTestId('target-framework');
afterEach(() => {
wrapper.destroy();
......@@ -32,7 +33,10 @@ describe('DependencyRow', () => {
describe('version', () => {
it('does not render any version information when not supplied', () => {
createComponent({ dependencyLink: withoutVersion });
createComponent({
...fullDependencyLink,
dependency: { ...dependency, versionPattern: undefined },
});
expect(dependencyVersion().exists()).toBe(false);
});
......@@ -41,13 +45,16 @@ describe('DependencyRow', () => {
createComponent();
expect(dependencyVersion().exists()).toBe(true);
expect(dependencyVersion().text()).toBe(fullLink.version_pattern);
expect(dependencyVersion().text()).toBe(dependency.versionPattern);
});
});
describe('target framework', () => {
it('does not render any framework information when not supplied', () => {
createComponent({ dependencyLink: withoutFramework });
createComponent({
...fullDependencyLink,
metadata: { ...metadata, targetFramework: undefined },
});
expect(dependencyFramework().exists()).toBe(false);
});
......@@ -56,7 +63,7 @@ describe('DependencyRow', () => {
createComponent();
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 = () => [
},
];
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 = () => [
{
createdAt: '2021-08-10T09:33:54Z',
......@@ -145,6 +180,9 @@ export const packageDetailsQuery = (extendPackage) => ({
nodes: packageVersions(),
__typename: 'PackageConnection',
},
dependencyLinks: {
nodes: dependencyLinks(),
},
__typename: 'PackageDetailsType',
...extendPackage,
},
......
......@@ -34,10 +34,8 @@ RSpec.shared_examples 'package details link' do |property|
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('Registry setup')
end
expect(page).to have_content('Installation')
expect(page).to have_content('Registry setup')
end
end
......
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