Merge branch 'backport-epic-in-issue' into 'master'
Backport epic in issue See merge request gitlab-org/gitlab-ce!15799
This commit is contained in:
commit
9c6ce2e8c9
11 changed files with 151 additions and 82 deletions
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -8,7 +8,6 @@ export default class SidebarMediator {
|
|||
if (!SidebarMediator.singleton) {
|
||||
this.initSingleton(options);
|
||||
}
|
||||
|
||||
return SidebarMediator.singleton;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -50,6 +50,11 @@
|
|||
&:not(.disabled) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: $gl-padding;
|
||||
height: $gl-padding;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -470,7 +470,8 @@
|
|||
}
|
||||
}
|
||||
|
||||
.milestone-title span {
|
||||
.milestone-title span,
|
||||
.collapse-truncated-title {
|
||||
@include str-truncated(100%);
|
||||
display: block;
|
||||
margin: 0 4px;
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue