Commit be2d1f2a authored by mgandres's avatar mgandres

Add branch switcher to empty state of pipeline editor

This adds the branch switcher in the empty state of the pipeline editor,
allowing the user to switch between branches with and without a CI
config.
parent 45fff735
......@@ -2,9 +2,11 @@
import { GlButton, GlSprintf } from '@gitlab/ui';
import { __ } from '~/locale';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import BranchSwitcher from '../file_nav/branch_switcher.vue';
export default {
components: {
BranchSwitcher,
GlButton,
GlSprintf,
},
......@@ -22,6 +24,9 @@ export default {
},
},
computed: {
showBranchSwitcher() {
return this.glFeatures.pipelineEditorBranchSwitcher;
},
showCTAButton() {
return this.glFeatures.pipelineEditorEmptyStateAction;
},
......@@ -34,23 +39,28 @@ export default {
};
</script>
<template>
<div class="gl-display-flex gl-flex-direction-column gl-align-items-center gl-mt-11">
<img :src="emptyStateIllustrationPath" />
<h1 class="gl-font-size-h1">{{ $options.i18n.title }}</h1>
<p class="gl-mt-3">
<gl-sprintf :message="$options.i18n.body">
<template #code="{ content }">
<code>{{ content }}</code>
</template>
</gl-sprintf>
</p>
<gl-button
v-if="showCTAButton"
variant="confirm"
class="gl-mt-3"
@click="createEmptyConfigFile"
>
{{ $options.i18n.btnText }}
</gl-button>
<div>
<div class="gl-mb-5">
<branch-switcher v-if="showBranchSwitcher" v-on="$listeners" />
</div>
<div class="gl-display-flex gl-flex-direction-column gl-align-items-center gl-mt-11">
<img :src="emptyStateIllustrationPath" />
<h1 class="gl-font-size-h1">{{ $options.i18n.title }}</h1>
<p class="gl-mt-3">
<gl-sprintf :message="$options.i18n.body">
<template #code="{ content }">
<code>{{ content }}</code>
</template>
</gl-sprintf>
</p>
<gl-button
v-if="showCTAButton"
variant="confirm"
class="gl-mt-3"
@click="createEmptyConfigFile"
>
{{ $options.i18n.btnText }}
</gl-button>
</div>
</div>
</template>
......@@ -80,6 +80,12 @@ export default {
this.lastCommittedContent = fileContent;
this.currentCiFileContent = fileContent;
// make sure to reset the start screen flag during a refetch
// e.g. when switching branches
if (fileContent.length) {
this.showStartScreen = false;
}
},
error(error) {
this.handleBlobContentError(error);
......@@ -236,6 +242,7 @@ export default {
<pipeline-editor-empty-state
v-else-if="showStartScreen"
@createEmptyConfigFile="setNewEmptyCiConfigFile"
@refetchContent="refetchContent"
/>
<div v-else>
<pipeline-editor-messages
......
import { GlButton, GlSprintf } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import BranchSwitcher from '~/pipeline_editor/components/file_nav/branch_switcher.vue';
import PipelineEditorEmptyState from '~/pipeline_editor/components/ui/pipeline_editor_empty_state.vue';
describe('Pipeline editor empty state', () => {
let wrapper;
const defaultProvide = {
glFeatures: {
pipelineEditorBranchSwitcher: true,
pipelineEditorEmptyStateAction: false,
},
emptyStateIllustrationPath: 'my/svg/path',
......@@ -17,6 +19,7 @@ describe('Pipeline editor empty state', () => {
});
};
const findBranchSwitcher = () => wrapper.findComponent(BranchSwitcher);
const findSvgImage = () => wrapper.find('img');
const findTitle = () => wrapper.find('h1');
const findConfirmButton = () => wrapper.findComponent(GlButton);
......@@ -45,6 +48,10 @@ describe('Pipeline editor empty state', () => {
expect(findDescription().html()).toContain(wrapper.vm.$options.i18n.body);
});
it('renders the branch switcher', () => {
expect(findBranchSwitcher().exists()).toBe(true);
});
describe('with feature flag off', () => {
it('does not renders a CTA button', () => {
expect(findConfirmButton().exists()).toBe(false);
......@@ -75,5 +82,17 @@ describe('Pipeline editor empty state', () => {
await findConfirmButton().vm.$emit('click');
expect(wrapper.emitted(expectedEvent)).toHaveLength(1);
});
describe('with branch switcher feature flag OFF', () => {
it('does not render the branch switcher', () => {
createComponent({
provide: {
glFeatures: { pipelineEditorBranchSwitcher: false },
},
});
expect(findBranchSwitcher().exists()).toBe(false);
});
});
});
});
......@@ -301,20 +301,60 @@ describe('Pipeline editor app component', () => {
});
describe('when refetching content', () => {
beforeEach(async () => {
it('refetches blob content', async () => {
await createComponentWithApollo();
jest
.spyOn(wrapper.vm.$apollo.queries.initialCiFileContent, 'refetch')
.mockImplementation(jest.fn());
});
it('refetches blob content', async () => {
expect(wrapper.vm.$apollo.queries.initialCiFileContent.refetch).toHaveBeenCalledTimes(0);
await wrapper.vm.refetchContent();
expect(wrapper.vm.$apollo.queries.initialCiFileContent.refetch).toHaveBeenCalledTimes(1);
});
it('hides start screen when refetch fetches CI file', async () => {
mockBlobContentData.mockRejectedValue({
response: {
status: httpStatusCodes.NOT_FOUND,
},
});
await createComponentWithApollo();
expect(findEmptyState().exists()).toBe(true);
expect(findEditorHome().exists()).toBe(false);
mockBlobContentData.mockResolvedValue(mockCiYml);
await wrapper.vm.$apollo.queries.initialCiFileContent.refetch();
expect(findEmptyState().exists()).toBe(false);
expect(findEditorHome().exists()).toBe(true);
});
it('shows start screen when refetch does not fetch CI file', async () => {
mockBlobContentData.mockResolvedValue(mockCiYml);
await createComponentWithApollo();
expect(findEmptyState().exists()).toBe(false);
expect(findEditorHome().exists()).toBe(true);
mockBlobContentData.mockRejectedValue({
response: {
status: httpStatusCodes.NOT_FOUND,
},
});
await wrapper.vm.$apollo.queries.initialCiFileContent.refetch();
await wrapper.vm.handleBlobContentError({
networkError: {
response: {
status: httpStatusCodes.NOT_FOUND,
},
},
});
expect(findEmptyState().exists()).toBe(true);
expect(findEditorHome().exists()).toBe(false);
});
});
});
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