Skip to content
Snippets Groups Projects
Commit f59bdbf0 authored by Regis Boudinot's avatar Regis Boudinot Committed by Jacob Schatz
Browse files

33874 confidential issue redesign

parent 1bed998e
No related branches found
No related tags found
No related merge requests found
Showing
with 434 additions and 28 deletions
<script>
/* global Flash */
import editForm from './edit_form.vue';
export default {
components: {
editForm,
},
props: {
isConfidential: {
required: true,
type: Boolean,
},
isEditable: {
required: true,
type: Boolean,
},
service: {
required: true,
type: Object,
},
},
data() {
return {
edit: false,
};
},
computed: {
faEye() {
const eye = this.isConfidential ? 'fa-eye-slash' : 'fa-eye';
return {
[eye]: true,
};
},
},
methods: {
toggleForm() {
this.edit = !this.edit;
},
updateConfidentialAttribute(confidential) {
this.service.update('issue', { confidential })
.then(() => location.reload())
.catch(() => new Flash('Something went wrong trying to change the confidentiality of this issue'));
},
},
};
</script>
<template>
<div class="block confidentiality">
<div class="sidebar-collapsed-icon">
<i class="fa" :class="faEye" aria-hidden="true" data-hidden="true"></i>
</div>
<div class="title hide-collapsed">
Confidentiality
<a
v-if="isEditable"
class="pull-right confidential-edit"
href="#"
@click.prevent="toggleForm"
>
Edit
</a>
</div>
<div class="value confidential-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>
None
</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>
This issue is confidential
</div>
</div>
</div>
</template>
<script>
import editFormButtons from './edit_form_buttons.vue';
export default {
components: {
editFormButtons,
},
props: {
isConfidential: {
required: true,
type: Boolean,
},
toggleForm: {
required: true,
type: Function,
},
updateConfidentialAttribute: {
required: true,
type: Function,
},
},
};
</script>
<template>
<div class="dropdown open">
<div class="dropdown-menu confidential-warning-message">
<div>
<p v-if="!isConfidential">
You are going to turn on the confidentiality. This means that only team members with
<strong>at least Reporter access</strong>
are able to see and leave comments on the issue.
</p>
<p v-else>
You are going to turn off the confidentiality. This means
<strong>everyone</strong>
will be able to see and leave a comment on this issue.
</p>
<edit-form-buttons
:is-confidential="isConfidential"
:toggle-form="toggleForm"
:update-confidential-attribute="updateConfidentialAttribute"
/>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
isConfidential: {
required: true,
type: Boolean,
},
toggleForm: {
required: true,
type: Function,
},
updateConfidentialAttribute: {
required: true,
type: Function,
},
},
computed: {
onOrOff() {
return this.isConfidential ? 'Turn Off' : 'Turn On';
},
updateConfidentialBool() {
return !this.isConfidential;
},
},
};
</script>
<template>
<div class="confidential-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="updateConfidentialAttribute(updateConfidentialBool)"
>
{{ onOrOff }}
</button>
</div>
</template>
import Vue from 'vue';
import sidebarTimeTracking from './components/time_tracking/sidebar_time_tracking';
import sidebarAssignees from './components/assignees/sidebar_assignees';
import confidential from './components/confidential/confidential_issue_sidebar.vue';
 
import Mediator from './sidebar_mediator';
 
Loading
Loading
@@ -10,13 +11,28 @@ function domContentLoaded() {
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);
const ConfidentialComp = Vue.extend(confidential);
new ConfidentialComp({
propsData: {
isConfidential: initialData.is_confidential,
isEditable: initialData.is_editable,
service: mediator.service,
},
}).$mount(confidentialEl);
}
new Vue(sidebarTimeTracking).$mount('#issuable-time-tracker');
}
 
Loading
Loading
Loading
Loading
@@ -5,6 +5,30 @@
margin-right: auto;
}
 
.is-confidential {
color: $orange-600;
background-color: $orange-50;
border-radius: 3px;
padding: 5px;
margin: 0 3px 0 -4px;
}
.is-not-confidential {
border-radius: 3px;
padding: 5px;
margin: 0 3px 0 -4px;
}
.confidentiality {
.is-not-confidential {
margin: auto;
}
.is-confidential {
margin: auto;
}
}
.limit-container-width {
.detail-page-header,
.page-content-header,
Loading
Loading
Loading
Loading
@@ -104,40 +104,51 @@
}
 
.confidential-issue-warning {
background-color: $gray-normal;
border-radius: 3px;
color: $orange-600;
background-color: $orange-50;
border-radius: $border-radius-default $border-radius-default 0 0;
border: 1px solid $border-gray-normal;
padding: 3px 12px;
margin: auto;
margin-top: 0;
text-align: center;
font-size: 12px;
align-items: center;
}
 
@media (max-width: $screen-md-max) {
// On smaller devices the warning becomes the fourth item in the list,
// rather than centering, and grows to span the full width of the
// comment area.
order: 4;
margin: 6px auto;
width: 100%;
.confidential-value {
.fa {
background-color: inherit;
}
}
 
.fa {
margin-right: 8px;
.confidential-warning-message {
line-height: 1.5;
padding: 16px;
.confidential-warning-message-actions {
display: flex;
button {
flex-grow: 1;
}
}
}
 
.not-confidential {
padding: 0;
border-top: none;
}
.right-sidebar-expanded {
.confidential-issue-warning {
// When the sidebar is open the warning becomes the fourth item in the list,
// rather than centering, and grows to span the full width of the
// comment area.
order: 4;
margin: 6px auto;
width: 100%;
.md-area {
border-radius: 0;
border-top: none;
}
}
 
.right-sidebar-collapsed {
.confidential-issue-warning {
border-bottom: none;
}
}
 
.discussion-form {
padding: $gl-padding-top $gl-padding $gl-padding;
Loading
Loading
- referenced_users = local_assigns.fetch(:referenced_users, nil)
 
- if defined?(@issue) && @issue.confidential?
%li.confidential-issue-warning
= confidential_icon(@issue)
%span This is a confidential issue. Your comment will not be visible to the public.
- else
%li.confidential-issue-warning.not-confidential
.md-area
.md-header
%ul.nav-links.clearfix
Loading
Loading
@@ -10,11 +17,6 @@
%a.js-md-preview-button{ href: "#md-preview-holder", tabindex: -1 }
Preview
 
- if defined?(@issue) && @issue.confidential?
%li.confidential-issue-warning
= icon('warning')
%span This is a confidential issue. Your comment will not be visible to the public.
%li.pull-right
.toolbar-group
= markdown_toolbar_button({ icon: "bold fw", data: { "md-tag" => "**" }, title: "Add bold text" })
Loading
Loading
Loading
Loading
@@ -19,7 +19,8 @@
= icon('angle-double-left')
 
.issuable-meta
= confidential_icon(@issue)
- if @issue.confidential
= icon('eye-slash', class: 'is-confidential')
= issuable_meta(@issue, @project, "Issue")
 
.issuable-actions
Loading
Loading
Loading
Loading
@@ -115,6 +115,10 @@
- if can? current_user, :admin_label, @project and @project
= render partial: "shared/issuable/label_page_create"
 
- if issuable.has_attribute?(:confidential)
%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
= render "shared/issuable/participants", participants: issuable.participants(current_user)
- if current_user
- subscribed = issuable.subscribed?(current_user, @project)
Loading
Loading
---
title: Update confidential issue UI - add confidential visibility and settings to
sidebar
merge_request:
author:
Loading
Loading
@@ -706,4 +706,30 @@ describe 'Issues' do
expect(page).to have_text("updated title")
end
end
describe 'confidential issue#show', js: true do
it 'shows confidential sibebar information as confidential and can be turned off' do
issue = create(:issue, :confidential, project: project)
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')
find('.confidential-edit').click
expect(page).to have_css('.confidential-warning-message')
within('.confidential-warning-message') do
find('.btn-close').click
end
wait_for_requests
visit project_issue_path(project, issue)
expect(page).not_to have_css('.is-confidential')
expect(page).to have_css('.is-not-confidential')
end
end
end
import Vue from 'vue';
import editFormButtons from '~/sidebar/components/confidential/edit_form_buttons.vue';
describe('Edit Form Buttons', () => {
let vm1;
let vm2;
beforeEach(() => {
const Component = Vue.extend(editFormButtons);
const toggleForm = () => { };
const updateConfidentialAttribute = () => { };
vm1 = new Component({
propsData: {
isConfidential: true,
toggleForm,
updateConfidentialAttribute,
},
}).$mount();
vm2 = new Component({
propsData: {
isConfidential: false,
toggleForm,
updateConfidentialAttribute,
},
}).$mount();
});
it('renders on or off text based on confidentiality', () => {
expect(
vm1.$el.innerHTML.includes('Turn Off'),
).toBe(true);
expect(
vm2.$el.innerHTML.includes('Turn On'),
).toBe(true);
});
});
import Vue from 'vue';
import editForm from '~/sidebar/components/confidential/edit_form.vue';
describe('Edit Form Dropdown', () => {
let vm1;
let vm2;
beforeEach(() => {
const Component = Vue.extend(editForm);
const toggleForm = () => { };
const updateConfidentialAttribute = () => { };
vm1 = new Component({
propsData: {
isConfidential: true,
toggleForm,
updateConfidentialAttribute,
},
}).$mount();
vm2 = new Component({
propsData: {
isConfidential: false,
toggleForm,
updateConfidentialAttribute,
},
}).$mount();
});
it('renders on the appropriate warning text', () => {
expect(
vm1.$el.innerHTML.includes('You are going to turn off the confidentiality.'),
).toBe(true);
expect(
vm2.$el.innerHTML.includes('You are going to turn on the confidentiality.'),
).toBe(true);
});
});
import Vue from 'vue';
import confidentialIssueSidebar from '~/sidebar/components/confidential/confidential_issue_sidebar.vue';
describe('Confidential Issue Sidebar Block', () => {
let vm1;
let vm2;
beforeEach(() => {
const Component = Vue.extend(confidentialIssueSidebar);
const service = {
update: () => new Promise((resolve, reject) => {
resolve(true);
reject('failed!');
}),
};
vm1 = new Component({
propsData: {
isConfidential: true,
isEditable: true,
service,
},
}).$mount();
vm2 = new Component({
propsData: {
isConfidential: false,
isEditable: false,
service,
},
}).$mount();
});
it('shows if confidential and/or editable', () => {
expect(
vm1.$el.innerHTML.includes('Edit'),
).toBe(true);
expect(
vm1.$el.innerHTML.includes('This issue is confidential'),
).toBe(true);
expect(
vm2.$el.innerHTML.includes('None'),
).toBe(true);
});
it('displays the edit form when editable', (done) => {
expect(vm1.edit).toBe(false);
vm1.$el.querySelector('.confidential-edit').click();
expect(vm1.edit).toBe(true);
setTimeout(() => {
expect(
vm1.$el
.innerHTML
.includes('You are going to turn off the confidentiality.'),
).toBe(true);
done();
});
});
});
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment