Commit 523cb9df authored by Natalia Tepluhina's avatar Natalia Tepluhina

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

Refactor and restore versions tab

See merge request gitlab-org/gitlab!67831
parents 5607675e b6d5e7f1
...@@ -20,7 +20,6 @@ import { numberToHumanSize } from '~/lib/utils/number_utils'; ...@@ -20,7 +20,6 @@ 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 DependencyRow from '~/packages/details/components/dependency_row.vue';
// import PackageListRow from '~/packages/shared/components/package_list_row.vue';
import PackagesListLoader from '~/packages/shared/components/packages_list_loader.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';
...@@ -28,6 +27,7 @@ import InstallationCommands from '~/packages_and_registries/package_registry/com ...@@ -28,6 +27,7 @@ import InstallationCommands from '~/packages_and_registries/package_registry/com
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';
import PackageTitle from '~/packages_and_registries/package_registry/components/details/package_title.vue'; import PackageTitle from '~/packages_and_registries/package_registry/components/details/package_title.vue';
import VersionRow from '~/packages_and_registries/package_registry/components/details/version_row.vue';
import { import {
PACKAGE_TYPE_NUGET, PACKAGE_TYPE_NUGET,
PACKAGE_TYPE_COMPOSER, PACKAGE_TYPE_COMPOSER,
...@@ -62,7 +62,7 @@ export default { ...@@ -62,7 +62,7 @@ export default {
GlSprintf, GlSprintf,
PackageTitle, PackageTitle,
PackagesListLoader, PackagesListLoader,
// PackageListRow, VersionRow,
// DependencyRow, // DependencyRow,
PackageHistory, PackageHistory,
AdditionalMetadata, AdditionalMetadata,
...@@ -138,7 +138,7 @@ export default { ...@@ -138,7 +138,7 @@ export default {
}; };
}, },
hasVersions() { hasVersions() {
return this.packageEntity.versions?.length > 0; return this.packageEntity.versions?.nodes?.length > 0;
}, },
packageDependencies() { packageDependencies() {
return this.packageEntity.dependency_links || []; return this.packageEntity.dependency_links || [];
...@@ -154,11 +154,6 @@ export default { ...@@ -154,11 +154,6 @@ export default {
formatSize(size) { formatSize(size) {
return numberToHumanSize(size); return numberToHumanSize(size);
}, },
getPackageVersions() {
if (!this.packageEntity.versions) {
// this.fetchPackageVersions();
}
},
async deletePackage() { async deletePackage() {
const { data } = await this.$apollo.mutate({ const { data } = await this.$apollo.mutate({
mutation: destroyPackageMutation, mutation: destroyPackageMutation,
...@@ -329,24 +324,13 @@ export default { ...@@ -329,24 +324,13 @@ export default {
</p> </p>
</gl-tab> </gl-tab>
<gl-tab <gl-tab :title="__('Other versions')" title-item-class="js-versions-tab">
:title="__('Other versions')"
title-item-class="js-versions-tab"
@click="getPackageVersions"
>
<template v-if="isLoading && !hasVersions"> <template v-if="isLoading && !hasVersions">
<packages-list-loader /> <packages-list-loader />
</template> </template>
<template v-else-if="hasVersions"> <template v-else-if="hasVersions">
<!-- <package-list-row <version-row v-for="v in packageEntity.versions.nodes" :key="v.id" :package-entity="v" />
v-for="v in packageEntity.versions"
:key="v.id"
:package-entity="{ name: packageEntity.name, ...v }"
:package-link="v.id.toString()"
:disable-delete="true"
:show-package-type="false"
/> -->
</template> </template>
<p v-else class="gl-mt-3" data-testid="no-versions-message"> <p v-else class="gl-mt-3" data-testid="no-versions-message">
......
<script>
import { GlLink, GlSprintf, GlTruncate } from '@gitlab/ui';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import PackageTags from '~/packages/shared/components/package_tags.vue';
import PublishMethod from '~/packages/shared/components/publish_method.vue';
import ListItem from '~/vue_shared/components/registry/list_item.vue';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import { PACKAGE_DEFAULT_STATUS } from '../../constants';
export default {
name: 'PackageListRow',
components: {
GlLink,
GlSprintf,
GlTruncate,
PackageTags,
PublishMethod,
ListItem,
TimeAgoTooltip,
},
props: {
packageEntity: {
type: Object,
required: true,
},
},
computed: {
packageLink() {
return `${getIdFromGraphQLId(this.packageEntity.id)}`;
},
disabledRow() {
return this.packageEntity.status && this.packageEntity.status !== PACKAGE_DEFAULT_STATUS;
},
},
};
</script>
<template>
<list-item :disabled="disabledRow">
<template #left-primary>
<div class="gl-display-flex gl-align-items-center gl-mr-3 gl-min-w-0">
<gl-link :href="packageLink" class="gl-text-body gl-min-w-0" :disabled="disabledRow">
<gl-truncate :text="packageEntity.name" />
</gl-link>
<package-tags
v-if="packageEntity.tags.nodes && packageEntity.tags.nodes.length"
class="gl-ml-3"
:tags="packageEntity.tags.nodes"
hide-label
:tag-display-limit="1"
/>
</div>
</template>
<template #left-secondary>
{{ packageEntity.version }}
</template>
<template #right-primary>
<publish-method :package-entity="packageEntity" />
</template>
<template #right-secondary>
<gl-sprintf :message="__('Created %{timestamp}')">
<template #timestamp>
<time-ago-tooltip :time="packageEntity.createdAt" />
</template>
</gl-sprintf>
</template>
</list-item>
</template>
...@@ -79,10 +79,10 @@ export const FETCH_PACKAGE_DETAILS_ERROR_MESSAGE = s__( ...@@ -79,10 +79,10 @@ export const FETCH_PACKAGE_DETAILS_ERROR_MESSAGE = s__(
'PackageRegistry|Failed to load the package data', 'PackageRegistry|Failed to load the package data',
); );
export const PACKAGE_ERROR_STATUS = 'error'; export const PACKAGE_ERROR_STATUS = 'ERROR';
export const PACKAGE_DEFAULT_STATUS = 'default'; export const PACKAGE_DEFAULT_STATUS = 'DEFAULT';
export const PACKAGE_HIDDEN_STATUS = 'hidden'; export const PACKAGE_HIDDEN_STATUS = 'HIDDEN';
export const PACKAGE_PROCESSING_STATUS = 'processing'; export const PACKAGE_PROCESSING_STATUS = 'PROCESSING';
export const NPM_PACKAGE_MANAGER = 'npm'; export const NPM_PACKAGE_MANAGER = 'npm';
export const YARN_PACKAGE_MANAGER = 'yarn'; export const YARN_PACKAGE_MANAGER = 'yarn';
...@@ -7,7 +7,10 @@ query getPackageDetails($id: ID!) { ...@@ -7,7 +7,10 @@ query getPackageDetails($id: ID!) {
createdAt createdAt
updatedAt updatedAt
status status
tags { project {
path
}
tags(first: 10) {
nodes { nodes {
id id
name name
...@@ -42,6 +45,21 @@ query getPackageDetails($id: ID!) { ...@@ -42,6 +45,21 @@ query getPackageDetails($id: ID!) {
downloadPath downloadPath
} }
} }
versions(first: 100) {
nodes {
id
name
createdAt
version
status
tags(first: 1) {
nodes {
id
name
}
}
}
}
metadata { metadata {
... on ComposerMetadata { ... on ComposerMetadata {
targetSha targetSha
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`VersionRow renders 1`] = `
<div
class="gl-display-flex gl-flex-direction-column gl-border-b-solid gl-border-t-solid gl-border-t-1 gl-border-b-1 gl-border-t-transparent gl-border-b-gray-100"
>
<div
class="gl-display-flex gl-align-items-center gl-py-3 gl-px-5"
>
<!---->
<div
class="gl-display-flex gl-xs-flex-direction-column gl-justify-content-space-between gl-align-items-stretch gl-flex-grow-1"
>
<div
class="gl-display-flex gl-flex-direction-column gl-xs-mb-3 gl-min-w-0 gl-flex-grow-1"
>
<div
class="gl-display-flex gl-align-items-center gl-text-body gl-font-weight-bold gl-min-h-6 gl-min-w-0"
>
<div
class="gl-display-flex gl-align-items-center gl-mr-3 gl-min-w-0"
>
<gl-link-stub
class="gl-text-body gl-min-w-0"
href="243"
>
<span
class="gl-truncate"
title="@gitlab-org/package-15"
>
<span
class="gl-truncate-end"
>
@gitlab-org/package-15
</span>
</span>
</gl-link-stub>
<package-tags-stub
class="gl-ml-3"
hidelabel="true"
tagdisplaylimit="1"
tags="[object Object],[object Object],[object Object]"
/>
</div>
<!---->
</div>
<div
class="gl-display-flex gl-align-items-center gl-text-gray-500 gl-min-h-6 gl-min-w-0 gl-flex-grow-1"
>
1.0.1
</div>
</div>
<div
class="gl-display-flex gl-flex-direction-column gl-sm-align-items-flex-end gl-justify-content-space-between gl-text-gray-500 gl-flex-shrink-0"
>
<div
class="gl-display-flex gl-align-items-center gl-sm-text-body gl-sm-font-weight-bold gl-min-h-6"
>
<publish-method-stub
packageentity="[object Object]"
/>
</div>
<div
class="gl-display-flex gl-align-items-center gl-min-h-6"
>
Created
<time-ago-tooltip-stub
cssclass=""
time="2021-08-10T09:33:54Z"
tooltipplacement="top"
/>
</div>
</div>
</div>
<!---->
</div>
<div
class="gl-display-flex"
>
<div
class="gl-w-7"
/>
<!---->
<div
class="gl-w-9"
/>
</div>
</div>
`;
...@@ -14,6 +14,7 @@ import InstallationCommands from '~/packages_and_registries/package_registry/com ...@@ -14,6 +14,7 @@ import InstallationCommands from '~/packages_and_registries/package_registry/com
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';
import PackageTitle from '~/packages_and_registries/package_registry/components/details/package_title.vue'; import PackageTitle from '~/packages_and_registries/package_registry/components/details/package_title.vue';
import VersionRow from '~/packages_and_registries/package_registry/components/details/version_row.vue';
import { import {
FETCH_PACKAGE_DETAILS_ERROR_MESSAGE, FETCH_PACKAGE_DETAILS_ERROR_MESSAGE,
DELETE_PACKAGE_ERROR_MESSAGE, DELETE_PACKAGE_ERROR_MESSAGE,
...@@ -28,6 +29,7 @@ import getPackageDetails from '~/packages_and_registries/package_registry/graphq ...@@ -28,6 +29,7 @@ import getPackageDetails from '~/packages_and_registries/package_registry/graphq
import { import {
packageDetailsQuery, packageDetailsQuery,
packageData, packageData,
packageVersions,
emptyPackageDetailsQuery, emptyPackageDetailsQuery,
packageDestroyMutation, packageDestroyMutation,
packageDestroyMutationError, packageDestroyMutationError,
...@@ -96,6 +98,8 @@ describe('PackagesApp', () => { ...@@ -96,6 +98,8 @@ describe('PackagesApp', () => {
const findDeleteButton = () => wrapper.findByTestId('delete-package'); const findDeleteButton = () => wrapper.findByTestId('delete-package');
const findPackageFiles = () => wrapper.findComponent(PackageFiles); const findPackageFiles = () => wrapper.findComponent(PackageFiles);
const findDeleteFileModal = () => wrapper.findByTestId('delete-file-modal'); const findDeleteFileModal = () => wrapper.findByTestId('delete-file-modal');
const findVersionRows = () => wrapper.findAllComponents(VersionRow);
const noVersionsMessage = () => wrapper.findByTestId('no-versions-message');
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
...@@ -362,4 +366,39 @@ describe('PackagesApp', () => { ...@@ -362,4 +366,39 @@ describe('PackagesApp', () => {
}); });
}); });
}); });
describe('versions', () => {
it('displays the correct version count when the package has versions', async () => {
createComponent();
await waitForPromises();
expect(findVersionRows()).toHaveLength(packageVersions().length);
});
it('binds the correct props', async () => {
const [versionPackage] = packageVersions();
// eslint-disable-next-line no-underscore-dangle
delete versionPackage.__typename;
delete versionPackage.tags;
createComponent();
await waitForPromises();
expect(findVersionRows().at(0).props()).toMatchObject({
packageEntity: expect.objectContaining(versionPackage),
});
});
it('displays the no versions message when there are none', async () => {
createComponent({
resolver: jest.fn().mockResolvedValue(packageDetailsQuery({ versions: { nodes: [] } })),
});
await waitForPromises();
expect(noVersionsMessage().exists()).toBe(true);
});
});
}); });
import { GlLink, GlSprintf, GlTruncate } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import PackageTags from '~/packages/shared/components/package_tags.vue';
import PublishMethod from '~/packages/shared/components/publish_method.vue';
import VersionRow from '~/packages_and_registries/package_registry/components/details/version_row.vue';
import ListItem from '~/vue_shared/components/registry/list_item.vue';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import { packageVersions } from '../../mock_data';
const packageVersion = packageVersions()[0];
describe('VersionRow', () => {
let wrapper;
const findListItem = () => wrapper.findComponent(ListItem);
const findLink = () => wrapper.findComponent(GlLink);
const findPackageTags = () => wrapper.findComponent(PackageTags);
const findPublishMethod = () => wrapper.findComponent(PublishMethod);
const findTimeAgoTooltip = () => wrapper.findComponent(TimeAgoTooltip);
function createComponent(packageEntity = packageVersion) {
wrapper = shallowMountExtended(VersionRow, {
propsData: {
packageEntity,
},
stubs: {
ListItem,
GlSprintf,
GlTruncate,
},
});
}
afterEach(() => {
wrapper.destroy();
});
it('renders', () => {
createComponent();
expect(wrapper.element).toMatchSnapshot();
});
it('has a link to the version detail', () => {
createComponent();
expect(findLink().attributes('href')).toBe(`${getIdFromGraphQLId(packageVersion.id)}`);
expect(findLink().text()).toBe(packageVersion.name);
});
it('has the version of the package', () => {
createComponent();
expect(wrapper.text()).toContain(packageVersion.version);
});
it('has a package tags component', () => {
createComponent();
expect(findPackageTags().props('tags')).toBe(packageVersion.tags.nodes);
});
it('has a publish method component', () => {
createComponent();
expect(findPublishMethod().props('packageEntity')).toBe(packageVersion);
});
it('has a time-ago tooltip', () => {
createComponent();
expect(findTimeAgoTooltip().props('time')).toBe(packageVersion.createdAt);
});
describe('disabled status', () => {
it('disables the list item', () => {
createComponent({ ...packageVersion, status: 'something' });
expect(findListItem().props('disabled')).toBe(true);
});
it('disables the link', () => {
createComponent({ ...packageVersion, status: 'something' });
expect(findLink().attributes('disabled')).toBe('true');
});
});
});
...@@ -51,6 +51,27 @@ export const packageFiles = () => [ ...@@ -51,6 +51,27 @@ export const packageFiles = () => [
}, },
]; ];
export const packageVersions = () => [
{
createdAt: '2021-08-10T09:33:54Z',
id: 'gid://gitlab/Packages::Package/243',
name: '@gitlab-org/package-15',
status: 'DEFAULT',
tags: { nodes: packageTags() },
version: '1.0.1',
__typename: 'Package',
},
{
createdAt: '2021-08-10T09:33:54Z',
id: 'gid://gitlab/Packages::Package/244',
name: '@gitlab-org/package-15',
status: 'DEFAULT',
tags: { nodes: packageTags() },
version: '1.0.2',
__typename: 'Package',
},
];
export const packageData = (extend) => ({ export const packageData = (extend) => ({
id: 'gid://gitlab/Packages::Package/111', id: 'gid://gitlab/Packages::Package/111',
name: '@gitlab-org/package-15', name: '@gitlab-org/package-15',
...@@ -105,6 +126,9 @@ export const packageDetailsQuery = (extendPackage) => ({ ...@@ -105,6 +126,9 @@ export const packageDetailsQuery = (extendPackage) => ({
...mavenMetadata(), ...mavenMetadata(),
...nugetMetadata(), ...nugetMetadata(),
}, },
project: {
path: 'projectPath',
},
tags: { tags: {
nodes: packageTags(), nodes: packageTags(),
__typename: 'PackageTagConnection', __typename: 'PackageTagConnection',
...@@ -117,6 +141,10 @@ export const packageDetailsQuery = (extendPackage) => ({ ...@@ -117,6 +141,10 @@ export const packageDetailsQuery = (extendPackage) => ({
nodes: packageFiles(), nodes: packageFiles(),
__typename: 'PackageFileConnection', __typename: 'PackageFileConnection',
}, },
versions: {
nodes: packageVersions(),
__typename: 'PackageConnection',
},
__typename: 'PackageDetailsType', __typename: 'PackageDetailsType',
...extendPackage, ...extendPackage,
}, },
......
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