From f59bdbf0f12b2f370a6931753d8ee14ba92d66ea Mon Sep 17 00:00:00 2001 From: Regis Boudinot Date: Mon, 7 Aug 2017 23:56:16 +0000 Subject: [PATCH] 33874 confidential issue redesign --- .../confidential_issue_sidebar.vue | 82 +++++++++++++++++++ .../components/confidential/edit_form.vue | 47 +++++++++++ .../confidential/edit_form_buttons.vue | 45 ++++++++++ .../javascripts/sidebar/sidebar_bundle.js | 18 +++- app/assets/stylesheets/pages/issuable.scss | 24 ++++++ app/assets/stylesheets/pages/note_form.scss | 53 +++++++----- app/views/projects/_md_preview.html.haml | 12 +-- app/views/projects/issues/show.html.haml | 3 +- app/views/shared/issuable/_sidebar.html.haml | 4 + changelogs/unreleased/33874_confi.yml | 5 ++ spec/features/issues_spec.rb | 26 ++++++ .../sidebar/confidential_edit_buttons_spec.js | 39 +++++++++ .../confidential_edit_form_buttons_spec.js | 39 +++++++++ .../confidential_issue_sidebar_spec.js | 65 +++++++++++++++ 14 files changed, 434 insertions(+), 28 deletions(-) create mode 100644 app/assets/javascripts/sidebar/components/confidential/confidential_issue_sidebar.vue create mode 100644 app/assets/javascripts/sidebar/components/confidential/edit_form.vue create mode 100644 app/assets/javascripts/sidebar/components/confidential/edit_form_buttons.vue create mode 100644 changelogs/unreleased/33874_confi.yml create mode 100644 spec/javascripts/sidebar/confidential_edit_buttons_spec.js create mode 100644 spec/javascripts/sidebar/confidential_edit_form_buttons_spec.js create mode 100644 spec/javascripts/sidebar/confidential_issue_sidebar_spec.js diff --git a/app/assets/javascripts/sidebar/components/confidential/confidential_issue_sidebar.vue b/app/assets/javascripts/sidebar/components/confidential/confidential_issue_sidebar.vue new file mode 100644 index 00000000000..422c02c7b7e --- /dev/null +++ b/app/assets/javascripts/sidebar/components/confidential/confidential_issue_sidebar.vue @@ -0,0 +1,82 @@ + + + diff --git a/app/assets/javascripts/sidebar/components/confidential/edit_form.vue b/app/assets/javascripts/sidebar/components/confidential/edit_form.vue new file mode 100644 index 00000000000..d578b663a54 --- /dev/null +++ b/app/assets/javascripts/sidebar/components/confidential/edit_form.vue @@ -0,0 +1,47 @@ + + + diff --git a/app/assets/javascripts/sidebar/components/confidential/edit_form_buttons.vue b/app/assets/javascripts/sidebar/components/confidential/edit_form_buttons.vue new file mode 100644 index 00000000000..97af4a3f505 --- /dev/null +++ b/app/assets/javascripts/sidebar/components/confidential/edit_form_buttons.vue @@ -0,0 +1,45 @@ + + + diff --git a/app/assets/javascripts/sidebar/sidebar_bundle.js b/app/assets/javascripts/sidebar/sidebar_bundle.js index a9df66748c5..9edded3ead6 100644 --- a/app/assets/javascripts/sidebar/sidebar_bundle.js +++ b/app/assets/javascripts/sidebar/sidebar_bundle.js @@ -1,6 +1,7 @@ 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'; @@ -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'); } diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss index 88343bd0113..b78db402c13 100644 --- a/app/assets/stylesheets/pages/issuable.scss +++ b/app/assets/stylesheets/pages/issuable.scss @@ -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, diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss index cdb1e65e4be..c90642178fc 100644 --- a/app/assets/stylesheets/pages/note_form.scss +++ b/app/assets/stylesheets/pages/note_form.scss @@ -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; diff --git a/app/views/projects/_md_preview.html.haml b/app/views/projects/_md_preview.html.haml index d0698285f84..6e13bf47ff6 100644 --- a/app/views/projects/_md_preview.html.haml +++ b/app/views/projects/_md_preview.html.haml @@ -1,5 +1,12 @@ - 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 @@ -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" }) diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml index a57844f974e..ad5befc6ee5 100644 --- a/app/views/projects/issues/show.html.haml +++ b/app/views/projects/issues/show.html.haml @@ -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 diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml index e7510c1d1ec..c2de6926460 100644 --- a/app/views/shared/issuable/_sidebar.html.haml +++ b/app/views/shared/issuable/_sidebar.html.haml @@ -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) diff --git a/changelogs/unreleased/33874_confi.yml b/changelogs/unreleased/33874_confi.yml new file mode 100644 index 00000000000..940753d9aaa --- /dev/null +++ b/changelogs/unreleased/33874_confi.yml @@ -0,0 +1,5 @@ +--- +title: Update confidential issue UI - add confidential visibility and settings to + sidebar +merge_request: +author: diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb index 489baa4291f..a5bb642221c 100644 --- a/spec/features/issues_spec.rb +++ b/spec/features/issues_spec.rb @@ -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 diff --git a/spec/javascripts/sidebar/confidential_edit_buttons_spec.js b/spec/javascripts/sidebar/confidential_edit_buttons_spec.js new file mode 100644 index 00000000000..482be466aad --- /dev/null +++ b/spec/javascripts/sidebar/confidential_edit_buttons_spec.js @@ -0,0 +1,39 @@ +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); + }); +}); diff --git a/spec/javascripts/sidebar/confidential_edit_form_buttons_spec.js b/spec/javascripts/sidebar/confidential_edit_form_buttons_spec.js new file mode 100644 index 00000000000..724f5126945 --- /dev/null +++ b/spec/javascripts/sidebar/confidential_edit_form_buttons_spec.js @@ -0,0 +1,39 @@ +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); + }); +}); diff --git a/spec/javascripts/sidebar/confidential_issue_sidebar_spec.js b/spec/javascripts/sidebar/confidential_issue_sidebar_spec.js new file mode 100644 index 00000000000..90eac1ed1ab --- /dev/null +++ b/spec/javascripts/sidebar/confidential_issue_sidebar_spec.js @@ -0,0 +1,65 @@ +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(); + }); + }); +}); -- GitLab