diff options
11 files changed, 151 insertions, 82 deletions
diff --git a/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.js b/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.js index 74c17bc14a2..9e47039d920 100644 --- a/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.js +++ b/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.js @@ -1,22 +1,32 @@ import Flash from '../../../flash'; import AssigneeTitle from './assignee_title'; import Assignees from './assignees'; - import Store from '../../stores/sidebar_store'; -import Mediator from '../../sidebar_mediator'; - import eventHub from '../../event_hub'; export default { name: 'SidebarAssignees', data() { return { - mediator: new Mediator(), store: new Store(), loading: false, - field: '', }; }, + props: { + mediator: { + type: Object, + required: true, + }, + field: { + type: String, + required: true, + }, + signedIn: { + type: Boolean, + required: false, + default: false, + }, + }, components: { 'assignee-title': AssigneeTitle, assignees: Assignees, @@ -61,10 +71,6 @@ export default { eventHub.$off('sidebar.removeAllAssignees', this.removeAllAssignees); eventHub.$off('sidebar.saveAssignees', this.saveAssignees); }, - beforeMount() { - this.field = this.$el.dataset.field; - this.signedIn = typeof this.$el.dataset.signedIn !== 'undefined'; - }, template: ` <div> <assignee-title diff --git a/app/assets/javascripts/sidebar/components/participants/sidebar_participants.vue b/app/assets/javascripts/sidebar/components/participants/sidebar_participants.vue index c1296b28db7..6fcd2f95309 100644 --- a/app/assets/javascripts/sidebar/components/participants/sidebar_participants.vue +++ b/app/assets/javascripts/sidebar/components/participants/sidebar_participants.vue @@ -1,15 +1,19 @@ <script> import Store from '../../stores/sidebar_store'; -import Mediator from '../../sidebar_mediator'; import participants from './participants.vue'; export default { data() { return { - mediator: new Mediator(), store: new Store(), }; }, + props: { + mediator: { + type: Object, + required: true, + }, + }, components: { participants, }, @@ -21,6 +25,7 @@ export default { <participants :loading="store.isFetching.participants" :participants="store.participants" - :number-of-less-participants="7" /> + :number-of-less-participants="7" + /> </div> </template> diff --git a/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions.vue b/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions.vue index 25acc099699..f4bae1d3dd5 100644 --- a/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions.vue +++ b/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions.vue @@ -1,6 +1,5 @@ <script> import Store from '../../stores/sidebar_store'; -import Mediator from '../../sidebar_mediator'; import eventHub from '../../event_hub'; import Flash from '../../../flash'; import { __ } from '../../../locale'; @@ -9,11 +8,15 @@ import subscriptions from './subscriptions.vue'; export default { data() { return { - mediator: new Mediator(), store: new Store(), }; }, - + props: { + mediator: { + type: Object, + required: true, + }, + }, components: { subscriptions, }, diff --git a/app/assets/javascripts/sidebar/mount_sidebar.js b/app/assets/javascripts/sidebar/mount_sidebar.js index 4032f156b15..56cc78ca0ca 100644 --- a/app/assets/javascripts/sidebar/mount_sidebar.js +++ b/app/assets/javascripts/sidebar/mount_sidebar.js @@ -10,6 +10,27 @@ import Translate from '../vue_shared/translate'; Vue.use(Translate); +function mountAssigneesComponent(mediator) { + const el = document.getElementById('js-vue-sidebar-assignees'); + + if (!el) return; + + // eslint-disable-next-line no-new + new Vue({ + el, + components: { + SidebarAssignees, + }, + render: createElement => createElement('sidebar-assignees', { + props: { + mediator, + field: el.dataset.field, + signedIn: el.hasAttribute('data-signed-in'), + }, + }), + }); +} + function mountConfidentialComponent(mediator) { const el = document.getElementById('js-confidential-entry-point'); @@ -49,9 +70,10 @@ function mountLockComponent(mediator) { }).$mount(el); } -function mountParticipantsComponent() { +function mountParticipantsComponent(mediator) { const el = document.querySelector('.js-sidebar-participants-entry-point'); + // eslint-disable-next-line no-new if (!el) return; // eslint-disable-next-line no-new @@ -60,11 +82,15 @@ function mountParticipantsComponent() { components: { sidebarParticipants, }, - render: createElement => createElement('sidebar-participants', {}), + render: createElement => createElement('sidebar-participants', { + props: { + mediator, + }, + }), }); } -function mountSubscriptionsComponent() { +function mountSubscriptionsComponent(mediator) { const el = document.querySelector('.js-sidebar-subscriptions-entry-point'); if (!el) return; @@ -75,22 +101,35 @@ function mountSubscriptionsComponent() { components: { sidebarSubscriptions, }, - render: createElement => createElement('sidebar-subscriptions', {}), + render: createElement => createElement('sidebar-subscriptions', { + props: { + mediator, + }, + }), }); } -function mount(mediator) { - const sidebarAssigneesEl = document.getElementById('js-vue-sidebar-assignees'); - // 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); - } +function mountTimeTrackingComponent() { + const el = document.getElementById('issuable-time-tracker'); + if (!el) return; + + // eslint-disable-next-line no-new + new Vue({ + el, + components: { + SidebarTimeTracking, + }, + render: createElement => createElement('sidebar-time-tracking', {}), + }); +} + +export function mountSidebar(mediator) { + mountAssigneesComponent(mediator); mountConfidentialComponent(mediator); mountLockComponent(mediator); - mountParticipantsComponent(); - mountSubscriptionsComponent(); + mountParticipantsComponent(mediator); + mountSubscriptionsComponent(mediator); new SidebarMoveIssue( mediator, @@ -98,7 +137,9 @@ function mount(mediator) { $('.js-move-issue-confirmation-button'), ).init(); - new Vue(SidebarTimeTracking).$mount('#issuable-time-tracker'); + mountTimeTrackingComponent(); } -export default mount; +export function getSidebarOptions() { + return JSON.parse(document.querySelector('.js-sidebar-options').innerHTML); +} diff --git a/app/assets/javascripts/sidebar/sidebar_bundle.js b/app/assets/javascripts/sidebar/sidebar_bundle.js index f78287e504b..04c39d7b6b5 100644 --- a/app/assets/javascripts/sidebar/sidebar_bundle.js +++ b/app/assets/javascripts/sidebar/sidebar_bundle.js @@ -1,9 +1,8 @@ import Mediator from './sidebar_mediator'; -import mountSidebar from './mount_sidebar'; +import { mountSidebar, getSidebarOptions } from './mount_sidebar'; function domContentLoaded() { - const sidebarOptions = JSON.parse(document.querySelector('.js-sidebar-options').innerHTML); - const mediator = new Mediator(sidebarOptions); + const mediator = new Mediator(getSidebarOptions()); mediator.fetch(); mountSidebar(mediator); diff --git a/app/assets/javascripts/sidebar/sidebar_mediator.js b/app/assets/javascripts/sidebar/sidebar_mediator.js index d4c07a188b3..abf6909a9b4 100644 --- a/app/assets/javascripts/sidebar/sidebar_mediator.js +++ b/app/assets/javascripts/sidebar/sidebar_mediator.js @@ -7,7 +7,6 @@ export default class SidebarMediator { if (!SidebarMediator.singleton) { this.initSingleton(options); } - return SidebarMediator.singleton; } diff --git a/app/assets/javascripts/sidebar/stores/sidebar_store.js b/app/assets/javascripts/sidebar/stores/sidebar_store.js index 73eb25e2333..f20cc6d8cca 100644 --- a/app/assets/javascripts/sidebar/stores/sidebar_store.js +++ b/app/assets/javascripts/sidebar/stores/sidebar_store.js @@ -1,33 +1,37 @@ export default class SidebarStore { - constructor(store) { + constructor(options) { if (!SidebarStore.singleton) { - const { currentUser, rootPath, editable } = store; - this.currentUser = currentUser; - this.rootPath = rootPath; - this.editable = editable; - this.timeEstimate = 0; - this.totalTimeSpent = 0; - this.humanTimeEstimate = ''; - this.humanTimeSpent = ''; - this.assignees = []; - this.isFetching = { - assignees: true, - participants: true, - subscriptions: true, - }; - this.isLoading = {}; - this.autocompleteProjects = []; - this.moveToProjectId = 0; - this.isLockDialogOpen = false; - this.participants = []; - this.subscribed = null; - - SidebarStore.singleton = this; + this.initSingleton(options); } return SidebarStore.singleton; } + initSingleton(options) { + const { currentUser, rootPath, editable } = options; + this.currentUser = currentUser; + this.rootPath = rootPath; + this.editable = editable; + this.timeEstimate = 0; + this.totalTimeSpent = 0; + this.humanTimeEstimate = ''; + this.humanTimeSpent = ''; + this.assignees = []; + this.isFetching = { + assignees: true, + participants: true, + subscriptions: true, + }; + this.isLoading = {}; + this.autocompleteProjects = []; + this.moveToProjectId = 0; + this.isLockDialogOpen = false; + this.participants = []; + this.subscribed = null; + + SidebarStore.singleton = this; + } + setAssigneeData(data) { this.isFetching.assignees = false; if (data.assignees) { diff --git a/app/assets/stylesheets/framework/sidebar.scss b/app/assets/stylesheets/framework/sidebar.scss index 792981fdc48..3ebba4f9efb 100644 --- a/app/assets/stylesheets/framework/sidebar.scss +++ b/app/assets/stylesheets/framework/sidebar.scss @@ -50,6 +50,11 @@ &:not(.disabled) { cursor: pointer; } + + svg { + width: $gl-padding; + height: $gl-padding; + } } } diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss index 11ee1232bfe..66951f9270a 100644 --- a/app/assets/stylesheets/pages/issuable.scss +++ b/app/assets/stylesheets/pages/issuable.scss @@ -470,7 +470,8 @@ } } - .milestone-title span { + .milestone-title span, + .collapse-truncated-title { @include str-truncated(100%); display: block; margin: 0 4px; diff --git a/spec/javascripts/sidebar/sidebar_assignees_spec.js b/spec/javascripts/sidebar/sidebar_assignees_spec.js index 929ba75e67d..b97e24d9dcf 100644 --- a/spec/javascripts/sidebar/sidebar_assignees_spec.js +++ b/spec/javascripts/sidebar/sidebar_assignees_spec.js @@ -4,20 +4,29 @@ import SidebarMediator from '~/sidebar/sidebar_mediator'; import SidebarService from '~/sidebar/services/sidebar_service'; import SidebarStore from '~/sidebar/stores/sidebar_store'; import Mock from './mock_data'; +import mountComponent from '../helpers/vue_mount_component_helper'; describe('sidebar assignees', () => { - let component; - let SidebarAssigneeComponent; + let vm; + let mediator; + let sidebarAssigneesEl; preloadFixtures('issues/open-issue.html.raw'); beforeEach(() => { Vue.http.interceptors.push(Mock.sidebarMockInterceptor); - SidebarAssigneeComponent = Vue.extend(SidebarAssignees); - spyOn(SidebarMediator.prototype, 'saveAssignees').and.callThrough(); - spyOn(SidebarMediator.prototype, 'assignYourself').and.callThrough(); - this.mediator = new SidebarMediator(Mock.mediator); + loadFixtures('issues/open-issue.html.raw'); - this.sidebarAssigneesEl = document.querySelector('#js-vue-sidebar-assignees'); + + mediator = new SidebarMediator(Mock.mediator); + spyOn(mediator, 'saveAssignees').and.callThrough(); + spyOn(mediator, 'assignYourself').and.callThrough(); + + const SidebarAssigneeComponent = Vue.extend(SidebarAssignees); + sidebarAssigneesEl = document.querySelector('#js-vue-sidebar-assignees'); + vm = mountComponent(SidebarAssigneeComponent, { + mediator, + field: sidebarAssigneesEl.dataset.field, + }, sidebarAssigneesEl); }); afterEach(() => { @@ -28,30 +37,24 @@ describe('sidebar assignees', () => { }); it('calls the mediator when saves the assignees', () => { - component = new SidebarAssigneeComponent() - .$mount(this.sidebarAssigneesEl); - component.saveAssignees(); - - expect(SidebarMediator.prototype.saveAssignees).toHaveBeenCalled(); + vm.saveAssignees(); + expect(mediator.saveAssignees).toHaveBeenCalled(); }); it('calls the mediator when "assignSelf" method is called', () => { - component = new SidebarAssigneeComponent() - .$mount(this.sidebarAssigneesEl); - component.assignSelf(); + vm.assignSelf(); - expect(SidebarMediator.prototype.assignYourself).toHaveBeenCalled(); - expect(this.mediator.store.assignees.length).toEqual(1); + expect(mediator.assignYourself).toHaveBeenCalled(); + expect(mediator.store.assignees.length).toEqual(1); }); it('hides assignees until fetched', (done) => { - component = new SidebarAssigneeComponent().$mount(this.sidebarAssigneesEl); - const currentAssignee = this.sidebarAssigneesEl.querySelector('.value'); + const currentAssignee = sidebarAssigneesEl.querySelector('.value'); expect(currentAssignee).toBe(null); - component.store.isFetching.assignees = false; + vm.store.isFetching.assignees = false; Vue.nextTick(() => { - expect(component.$el.querySelector('.value')).toBeVisible(); + expect(vm.$el.querySelector('.value')).toBeVisible(); done(); }); }); diff --git a/spec/javascripts/sidebar/sidebar_subscriptions_spec.js b/spec/javascripts/sidebar/sidebar_subscriptions_spec.js index 7adf22b0f1f..a6113cb0bae 100644 --- a/spec/javascripts/sidebar/sidebar_subscriptions_spec.js +++ b/spec/javascripts/sidebar/sidebar_subscriptions_spec.js @@ -26,11 +26,14 @@ describe('Sidebar Subscriptions', function () { }); it('calls the mediator toggleSubscription on event', () => { - spyOn(SidebarMediator.prototype, 'toggleSubscription').and.returnValue(Promise.resolve()); - vm = mountComponent(SidebarSubscriptions, {}); + const mediator = new SidebarMediator(); + spyOn(mediator, 'toggleSubscription').and.returnValue(Promise.resolve()); + vm = mountComponent(SidebarSubscriptions, { + mediator, + }); eventHub.$emit('toggleSubscription'); - expect(SidebarMediator.prototype.toggleSubscription).toHaveBeenCalled(); + expect(mediator.toggleSubscription).toHaveBeenCalled(); }); }); |