Commit c299f62a authored by Bryce Johnson's avatar Bryce Johnson

Wire up approvals front end and backend, mostly.

parent 3be2fb3f
......@@ -2,13 +2,8 @@
//= require ../services/approvals_api
(() => {
const app = gl.MergeRequestWidget;
const api = app.ApprovalsApi;
const componentRegistry = app.Components || (app.Components = {});
componentRegistry.approvalsBody = {
name: 'ApprovalsBody',
Vue.component('approvals-body', {
name: 'approvals-body',
props: ['approverNames', 'approvalsLeft', 'userCanApprove', 'userHasApproved'],
data() {
return {
......@@ -34,11 +29,11 @@
},
methods: {
approveMergeRequest() {
return api.approveMergeRequest();
return gl.ApprovalsStore.approve();
},
},
beforeCreate() {
api.fetchApprovals().then(() => {
gl.ApprovalsStore.fetch().then(() => {
this.loading = false;
});
},
......@@ -57,5 +52,5 @@
<loading-icon v-if='loading'></loading-icon>
</div>
`,
};
});
})();
//= require ../services/approvals_api
//= require ../stores/approvals_store
//= require vue_common_component/link_to_member_avatar
//= require vue_common_component/loading_icon
(() => {
const app = gl.MergeRequestWidget;
const api = gl.MergeRequestWidget.ApprovalsApi;
const componentRegistry = app.Components || (app.Components = {});
componentRegistry.approvalsFooter = {
name: 'ApprovalsFooter',
Vue.component('approvals-footer', {
name: 'approvals-footer',
props: ['userCanApprove', 'userHasApproved', 'approvedByUsers', 'approvalsLeft', 'pendingAvatarSvg', 'checkmarkSvg'],
data() {
return {
......@@ -22,15 +19,14 @@
showUnapproveButton() {
return this.userCanApprove && this.userHasApproved;
},
},
methods: {
removeApproval() {
return api.unapproveMergeRequest();
return gl.ApprovalsStore.unapprove();
},
},
beforeCreate() {
api.fetchApprovals().then(() => {
return gl.ApprovalsStore.fetch().then(() => {
this.loading = false;
});
},
......@@ -62,5 +58,5 @@
<loading-icon v-if='loading'></loading-icon>
</div>
`,
};
});
})();
......@@ -3,32 +3,35 @@
(() => {
class ApprovalsApi {
constructor() {
this.resource = gl.ApprovalsResource = new gl.SubbableResource('my/endpoint');
this.store = gl.MergeRequestWidget.ApprovalsStore;
constructor(endpoint) {
gl.ApprovalsApi = this;
this.init(endpoint);
}
init(mergeRequestEndpoint) {
const approvalsEndpoint = `${mergeRequestEndpoint}/approvals`;
this.resource = gl.ApprovalsResource = new gl.SubbableResource(approvalsEndpoint);
}
fetchApprovals() {
return this.resource.get();
return this.resource.get().fail((err) => {
console.error(`Error fetching approvals. ${err}`);
});
}
approveMergeRequest() {
return this.resource.post().then(() => {
gl.MergeRequestWidget.ApprovalsStore.approve();
return this.resource.post().fail((err) => {
console.error(`Error approving merge request. ${err}`);
});
}
unapproveMergeRequest() {
return this.resource.delete().then(() => {
gl.MergeRequestWidget.ApprovalsStore.unapprove();
return this.resource.delete().fail((err) => {
console.error(`Error unapproving merge request. ${err}`);
});
}
updateStore(newState = {}) {
this.store = gl.MergeRequestWidget.Store.data.approvals;
return Object.assign(this.store, newState);
}
}
gl.MergeRequestWidget.ApprovalsApi = new ApprovalsApi();
gl.ApprovalsApi = ApprovalsApi;
})();
//= require ../services/approvals_api
(() => {
let singleton;
class ApprovalsStore {
constructor(rootEl) {
constructor(rootStore) {
if (!singleton) {
singleton = gl.MergeRequestWidget.ApprovalsStore = this;
this.init(rootEl);
singleton = gl.ApprovalsStore = this;
this.init(rootStore);
}
return singleton;
}
init(rootEl) {
init(rootStore) {
this.rootStore = rootStore;
this.api = new gl.ApprovalsApi(rootStore.dataset.endpoint);
}
assignToRootStore(data) {
return this.rootStore.assignToData('approvals', data);
}
assignToData(val) {
fetch() {
return this.api.fetchApprovals({ type: 'GET' })
.then((data) => this.rootStore.assignToData(data));
}
/** TODO: remove after backend integerated */
approve() {
return this.api.approveMergeRequest({ type: 'POST' })
.then((data) => this.rootStore.assignToData(data));
}
unapprove() {
return this.api.unapproveMergeRequest({ type: 'DELETE' })
.then((data) => this.rootStore.assignToData(data));
}
}
gl.MergeRequestWidget.ApprovalsStore = ApprovalsStore;
gl.ApprovalsStore = ApprovalsStore;
})();
//= require ./widget_store
//= require ./approvals/services/approvals_api
//= require ./approvals/approvals_bundle
((MergeRequestWidget) => {
(() => {
$(() => {
const rootEl = document.getElementById('merge-request-widget-app');
const store = new MergeRequestWidget.Store(rootEl);
const components = MergeRequestWidget.Components;
const widgetSharedStore = new gl.MergeRequestWidgetStore(rootEl); // TODO: encapsulate better
MergeRequestWidget.App = new Vue({
gl.MergeRequestWidgetApp = new Vue({
el: rootEl,
data: store.data,
components: {
'approvals-body': components.approvalsBody,
'approvals-footer': components.approvalsFooter,
},
data: widgetSharedStore.data,
});
});
})(gl.MergeRequestWidget || (gl.MergeRequestWidget = {}));
})(window.gl || (window.gl = {}));
//= require ./approvals/stores/approvals_store
((MergeRequestWidget) => {
(() => {
let singleton;
class MergeRequestWidgetStore {
constructor(rootEl) {
if (!singleton) {
singleton = MergeRequestWidget.Store = this;
singleton = gl.MergeRequestWidget.Store = this;
this.init(rootEl);
}
return singleton;
// TODO: add the following to the root el dataset: approvedByUsers,
// approverNames, approvalsNeeded, canUpdateMergeRequest, endpoint
}
init(rootEl) {
this.rootEl = rootEl;
this.dataset = rootEl.dataset;
this.data = {};
this.initResource();
this.initPermissions();
this.initApprovals();
}
/* General Resources */
initResource() {
this.assignToData('resource', {
endpoint: 'my/endpoint',
});
}
initPermissions() {
this.assignToData('permissions', {
canUpdateMergeRequest: Boolean(this.dataset.canUpdateMergeRequest),
});
// init other widget stores here
this.initApprovals();
}
/* Component-specific */
initApprovals() {
const approvalsStore = new gl.MergeRequestWidget.ApprovalsStore(this.rootEl);
const approvalsStore = new gl.ApprovalsStore(this);
this.assignToData('approvals', approvalsStore.data);
}
......@@ -48,6 +31,5 @@
Object.assign(this.data[key], val);
}
}
MergeRequestWidget.Store = MergeRequestWidgetStore;
})(gl.MergeRequestWidget || (MergeRequestWidget = {}));
gl.MergeRequestWidgetStore = MergeRequestWidgetStore;
})(window.gl || (window.gl = {}));
#merge-request-widget-app.mr-state-widget{'data-endpoint'=> '/myendpoint/tho'}
- content_for :page_specific_javascripts do
= page_specific_javascript_tag('merge_request_widget/widget_bundle.js')
#merge-request-widget-app.mr-state-widget{ 'data-approvals' => @merge_request.approvals.to_json, 'data-endpoint'=> merge_request_path(@merge_request)}
= render 'projects/merge_requests/widget/heading'
.mr-widget-body
-# After conflicts are resolved, the user is redirected back to the MR page.
......@@ -50,6 +53,4 @@
- if @merge_request.approvals.any?
%approvals-footer{'pending-avatar-svg' => custom_icon('icon_dotted_circle'), 'checkmark-svg' => custom_icon('icon_checkmark') }
- content_for :page_specific_javascripts do
= page_specific_javascript_tag('merge_request_widget/widget_bundle.js')
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment