Commit 7c85f127 authored by Olena Horal-Koretska's avatar Olena Horal-Koretska

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

Refactor history component to new apollo aproach

See merge request gitlab-org/gitlab!66749
parents 15cf698b 869367a4
...@@ -23,10 +23,10 @@ import { s__, __ } from '~/locale'; ...@@ -23,10 +23,10 @@ import { s__, __ } from '~/locale';
// import DependencyRow from '~/packages/details/components/dependency_row.vue'; // import DependencyRow from '~/packages/details/components/dependency_row.vue';
// import InstallationCommands from '~/packages/details/components/installation_commands.vue'; // import InstallationCommands from '~/packages/details/components/installation_commands.vue';
// import PackageFiles from '~/packages/details/components/package_files.vue'; // import PackageFiles from '~/packages/details/components/package_files.vue';
// import PackageHistory from '~/packages/details/components/package_history.vue';
// import PackageListRow from '~/packages/shared/components/package_list_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 PackageHistory from '~/packages_and_registries/package_registry/components/details/package_history.vue';
import { import {
PACKAGE_TYPE_NUGET, PACKAGE_TYPE_NUGET,
PACKAGE_TYPE_COMPOSER, PACKAGE_TYPE_COMPOSER,
...@@ -60,7 +60,7 @@ export default { ...@@ -60,7 +60,7 @@ export default {
PackagesListLoader, PackagesListLoader,
// PackageListRow, // PackageListRow,
// DependencyRow, // DependencyRow,
// PackageHistory, PackageHistory,
// AdditionalMetadata, // AdditionalMetadata,
// InstallationCommands, // InstallationCommands,
// PackageFiles, // PackageFiles,
...@@ -124,10 +124,10 @@ export default { ...@@ -124,10 +124,10 @@ export default {
return this.packageEntity.packageFiles; return this.packageEntity.packageFiles;
}, },
isLoading() { isLoading() {
return this.$apollo.queries.package; return this.$apollo.queries.packageEntity.loading;
}, },
isValidPackage() { isValidPackage() {
return Boolean(this.packageEntity?.name); return this.isLoading || Boolean(this.packageEntity?.name);
}, },
tracking() { tracking() {
return { return {
...@@ -237,10 +237,10 @@ export default { ...@@ -237,10 +237,10 @@ export default {
<gl-tabs> <gl-tabs>
<gl-tab :title="__('Detail')"> <gl-tab :title="__('Detail')">
<div data-qa-selector="package_information_content"> <div v-if="!isLoading" data-qa-selector="package_information_content">
<!-- <package-history :package-entity="packageEntity" :project-name="projectName" /> <package-history :package-entity="packageEntity" :project-name="projectName" />
<installation-commands <!-- <installation-commands
:package-entity="packageEntity" :package-entity="packageEntity"
:npm-path="npmPath" :npm-path="npmPath"
:npm-help-path="npmHelpPath" :npm-help-path="npmHelpPath"
......
<script> <script>
import { GlLink, GlSprintf } from '@gitlab/ui'; import { GlLink, GlSprintf } from '@gitlab/ui';
import { first } from 'lodash'; import { first } from 'lodash';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { truncateSha } from '~/lib/utils/text_utility'; import { truncateSha } from '~/lib/utils/text_utility';
import { s__, n__ } from '~/locale'; import { s__, n__ } from '~/locale';
import { HISTORY_PIPELINES_LIMIT } from '~/packages/details/constants'; import { HISTORY_PIPELINES_LIMIT } from '~/packages/details/constants';
...@@ -45,7 +46,7 @@ export default { ...@@ -45,7 +46,7 @@ export default {
}, },
computed: { computed: {
pipelines() { pipelines() {
return this.packageEntity.pipelines || []; return this.packageEntity?.pipelines?.nodes || [];
}, },
firstPipeline() { firstPipeline() {
return first(this.pipelines); return first(this.pipelines);
...@@ -71,6 +72,9 @@ export default { ...@@ -71,6 +72,9 @@ export default {
truncate(value) { truncate(value) {
return truncateSha(value); return truncateSha(value);
}, },
convertToBaseId(value) {
return getIdFromGraphQLId(value);
},
}, },
}; };
</script> </script>
...@@ -88,7 +92,7 @@ export default { ...@@ -88,7 +92,7 @@ export default {
<strong>{{ packageEntity.version }}</strong> <strong>{{ packageEntity.version }}</strong>
</template> </template>
<template #datetime> <template #datetime>
<time-ago-tooltip :time="packageEntity.created_at" /> <time-ago-tooltip :time="packageEntity.createdAt" />
</template> </template>
</gl-sprintf> </gl-sprintf>
</history-item> </history-item>
...@@ -98,9 +102,7 @@ export default { ...@@ -98,9 +102,7 @@ export default {
<history-item icon="commit" data-testid="first-pipeline-commit"> <history-item icon="commit" data-testid="first-pipeline-commit">
<gl-sprintf :message="$options.i18n.createdByCommitText"> <gl-sprintf :message="$options.i18n.createdByCommitText">
<template #link> <template #link>
<gl-link :href="firstPipeline.project.commit_url" <gl-link :href="firstPipeline.commitPath">#{{ truncate(firstPipeline.sha) }}</gl-link>
>#{{ truncate(firstPipeline.sha) }}</gl-link
>
</template> </template>
<template #branch> <template #branch>
<strong>{{ firstPipeline.ref }}</strong> <strong>{{ firstPipeline.ref }}</strong>
...@@ -110,10 +112,10 @@ export default { ...@@ -110,10 +112,10 @@ export default {
<history-item icon="pipeline" data-testid="first-pipeline-pipeline"> <history-item icon="pipeline" data-testid="first-pipeline-pipeline">
<gl-sprintf :message="$options.i18n.createdByPipelineText"> <gl-sprintf :message="$options.i18n.createdByPipelineText">
<template #link> <template #link>
<gl-link :href="firstPipeline.project.pipeline_url">#{{ firstPipeline.id }}</gl-link> <gl-link :href="firstPipeline.path">#{{ convertToBaseId(firstPipeline.id) }}</gl-link>
</template> </template>
<template #datetime> <template #datetime>
<time-ago-tooltip :time="firstPipeline.created_at" /> <time-ago-tooltip :time="firstPipeline.createdAt" />
</template> </template>
<template #author>{{ firstPipeline.user.name }}</template> <template #author>{{ firstPipeline.user.name }}</template>
</gl-sprintf> </gl-sprintf>
...@@ -127,7 +129,7 @@ export default { ...@@ -127,7 +129,7 @@ export default {
<strong>{{ projectName }}</strong> <strong>{{ projectName }}</strong>
</template> </template>
<template #datetime> <template #datetime>
<time-ago-tooltip :time="packageEntity.created_at" /> <time-ago-tooltip :time="packageEntity.createdAt" />
</template> </template>
</gl-sprintf> </gl-sprintf>
</history-item> </history-item>
...@@ -149,16 +151,16 @@ export default { ...@@ -149,16 +151,16 @@ export default {
> >
<gl-sprintf :message="$options.i18n.combinedUpdateText"> <gl-sprintf :message="$options.i18n.combinedUpdateText">
<template #link> <template #link>
<gl-link :href="pipeline.project.commit_url">#{{ truncate(pipeline.sha) }}</gl-link> <gl-link :href="pipeline.commitPath">#{{ truncate(pipeline.sha) }}</gl-link>
</template> </template>
<template #branch> <template #branch>
<strong>{{ pipeline.ref }}</strong> <strong>{{ pipeline.ref }}</strong>
</template> </template>
<template #pipeline> <template #pipeline>
<gl-link :href="pipeline.project.pipeline_url">#{{ pipeline.id }}</gl-link> <gl-link :href="pipeline.path">#{{ convertToBaseId(pipeline.id) }}</gl-link>
</template> </template>
<template #datetime> <template #datetime>
<time-ago-tooltip :time="pipeline.created_at" /> <time-ago-tooltip :time="pipeline.createdAt" />
</template> </template>
</gl-sprintf> </gl-sprintf>
</history-item> </history-item>
......
...@@ -15,13 +15,22 @@ query getPackageDetails($id: ID!) { ...@@ -15,13 +15,22 @@ query getPackageDetails($id: ID!) {
} }
pipelines(first: 3) { pipelines(first: 3) {
nodes { nodes {
ref
id
sha
createdAt
commitPath
path
user {
name
}
project { project {
name name
webUrl webUrl
} }
} }
} }
packageFiles(first: 1000) { packageFiles(first: 100) {
nodes { nodes {
id id
fileMd5 fileMd5
......
...@@ -6,10 +6,11 @@ import waitForPromises from 'helpers/wait_for_promises'; ...@@ -6,10 +6,11 @@ import waitForPromises from 'helpers/wait_for_promises';
import createFlash from '~/flash'; import createFlash from '~/flash';
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 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 { FETCH_PACKAGE_DETAILS_ERROR_MESSAGE } from '~/packages_and_registries/package_registry/constants'; import { FETCH_PACKAGE_DETAILS_ERROR_MESSAGE } from '~/packages_and_registries/package_registry/constants';
import getPackageDetails from '~/packages_and_registries/package_registry/graphql/queries/get_package_details.query.graphql'; import getPackageDetails from '~/packages_and_registries/package_registry/graphql/queries/get_package_details.query.graphql';
import { packageDetailsQuery, packageData } from '../../mock_data'; import { packageDetailsQuery, packageData, emptyPackageDetailsQuery } from '../../mock_data';
jest.mock('~/flash'); jest.mock('~/flash');
...@@ -19,6 +20,18 @@ describe('PackagesApp', () => { ...@@ -19,6 +20,18 @@ describe('PackagesApp', () => {
let wrapper; let wrapper;
let apolloProvider; let apolloProvider;
const provide = {
packageId: '111',
titleComponent: 'PackageTitle',
projectName: 'projectName',
canDelete: 'canDelete',
svgPath: 'svgPath',
npmPath: 'npmPath',
npmHelpPath: 'npmHelpPath',
projectListUrl: 'projectListUrl',
groupListUrl: 'groupListUrl',
};
function createComponent({ resolver = jest.fn().mockResolvedValue(packageDetailsQuery()) } = {}) { function createComponent({ resolver = jest.fn().mockResolvedValue(packageDetailsQuery()) } = {}) {
localVue.use(VueApollo); localVue.use(VueApollo);
...@@ -28,29 +41,22 @@ describe('PackagesApp', () => { ...@@ -28,29 +41,22 @@ describe('PackagesApp', () => {
wrapper = shallowMount(PackagesApp, { wrapper = shallowMount(PackagesApp, {
localVue, localVue,
apolloProvider, apolloProvider,
provide: { provide,
packageId: '111',
titleComponent: 'PackageTitle',
projectName: 'projectName',
canDelete: 'canDelete',
svgPath: 'svgPath',
npmPath: 'npmPath',
npmHelpPath: 'npmHelpPath',
projectListUrl: 'projectListUrl',
groupListUrl: 'groupListUrl',
},
}); });
} }
const findEmptyState = () => wrapper.findComponent(GlEmptyState); const findEmptyState = () => wrapper.findComponent(GlEmptyState);
const findPackageTitle = () => wrapper.findComponent(PackageTitle); const findPackageTitle = () => wrapper.findComponent(PackageTitle);
const findPackageHistory = () => wrapper.findComponent(PackageHistory);
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
}); });
it('renders an empty state component', () => { it('renders an empty state component', async () => {
createComponent(); createComponent({ resolver: jest.fn().mockResolvedValue(emptyPackageDetailsQuery) });
await waitForPromises();
expect(findEmptyState().exists()).toBe(true); expect(findEmptyState().exists()).toBe(true);
}); });
...@@ -77,4 +83,16 @@ describe('PackagesApp', () => { ...@@ -77,4 +83,16 @@ describe('PackagesApp', () => {
}), }),
); );
}); });
it('renders history and has the right props', async () => {
createComponent();
await waitForPromises();
expect(findPackageHistory().exists()).toBe(true);
expect(findPackageHistory().props()).toMatchObject({
packageEntity: expect.objectContaining(packageData()),
projectName: provide.projectName,
});
});
}); });
import { GlLink, GlSprintf } from '@gitlab/ui'; import { GlLink, GlSprintf } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { stubComponent } from 'helpers/stub_component'; import { stubComponent } from 'helpers/stub_component';
import { mavenPackage, mockPipelineInfo } from 'jest/packages/mock_data'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import {
packageData,
packagePipelines,
} from 'jest/packages_and_registries/package_registry/mock_data';
import { HISTORY_PIPELINES_LIMIT } from '~/packages/details/constants'; import { HISTORY_PIPELINES_LIMIT } from '~/packages/details/constants';
import component from '~/packages_and_registries/package_registry/components/details/package_history.vue'; import component from '~/packages_and_registries/package_registry/components/details/package_history.vue';
import HistoryItem from '~/vue_shared/components/registry/history_item.vue'; import HistoryItem from '~/vue_shared/components/registry/history_item.vue';
...@@ -11,14 +14,16 @@ describe('Package History', () => { ...@@ -11,14 +14,16 @@ describe('Package History', () => {
let wrapper; let wrapper;
const defaultProps = { const defaultProps = {
projectName: 'baz project', projectName: 'baz project',
packageEntity: { ...mavenPackage }, packageEntity: { ...packageData() },
}; };
const [onePipeline] = packagePipelines();
const createPipelines = (amount) => const createPipelines = (amount) =>
[...Array(amount)].map((x, index) => ({ ...mockPipelineInfo, id: index + 1 })); [...Array(amount)].map((x, index) => packagePipelines({ id: index + 1 })[0]);
const mountComponent = (props) => { const mountComponent = (props) => {
wrapper = shallowMount(component, { wrapper = shallowMountExtended(component, {
propsData: { ...defaultProps, ...props }, propsData: { ...defaultProps, ...props },
stubs: { stubs: {
HistoryItem: stubComponent(HistoryItem, { HistoryItem: stubComponent(HistoryItem, {
...@@ -31,14 +36,13 @@ describe('Package History', () => { ...@@ -31,14 +36,13 @@ describe('Package History', () => {
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
wrapper = null;
}); });
const findHistoryElement = (testId) => wrapper.find(`[data-testid="${testId}"]`); const findHistoryElement = (testId) => wrapper.findByTestId(testId);
const findElementLink = (container) => container.find(GlLink); const findElementLink = (container) => container.findComponent(GlLink);
const findElementTimeAgo = (container) => container.find(TimeAgoTooltip); const findElementTimeAgo = (container) => container.findComponent(TimeAgoTooltip);
const findTitle = () => wrapper.find('[data-testid="title"]'); const findTitle = () => wrapper.findByTestId('title');
const findTimeline = () => wrapper.find('[data-testid="timeline"]'); const findTimeline = () => wrapper.findByTestId('timeline');
it('has the correct title', () => { it('has the correct title', () => {
mountComponent(); mountComponent();
...@@ -59,23 +63,25 @@ describe('Package History', () => { ...@@ -59,23 +63,25 @@ describe('Package History', () => {
expect.arrayContaining(['timeline', 'main-notes-list', 'notes']), expect.arrayContaining(['timeline', 'main-notes-list', 'notes']),
); );
}); });
describe.each` describe.each`
name | amount | icon | text | timeAgoTooltip | link name | amount | icon | text | timeAgoTooltip | link
${'created-on'} | ${HISTORY_PIPELINES_LIMIT + 2} | ${'clock'} | ${'Test package version 1.0.0 was first created'} | ${mavenPackage.created_at} | ${null} ${'created-on'} | ${HISTORY_PIPELINES_LIMIT + 2} | ${'clock'} | ${'@gitlab-org/package-15 version 1.0.0 was first created'} | ${packageData().createdAt} | ${null}
${'first-pipeline-commit'} | ${HISTORY_PIPELINES_LIMIT + 2} | ${'commit'} | ${'Created by commit #sha-baz on branch branch-name'} | ${null} | ${mockPipelineInfo.project.commit_url} ${'first-pipeline-commit'} | ${HISTORY_PIPELINES_LIMIT + 2} | ${'commit'} | ${'Created by commit #b83d6e39 on branch master'} | ${null} | ${onePipeline.commitPath}
${'first-pipeline-pipeline'} | ${HISTORY_PIPELINES_LIMIT + 2} | ${'pipeline'} | ${'Built by pipeline #1 triggered by foo'} | ${mockPipelineInfo.created_at} | ${mockPipelineInfo.project.pipeline_url} ${'first-pipeline-pipeline'} | ${HISTORY_PIPELINES_LIMIT + 2} | ${'pipeline'} | ${'Built by pipeline #1 triggered by Administrator'} | ${onePipeline.createdAt} | ${onePipeline.path}
${'published'} | ${HISTORY_PIPELINES_LIMIT + 2} | ${'package'} | ${'Published to the baz project Package Registry'} | ${mavenPackage.created_at} | ${null} ${'published'} | ${HISTORY_PIPELINES_LIMIT + 2} | ${'package'} | ${'Published to the baz project Package Registry'} | ${packageData().createdAt} | ${null}
${'archived'} | ${HISTORY_PIPELINES_LIMIT + 2} | ${'history'} | ${'Package has 1 archived update'} | ${null} | ${null} ${'archived'} | ${HISTORY_PIPELINES_LIMIT + 2} | ${'history'} | ${'Package has 1 archived update'} | ${null} | ${null}
${'archived'} | ${HISTORY_PIPELINES_LIMIT + 3} | ${'history'} | ${'Package has 2 archived updates'} | ${null} | ${null} ${'archived'} | ${HISTORY_PIPELINES_LIMIT + 3} | ${'history'} | ${'Package has 2 archived updates'} | ${null} | ${null}
${'pipeline-entry'} | ${HISTORY_PIPELINES_LIMIT + 2} | ${'pencil'} | ${'Package updated by commit #sha-baz on branch branch-name, built by pipeline #3, and published to the registry'} | ${mavenPackage.created_at} | ${mockPipelineInfo.project.commit_url} ${'pipeline-entry'} | ${HISTORY_PIPELINES_LIMIT + 2} | ${'pencil'} | ${'Package updated by commit #b83d6e39 on branch master, built by pipeline #3, and published to the registry'} | ${packageData().createdAt} | ${onePipeline.commitPath}
`( `(
'with $amount pipelines history element $name', 'with $amount pipelines history element $name',
({ name, icon, text, timeAgoTooltip, link, amount }) => { ({ name, icon, text, timeAgoTooltip, link, amount }) => {
let element; let element;
beforeEach(() => { beforeEach(() => {
const packageEntity = { ...packageData(), pipelines: { nodes: createPipelines(amount) } };
mountComponent({ mountComponent({
packageEntity: { ...mavenPackage, pipelines: createPipelines(amount) }, packageEntity,
}); });
element = findHistoryElement(name); element = findHistoryElement(name);
}); });
......
...@@ -6,11 +6,21 @@ export const packageTags = () => [ ...@@ -6,11 +6,21 @@ export const packageTags = () => [
export const packagePipelines = (extend) => [ export const packagePipelines = (extend) => [
{ {
commitPath: '/namespace14/project14/-/commit/b83d6e391c22777fca1ed3012fce84f633d7fed0',
createdAt: '2020-08-17T14:23:32Z',
id: 'gid://gitlab/Ci::Pipeline/36',
path: '/namespace14/project14/-/pipelines/36',
name: 'project14',
ref: 'master',
sha: 'b83d6e391c22777fca1ed3012fce84f633d7fed0',
project: { project: {
name: 'project14', name: 'project14',
webUrl: 'http://gdk.test:3000/namespace14/project14', webUrl: 'http://gdk.test:3000/namespace14/project14',
__typename: 'Project', __typename: 'Project',
}, },
user: {
name: 'Administrator',
},
...extend, ...extend,
__typename: 'Pipeline', __typename: 'Pipeline',
}, },
...@@ -68,3 +78,11 @@ export const packageDetailsQuery = () => ({ ...@@ -68,3 +78,11 @@ export const packageDetailsQuery = () => ({
}, },
}, },
}); });
export const emptyPackageDetailsQuery = () => ({
data: {
package: {
__typename: 'PackageDetailsType',
},
},
});
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