Commit c8bf1bc0 authored by Sean Nichols's avatar Sean Nichols Committed by Paul Slaughter

Refactor WebIDE error message to use GlAlert

https://gitlab.com/gitlab-org/gitlab/-/merge_requests/23300
parent 8b5f1fc2
<script> <script>
import { mapActions } from 'vuex'; import { mapActions } from 'vuex';
import { GlLoadingIcon } from '@gitlab/ui'; import { GlAlert, GlLoadingIcon } from '@gitlab/ui';
export default { export default {
components: { components: {
GlAlert,
GlLoadingIcon, GlLoadingIcon,
}, },
props: { props: {
...@@ -17,9 +18,14 @@ export default { ...@@ -17,9 +18,14 @@ export default {
isLoading: false, isLoading: false,
}; };
}, },
computed: {
canDismiss() {
return !this.message.action;
},
},
methods: { methods: {
...mapActions(['setErrorMessage']), ...mapActions(['setErrorMessage']),
clickAction() { doAction() {
if (this.isLoading) return; if (this.isLoading) return;
this.isLoading = true; this.isLoading = true;
...@@ -33,28 +39,23 @@ export default { ...@@ -33,28 +39,23 @@ export default {
this.isLoading = false; this.isLoading = false;
}); });
}, },
clickFlash() { dismiss() {
if (!this.message.action) {
this.setErrorMessage(null); this.setErrorMessage(null);
}
}, },
}, },
}; };
</script> </script>
<template> <template>
<div class="flash-container flash-container-page" @click="clickFlash"> <gl-alert
<div class="flash-alert" data-qa-selector="flash_alert"> data-qa-selector="flash_alert"
<span v-html="message.text"> </span> variant="danger"
<button :dismissible="canDismiss"
v-if="message.action" :primary-button-text="message.actionText"
type="button" @dismiss="dismiss"
class="flash-action text-white p-0 border-top-0 border-right-0 border-left-0 bg-transparent" @primaryAction="doAction"
@click.stop.prevent="clickAction"
> >
{{ message.actionText }} <span v-html="message.text"></span>
<gl-loading-icon v-show="isLoading" inline /> <gl-loading-icon v-show="isLoading" inline class="vertical-align-middle ml-1" />
</button> </gl-alert>
</div>
</div>
</template> </template>
---
title: Fix Web IDE alert message look and feel
merge_request: 23300
author: Sean Nichols
type: fixed
import { shallowMount, createLocalVue } from '@vue/test-utils'; import { mount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex'; import Vuex from 'vuex';
import { GlLoadingIcon } from '@gitlab/ui'; import { GlLoadingIcon } from '@gitlab/ui';
import ErrorMessage from '~/ide/components/error_message.vue'; import ErrorMessage from '~/ide/components/error_message.vue';
...@@ -15,7 +15,7 @@ describe('IDE error message component', () => { ...@@ -15,7 +15,7 @@ describe('IDE error message component', () => {
actions: { setErrorMessage: setErrorMessageMock }, actions: { setErrorMessage: setErrorMessageMock },
}); });
wrapper = shallowMount(ErrorMessage, { wrapper = mount(ErrorMessage, {
propsData: { propsData: {
message: { message: {
text: 'some text', text: 'some text',
...@@ -38,15 +38,18 @@ describe('IDE error message component', () => { ...@@ -38,15 +38,18 @@ describe('IDE error message component', () => {
wrapper = null; wrapper = null;
}); });
const findDismissButton = () => wrapper.find('button[aria-label=Dismiss]');
const findActionButton = () => wrapper.find('button.gl-alert-action');
it('renders error message', () => { it('renders error message', () => {
const text = 'error message'; const text = 'error message';
createComponent({ text }); createComponent({ text });
expect(wrapper.text()).toContain(text); expect(wrapper.text()).toContain(text);
}); });
it('clears error message on click', () => { it('clears error message on dismiss click', () => {
createComponent(); createComponent();
wrapper.trigger('click'); findDismissButton().trigger('click');
expect(setErrorMessageMock).toHaveBeenCalledWith(expect.any(Object), null, undefined); expect(setErrorMessageMock).toHaveBeenCalledWith(expect.any(Object), null, undefined);
}); });
...@@ -68,29 +71,27 @@ describe('IDE error message component', () => { ...@@ -68,29 +71,27 @@ describe('IDE error message component', () => {
}); });
it('renders action button', () => { it('renders action button', () => {
const button = wrapper.find('button'); const button = findActionButton();
expect(button.exists()).toBe(true); expect(button.exists()).toBe(true);
expect(button.text()).toContain(message.actionText); expect(button.text()).toContain(message.actionText);
}); });
it('does not clear error message on click', () => { it('does not show dismiss button', () => {
wrapper.trigger('click'); expect(findDismissButton().exists()).toBe(false);
expect(setErrorMessageMock).not.toHaveBeenCalled();
}); });
it('dispatches action', () => { it('dispatches action', () => {
wrapper.find('button').trigger('click'); findActionButton().trigger('click');
expect(actionMock).toHaveBeenCalledWith(message.actionPayload); expect(actionMock).toHaveBeenCalledWith(message.actionPayload);
}); });
it('does not dispatch action when already loading', () => { it('does not dispatch action when already loading', () => {
wrapper.find('button').trigger('click'); findActionButton().trigger('click');
actionMock.mockReset(); actionMock.mockReset();
return wrapper.vm.$nextTick(() => { return wrapper.vm.$nextTick(() => {
wrapper.find('button').trigger('click'); findActionButton().trigger('click');
return wrapper.vm.$nextTick().then(() => { return wrapper.vm.$nextTick().then(() => {
expect(actionMock).not.toHaveBeenCalled(); expect(actionMock).not.toHaveBeenCalled();
...@@ -106,7 +107,7 @@ describe('IDE error message component', () => { ...@@ -106,7 +107,7 @@ describe('IDE error message component', () => {
resolveAction = resolve; resolveAction = resolve;
}), }),
); );
wrapper.find('button').trigger('click'); findActionButton().trigger('click');
return wrapper.vm.$nextTick(() => { return wrapper.vm.$nextTick(() => {
expect(wrapper.find(GlLoadingIcon).isVisible()).toBe(true); expect(wrapper.find(GlLoadingIcon).isVisible()).toBe(true);
...@@ -115,7 +116,7 @@ describe('IDE error message component', () => { ...@@ -115,7 +116,7 @@ describe('IDE error message component', () => {
}); });
it('hides loading icon when operation finishes', () => { it('hides loading icon when operation finishes', () => {
wrapper.find('button').trigger('click'); findActionButton().trigger('click');
return actionMock() return actionMock()
.then(() => wrapper.vm.$nextTick()) .then(() => wrapper.vm.$nextTick())
.then(() => { .then(() => {
......
...@@ -61,14 +61,14 @@ describe('ide component, non-empty repo', () => { ...@@ -61,14 +61,14 @@ describe('ide component, non-empty repo', () => {
}); });
it('shows error message when set', done => { it('shows error message when set', done => {
expect(vm.$el.querySelector('.flash-container')).toBe(null); expect(vm.$el.querySelector('.gl-alert')).toBe(null);
vm.$store.state.errorMessage = { vm.$store.state.errorMessage = {
text: 'error', text: 'error',
}; };
vm.$nextTick(() => { vm.$nextTick(() => {
expect(vm.$el.querySelector('.flash-container')).not.toBe(null); expect(vm.$el.querySelector('.gl-alert')).not.toBe(null);
done(); done();
}); });
......
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