Commit 909bfa15 authored by Kushal Pandya's avatar Kushal Pandya

Merge branch '337615-load-mr-widget-artifacts-on-mount-instead-of-click' into 'master'

Load MR pipeline widget artifacts on mount

See merge request gitlab-org/gitlab!71785
parents b580dde8 27a5ba94
<script>
import {
GlAlert,
GlDropdown,
GlDropdownItem,
GlDropdownSectionHeader,
GlLoadingIcon,
GlTooltipDirective,
} from '@gitlab/ui';
import axios from '~/lib/utils/axios_utils';
import { __, s__ } from '~/locale';
import { __ } from '~/locale';
export const i18n = {
artifacts: __('Artifacts'),
artifactSectionHeader: __('Download artifacts'),
artifactsFetchErrorMessage: s__('Pipelines|Could not load artifacts.'),
noArtifacts: s__('Pipelines|No artifacts available'),
};
export default {
......@@ -23,11 +18,9 @@ export default {
GlTooltip: GlTooltipDirective,
},
components: {
GlAlert,
GlDropdown,
GlDropdownItem,
GlDropdownSectionHeader,
GlLoadingIcon,
},
inject: {
artifactsEndpoint: {
......@@ -42,39 +35,22 @@ export default {
type: Number,
required: true,
},
artifacts: {
type: Array,
required: false,
default: () => [],
},
data() {
return {
artifacts: [],
hasError: false,
isLoading: false,
};
},
methods: {
fetchArtifacts() {
this.isLoading = true;
// Replace the placeholder with the ID of the pipeline we are viewing
const endpoint = this.artifactsEndpoint.replace(
this.artifactsEndpointPlaceholder,
this.pipelineId,
);
return axios
.get(endpoint)
.then(({ data }) => {
this.artifacts = data.artifacts;
})
.catch(() => {
this.hasError = true;
})
.finally(() => {
this.isLoading = false;
});
computed: {
shouldShowDropdown() {
return this.artifacts?.length;
},
},
};
</script>
<template>
<gl-dropdown
v-if="shouldShowDropdown"
v-gl-tooltip
class="build-artifacts js-pipeline-dropdown-download"
:title="$options.i18n.artifacts"
......@@ -84,22 +60,11 @@ export default {
right
lazy
text-sr-only
@show.once="fetchArtifacts"
>
<gl-dropdown-section-header>{{
$options.i18n.artifactSectionHeader
}}</gl-dropdown-section-header>
<gl-alert v-if="hasError" variant="danger" :dismissible="false">
{{ $options.i18n.artifactsFetchErrorMessage }}
</gl-alert>
<gl-loading-icon v-else-if="isLoading" size="sm" />
<gl-alert v-else-if="!artifacts.length" variant="info" :dismissible="false">
{{ $options.i18n.noArtifacts }}
</gl-alert>
<gl-dropdown-item
v-for="(artifact, i) in artifacts"
:key="i"
......
......@@ -101,6 +101,9 @@ export default {
? this.pipeline.details.status
: {};
},
artifacts() {
return this.pipeline?.details?.artifacts;
},
hasStages() {
return this.pipeline?.details?.stages?.length > 0;
},
......@@ -285,7 +288,7 @@ export default {
/>
</span>
<linked-pipelines-mini-list v-if="triggered.length" :triggered="triggered" />
<pipeline-artifacts :pipeline-id="pipeline.id" class="gl-ml-3" />
<pipeline-artifacts :pipeline-id="pipeline.id" :artifacts="artifacts" class="gl-ml-3" />
</span>
</div>
</div>
......
......@@ -25557,9 +25557,6 @@ msgstr ""
msgid "Pipelines|More Information"
msgstr ""
msgid "Pipelines|No artifacts available"
msgstr ""
msgid "Pipelines|No triggers have been created yet. Add one using the form above."
msgstr ""
......
import { GlAlert, GlDropdown, GlDropdownItem, GlLoadingIcon, GlSprintf } from '@gitlab/ui';
import { GlDropdown, GlDropdownItem, GlSprintf } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import waitForPromises from 'helpers/wait_for_promises';
import axios from '~/lib/utils/axios_utils';
import PipelineArtifacts, {
i18n,
} from '~/pipelines/components/pipelines_list/pipelines_artifacts.vue';
import PipelineArtifacts from '~/pipelines/components/pipelines_list/pipelines_artifacts.vue';
describe('Pipelines Artifacts dropdown', () => {
let wrapper;
let mockAxios;
const artifacts = [
{
......@@ -21,23 +15,13 @@ describe('Pipelines Artifacts dropdown', () => {
path: '/download/path-two',
},
];
const artifactsEndpointPlaceholder = ':pipeline_artifacts_id';
const artifactsEndpoint = `endpoint/${artifactsEndpointPlaceholder}/artifacts.json`;
const pipelineId = 108;
const createComponent = ({ mockData = {} } = {}) => {
const createComponent = ({ mockArtifacts = artifacts } = {}) => {
wrapper = shallowMount(PipelineArtifacts, {
provide: {
artifactsEndpoint,
artifactsEndpointPlaceholder,
},
propsData: {
pipelineId,
},
data() {
return {
...mockData,
};
artifacts: mockArtifacts,
},
stubs: {
GlSprintf,
......@@ -45,80 +29,33 @@ describe('Pipelines Artifacts dropdown', () => {
});
};
const findAlert = () => wrapper.findComponent(GlAlert);
const findDropdown = () => wrapper.findComponent(GlDropdown);
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const findFirstGlDropdownItem = () => wrapper.find(GlDropdownItem);
const findAllGlDropdownItems = () => wrapper.find(GlDropdown).findAll(GlDropdownItem);
beforeEach(() => {
mockAxios = new MockAdapter(axios);
});
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
it('should render the dropdown', () => {
createComponent();
expect(findDropdown().exists()).toBe(true);
});
it('should fetch artifacts on dropdown click', async () => {
const endpoint = artifactsEndpoint.replace(artifactsEndpointPlaceholder, pipelineId);
mockAxios.onGet(endpoint).replyOnce(200, { artifacts });
createComponent();
findDropdown().vm.$emit('show');
await waitForPromises();
expect(mockAxios.history.get).toHaveLength(1);
expect(wrapper.vm.artifacts).toEqual(artifacts);
});
it('should render a dropdown with all the provided artifacts', () => {
createComponent({ mockData: { artifacts } });
createComponent();
expect(findAllGlDropdownItems()).toHaveLength(artifacts.length);
});
it('should render a link with the provided path', () => {
createComponent({ mockData: { artifacts } });
createComponent();
expect(findFirstGlDropdownItem().attributes('href')).toBe(artifacts[0].path);
expect(findFirstGlDropdownItem().text()).toBe(artifacts[0].name);
});
describe('with a failing request', () => {
it('should render an error message', async () => {
const endpoint = artifactsEndpoint.replace(artifactsEndpointPlaceholder, pipelineId);
mockAxios.onGet(endpoint).replyOnce(500);
createComponent();
findDropdown().vm.$emit('show');
await waitForPromises();
const error = findAlert();
expect(error.exists()).toBe(true);
expect(error.text()).toBe(i18n.artifactsFetchErrorMessage);
});
});
describe('with no artifacts received', () => {
it('should render empty alert message', () => {
createComponent({ mockData: { artifacts: [] } });
const emptyAlert = findAlert();
expect(emptyAlert.exists()).toBe(true);
expect(emptyAlert.text()).toBe(i18n.noArtifacts);
});
});
describe('when artifacts are loading', () => {
it('should show loading icon', () => {
createComponent({ mockData: { isLoading: true } });
describe('with no artifacts', () => {
it('should not render the dropdown', () => {
createComponent({ mockArtifacts: [] });
expect(findLoadingIcon().exists()).toBe(true);
expect(findDropdown().exists()).toBe(false);
});
});
});
import { GlLoadingIcon } from '@gitlab/ui';
import { shallowMount, mount } from '@vue/test-utils';
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import { trimText } from 'helpers/text_helper';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import PipelineMiniGraph from '~/pipelines/components/pipelines_list/pipeline_mini_graph.vue';
......@@ -39,6 +41,8 @@ describe('MRWidgetPipeline', () => {
const findMonitoringPipelineMessage = () => wrapper.findByTestId('monitoring-pipeline-message');
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const mockArtifactsRequest = () => new MockAdapter(axios).onGet().reply(200, []);
const createWrapper = (props = {}, mountFn = shallowMount) => {
wrapper = extendedWrapper(
mountFn(PipelineComponent, {
......@@ -71,6 +75,8 @@ describe('MRWidgetPipeline', () => {
describe('with a pipeline', () => {
beforeEach(() => {
mockArtifactsRequest();
createWrapper(
{
pipelineCoverageDelta: mockData.pipelineCoverageDelta,
......
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