Merge FE

上级 994e7d13
......@@ -6,10 +6,11 @@
import TaskList from '../../task_list';
import * as constants from '../constants';
import eventHub from '../event_hub';
import confidentialIssue from '../../vue_shared/components/issue/confidential_issue_warning.vue';
import issueWarning from '../../vue_shared/components/issue/issue_warning.vue';
import issueNoteSignedOutWidget from './issue_note_signed_out_widget.vue';
import markdownField from '../../vue_shared/components/markdown/field.vue';
import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
import issuableStateMixin from '../mixins/issuable_state';
export default {
name: 'issueCommentForm',
......@@ -25,7 +26,7 @@
};
},
components: {
confidentialIssue,
issueWarning,
issueNoteSignedOutWidget,
markdownField,
userAvatarLink,
......@@ -54,6 +55,9 @@
isIssueOpen() {
return this.issueState === constants.OPENED || this.issueState === constants.REOPENED;
},
canCreate() {
return this.getIssueData.current_user.can_create_note;
},
issueActionButtonTitle() {
if (this.note.length) {
const actionText = this.isIssueOpen ? 'close' : 'reopen';
......@@ -89,9 +93,6 @@
endpoint() {
return this.getIssueData.create_note_path;
},
isConfidentialIssue() {
return this.getIssueData.confidential;
},
},
methods: {
...mapActions([
......@@ -206,6 +207,9 @@
});
},
},
mixins: [
issuableStateMixin,
],
mounted() {
// jQuery is needed here because it is a custom event being dispatched with jQuery.
$(document).on('issuable:change', (e, isClosed) => {
......@@ -239,15 +243,22 @@
<div class="timeline-content timeline-content-form">
<form
ref="commentForm"
class="new-note js-quick-submit common-note-form gfm-form js-main-target-form">
<confidentialIssue v-if="isConfidentialIssue" />
class="new-note js-quick-submit common-note-form gfm-form js-main-target-form"
>
<issue-warning
v-if="hasIssueWarning(getIssueData)"
:is-locked="isIssueLocked(getIssueData)"
:is-confidential="isIssueConfidential(getIssueData)"
/>
<div class="error-alert"></div>
<markdown-field
:markdown-preview-path="markdownPreviewPath"
:markdown-docs-path="markdownDocsPath"
:quick-actions-docs-path="quickActionsDocsPath"
:add-spacing-classes="false"
:is-confidential-issue="isConfidentialIssue">
:is-confidential-issue="isIssueConfidential(getIssueData)">
<textarea
id="note-body"
name="note[note]"
......
<script>
import { mapGetters } from 'vuex';
import eventHub from '../event_hub';
import confidentialIssue from '../../vue_shared/components/issue/confidential_issue_warning.vue';
import issueWarning from '../../vue_shared/components/issue/issue_warning.vue';
import markdownField from '../../vue_shared/components/markdown/field.vue';
import issuableStateMixin from '../mixins/issuable_state';
export default {
name: 'issueNoteForm',
......@@ -39,12 +40,13 @@
};
},
components: {
confidentialIssue,
issueWarning,
markdownField,
},
computed: {
...mapGetters([
'getDiscussionLastNote',
'getIssueData',
'getIssueDataByProp',
'getNotesDataByProp',
'getUserDataByProp',
......@@ -67,9 +69,6 @@
isDisabled() {
return !this.note.length || this.isSubmitting;
},
isConfidentialIssue() {
return this.getIssueDataByProp('confidential');
},
},
methods: {
handleUpdate() {
......@@ -95,6 +94,9 @@
this.$emit('cancelFormEdition', shouldConfirm, this.noteBody !== this.note);
},
},
mixins: [
issuableStateMixin,
],
mounted() {
this.$refs.textarea.focus();
},
......@@ -125,7 +127,13 @@
<div class="flash-container timeline-content"></div>
<form
class="edit-note common-note-form js-quick-submit gfm-form">
<confidentialIssue v-if="isConfidentialIssue" />
<issue-warning
v-if="hasIssueWarning(getIssueData)"
:is-locked="isIssueLocked(getIssueData)"
:is-confidential="isIssueConfidential(getIssueData)"
/>
<markdown-field
:markdown-preview-path="markdownPreviewPath"
:markdown-docs-path="markdownDocsPath"
......
export default {
methods: {
isIssueConfidential(issue) {
return !!issue.confidential;
},
isIssueLocked(issue) {
return !!issue.discussion_locked;
},
hasIssueWarning(issue) {
return this.isIssueConfidential(issue) || this.isIssueLocked(issue);
},
},
};
......@@ -47,9 +47,9 @@ export default {
</script>
<template>
<div class="block confidentiality">
<div class="block issuable-sidebar-item confidentiality">
<div class="sidebar-collapsed-icon">
<i class="fa" :class="faEye" aria-hidden="true" data-hidden="true"></i>
<i class="fa" :class="faEye" aria-hidden="true"></i>
</div>
<div class="title hide-collapsed">
Confidentiality
......@@ -62,19 +62,19 @@ export default {
Edit
</a>
</div>
<div class="value confidential-value hide-collapsed">
<div class="value sidebar-item-value hide-collapsed">
<editForm
v-if="edit"
:toggle-form="toggleForm"
:is-confidential="isConfidential"
:update-confidential-attribute="updateConfidentialAttribute"
/>
<div v-if="!isConfidential" class="no-value confidential-value">
<i class="fa fa-eye is-not-confidential"></i>
<div v-if="!isConfidential" class="no-value sidebar-item-value">
<i class="fa fa-eye not-active"></i>
Not confidential
</div>
<div v-else class="value confidential-value hide-collapsed">
<i aria-hidden="true" data-hidden="true" class="fa fa-eye-slash is-confidential"></i>
<div v-else class="value sidebar-item-value hide-collapsed">
<i aria-hidden="true" class="fa fa-eye-slash is-active"></i>
This issue is confidential
</div>
</div>
......
......@@ -2,9 +2,6 @@
import editFormButtons from './edit_form_buttons.vue';
export default {
components: {
editFormButtons,
},
props: {
isConfidential: {
required: true,
......@@ -19,12 +16,16 @@ export default {
type: Function,
},
},
components: {
editFormButtons,
},
};
</script>
<template>
<div class="dropdown open">
<div class="dropdown-menu confidential-warning-message">
<div class="dropdown-menu sidebar-item-warning-message">
<div>
<p v-if="!isConfidential">
You are going to turn on the confidentiality. This means that only team members with
......
......@@ -15,7 +15,7 @@ export default {
},
},
computed: {
onOrOff() {
buttonText() {
return this.isConfidential ? 'Turn Off' : 'Turn On';
},
updateConfidentialBool() {
......@@ -26,7 +26,7 @@ export default {
</script>
<template>
<div class="confidential-warning-message-actions">
<div class="sidebar-item-warning-message-actions">
<button
type="button"
class="btn btn-default append-right-10"
......@@ -39,7 +39,7 @@ export default {
class="btn btn-close"
@click.prevent="updateConfidentialAttribute(updateConfidentialBool)"
>
{{ onOrOff }}
{{ buttonText }}
</button>
</div>
</template>
<script>
import editFormButtons from './edit_form_buttons.vue';
import issuableMixin from '../../../vue_shared/mixins/issuable';
export default {
props: {
isLocked: {
required: true,
type: Boolean,
},
toggleForm: {
required: true,
type: Function,
},
updateLockedAttribute: {
required: true,
type: Function,
},
issuableType: {
required: true,
type: String,
},
},
mixins: [
issuableMixin,
],
components: {
editFormButtons,
},
};
</script>
<template>
<div class="dropdown open">
<div class="dropdown-menu sidebar-item-warning-message">
<div>
<p v-if="isLocked">
{{ __(`Unlock this ${issuableDisplayName(issuableType)}?`) }}
<strong>{{ __('Everyone') }}</strong>
{{ __('will be able to comment.') }}
</p>
<p v-else>
{{ __(`Lock this ${issuableDisplayName(issuableType)}? Only`) }}
<strong>{{ __('project members') }}</strong>
{{ __('will be able to comment.') }}
</p>
<edit-form-buttons
:is-locked="isLocked"
:toggle-form="toggleForm"
:update-locked-attribute="updateLockedAttribute"
/>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
isLocked: {
required: true,
type: Boolean,
},
toggleForm: {
required: true,
type: Function,
},
updateLockedAttribute: {
required: true,
type: Function,
},
},
computed: {
buttonText() {
return this.isLocked ? this.__('Unlock') : this.__('Lock');
},
updateLockedBool() {
return !this.isLocked;
},
},
};
</script>
<template>
<div class="sidebar-item-warning-message-actions">
<button
type="button"
class="btn btn-default append-right-10"
@click="toggleForm"
>
{{ __('Cancel') }}
</button>
<button
type="button"
class="btn btn-close"
@click.prevent="updateLockedAttribute(updateLockedBool)"
>
{{ buttonText }}
</button>
</div>
</template>
<script>
/* global Flash */
import editForm from './edit_form.vue';
import issuableMixin from '../../../vue_shared/mixins/issuable';
export default {
props: {
isLocked: {
required: true,
type: Boolean,
},
isEditable: {
required: true,
type: Boolean,
},
mediator: {
required: true,
type: Object,
validator(mediatorObject) {
return mediatorObject.service && mediatorObject.service.update && mediatorObject.store;
},
},
issuableType: {
required: true,
type: String,
},
},
mixins: [
issuableMixin,
],
components: {
editForm,
},
computed: {
lockIconClass() {
return this.isLocked ? 'fa-lock' : 'fa-unlock';
},
isLockDialogOpen() {
return this.mediator.store.isLockDialogOpen;
},
},
methods: {
toggleForm() {
this.mediator.store.isLockDialogOpen = !this.mediator.store.isLockDialogOpen;
},
updateLockedAttribute(locked) {
this.mediator.service.update(this.issuableType, {
discussion_locked: locked,
})
.then(() => location.reload())
.catch(() => Flash(this.__(`Something went wrong trying to change the locked state of this ${issuableDisplayName(this.issuableType)}`)));
},
},
};
</script>
<template>
<div class="block issuable-sidebar-item lock">
<div class="sidebar-collapsed-icon">
<i
class="fa"
:class="lockIconClass"
aria-hidden="true"
></i>
</div>
<div class="title hide-collapsed">
{{ __(`Lock ${issuableDisplayName(issuableType)}`) }}
<button
v-if="isEditable"
class="pull-right lock-edit btn btn-blank"
type="button"
@click.prevent="toggleForm"
>
{{ __('Edit') }}
</button>
</div>
<div class="value sidebar-item-value hide-collapsed">
<editForm
v-if="isLockDialogOpen"
:toggle-form="toggleForm"
:is-locked="isLocked"
:update-locked-attribute="updateLockedAttribute"
:issuable-type="issuableType"
/>
<div v-if="isLocked" class="value sidebar-item-value">
<i aria-hidden="true" class="fa fa-lock is-active"></i>
{{ __('Locked') }}
</div>
<div v-else class="no-value sidebar-item-value hide-collapsed">
<i aria-hidden="true" class="fa fa-unlock not-active"></i>
{{ __('Unlocked') }}
</div>
</div>
</div>
</template>
......@@ -3,42 +3,72 @@ import sidebarTimeTracking from './components/time_tracking/sidebar_time_trackin
import sidebarAssignees from './components/assignees/sidebar_assignees';
import confidential from './components/confidential/confidential_issue_sidebar.vue';
import SidebarMoveIssue from './lib/sidebar_move_issue';
import lockBlock from './components/lock/lock_issue_sidebar.vue';
import Translate from '../vue_shared/translate';
import Mediator from './sidebar_mediator';
Vue.use(Translate);
function mountConfidentialComponent(mediator) {
const el = document.querySelector('#js-confidential-entry-point');
if (!el) return;
const dataNode = document.getElementById('js-confidential-issue-data');
const initialData = JSON.parse(dataNode.innerHTML);
const ConfidentialComp = Vue.extend(confidential);
new ConfidentialComp({
propsData: {
isConfidential: initialData.is_confidential,
isEditable: initialData.is_editable,
service: mediator.service,
},
}).$mount(el);
}
function mountLockComponent(mediator) {
const el = document.querySelector('#js-lock-entry-point');
if (!el) return;
const dataNode = document.getElementById('js-lock-issue-data');
const initialData = JSON.parse(dataNode.innerHTML);
const LockComp = Vue.extend(lockBlock);
new LockComp({
propsData: {
isLocked: initialData.is_locked,
isEditable: initialData.is_editable,
mediator,
issuableType: gl.utils.isInIssuePage() ? 'issue' : 'merge_request',
},
}).$mount(el);
}
function domContentLoaded() {
const sidebarOptions = JSON.parse(document.querySelector('.js-sidebar-options').innerHTML);
const mediator = new Mediator(sidebarOptions);
mediator.fetch();
const sidebarAssigneesEl = document.querySelector('#js-vue-sidebar-assignees');
const confidentialEl = document.querySelector('#js-confidential-entry-point');
// Only create the sidebarAssignees vue app if it is found in the DOM
// We currently do not use sidebarAssignees for the MR page
if (sidebarAssigneesEl) {
new Vue(sidebarAssignees).$mount(sidebarAssigneesEl);
}
if (confidentialEl) {
const dataNode = document.getElementById('js-confidential-issue-data');
const initialData = JSON.parse(dataNode.innerHTML);
mountConfidentialComponent(mediator);
mountLockComponent(mediator);
const ConfidentialComp = Vue.extend(confidential);
new ConfidentialComp({
propsData: {
isConfidential: initialData.is_confidential,
isEditable: initialData.is_editable,
service: mediator.service,
},
}).$mount(confidentialEl);
new SidebarMoveIssue(
mediator,
$('.js-move-issue'),
$('.js-move-issue-confirmation-button'),
).init();
}
new SidebarMoveIssue(
mediator,
$('.js-move-issue'),
$('.js-move-issue-confirmation-button'),
).init();
new Vue(sidebarTimeTracking).$mount('#issuable-time-tracker');
}
......
......@@ -15,6 +15,7 @@ export default class SidebarStore {
};
this.autocompleteProjects = [];
this.moveToProjectId = 0;
this.isLockDialogOpen = false;
SidebarStore.singleton = this;
}
......
<script>
export default {
name: 'confidentialIssueWarning',
};
</script>
<template>
<div class="confidential-issue-warning">
<i
aria-hidden="true"
class="fa fa-eye-slash">
</i>
<span>
This is a confidential issue. Your comment will not be visible to the public.
</span>
</div>
</template>
<script>
export default {
props: {
isLocked: {
type: Boolean,
default: false,
},
isConfidential: {
type: Boolean,
default: false,
},
},
computed: {
iconClass() {
return {
'fa-eye-slash': this.isConfidential,
'fa-lock': this.isLocked,
};
},
isLockedAndConfidential() {
return this.isConfidential && this.isLocked;
},
},
};
</script>
<template>
<div class="issuable-note-warning">
<i
aria-hidden="true"
class="fa"
:class="iconClass"
v-if="!isLockedAndConfidential"
></i>
<span v-if="isLockedAndConfidential">
{{ __('This issue is confidential and locked.') }}
{{ __('People without permission will never get a notification and not be able to comment.') }}
</span>
<span v-else-if="isConfidential">
{{ __('This is a confidential issue.') }}
{{ __('Your comment will not be visible to the public.') }}
</span>
<span v-else-if="isLocked">
{{ __('This issue is locked.') }}
{{ __('Only project members can comment.') }}
</span>
</div>
</template>
export default {
methods: {
issuableDisplayName(issuableType) {
return issuableType.replace(/_/, ' ');
},
},
};
......@@ -385,7 +385,11 @@
background: transparent;
border: 0;
&:hover,
&:active,
&:focus {
outline: 0;
background: transparent;
box-shadow: none;
}
}
......@@ -694,3 +694,8 @@ Project Templates Icons
$rails: #c00;
$node: #353535;
$java: #70ad51;
/*
Issuable warning
*/
$issuable-warning-size: 24px;
......@@ -5,27 +5,28 @@
margin-right: auto;
}
.is-confidential {
.issuable-warning-icon {
color: $orange-600;
background-color: $orange-50;
border-radius: $border-radius-default;
padding: 5px;
margin: 0 3px 0 -4px;
margin: 0 $btn-side-margin 0 0;
width: $issuable-warning-size;
height: $issuable-warning-size;
text-align: center;
}
.is-not-confidential {
border-radius: $border-radius-default;
padding: 5px;
margin: 0 3px 0 -4px;
}
.confidentiality {
.is-not-confidential {
margin: auto;
.issuable-sidebar-item {
.not-active,
.is-active {
border-radius: $border-radius-default;
padding: 5px;
margin: 0 3px 0 -4px;
}
.is-confidential {
margin: auto;
.is-active {
color: $orange-600;
background-color: $orange-50;
}
}
......
/**
* Note Form
*/
.comment-btn {
.comment-btn {
@extend .btn-create;
}
......@@ -101,7 +101,7 @@
}
}
.confidential-issue-warning {
.issuable-note-warning {
color: $orange-600;
background-color: $orange-50;
border-radius: $border-radius-default $border-radius-default 0 0;
......@@ -112,17 +112,21 @@
align-items: center;
}
.confidential-value {
.sidebar-item-value {
.fa {
background-color: inherit;
}
}
.confidential-warning-message {
.sidebar-item-warning-message {
line-height: 1.5;
padding: 16px;
.confidential-warning-message-actions {
p {
color: $text-color;
}
.sidebar-item-warning-message-actions {
display: flex;
button {
......@@ -131,7 +135,7 @@
}
}
.confidential-issue-warning + .md-area {
.issuable-note-warning + .md-area {
border-top-left-radius: 0;
border-top-right-radius: 0;
}
......
- referenced_users = local_assigns.fetch(:referenced_users, nil)
- if defined?(@merge_request) && @merge_request.discussion_locked?
.issuable-note-warning
= icon('lock')
%span
= _('This merge request is locked.')
= _('Only project members can comment.')
.md-area
.md-header
%ul.nav-links.clearfix
......
......@@ -27,8 +27,9 @@
.issuable-meta
- if @issue.confidential
= icon('eye-slash', class: 'is-confidential')
= issuable_meta(@issue, @project, "Issue")
= icon('eye-slash', class: 'issuable-warning-icon')
- if @issue.discussion_locked?
= icon('lock', class: 'issuable-warning-icon')
.issuable-actions.js-issuable-actions
.clearfix.issue-btn-group.dropdown
......
......@@ -15,6 +15,8 @@
= icon('angle-double-left')
.issuable-meta
- if @merge_request.discussion_locked
= icon('lock', class: 'issuable-warning-icon')
= issuable_meta(@merge_request, @project, "Merge request")
.issuable-actions.js-issuable-actions
......
......@@ -119,6 +119,10 @@
%script#js-confidential-issue-data{ type: "application/json" }= { is_confidential: @issue.confidential, is_editable: can_edit_issuable }.to_json.html_safe
#js-confidential-entry-point
- if issuable.has_attribute?(:discussion_locked)
%script#js-lock-issue-data{ type: "application/json" }= { is_locked: issuable.discussion_locked?, is_editable: can_edit_issuable }.to_json.html_safe
#js-lock-entry-point
= render "shared/issuable/participants", participants: issuable.participants(current_user)
- if current_user
- subscribed = issuable.subscribed?(current_user, @project)
......
......@@ -725,14 +725,14 @@ describe 'Issues' do
visit project_issue_path(project, issue)
expect(page).to have_css('.confidential-issue-warning')
expect(page).to have_css('.is-confidential')
expect(page).not_to have_css('.is-not-confidential')
expect(page).to have_css('.issuable-note-warning')
expect(find('.issuable-sidebar-item.confidentiality')).to have_css('.is-active')
expect(find('.issuable-sidebar-item.confidentiality')).not_to have_css('.not-active')
find('.confidential-edit').click
expect(page).to have_css('.confidential-warning-message')
expect(page).to have_css('.sidebar-item-warning-message')
within('.confidential-warning-message') do
within('.sidebar-item-warning-message') do
find('.btn-close').click
end
......@@ -740,7 +740,7 @@ describe 'Issues' do
visit project_issue_path(project, issue)
expect(page).not_to have_css('.is-confidential')
expect(page).not_to have_css('.is-active')
end
end
end
import Vue from 'vue';
import editFormButtons from '~/sidebar/components/lock/edit_form_buttons.vue';
import mountComponent from '../../helpers/vue_mount_component_helper';
describe('EditFormButtons', () => {
let vm1;
let vm2;
beforeEach(() => {
const Component = Vue.extend(editFormButtons);
const toggleForm = () => { };
const updateLockedAttribute = () => { };
vm1 = mountComponent(Component, {
isLocked: true,
toggleForm,
updateLockedAttribute,
});
vm2 = mountComponent(Component, {
isLocked: false,
toggleForm,
updateLockedAttribute,
});
});
it('renders unlock or lock text based on locked state', () => {
expect(
vm1.$el.innerHTML.includes('Unlock'),
).toBe(true);
expect(
vm2.$el.innerHTML.includes('Lock'),
).toBe(true);
});
});
import Vue from 'vue';
import editForm from '~/sidebar/components/lock/edit_form.vue';
describe('EditForm', () => {
let vm1;
let vm2;
beforeEach(() => {
const Component = Vue.extend(editForm);
const toggleForm = () => { };
const updateLockedAttribute = () => { };
vm1 = new Component({
propsData: {
isLocked: true,
toggleForm,
updateLockedAttribute,
issuableType: 'issue',
},
}).$mount();
vm2 = new Component({
propsData: {
isLocked: false,
toggleForm,
updateLockedAttribute,
issuableType: 'merge_request',
},
}).$mount();
});
it('renders on the appropriate warning text', () => {
expect(
vm1.$el.innerHTML.includes('Unlock this issue?'),
).toBe(true);
expect(
vm2.$el.innerHTML.includes('Lock this merge request?'),
).toBe(true);
});
});
import Vue from 'vue';
import lockIssueSidebar from '~/sidebar/components/lock/lock_issue_sidebar.vue';
describe('LockIssueSidebar', () => {
let vm1;
let vm2;
beforeEach(() => {
const Component = Vue.extend(lockIssueSidebar);
const mediator = {
service: {
update: () => new Promise((resolve) => {
resolve(true);
}),
},
store: {
isLockDialogOpen: false,
},
};
vm1 = new Component({
propsData: {
isLocked: true,
isEditable: true,
mediator,
issuableType: 'issue',
},
}).$mount();
vm2 = new Component({
propsData: {
isLocked: false,
isEditable: false,
mediator,
issuableType: 'merge_request',
},
}).$mount();
});
it('shows if locked and/or editable', () => {
expect(
vm1.$el.innerHTML.includes('Edit'),
).toBe(true);
expect(
vm1.$el.innerHTML.includes('Locked'),
).toBe(true);
expect(
vm2.$el.innerHTML.includes('Unlocked'),
).toBe(true);
});
it('displays the edit form when editable', (done) => {
expect(vm1.isLockDialogOpen).toBe(false);
vm1.$el.querySelector('.lock-edit').click();
expect(vm1.isLockDialogOpen).toBe(true);
vm1.$nextTick(() => {
expect(
vm1.$el
.innerHTML
.includes('Unlock this issue?'),
).toBe(true);
done();
});
});
});
import Vue from 'vue';
import confidentialIssue from '~/vue_shared/components/issue/confidential_issue_warning.vue';
describe('Confidential Issue Warning Component', () => {
let vm;
beforeEach(() => {
const Component = Vue.extend(confidentialIssue);
vm = new Component().$mount();
});
afterEach(() => {
vm.$destroy();
});
it('should render confidential issue warning information', () => {
expect(vm.$el.querySelector('i').className).toEqual('fa fa-eye-slash');
expect(vm.$el.querySelector('span').textContent.trim()).toEqual('This is a confidential issue. Your comment will not be visible to the public.');
});
});
import Vue from 'vue';
import issueWarning from '~/vue_shared/components/issue/issue_warning.vue';
import mountComponent from '../../../helpers/vue_mount_component_helper';
const IssueWarning = Vue.extend(issueWarning);
function formatWarning(string) {
return string.trim().replace(/\n/g, ' ').replace(/\s\s+/g, ' ');
}
describe('Issue Warning Component', () => {
describe('isLocked', () => {
it('should render locked issue warning information', () => {
const vm = mountComponent(IssueWarning, {
isLocked: true,
});
expect(vm.$el.querySelector('i').className).toEqual('fa fa-lock');
expect(formatWarning(vm.$el.querySelector('span').textContent)).toEqual('This issue is locked. Only project members can comment.');
});
});
describe('isConfidential', () => {
it('should render confidential issue warning information', () => {
const vm = mountComponent(IssueWarning, {
isConfidential: true,
});
expect(vm.$el.querySelector('i').className).toEqual('fa fa-eye-slash');
expect(formatWarning(vm.$el.querySelector('span').textContent)).toEqual('This is a confidential issue. Your comment will not be visible to the public.');
});
});
describe('isLocked and isConfidential', () => {
it('should render locked and confidential issue warning information', () => {
const vm = mountComponent(IssueWarning, {
isLocked: true,
isConfidential: true,
});
expect(vm.$el.querySelector('i')).toBeFalsy();
expect(formatWarning(vm.$el.querySelector('span').textContent)).toEqual('This issue is confidential and locked. People without permission will never get a notification and not be able to comment.');
});
});
});
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册