Commit 14fb668e authored by Olena Horal-Koretska's avatar Olena Horal-Koretska

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

Refactor package metadata to apollo aproach

See merge request gitlab-org/gitlab!67122
parents c63d8bdb fce54015
<script> <script>
import { GlLink, GlSprintf } from '@gitlab/ui'; import { GlLink, GlSprintf } from '@gitlab/ui';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import { PackageType } from '~/packages/shared/constants'; import {
PACKAGE_TYPE_NUGET,
PACKAGE_TYPE_CONAN,
PACKAGE_TYPE_MAVEN,
} from '~/packages_and_registries/package_registry/constants';
import DetailsRow from '~/vue_shared/components/registry/details_row.vue'; import DetailsRow from '~/vue_shared/components/registry/details_row.vue';
export default { export default {
...@@ -25,12 +29,18 @@ export default { ...@@ -25,12 +29,18 @@ export default {
}, },
computed: { computed: {
showMetadata() { showMetadata() {
const visibilityConditions = { return [PACKAGE_TYPE_NUGET, PACKAGE_TYPE_CONAN, PACKAGE_TYPE_MAVEN].includes(
[PackageType.NUGET]: this.packageEntity.nuget_metadatum, this.packageEntity.packageType,
[PackageType.CONAN]: this.packageEntity.conan_metadatum, );
[PackageType.MAVEN]: this.packageEntity.maven_metadatum, },
}; showNugetMetadata() {
return visibilityConditions[this.packageEntity.package_type]; return this.packageEntity.packageType === PACKAGE_TYPE_NUGET;
},
showConanMetadata() {
return this.packageEntity.packageType === PACKAGE_TYPE_CONAN;
},
showMavenMetadata() {
return this.packageEntity.packageType === PACKAGE_TYPE_MAVEN;
}, },
}, },
}; };
...@@ -41,12 +51,12 @@ export default { ...@@ -41,12 +51,12 @@ export default {
<h3 class="gl-font-lg" data-testid="title">{{ __('Additional Metadata') }}</h3> <h3 class="gl-font-lg" data-testid="title">{{ __('Additional Metadata') }}</h3>
<div class="gl-bg-gray-50 gl-inset-border-1-gray-100 gl-rounded-base" data-testid="main"> <div class="gl-bg-gray-50 gl-inset-border-1-gray-100 gl-rounded-base" data-testid="main">
<template v-if="packageEntity.nuget_metadatum"> <template v-if="showNugetMetadata">
<details-row icon="project" padding="gl-p-4" dashed data-testid="nuget-source"> <details-row icon="project" padding="gl-p-4" dashed data-testid="nuget-source">
<gl-sprintf :message="$options.i18n.sourceText"> <gl-sprintf :message="$options.i18n.sourceText">
<template #link> <template #link>
<gl-link :href="packageEntity.nuget_metadatum.project_url" target="_blank">{{ <gl-link :href="packageEntity.metadata.projectUrl" target="_blank">{{
packageEntity.nuget_metadatum.project_url packageEntity.metadata.projectUrl
}}</gl-link> }}</gl-link>
</template> </template>
</gl-sprintf> </gl-sprintf>
...@@ -54,8 +64,8 @@ export default { ...@@ -54,8 +64,8 @@ export default {
<details-row icon="license" padding="gl-p-4" data-testid="nuget-license"> <details-row icon="license" padding="gl-p-4" data-testid="nuget-license">
<gl-sprintf :message="$options.i18n.licenseText"> <gl-sprintf :message="$options.i18n.licenseText">
<template #link> <template #link>
<gl-link :href="packageEntity.nuget_metadatum.license_url" target="_blank">{{ <gl-link :href="packageEntity.metadata.licenseUrl" target="_blank">{{
packageEntity.nuget_metadatum.license_url packageEntity.metadata.licenseUrl
}}</gl-link> }}</gl-link>
</template> </template>
</gl-sprintf> </gl-sprintf>
...@@ -63,28 +73,28 @@ export default { ...@@ -63,28 +73,28 @@ export default {
</template> </template>
<details-row <details-row
v-else-if="packageEntity.conan_metadatum" v-else-if="showConanMetadata"
icon="information-o" icon="information-o"
padding="gl-p-4" padding="gl-p-4"
data-testid="conan-recipe" data-testid="conan-recipe"
> >
<gl-sprintf :message="$options.i18n.recipeText"> <gl-sprintf :message="$options.i18n.recipeText">
<template #recipe>{{ packageEntity.name }}</template> <template #recipe>{{ packageEntity.metadata.recipe }}</template>
</gl-sprintf> </gl-sprintf>
</details-row> </details-row>
<template v-else-if="packageEntity.maven_metadatum"> <template v-else-if="showMavenMetadata">
<details-row icon="information-o" padding="gl-p-4" dashed data-testid="maven-app"> <details-row icon="information-o" padding="gl-p-4" dashed data-testid="maven-app">
<gl-sprintf :message="$options.i18n.appName"> <gl-sprintf :message="$options.i18n.appName">
<template #name> <template #name>
<strong>{{ packageEntity.maven_metadatum.app_name }}</strong> <strong>{{ packageEntity.metadata.appName }}</strong>
</template> </template>
</gl-sprintf> </gl-sprintf>
</details-row> </details-row>
<details-row icon="information-o" padding="gl-p-4" data-testid="maven-group"> <details-row icon="information-o" padding="gl-p-4" data-testid="maven-group">
<gl-sprintf :message="$options.i18n.appGroup"> <gl-sprintf :message="$options.i18n.appGroup">
<template #group> <template #group>
<strong>{{ packageEntity.maven_metadatum.app_group }}</strong> <strong>{{ packageEntity.metadata.appGroup }}</strong>
</template> </template>
</gl-sprintf> </gl-sprintf>
</details-row> </details-row>
......
...@@ -19,13 +19,13 @@ import { convertToGraphQLId } from '~/graphql_shared/utils'; ...@@ -19,13 +19,13 @@ 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 AdditionalMetadata from '~/packages/details/components/additional_metadata.vue';
// 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 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 AdditionalMetadata from '~/packages_and_registries/package_registry/components/details/additional_metadata.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 { import {
PACKAGE_TYPE_NUGET, PACKAGE_TYPE_NUGET,
...@@ -61,7 +61,7 @@ export default { ...@@ -61,7 +61,7 @@ export default {
// PackageListRow, // PackageListRow,
// DependencyRow, // DependencyRow,
PackageHistory, PackageHistory,
// AdditionalMetadata, AdditionalMetadata,
// InstallationCommands, // InstallationCommands,
// PackageFiles, // PackageFiles,
}, },
...@@ -244,9 +244,9 @@ export default { ...@@ -244,9 +244,9 @@ export default {
:package-entity="packageEntity" :package-entity="packageEntity"
:npm-path="npmPath" :npm-path="npmPath"
:npm-help-path="npmHelpPath" :npm-help-path="npmHelpPath"
/> /> -->
<additional-metadata :package-entity="packageEntity" /> --> <additional-metadata :package-entity="packageEntity" />
</div> </div>
<!-- <package-files <!-- <package-files
......
{
"__schema": {
"types": [
{
"kind": "UNION",
"name": "PackageMetadata",
"possibleTypes": [
{ "name": "ComposerMetadata" },
{ "name": "ConanMetadata" },
{ "name": "MavenMetadata" },
{ "name": "NugetMetadata" },
{ "name": "PypiMetadata" }
]
}
]
}
}
import { IntrospectionFragmentMatcher } from 'apollo-cache-inmemory';
import Vue from 'vue'; import Vue from 'vue';
import VueApollo from 'vue-apollo'; import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql'; import createDefaultClient from '~/lib/graphql';
import introspectionQueryResultData from './fragmentTypes.json';
const fragmentMatcher = new IntrospectionFragmentMatcher({
introspectionQueryResultData,
});
Vue.use(VueApollo); Vue.use(VueApollo);
...@@ -8,6 +14,9 @@ export const apolloProvider = new VueApollo({ ...@@ -8,6 +14,9 @@ export const apolloProvider = new VueApollo({
defaultClient: createDefaultClient( defaultClient: createDefaultClient(
{}, {},
{ {
cacheConfig: {
fragmentMatcher,
},
assumeImmutableResults: true, assumeImmutableResults: true,
}, },
), ),
......
...@@ -40,5 +40,35 @@ query getPackageDetails($id: ID!) { ...@@ -40,5 +40,35 @@ query getPackageDetails($id: ID!) {
size size
} }
} }
metadata {
... on ComposerMetadata {
targetSha
composerJson {
license
version
}
}
... on PypiMetadata {
requiredPython
}
... on ConanMetadata {
packageChannel
packageUsername
recipe
recipePath
}
... on MavenMetadata {
appName
appGroup
appVersion
path
}
... on NugetMetadata {
iconUrl
licenseUrl
projectUrl
}
}
} }
} }
import { GlLink, GlSprintf } from '@gitlab/ui'; import { GlLink, GlSprintf } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { mavenPackage, conanPackage, nugetPackage, npmPackage } from 'jest/packages/mock_data'; import {
conanMetadata,
mavenMetadata,
nugetMetadata,
packageData,
} from 'jest/packages_and_registries/package_registry/mock_data';
import component from '~/packages_and_registries/package_registry/components/details/additional_metadata.vue'; import component from '~/packages_and_registries/package_registry/components/details/additional_metadata.vue';
import {
PACKAGE_TYPE_NUGET,
PACKAGE_TYPE_CONAN,
PACKAGE_TYPE_MAVEN,
PACKAGE_TYPE_NPM,
} from '~/packages_and_registries/package_registry/constants';
import DetailsRow from '~/vue_shared/components/registry/details_row.vue'; import DetailsRow from '~/vue_shared/components/registry/details_row.vue';
const mavenPackage = { packageType: PACKAGE_TYPE_MAVEN, metadata: mavenMetadata() };
const conanPackage = { packageType: PACKAGE_TYPE_CONAN, metadata: conanMetadata() };
const nugetPackage = { packageType: PACKAGE_TYPE_NUGET, metadata: nugetMetadata() };
const npmPackage = { packageType: PACKAGE_TYPE_NPM, metadata: {} };
describe('Package Additional Metadata', () => { describe('Package Additional Metadata', () => {
let wrapper; let wrapper;
const defaultProps = { const defaultProps = {
packageEntity: { ...mavenPackage }, packageEntity: {
...packageData(mavenPackage),
},
}; };
const mountComponent = (props) => { const mountComponent = (props) => {
wrapper = shallowMount(component, { wrapper = shallowMountExtended(component, {
propsData: { ...defaultProps, ...props }, propsData: { ...defaultProps, ...props },
stubs: { stubs: {
DetailsRow, DetailsRow,
...@@ -25,14 +43,14 @@ describe('Package Additional Metadata', () => { ...@@ -25,14 +43,14 @@ describe('Package Additional Metadata', () => {
wrapper = null; wrapper = null;
}); });
const findTitle = () => wrapper.find('[data-testid="title"]'); const findTitle = () => wrapper.findByTestId('title');
const findMainArea = () => wrapper.find('[data-testid="main"]'); const findMainArea = () => wrapper.findByTestId('main');
const findNugetSource = () => wrapper.find('[data-testid="nuget-source"]'); const findNugetSource = () => wrapper.findByTestId('nuget-source');
const findNugetLicense = () => wrapper.find('[data-testid="nuget-license"]'); const findNugetLicense = () => wrapper.findByTestId('nuget-license');
const findConanRecipe = () => wrapper.find('[data-testid="conan-recipe"]'); const findConanRecipe = () => wrapper.findByTestId('conan-recipe');
const findMavenApp = () => wrapper.find('[data-testid="maven-app"]'); const findMavenApp = () => wrapper.findByTestId('maven-app');
const findMavenGroup = () => wrapper.find('[data-testid="maven-group"]'); const findMavenGroup = () => wrapper.findByTestId('maven-group');
const findElementLink = (container) => container.find(GlLink); const findElementLink = (container) => container.findComponent(GlLink);
it('has the correct title', () => { it('has the correct title', () => {
mountComponent(); mountComponent();
...@@ -43,27 +61,21 @@ describe('Package Additional Metadata', () => { ...@@ -43,27 +61,21 @@ describe('Package Additional Metadata', () => {
expect(title.text()).toBe('Additional Metadata'); expect(title.text()).toBe('Additional Metadata');
}); });
describe.each` it.each`
packageEntity | visible | metadata packageEntity | visible | packageType
${mavenPackage} | ${true} | ${'maven_metadatum'} ${mavenPackage} | ${true} | ${PACKAGE_TYPE_MAVEN}
${conanPackage} | ${true} | ${'conan_metadatum'} ${conanPackage} | ${true} | ${PACKAGE_TYPE_CONAN}
${nugetPackage} | ${true} | ${'nuget_metadatum'} ${nugetPackage} | ${true} | ${PACKAGE_TYPE_NUGET}
${npmPackage} | ${false} | ${null} ${npmPackage} | ${false} | ${PACKAGE_TYPE_NPM}
`('Component visibility', ({ packageEntity, visible, metadata }) => { `(
it(`Is ${visible} that the component markup is visible when the package is ${packageEntity.package_type}`, () => { `It is $visible that the component is visible when the package is $packageType`,
({ packageEntity, visible }) => {
mountComponent({ packageEntity }); mountComponent({ packageEntity });
expect(findTitle().exists()).toBe(visible); expect(findTitle().exists()).toBe(visible);
expect(findMainArea().exists()).toBe(visible); expect(findMainArea().exists()).toBe(visible);
}); },
);
it(`The component is hidden if ${metadata} is missing`, () => {
mountComponent({ packageEntity: { ...packageEntity, [metadata]: null } });
expect(findTitle().exists()).toBe(false);
expect(findMainArea().exists()).toBe(false);
});
});
describe('nuget metadata', () => { describe('nuget metadata', () => {
beforeEach(() => { beforeEach(() => {
...@@ -71,15 +83,15 @@ describe('Package Additional Metadata', () => { ...@@ -71,15 +83,15 @@ describe('Package Additional Metadata', () => {
}); });
it.each` it.each`
name | finderFunction | text | link | icon name | finderFunction | text | link | icon
${'source'} | ${findNugetSource} | ${'Source project located at project-foo-url'} | ${'project_url'} | ${'project'} ${'source'} | ${findNugetSource} | ${'Source project located at projectUrl'} | ${'projectUrl'} | ${'project'}
${'license'} | ${findNugetLicense} | ${'License information located at license-foo-url'} | ${'license_url'} | ${'license'} ${'license'} | ${findNugetLicense} | ${'License information located at licenseUrl'} | ${'licenseUrl'} | ${'license'}
`('$name element', ({ finderFunction, text, link, icon }) => { `('$name element', ({ finderFunction, text, link, icon }) => {
const element = finderFunction(); const element = finderFunction();
expect(element.exists()).toBe(true); expect(element.exists()).toBe(true);
expect(element.text()).toBe(text); expect(element.text()).toBe(text);
expect(element.props('icon')).toBe(icon); expect(element.props('icon')).toBe(icon);
expect(findElementLink(element).attributes('href')).toBe(nugetPackage.nuget_metadatum[link]); expect(findElementLink(element).attributes('href')).toBe(nugetPackage.metadata[link]);
}); });
}); });
...@@ -89,8 +101,8 @@ describe('Package Additional Metadata', () => { ...@@ -89,8 +101,8 @@ describe('Package Additional Metadata', () => {
}); });
it.each` it.each`
name | finderFunction | text | icon name | finderFunction | text | icon
${'recipe'} | ${findConanRecipe} | ${'Recipe: conan-package/1.0.0@conan+conan-package/stable'} | ${'information-o'} ${'recipe'} | ${findConanRecipe} | ${'Recipe: package-8/1.0.0@gitlab-org+gitlab-test/stable'} | ${'information-o'}
`('$name element', ({ finderFunction, text, icon }) => { `('$name element', ({ finderFunction, text, icon }) => {
const element = finderFunction(); const element = finderFunction();
expect(element.exists()).toBe(true); expect(element.exists()).toBe(true);
...@@ -105,9 +117,9 @@ describe('Package Additional Metadata', () => { ...@@ -105,9 +117,9 @@ describe('Package Additional Metadata', () => {
}); });
it.each` it.each`
name | finderFunction | text | icon name | finderFunction | text | icon
${'app'} | ${findMavenApp} | ${'App name: test-app'} | ${'information-o'} ${'app'} | ${findMavenApp} | ${'App name: appName'} | ${'information-o'}
${'group'} | ${findMavenGroup} | ${'App group: com.test.app'} | ${'information-o'} ${'group'} | ${findMavenGroup} | ${'App group: appGroup'} | ${'information-o'}
`('$name element', ({ finderFunction, text, icon }) => { `('$name element', ({ finderFunction, text, icon }) => {
const element = finderFunction(); const element = finderFunction();
expect(element.exists()).toBe(true); expect(element.exists()).toBe(true);
......
...@@ -5,6 +5,7 @@ import createMockApollo from 'helpers/mock_apollo_helper'; ...@@ -5,6 +5,7 @@ import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises'; import waitForPromises from 'helpers/wait_for_promises';
import createFlash from '~/flash'; 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 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 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';
...@@ -48,6 +49,7 @@ describe('PackagesApp', () => { ...@@ -48,6 +49,7 @@ describe('PackagesApp', () => {
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); const findPackageHistory = () => wrapper.findComponent(PackageHistory);
const findAdditionalMetadata = () => wrapper.findComponent(AdditionalMetadata);
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
...@@ -95,4 +97,15 @@ describe('PackagesApp', () => { ...@@ -95,4 +97,15 @@ describe('PackagesApp', () => {
projectName: provide.projectName, projectName: provide.projectName,
}); });
}); });
it('renders additional metadata and has the right props', async () => {
createComponent();
await waitForPromises();
expect(findAdditionalMetadata().exists()).toBe(true);
expect(findAdditionalMetadata().props()).toMatchObject({
packageEntity: expect.objectContaining(packageData()),
});
});
}); });
...@@ -58,10 +58,49 @@ export const packageData = (extend) => ({ ...@@ -58,10 +58,49 @@ export const packageData = (extend) => ({
...extend, ...extend,
}); });
export const conanMetadata = () => ({
packageChannel: 'stable',
packageUsername: 'gitlab-org+gitlab-test',
recipe: 'package-8/1.0.0@gitlab-org+gitlab-test/stable',
recipePath: 'package-8/1.0.0/gitlab-org+gitlab-test/stable',
});
export const composerMetadata = () => ({
targetSha: 'b83d6e391c22777fca1ed3012fce84f633d7fed0',
composerJson: {
license: 'MIT',
version: '1.0.0',
},
});
export const pypyMetadata = () => ({
requiredPython: '1.0.0',
});
export const mavenMetadata = () => ({
appName: 'appName',
appGroup: 'appGroup',
appVersion: 'appVersion',
path: 'path',
});
export const nugetMetadata = () => ({
iconUrl: 'iconUrl',
licenseUrl: 'licenseUrl',
projectUrl: 'projectUrl',
});
export const packageDetailsQuery = () => ({ export const packageDetailsQuery = () => ({
data: { data: {
package: { package: {
...packageData(), ...packageData(),
metadata: {
...conanMetadata(),
...composerMetadata(),
...pypyMetadata(),
...mavenMetadata(),
...nugetMetadata(),
},
tags: { tags: {
nodes: packageTags(), nodes: packageTags(),
__typename: 'PackageTagConnection', __typename: 'PackageTagConnection',
......
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