Commit 066f1b93 authored by Filipa Lacerda's avatar Filipa Lacerda

Merge branch 'winh-unify-modals' into 'master'

Unify dialog modal/popup dialog/confirmation dialog/modal to modal

See merge request gitlab-org/gitlab-ce!15865
parents 9d0fc98c 16a8a594
<script>
import { s__ } from '../../locale';
import tooltip from '../../vue_shared/directives/tooltip';
import PopupDialog from '../../vue_shared/components/popup_dialog.vue';
import modal from '../../vue_shared/components/modal.vue';
import eventHub from '../event_hub';
import { COMMON_STR } from '../constants';
import Icon from '../../vue_shared/components/icon.vue';
......@@ -9,7 +9,7 @@ import Icon from '../../vue_shared/components/icon.vue';
export default {
components: {
Icon,
PopupDialog,
modal,
},
directives: {
tooltip,
......@@ -27,7 +27,7 @@ export default {
},
data() {
return {
dialogStatus: false,
modalStatus: false,
};
},
computed: {
......@@ -43,10 +43,10 @@ export default {
},
methods: {
onLeaveGroup() {
this.dialogStatus = true;
this.modalStatus = true;
},
leaveGroup(leaveConfirmed) {
this.dialogStatus = false;
this.modalStatus = false;
if (leaveConfirmed) {
eventHub.$emit('leaveGroup', this.group, this.parentGroup);
}
......@@ -82,8 +82,8 @@ export default {
class="fa fa-sign-out"
aria-hidden="true"/>
</a>
<popup-dialog
v-show="dialogStatus"
<modal
v-show="modalStatus"
:primary-button-label="__('Leave')"
kind="warning"
:title="__('Are you sure?')"
......
......@@ -9,7 +9,7 @@ import titleComponent from './title.vue';
import descriptionComponent from './description.vue';
import editedComponent from './edited.vue';
import formComponent from './form.vue';
import RecaptchaDialogImplementor from '../../vue_shared/mixins/recaptcha_dialog_implementor';
import recaptchaModalImplementor from '../../vue_shared/mixins/recaptcha_modal_implementor';
export default {
props: {
......@@ -152,7 +152,7 @@ export default {
},
mixins: [
RecaptchaDialogImplementor,
recaptchaModalImplementor,
],
methods: {
......@@ -197,7 +197,7 @@ export default {
});
},
closeRecaptchaDialog() {
closeRecaptchaModal() {
this.store.setFormState({
updateLoading: false,
});
......@@ -273,10 +273,10 @@ export default {
:enable-autocomplete="enableAutocomplete"
/>
<recaptcha-dialog
<recaptcha-modal
v-show="showRecaptcha"
:html="recaptchaHTML"
@close="closeRecaptchaDialog"
@close="closeRecaptchaModal"
/>
</div>
<div v-else>
......
<script>
import animateMixin from '../mixins/animate';
import TaskList from '../../task_list';
import RecaptchaDialogImplementor from '../../vue_shared/mixins/recaptcha_dialog_implementor';
import recaptchaModalImplementor from '../../vue_shared/mixins/recaptcha_modal_implementor';
export default {
mixins: [
animateMixin,
RecaptchaDialogImplementor,
recaptchaModalImplementor,
],
props: {
......@@ -126,7 +126,7 @@
>
</textarea>
<recaptcha-dialog
<recaptcha-modal
v-show="showRecaptcha"
:html="recaptchaHTML"
@close="closeRecaptcha"
......
<script>
import popupDialog from '../../../vue_shared/components/popup_dialog.vue';
import modal from '../../../vue_shared/components/modal.vue';
import { __, s__, sprintf } from '../../../locale';
import csrf from '../../../lib/utils/csrf';
......@@ -26,7 +26,7 @@
};
},
components: {
popupDialog,
modal,
},
computed: {
csrfToken() {
......@@ -89,7 +89,7 @@ Once you confirm %{deleteAccount}, it cannot be undone or recovered.`),
<template>
<div>
<popup-dialog
<modal
v-if="isOpen"
:title="s__('Profiles|Delete your account?')"
:text="text"
......@@ -134,7 +134,7 @@ Once you confirm %{deleteAccount}, it cannot be undone or recovered.`),
</form>
</template>
</popup-dialog>
</modal>
<button
type="button"
......
<script>
import { mapActions } from 'vuex';
import { __ } from '../../../locale';
import popupDialog from '../../../vue_shared/components/popup_dialog.vue';
import modal from '../../../vue_shared/components/modal.vue';
export default {
props: {
......@@ -20,7 +20,7 @@
};
},
components: {
popupDialog,
modal,
},
methods: {
...mapActions([
......@@ -68,7 +68,7 @@
</script>
<template>
<popup-dialog
<modal
:title="modalTitle"
:primary-button-label="buttonLabel"
kind="success"
......@@ -94,5 +94,5 @@
</div>
</fieldset>
</form>
</popup-dialog>
</modal>
</template>
......@@ -2,12 +2,12 @@
import { mapGetters, mapState, mapActions } from 'vuex';
import tooltip from '../../vue_shared/directives/tooltip';
import icon from '../../vue_shared/components/icon.vue';
import PopupDialog from '../../vue_shared/components/popup_dialog.vue';
import modal from '../../vue_shared/components/modal.vue';
import commitFilesList from './commit_sidebar/list.vue';
export default {
components: {
PopupDialog,
modal,
icon,
commitFilesList,
},
......@@ -16,7 +16,7 @@ export default {
},
data() {
return {
showNewBranchDialog: false,
showNewBranchModal: false,
submitCommitsLoading: false,
startNewMR: false,
commitMessage: '',
......@@ -58,7 +58,7 @@ export default {
start_branch: createNewBranch ? this.currentBranch : undefined,
};
this.showNewBranchDialog = false;
this.showNewBranchModal = false;
this.submitCommitsLoading = true;
this.commitChanges({ payload, newMr: this.startNewMR })
......@@ -76,7 +76,7 @@ export default {
this.checkCommitStatus()
.then((branchChanged) => {
if (branchChanged) {
this.showNewBranchDialog = true;
this.showNewBranchModal = true;
} else {
this.makeCommit();
}
......@@ -99,13 +99,13 @@ export default {
'is-collapsed': collapsed,
}"
>
<popup-dialog
v-if="showNewBranchDialog"
<modal
v-if="showNewBranchModal"
:primary-button-label="__('Create new branch')"
kind="primary"
:title="__('Branch has changed')"
:text="__('This branch has changed since you started editing. Would you like to create a new branch?')"
@toggle="showNewBranchDialog = false"
@toggle="showNewBranchModal = false"
@submit="makeCommit(true)"
/>
<button
......
<script>
import { mapGetters, mapActions, mapState } from 'vuex';
import popupDialog from '../../vue_shared/components/popup_dialog.vue';
import modal from '../../vue_shared/components/modal.vue';
export default {
components: {
popupDialog,
modal,
},
computed: {
...mapState([
......@@ -43,7 +43,7 @@ export default {
{{buttonLabel}}
</span>
</button>
<popup-dialog
<modal
v-if="discardPopupOpen"
class="text-left"
:primary-button-label="__('Discard changes')"
......
<script>
export default {
name: 'popup-dialog',
name: 'modal',
props: {
title: {
......@@ -75,7 +75,7 @@ export default {
<template>
<div class="modal-open">
<div
class="modal popup-dialog"
class="modal show"
role="dialog"
tabindex="-1"
>
......
<script>
import PopupDialog from './popup_dialog.vue';
import modal from './modal.vue';
export default {
name: 'recaptcha-dialog',
name: 'recaptcha-modal',
props: {
html: {
......@@ -20,7 +20,7 @@ export default {
},
components: {
PopupDialog,
modal,
},
methods: {
......@@ -65,9 +65,9 @@ export default {
</script>
<template>
<popup-dialog
<modal
kind="warning"
class="recaptcha-dialog js-recaptcha-dialog"
class="recaptcha-modal js-recaptcha-modal"
:hide-footer="true"
:title="__('Please solve the reCAPTCHA')"
@toggle="close"
......@@ -81,5 +81,5 @@ export default {
v-html="html"
></div>
</div>
</popup-dialog>
</modal>
</template>
import RecaptchaDialog from '../components/recaptcha_dialog.vue';
import recaptchaModal from '../components/recaptcha_modal.vue';
export default {
data() {
......@@ -9,7 +9,7 @@ export default {
},
components: {
RecaptchaDialog,
recaptchaModal,
},
methods: {
......
......@@ -44,11 +44,18 @@ body.modal-open {
}
}
.modal.popup-dialog {
display: block;
.modal {
background-color: $black-transparent;
z-index: 2100;
@media (min-width: $screen-md-min) {
.modal-dialog {
margin: 30px auto;
}
}
}
.recaptcha-dialog .recaptcha-form {
.recaptcha-modal .recaptcha-form {
display: inline-block;
.recaptcha {
......
.modal.popup-dialog {
display: block;
background-color: $black-transparent;
z-index: 2100;
@media (min-width: $screen-md-min) {
.modal-dialog {
width: 600px;
margin: 30px auto;
}
}
}
.project-refs-form,
.project-refs-target-form {
display: inline-block;
......
......@@ -10,7 +10,7 @@
* [Tables](#tables)
* [Blocks](#blocks)
* [Panels](#panels)
* [Dialog modals](#dialog-modals)
* [Modals](#modals)
* [Alerts](#alerts)
* [Forms](#forms)
* [Search box](#search-box)
......@@ -255,18 +255,18 @@ Skeleton loading can replace any existing UI elements for the period in which th
---
## Dialog modals
## Modals
Dialog modals are only used for having a conversation and confirmation with the user. The user is not able to access the features on the main page until closing the modal.
Modals are only used for having a conversation and confirmation with the user. The user is not able to access the features on the main page until closing the modal.
### Usage
* When the action is irreversible, dialog modals provide the details and confirm with the user before they take an advanced action.
* When the action will affect privacy or authorization, dialog modals provide advanced information and confirm with the user.
* When the action is irreversible, modals provide the details and confirm with the user before they take an advanced action.
* When the action will affect privacy or authorization, modals provide advanced information and confirm with the user.
### Style
* Dialog modals contain the header, body, and actions.
* Modals contain the header, body, and actions.
* **Header(1):** The header title is a question instead of a descriptive phrase.
* **Body(2):** The content in body should never be ambiguous and unclear. It provides specific information.
* **Actions(3):** Contains a affirmative action, a dismissive action, and an extra action. The order of actions from left to right: Dismissive action → Extra action → Affirmative action
......@@ -277,13 +277,13 @@ Dialog modals are only used for having a conversation and confirmation with the
### Placement
* Dialog modals should always be the center of the screen horizontally and be positioned **72px** from the top.
* Modals should always be the center of the screen horizontally and be positioned **72px** from the top.
| Dialog with 2 actions | Dialog with 3 actions | Special confirmation |
| Modal with 2 actions | Modal with 3 actions | Special confirmation |
| --------------------- | --------------------- | -------------------- |
| ![two-actions](img/modals-general-confimation-dialog.png) | ![three-actions](img/modals-three-buttons.png) | ![spcial-confirmation](img/modals-special-confimation-dialog.png) |
> TODO: Special case for dialog modal.
> TODO: Special case for modal.
---
......
......@@ -46,11 +46,11 @@ Avoid using periods in solitary sentences in these elements:
* Labels
* Hover text
* Bulleted lists
* Dialog body text
* Modal body text
Periods should be used for:
* Lists or dialogs with multiple sentences
* Lists or modals with multiple sentences
* Any sentence followed by a link
| :white_check_mark: **Do** place periods after sentences followed by a link | :no_entry_sign: **Don’t** place periods after a link if it‘s not followed by a sentence |
......@@ -80,7 +80,7 @@ Omit punctuation after phrases and labels to create a cleaner and more readable
| Punctuation mark | Copy and paste | HTML entity | Unicode | Mac shortcut | Windows shortcut | Description |
|---|---|---|---|---|---|---|
| Period | **.** | | | | | Omit for single sentences in affordances like labels, hover text, bulleted lists, and dialog body text.<br><br>Use in lists or dialogs with multiple sentences, and any sentence followed by a link or inline code.<br><br>Place inside quotation marks unless you’re telling the reader what to enter and it’s ambiguous whether to include the period. |
| Period | **.** | | | | | Omit for single sentences in affordances like labels, hover text, bulleted lists, and modal body text.<br><br>Use in lists or modals with multiple sentences, and any sentence followed by a link or inline code.<br><br>Place inside quotation marks unless you’re telling the reader what to enter and it’s ambiguous whether to include the period. |
| Comma | **,** | | | | | Place inside quotation marks.<br><br>Use a [serial comma][serial comma] in lists of three or more terms. |
| Exclamation point | **!** | | | | | Avoid exclamation points as they tend to come across as shouting. Some exceptions include greetings or congratulatory messages. |
| Colon | **:** | `&#58;` | `\u003A` | | | Omit from labels, for example, in the labels for fields in a form. |
......@@ -88,7 +88,7 @@ Omit punctuation after phrases and labels to create a cleaner and more readable
| Quotation marks | **“**<br><br>**”**<br><br>**‘**<br><br>**’** | `&ldquo;`<br><br>`&rdquo;`<br><br>`&lsquo;`<br><br>`&rsquo;` | `\u201C`<br><br>`\u201D`<br><br>`\u2018`<br><br>`\u2019` | <kbd>⌥ Option</kbd>+<kbd>[</kbd><br><br><kbd>⌥ Option</kbd>+<kbd>⇧ Shift</kbd>+<kbd>[</kbd><br><br><kbd>⌥ Option</kbd>+<kbd>]</kbd><br><br><kbd>⌥ Option</kbd>+<kbd>⇧ Shift</kbd>+<kbd>]</kbd> | <kbd>Alt</kbd>+<kbd>0 1 4 7</kbd><br><br><kbd>Alt</kbd>+<kbd>0 1 4 8</kbd><br><br><kbd>Alt</kbd>+<kbd>0 1 4 5</kbd><br><br><kbd>Alt</kbd>+<kbd>0 1 4 6</kbd> | Use proper quotation marks (also known as smart quotes, curly quotes, or typographer’s quotes) for quotes. Single quotation marks are used for quotes inside of quotes.<br><br>The right single quotation mark symbol is also used for apostrophes.<br><br>Don’t use primes, straight quotes, or free-standing accents for quotation marks. |
| Primes | **′**<br><br>**″** | `&prime;`<br><br>`&Prime;` | `\u2032`<br><br>`\u2033` | | <kbd>Alt</kbd>+<kbd>8 2 4 2</kbd><br><br><kbd>Alt</kbd>+<kbd>8 2 4 3</kbd> | Use prime (′) only in abbreviations for feet, arcminutes, and minutes: 3° 15′<br><br>Use double-prime (″) only in abbreviations for inches, arcseconds, and seconds: 3° 15′ 35″<br><br>Don’t use quotation marks, straight quotes, or free-standing accents for primes. |
| Straight quotes and accents | **"**<br><br>**'**<br><br>**`**<br><br>**´** | `&quot;`<br><br>`&#39;`<br><br>`&#96;`<br><br>`&acute;` | `\u0022`<br><br>`\u0027`<br><br>`\u0060`<br><br>`\u00B4` | | | Don’t use straight quotes or free-standing accents for primes or quotation marks.<br><br>Proper typography never uses straight quotes. They are left over from the age of typewriters and their only modern use is for code. |
| Ellipsis | **…** | `&hellip;` | | <kbd>⌥ Option</kbd>+<kbd>;</kbd> | <kbd>Alt</kbd>+<kbd>0 1 3 3</kbd> | Use to indicate an action in progress (“Downloading…”) or incomplete or truncated text. No space before the ellipsis.<br><br>Omit from menu items or buttons that open a dialog or start some other process. |
| Ellipsis | **…** | `&hellip;` | | <kbd>⌥ Option</kbd>+<kbd>;</kbd> | <kbd>Alt</kbd>+<kbd>0 1 3 3</kbd> | Use to indicate an action in progress (“Downloading…”) or incomplete or truncated text. No space before the ellipsis.<br><br>Omit from menu items or buttons that open a modal or start some other process. |
| Chevrons | **«**<br><br>**»**<br><br>**‹**<br><br>**›**<br><br>**<**<br><br>**>** | `&#171;`<br><br>`&#187;`<br><br>`&#8249;`<br><br>`&#8250;`<br><br>`&lt;`<br><br>`&gt;` | `\u00AB`<br><br>`\u00BB`<br><br>`\u2039`<br><br>`\u203A`<br><br>`\u003C`<br><br>`\u003E`<br><br> | | | Omit from links or buttons that open another page or move to the next or previous step in a process. Also known as angle brackets, angular quote brackets, or guillemets. |
| Em dash | **—** | `&mdash;` | `\u2014` | <kbd>⌥ Option</kbd>+<kbd>⇧ Shift</kbd>+<kbd>-</kbd> | <kbd>Alt</kbd>+<kbd>0 1 5 1</kbd> | Avoid using dashes to separate text. If you must use dashes for this purpose — like this — use an em dash surrounded by spaces. |
| En dash | **–** | `&ndash;` | `\u2013` | <kbd>⌥ Option</kbd>+<kbd>-</kbd> | <kbd>Alt</kbd>+<kbd>0 1 5 0</kbd> | Use an en dash without spaces instead of a hyphen to indicate a range of values, such as numbers, times, and dates: “3–5 kg”, “8:00 AM–12:30 PM”, “10–17 Jan” |
......@@ -175,7 +175,7 @@ A **comment** is a written piece of text that users of GitLab can create. Commen
#### Discussion
A **discussion** is a group of 1 or more comments. A discussion can include subdiscussions. Some discussions have the special capability of being able to be **resolved**. Both the comments in the discussion and the discussion itself can be resolved.
## Confirmation dialogs
## Modals
- Destruction buttons should be clear and always say what they are destroying.
E.g., `Delete page` instead of just `Delete`.
......@@ -184,6 +184,8 @@ A **discussion** is a group of 1 or more comments. A discussion can include subd
- Avoid the word `cancel` or `canceled` in the descriptive copy. It can be
confusing when you then see the `Cancel` button.
see also: guidelines for [modal components](components.md#modals)
---
Portions of this page are modifications based on work created and shared by the [Android Open Source Project][android project] and used according to terms described in the [Creative Commons 2.5 Attribution License][creative commons].
......
......@@ -25,7 +25,7 @@ describe 'Profile account page', :js do
fill_in 'password', with: '12345678'
page.within '.popup-dialog' do
page.within '.modal' do
click_button 'Delete account'
end
......@@ -38,7 +38,7 @@ describe 'Profile account page', :js do
fill_in 'password', with: 'testing123'
page.within '.popup-dialog' do
page.within '.modal' do
click_button 'Delete account'
end
......
......@@ -20,7 +20,7 @@ feature 'Multi-file editor new directory', :js do
click_link('New directory')
page.within('.popup-dialog') do
page.within('.modal') do
find('.form-control').set('foldername')
click_button('Create directory')
......
......@@ -20,7 +20,7 @@ feature 'Multi-file editor new file', :js do
click_link('New file')
page.within('.popup-dialog') do
page.within('.modal') do
find('.form-control').set('filename')
click_button('Create file')
......
......@@ -36,27 +36,27 @@ describe('ItemActionsComponent', () => {
describe('methods', () => {
describe('onLeaveGroup', () => {
it('should change `dialogStatus` prop to `true` which shows confirmation dialog', () => {
expect(vm.dialogStatus).toBeFalsy();
it('should change `modalStatus` prop to `true` which shows confirmation dialog', () => {
expect(vm.modalStatus).toBeFalsy();
vm.onLeaveGroup();
expect(vm.dialogStatus).toBeTruthy();
expect(vm.modalStatus).toBeTruthy();
});
});
describe('leaveGroup', () => {
it('should change `dialogStatus` prop to `false` and emit `leaveGroup` event with required params when called with `leaveConfirmed` as `true`', () => {
it('should change `modalStatus` prop to `false` and emit `leaveGroup` event with required params when called with `leaveConfirmed` as `true`', () => {
spyOn(eventHub, '$emit');
vm.dialogStatus = true;
vm.modalStatus = true;
vm.leaveGroup(true);
expect(vm.dialogStatus).toBeFalsy();
expect(vm.modalStatus).toBeFalsy();
expect(eventHub.$emit).toHaveBeenCalledWith('leaveGroup', vm.group, vm.parentGroup);
});
it('should change `dialogStatus` prop to `false` and should NOT emit `leaveGroup` event when called with `leaveConfirmed` as `false`', () => {
it('should change `modalStatus` prop to `false` and should NOT emit `leaveGroup` event when called with `leaveConfirmed` as `false`', () => {
spyOn(eventHub, '$emit');
vm.dialogStatus = true;
vm.modalStatus = true;
vm.leaveGroup(false);
expect(vm.dialogStatus).toBeFalsy();
expect(vm.modalStatus).toBeFalsy();
expect(eventHub.$emit).not.toHaveBeenCalled();
});
});
......@@ -99,9 +99,9 @@ describe('ItemActionsComponent', () => {
newVm.$destroy();
});
it('should show modal dialog when `dialogStatus` is set to `true`', () => {
vm.dialogStatus = true;
const modalDialogEl = vm.$el.querySelector('.modal.popup-dialog');
it('should show modal dialog when `modalStatus` is set to `true`', () => {
vm.modalStatus = true;
const modalDialogEl = vm.$el.querySelector('.modal');
expect(modalDialogEl).toBeDefined();
expect(modalDialogEl.querySelector('.modal-title').innerText.trim()).toBe('Are you sure?');
expect(modalDialogEl.querySelector('.btn.btn-warning').innerText.trim()).toBe('Leave');
......
......@@ -272,10 +272,10 @@ describe('Issuable output', () => {
});
});
it('opens recaptcha dialog if update rejected as spam', (done) => {
it('opens recaptcha modal if update rejected as spam', (done) => {
function mockScriptSrc() {
const recaptchaChild = vm.$children
.find(child => child.$options._componentTag === 'recaptcha-dialog'); // eslint-disable-line no-underscore-dangle
.find(child => child.$options._componentTag === 'recaptcha-modal'); // eslint-disable-line no-underscore-dangle
recaptchaChild.scriptSrc = '//scriptsrc';
}
......@@ -302,7 +302,7 @@ describe('Issuable output', () => {
.then(promise)
.then(() => setTimeoutPromise())
.then(() => {
modal = vm.$el.querySelector('.js-recaptcha-dialog');
modal = vm.$el.querySelector('.js-recaptcha-modal');
expect(modal.style.display).not.toEqual('none');
expect(modal.querySelector('.g-recaptcha').textContent).toEqual('recaptcha_html');
......
......@@ -54,7 +54,7 @@ describe('Description component', () => {
it('opens recaptcha dialog if update rejected as spam', (done) => {
let modal;
const recaptchaChild = vm.$children
.find(child => child.$options._componentTag === 'recaptcha-dialog'); // eslint-disable-line no-underscore-dangle
.find(child => child.$options._componentTag === 'recaptcha-modal'); // eslint-disable-line no-underscore-dangle
recaptchaChild.scriptSrc = '//scriptsrc';
......@@ -64,7 +64,7 @@ describe('Description component', () => {
vm.$nextTick()
.then(() => {
modal = vm.$el.querySelector('.js-recaptcha-dialog');
modal = vm.$el.querySelector('.js-recaptcha-modal');
expect(modal.style.display).not.toEqual('none');
expect(modal.querySelector('.g-recaptcha').textContent).toEqual('recaptcha_html');
......
import Vue from 'vue';
import PopupDialog from '~/vue_shared/components/popup_dialog.vue';
import modal from '~/vue_shared/components/modal.vue';
import mountComponent from '../../helpers/vue_mount_component_helper';
describe('PopupDialog', () => {
describe('Modal', () => {
it('does not render a primary button if no primaryButtonLabel', () => {
const popupDialog = Vue.extend(PopupDialog);
const vm = mountComponent(popupDialog);
const modalComponent = Vue.extend(modal);
const vm = mountComponent(modalComponent);
expect(vm.$el.querySelector('.js-primary-button')).toBeNull();
});
......
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