Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
ad42c265
Commit
ad42c265
authored
Feb 08, 2017
by
Rémy Coutable
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'origin/master' into rc/ce-to-ee-wednesday
parents
11e62405
9ba32fea
Changes
22
Hide whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
348 additions
and
383 deletions
+348
-383
app/assets/javascripts/commit/pipelines/pipelines_store.js.es6
...ssets/javascripts/commit/pipelines/pipelines_store.js.es6
+1
-1
app/assets/javascripts/diff_notes/components/comment_resolve_btn.js.es6
...ascripts/diff_notes/components/comment_resolve_btn.js.es6
+1
-0
app/assets/javascripts/diff_notes/components/jump_to_discussion.js.es6
...vascripts/diff_notes/components/jump_to_discussion.js.es6
+1
-0
app/assets/javascripts/diff_notes/components/resolve_btn.js.es6
...sets/javascripts/diff_notes/components/resolve_btn.js.es6
+4
-7
app/assets/javascripts/diff_notes/components/resolve_count.js.es6
...ts/javascripts/diff_notes/components/resolve_count.js.es6
+1
-0
app/assets/javascripts/diff_notes/components/resolve_discussion_btn.js.es6
...ripts/diff_notes/components/resolve_discussion_btn.js.es6
+5
-4
app/assets/javascripts/diff_notes/diff_notes_bundle.js.es6
app/assets/javascripts/diff_notes/diff_notes_bundle.js.es6
+6
-1
app/assets/javascripts/diff_notes/services/resolve.js.es6
app/assets/javascripts/diff_notes/services/resolve.js.es6
+10
-11
app/assets/javascripts/merge_request_widget/approvals/approvals_api.js.es6
...ripts/merge_request_widget/approvals/approvals_api.js.es6
+27
-25
app/assets/javascripts/merge_request_widget/approvals/approvals_bundle.js.es6
...ts/merge_request_widget/approvals/approvals_bundle.js.es6
+2
-4
app/assets/javascripts/merge_request_widget/approvals/approvals_store.js.es6
...pts/merge_request_widget/approvals/approvals_store.js.es6
+51
-53
app/assets/javascripts/merge_request_widget/approvals/components/approvals_body.js.es6
...request_widget/approvals/components/approvals_body.js.es6
+79
-80
app/assets/javascripts/merge_request_widget/approvals/components/approvals_footer.js.es6
...quest_widget/approvals/components/approvals_footer.js.es6
+82
-83
app/assets/javascripts/merge_request_widget/widget_bundle.js.es6
...ets/javascripts/merge_request_widget/widget_bundle.js.es6
+15
-11
app/assets/javascripts/merge_request_widget/widget_store.js.es6
...sets/javascripts/merge_request_widget/widget_store.js.es6
+31
-31
app/assets/javascripts/vue_realtime_listener/index.js.es6
app/assets/javascripts/vue_realtime_listener/index.js.es6
+11
-0
app/views/projects/merge_requests/_show.html.haml
app/views/projects/merge_requests/_show.html.haml
+1
-2
changelogs/unreleased/23104-remove-public-param-for-projects.yml
...ogs/unreleased/23104-remove-public-param-for-projects.yml
+4
-0
doc/api/projects.md
doc/api/projects.md
+0
-3
lib/api/projects.rb
lib/api/projects.rb
+4
-15
spec/javascripts/commit/pipelines/pipelines_store_spec.js.es6
.../javascripts/commit/pipelines/pipelines_store_spec.js.es6
+3
-0
spec/requests/api/projects_spec.rb
spec/requests/api/projects_spec.rb
+9
-52
No files found.
app/assets/javascripts/commit/pipelines/pipelines_store.js.es6
View file @
ad42c265
...
...
@@ -26,7 +26,7 @@ class PipelinesStore {
*/
startTimeAgoLoops() {
const startTimeLoops = () => {
this.timeLoopInterval = setInterval(
function timeloopInterval()
{
this.timeLoopInterval = setInterval(
() =>
{
this.$children[0].$children.reduce((acc, component) => {
const timeAgoComponent = component.$children.filter(el => el.$options._componentTag === 'time-ago')[0];
acc.push(timeAgoComponent);
...
...
app/assets/javascripts/diff_notes/components/comment_resolve_btn.js.es6
View file @
ad42c265
/* eslint-disable comma-dangle, object-shorthand, func-names, no-else-return, quotes, no-lonely-if, max-len */
/* global Vue */
/* global CommentsStore */
const Vue = require('vue');
(() => {
const CommentAndResolveBtn = Vue.extend({
...
...
app/assets/javascripts/diff_notes/components/jump_to_discussion.js.es6
View file @
ad42c265
...
...
@@ -2,6 +2,7 @@
/* global Vue */
/* global DiscussionMixins */
/* global CommentsStore */
const Vue = require('vue');
(() => {
const JumpToDiscussion = Vue.extend({
...
...
app/assets/javascripts/diff_notes/components/resolve_btn.js.es6
View file @
ad42c265
...
...
@@ -3,6 +3,7 @@
/* global CommentsStore */
/* global ResolveService */
/* global Flash */
const Vue = require('vue');
(() => {
const ResolveBtn = Vue.extend({
...
...
@@ -16,6 +17,7 @@
},
data: function () {
return {
note: {},
discussions: CommentsStore.state,
loading: false
};
...
...
@@ -30,13 +32,6 @@
discussion: function () {
return this.discussions[this.discussionId];
},
note: function () {
if (this.discussion) {
return this.discussion.getNote(this.noteId);
} else {
return undefined;
}
},
buttonText: function () {
if (this.isResolved) {
return `Resolved by ${this.resolvedByName}`;
...
...
@@ -106,6 +101,8 @@
},
created: function () {
CommentsStore.create(this.discussionId, this.noteId, this.canResolve, this.resolved, this.resolvedBy);
this.note = this.discussion.getNote(this.noteId);
}
});
...
...
app/assets/javascripts/diff_notes/components/resolve_count.js.es6
View file @
ad42c265
...
...
@@ -2,6 +2,7 @@
/* global Vue */
/* global DiscussionMixins */
/* global CommentsStore */
const Vue = require('vue');
((w) => {
w.ResolveCount = Vue.extend({
...
...
app/assets/javascripts/diff_notes/components/resolve_discussion_btn.js.es6
View file @
ad42c265
...
...
@@ -2,6 +2,7 @@
/* global Vue */
/* global CommentsStore */
/* global ResolveService */
const Vue = require('vue');
(() => {
const ResolveDiscussionBtn = Vue.extend({
...
...
@@ -13,13 +14,11 @@
},
data: function() {
return {
discussions: CommentsStore.state
discussions: CommentsStore.state,
discussion: {},
};
},
computed: {
discussion: function () {
return this.discussions[this.discussionId];
},
showButton: function () {
if (this.discussion) {
return this.discussion.isResolvable();
...
...
@@ -56,6 +55,8 @@
},
created: function () {
CommentsStore.createDiscussion(this.discussionId, this.canResolve);
this.discussion = this.discussions[this.discussionId];
}
});
...
...
app/assets/javascripts/diff_notes/diff_notes_bundle.js.es6
View file @
ad42c265
/* eslint-disable func-names, comma-dangle, new-cap, no-new, import/newline-after-import, no-multi-spaces, max-len */
/* global Vue */
/* global ResolveCount */
/* global ResolveServiceClass */
function requireAll(context) { return context.keys().map(context); }
const Vue = require('vue');
requireAll(require.context('./models', false, /^\.\/.*\.(js|es6)$/));
requireAll(require.context('./stores', false, /^\.\/.*\.(js|es6)$/));
requireAll(require.context('./services', false, /^\.\/.*\.(js|es6)$/));
...
...
@@ -10,11 +12,14 @@ requireAll(require.context('./mixins', false, /^\.\/.*\.(js|es6)$/));
requireAll(require.context('./components', false, /^\.\/.*\.(js|es6)$/));
$(() => {
const projectPath = document.querySelector('.merge-request').dataset.projectPath;
const COMPONENT_SELECTOR = 'resolve-btn, resolve-discussion-btn, jump-to-discussion, comment-and-resolve-btn';
window.gl = window.gl || {};
window.gl.diffNoteApps = {};
window.ResolveService = new ResolveServiceClass(projectPath);
gl.diffNotesCompileComponents = () => {
const $components = $(COMPONENT_SELECTOR).filter(function () {
return $(this).closest('resolve-count').length !== 1;
...
...
@@ -44,6 +49,6 @@ $(() => {
el: '#resolve-count-app',
components: {
'resolve-count': ResolveCount
}
}
,
});
});
app/assets/javascripts/diff_notes/services/resolve.js.es6
View file @
ad42c265
...
...
@@ -3,20 +3,21 @@
/* global Flash */
/* global CommentsStore */
((w) => {
class ResolveServiceClass {
constructor() {
this.noteResource = Vue.resource('notes{/noteId}/resolve');
this.discussionResource = Vue.resource('merge_requests{/mergeRequestId}/discussions{/discussionId}/resolve');
window.Vue.use(require('vue-resource'));
(() => {
window.ResolveServiceClass = class ResolveServiceClass {
constructor(rootPath) {
this.noteResource = Vue.resource(`${rootPath}/notes{/noteId}/resolve`);
this.discussionResource = Vue.resource(`${rootPath}/merge_requests{/mergeRequestId}/discussions{/discussionId}/resolve`);
}
setCSRF() {
Vue.http.headers.common['X-CSRF-Token'] = $.rails.csrfToken();
}
prepareRequest(
root
) {
prepareRequest() {
this.setCSRF();
Vue.http.options.root = root;
}
resolve(projectPath, noteId) {
...
...
@@ -87,7 +88,5 @@
discussionId
}, {});
}
}
w.ResolveService = new ResolveServiceClass();
})(window);
};
})();
app/assets/javascripts/merge_request_widget/approvals/approvals_api.js.es6
View file @
ad42c265
/* global Vue */
/* global Flash */
window.Vue = require('vue');
window.Vue.use(require('vue-resource'));
const Vue = window.Vue;
require('./approvals_store');
(() => {
class ApprovalsApi {
constructor(endpoint) {
gl.ApprovalsApi = this;
this.init(endpoint);
}
class ApprovalsApi {
constructor(endpoint) {
gl.ApprovalsApi = this;
this.init(endpoint);
}
init(mergeRequestEndpoint) {
this.baseEndpoint = `${mergeRequestEndpoint}/approvals`;
Vue.http.headers.common['X-CSRF-Token'] = $.rails.csrfToken();
}
init(mergeRequestEndpoint) {
this.baseEndpoint = `${mergeRequestEndpoint}/approvals`;
Vue.http.headers.common['X-CSRF-Token'] = $.rails.csrfToken();
}
fetchApprovals() {
const flashErrorMessage = 'An error occured while retrieving approval data for this merge request.';
fetchApprovals() {
const flashErrorMessage = 'An error occured while retrieving approval data for this merge request.';
return Vue.http.get(this.baseEndpoint).catch(() => new Flash(flashErrorMessage));
}
return Vue.http.get(this.baseEndpoint).catch(() => new Flash(flashErrorMessage));
}
approveMergeRequest() {
const flashErrorMessage = 'An error occured while submitting your approval.';
approveMergeRequest() {
const flashErrorMessage = 'An error occured while submitting your approval.';
return Vue.http.post(this.baseEndpoint).catch(() => new Flash(flashErrorMessage));
}
return Vue.http.post(this.baseEndpoint).catch(() => new Flash(flashErrorMessage));
}
unapproveMergeRequest() {
const flashErrorMessage = 'An error occured while removing your approval.';
unapproveMergeRequest() {
const flashErrorMessage = 'An error occured while removing your approval.';
return Vue.http.delete(this.baseEndpoint).catch(() => new Flash(flashErrorMessage));
}
return Vue.http.delete(this.baseEndpoint).catch(() => new Flash(flashErrorMessage));
}
}
gl.ApprovalsApi = ApprovalsApi
;
})()
;
window.gl = window.gl || {}
;
window.gl.ApprovalsApi = ApprovalsApi
;
app/assets/javascripts/merge_request_widget/approvals/approvals_bundle.js.es6
View file @
ad42c265
function requireAll(context) { return context.keys().map(context); }
require('./approvals_store');
require('./approvals_api');
require
All(require.context('./components', true, /^\.\/.*\.(js|es6)$/)
);
require('./components/approvals_body');
require
('./components/approvals_footer'
);
app/assets/javascripts/merge_request_widget/approvals/approvals_store.js.es6
View file @
ad42c265
/* global Vue */
require('./approvals_api');
(() => {
let singleton;
let singleton;
class MergeRequestApprovalsStore {
constructor(rootStore) {
if (!singleton) {
singleton = this;
this.init(rootStore);
}
return singleton;
class MergeRequestApprovalsStore {
constructor(rootStore) {
if (!singleton) {
singleton = this;
this.init(rootStore);
}
return singleton;
}
init(rootStore) {
this.rootStore = rootStore;
this.api = new gl.ApprovalsApi(rootStore.rootEl.dataset.endpoint);
this.state = {
fetching: false,
};
}
init(rootStore) {
this.rootStore = rootStore;
this.api = new gl.ApprovalsApi(rootStore.rootEl.dataset.endpoint);
this.state = {
fetching: false,
};
}
initStoreOnce() {
const state = this.state;
if (!state.fetching) {
state.fetching = true;
return this.fetch()
.then(() => {
state.fetching = false;
this.assignToRootStore('showApprovals', true);
});
}
return Promise.resolve();
}
initStoreOnce() {
const state = this.state;
if (!state.fetching) {
state.fetching = true;
return this.fetch()
.then(() => {
state.fetching = false;
this.assignToRootStore('showApprovals', true);
});
}
return Promise.resolve();
}
fetch() {
return this.api.fetchApprovals()
.then(res => this.assignToRootStore('approvals', res.json()))
.then(data => this.setMergeRequestAcceptanceStatus(data.approvals_left));
}
fetch() {
return this.api.fetchApprovals()
.then(res => this.assignToRootStore('approvals', res.json()))
.then(data => this.setMergeRequestAcceptanceStatus(data.approvals_left));
}
approve() {
return this.api.approveMergeRequest()
.then(res => this.assignToRootStore('approvals', res.json()))
.then(data => this.setMergeRequestAcceptanceStatus(data.approvals_left));
}
approve() {
return this.api.approveMergeRequest()
.then(res => this.assignToRootStore('approvals', res.json()))
.then(data => this.setMergeRequestAcceptanceStatus(data.approvals_left));
}
unapprove() {
return this.api.unapproveMergeRequest()
.then(res => this.assignToRootStore('approvals', res.json()))
.then(data => this.setMergeRequestAcceptanceStatus(data.approvals_left));
}
unapprove() {
return this.api.unapproveMergeRequest()
.then(res => this.assignToRootStore('approvals', res.json()))
.then(data => this.setMergeRequestAcceptanceStatus(data.approvals_left));
}
setMergeRequestAcceptanceStatus(approvalsLeft) {
return this.rootStore.assignToData('disableAcceptance', !!approvalsLeft);
}
setMergeRequestAcceptanceStatus(approvalsLeft) {
return this.rootStore.assignToData('disableAcceptance', !!approvalsLeft);
}
assignToRootStore(key, data) {
return this.rootStore.assignToData(key, data);
}
assignToRootStore(key, data) {
return this.rootStore.assignToData(key, data);
}
gl.MergeRequestApprovalsStore = MergeRequestApprovalsStore;
})(window.gl || (window.gl = {}));
}
window.gl = window.gl || {};
window.gl.MergeRequestApprovalsStore = MergeRequestApprovalsStore;
app/assets/javascripts/merge_request_widget/approvals/components/approvals_body.js.es6
View file @
ad42c265
/* global Vue */
const Vue = require('vue');
require('../approvals_store');
require('../approvals_api');
(() => {
Vue.component('approvals-body', {
name: 'approvals-body',
props: {
approvedBy: {
type: Array,
required: false,
},
approvalsLeft: {
type: Number,
required: false,
},
userCanApprove: {
type: Boolean,
required: false,
},
userHasApproved: {
type: Boolean,
required: false,
},
suggestedApprovers: {
type: Array,
required: false,
},
Vue.component('approvals-body', {
name: 'approvals-body',
props: {
approvedBy: {
type: Array,
required: false,
},
data() {
return {
approving: false,
};
approvalsLeft: {
type: Number,
required: false,
},
computed: {
approvalsRequiredStringified() {
const baseString = `${this.approvalsLeft} more approval`;
return this.approvalsLeft === 1 ? baseString : `${baseString}s`;
},
approverNamesStringified() {
const approvers = this.suggestedApprovers;
userCanApprove: {
type: Boolean,
required: false,
},
userHasApproved: {
type: Boolean,
required: false,
},
suggestedApprovers: {
type: Array,
required: false,
},
},
data() {
return {
approving: false,
};
},
computed: {
approvalsRequiredStringified() {
const baseString = `${this.approvalsLeft} more approval`;
return this.approvalsLeft === 1 ? baseString : `${baseString}s`;
},
approverNamesStringified() {
const approvers = this.suggestedApprovers;
if (!approvers) {
return '';
}
if (!approvers) {
return '';
}
return approvers.length === 1 ? approvers[0].name :
approvers.reduce((memo, curr, index) => {
const nextMemo = `${memo}${curr.name}`;
return approvers.length === 1 ? approvers[0].name :
approvers.reduce((memo, curr, index) => {
const nextMemo = `${memo}${curr.name}`;
if (index === approvers.length - 2) { // second to last index
return `${nextMemo} or `;
} else if (index === approvers.length - 1) { // last index
return nextMemo;
}
if (index === approvers.length - 2) { // second to last index
return `${nextMemo} or `;
} else if (index === approvers.length - 1) { // last index
return nextMemo;
}
return `${nextMemo}, `;
}, '');
},
showApproveButton() {
return this.userCanApprove && !this.userHasApproved;
},
showSuggestedApprovers() {
return this.suggestedApprovers && this.suggestedApprovers.length;
},
return `${nextMemo}, `;
}, '');
},
showApproveButton() {
return this.userCanApprove && !this.userHasApproved;
},
methods: {
approveMergeRequest() {
this.approving = true;
return gl.ApprovalsStore.approve().then(() => {
this.approving = false;
});
},
showSuggestedApprovers() {
return this.suggestedApprovers && this.suggestedApprovers.length;
},
beforeCreate() {
gl.ApprovalsStore.initStoreOnce();
},
methods: {
approveMergeRequest() {
this.approving = true;
return gl.ApprovalsStore.approve().then(() => {
this.approving = false;
});
},
template: `
<div class='approvals-body mr-widget-footer mr-approvals-footer'>
<h4> Requires {{ approvalsRequiredStringified }}
<span v-if='showSuggestedApprovers'> (from {{ approverNamesStringified }}) </span>
</h4>
<div v-if='showApproveButton' class='append-bottom-10'>
<button
:disabled='approving'
@click='approveMergeRequest'
class='btn btn-primary approve-btn'>
Approve Merge Request
</button>
</div>
},
beforeCreate() {
gl.ApprovalsStore.initStoreOnce();
},
template: `
<div class='approvals-body mr-widget-footer mr-approvals-footer'>
<h4> Requires {{ approvalsRequiredStringified }}
<span v-if='showSuggestedApprovers'> (from {{ approverNamesStringified }}) </span>
</h4>
<div v-if='showApproveButton' class='append-bottom-10'>
<button
:disabled='approving'
@click='approveMergeRequest'
class='btn btn-primary approve-btn'>
Approve Merge Request
</button>
</div>
`,
});
})
()
;
</div>
`,
});
app/assets/javascripts/merge_request_widget/approvals/components/approvals_footer.js.es6
View file @
ad42c265
/* global Vue */
const Vue = require('vue');
require('../approvals_store');
require('../../../vue_common_component/link_to_member_avatar');
(() => {
Vue.component('approvals-footer', {
name: 'approvals-footer',
props: {
approvedBy: {
type: Array,
required: false,
},
approvalsLeft: {
type: Number,
required: false,
},
userCanApprove: {
type: Boolean,
required: false,
},
userHasApproved: {
type: Boolean,
required: false,
},
suggestedApprovers: {
type: Array,
required: false,
},
pendingAvatarSvg: {
type: String,
required: true,
},
checkmarkSvg: {
type: String,
required: true,
},
Vue.component('approvals-footer', {
name: 'approvals-footer',
props: {
approvedBy: {
type: Array,
required: false,
},
data() {
return {
unapproving: false,
};
approvalsLeft: {
type: Number,
required: false,
},
computed: {
showUnapproveButton() {
return this.userHasApproved && !this.userCanApprove;
},
userCanApprove: {
type: Boolean,
required: false,
},
methods: {
unapproveMergeRequest() {
this.unapproving = true;
gl.ApprovalsStore.unapprove().then(() => {
this.unapproving = false;
});
},
userHasApproved: {
type: Boolean,
required: false,
},
beforeCreate() {
gl.ApprovalsStore.initStoreOnce();
suggestedApprovers: {
type: Array,
required: false,
},
template: `
<div class='mr-widget-footer approved-by-users approvals-footer clearfix mr-approvals-footer'>
<span class='approvers-prefix'> Approved by </span>
<span v-for='approver in approvedBy'>
<link-to-member-avatar
extra-link-class='approver-avatar'
:avatar-url='approver.user.avatar_url'
:display-name='approver.user.name'
:profile-url='approver.user.web_url'
:avatar-html='checkmarkSvg'
:show-tooltip='true'>
</link-to-member-avatar>
</span>
<span v-for='n in approvalsLeft'>
<link-to-member-avatar
:clickable='false'
:avatar-html='pendingAvatarSvg'
:show-tooltip='false'
extra-link-class='hide-asset'>
</link-to-member-avatar>
</span>
<span class='unapprove-btn-wrap' v-if='showUnapproveButton'>
<button
:disabled='unapproving'
@click='unapproveMergeRequest'
class='btn btn-link unapprove-btn'>
<i class='fa fa-close'></i>
Remove your approval</span>
</button>
</span>
</div>
`,
});
})();
pendingAvatarSvg: {
type: String,
required: true,
},
checkmarkSvg: {
type: String,
required: true,
},
},
data() {
return {
unapproving: false,
};
},
computed: {
showUnapproveButton() {
return this.userHasApproved && !this.userCanApprove;
},
},
methods: {
unapproveMergeRequest() {
this.unapproving = true;
gl.ApprovalsStore.unapprove().then(() => {
this.unapproving = false;
});
},
},
beforeCreate() {
gl.ApprovalsStore.initStoreOnce();
},
template: `
<div class='mr-widget-footer approved-by-users approvals-footer clearfix mr-approvals-footer'>
<span class='approvers-prefix'> Approved by </span>
<span v-for='approver in approvedBy'>
<link-to-member-avatar
extra-link-class='approver-avatar'
:avatar-url='approver.user.avatar_url'
:display-name='approver.user.name'
:profile-url='approver.user.web_url'
:avatar-html='checkmarkSvg'
:show-tooltip='true'>
</link-to-member-avatar>
</span>
<span v-for='n in approvalsLeft'>
<link-to-member-avatar
:clickable='false'
:avatar-html='pendingAvatarSvg'
:show-tooltip='false'
extra-link-class='hide-asset'>
</link-to-member-avatar>
</span>
<span class='unapprove-btn-wrap' v-if='showUnapproveButton'>
<button
:disabled='unapproving'
@click='unapproveMergeRequest'
class='btn btn-link unapprove-btn'>
<i class='fa fa-close'></i>
Remove your approval</span>
</button>
</span>
</div>
`,
});
app/assets/javascripts/merge_request_widget/widget_bundle.js.es6
View file @
ad42c265
/* global
Vue
*/
/* global
merge_request_widget
*/
const Vue = require('vue');
require('./widget_store');
require('./approvals/approvals_bundle');
(() => {
$(() => {
const rootEl = document.getElementById('merge-request-widget-app');
const widgetSharedStore = new gl.MergeRequestWidgetStore(rootEl);
window.gl = window.gl || {};
$(() => {
const rootEl = document.getElementById('merge-request-widget-app');
const widgetSharedStore = new gl.MergeRequestWidgetStore(rootEl);
gl.MergeRequestWidgetApp = new Vue({
el: rootEl,
data: widgetSharedStore.data,
});
gl.MergeRequestWidgetApp = new Vue({
el: rootEl,
data: widgetSharedStore.data,
mounted() {
// re-init the MiniPipelineGraph because of Vue is messing with the element
merge_request_widget.initMiniPipelineGraph();
},
});
})
(window.gl || (window.gl = {}))
;
});
app/assets/javascripts/merge_request_widget/widget_store.js.es6
View file @
ad42c265
require('./approvals/approvals_store');
(() => {
let singleton;
class MergeRequestWidgetStore {
constructor(rootEl) {
if (!singleton) {
singleton = gl.MergeRequestWidget.Store = this;
this.init(rootEl);
}
return singleton;
let singleton;
class MergeRequestWidgetStore {
constructor(rootEl) {
if (!singleton) {
singleton = gl.MergeRequestWidget.Store = this;
this.init(rootEl);
}
return singleton;
}
init(rootEl) {
this.rootEl = rootEl;
this.data = {};
init(rootEl) {
this.rootEl = rootEl;
this.data = {};
// init other widget stores here
this.initWidgetState();
this.initApprovals();
}
// init other widget stores here
this.initWidgetState();
this.initApprovals();
}
initWidgetState() {
this.assignToData('showApprovals', false);
this.assignToData('disableAcceptance', this.rootEl.dataset.approvalPending === 'true');
}
initWidgetState() {
this.assignToData('showApprovals', false);
this.assignToData('disableAcceptance', this.rootEl.dataset.approvalPending === 'true');
}
initApprovals() {
gl.ApprovalsStore = new gl.MergeRequestApprovalsStore(this);
this.assignToData('approvals', {});
}
initApprovals() {
gl.ApprovalsStore = new gl.MergeRequestApprovalsStore(this);
this.assignToData('approvals', {});
}
assignToData(key, val) {
this.data[key] = val;
return val;
}
assignToData(key, val) {
this.data[key] = val;
return val;
}
gl.MergeRequestWidgetStore = MergeRequestWidgetStore;
})(window.gl || (window.gl = {}));
}
window.gl = window.gl || {};
window.gl.MergeRequestWidgetStore = MergeRequestWidgetStore;
app/assets/javascripts/vue_realtime_listener/index.js.es6
View file @
ad42c265
...
...
@@ -14,5 +14,16 @@
window.addEventListener('focus', startIntervals);
window.addEventListener('blur', removeIntervals);
document.addEventListener('beforeunload', removeAll);
// add removeAll methods to stack
const stack = gl.VueRealtimeListener.reset;
gl.VueRealtimeListener.reset = () => {
gl.VueRealtimeListener.reset = stack;
removeAll();
stack();
};
};
// remove all event listeners and intervals
gl.VueRealtimeListener.reset = () => undefined; // noop
})(window.gl || (window.gl = {}));
app/views/projects/merge_requests/_show.html.haml
View file @
ad42c265
...
...
@@ -3,10 +3,9 @@
-
page_description
@merge_request
.
description
-
page_card_attributes
@merge_request
.
card_attributes
-
content_for
:page_specific_javascripts
do
=
page_specific_javascript_bundle_tag
(
'lib_vue'
)
=
page_specific_javascript_bundle_tag
(
'diff_notes'
)
.merge-request
{
'data-url'
=>
merge_request_path
(
@merge_request
)
}
.merge-request
{
'data-url'
=>
merge_request_path
(
@merge_request
)
,
'data-project-path'
=>
project_path
(
@merge_request
.
project
)
}
=
render
"projects/merge_requests/show/mr_title"
.merge-request-details.issuable-details
{
data:
{
id:
@merge_request
.
project
.
id
}
}
...
...
changelogs/unreleased/23104-remove-public-param-for-projects.yml
0 → 100644
View file @
ad42c265
---
title
:
'
API:
remove
`public`
param
for
projects'
merge_request
:
8736
author
:
doc/api/projects.md
View file @
ad42c265
...
...
@@ -644,7 +644,6 @@ Parameters:
|
`snippets_enabled`
| boolean | no | Enable snippets for this project |
|
`container_registry_enabled`
| boolean | no | Enable container registry for this project |
|
`shared_runners_enabled`
| boolean | no | Enable shared runners for this project |
|
`public`
| boolean | no | If
`true`
, the same as setting
`visibility_level`
to 20 |
|
`visibility_level`
| integer | no | See
[
project visibility level
](
#project-visibility-level
)
|
|
`import_url`
| string | no | URL to import repository from |
|
`public_builds`
| boolean | no | If
`true`
, builds can be viewed by non-project-members |
...
...
@@ -679,7 +678,6 @@ Parameters:
|
`snippets_enabled`
| boolean | no | Enable snippets for this project |
|
`container_registry_enabled`
| boolean | no | Enable container registry for this project |
|
`shared_runners_enabled`
| boolean | no | Enable shared runners for this project |
|
`public`
| boolean | no | If
`true`
, the same as setting
`visibility_level`
to 20 |
|
`visibility_level`
| integer | no | See
[
project visibility level
](
#project-visibility-level
)
|
|
`import_url`
| string | no | URL to import repository from |
|
`public_builds`
| boolean | no | If
`true`
, builds can be viewed by non-project-members |
...
...
@@ -714,7 +712,6 @@ Parameters:
|
`snippets_enabled`
| boolean | no | Enable snippets for this project |
|
`container_registry_enabled`
| boolean | no | Enable container registry for this project |
|
`shared_runners_enabled`
| boolean | no | Enable shared runners for this project |
|
`public`
| boolean | no | If
`true`
, the same as setting
`visibility_level`
to 20 |
|
`visibility_level`
| integer | no | See
[
project visibility level
](
#project-visibility-level
)
|
|
`import_url`
| string | no | URL to import repository from |
|
`public_builds`
| boolean | no | If
`true`
, builds can be viewed by non-project-members |
...
...
lib/api/projects.rb
View file @
ad42c265
...
...
@@ -16,7 +16,6 @@ module API
optional
:shared_runners_enabled
,
type:
Boolean
,
desc:
'Flag indication if shared runners are enabled for that project'
optional
:container_registry_enabled
,
type:
Boolean
,
desc:
'Flag indication if the container registry is enabled for that project'
optional
:lfs_enabled
,
type:
Boolean
,
desc:
'Flag indication if Git LFS is enabled for that project'
optional
:public
,
type:
Boolean
,
desc:
'Create a public project. The same as visibility_level = 20.'
optional
:visibility_level
,
type:
Integer
,
values:
[
Gitlab
::
VisibilityLevel
::
PRIVATE
,
Gitlab
::
VisibilityLevel
::
INTERNAL
,
...
...
@@ -30,16 +29,6 @@ module API
optional
:repository_storage
,
type:
String
,
desc:
'Which storage shard the repository is on. Available only to admins'
optional
:approvals_before_merge
,
type:
Integer
,
desc:
'How many approvers should approve merge request by default'
end
def
map_public_to_visibility_level
(
attrs
)
publik
=
attrs
.
delete
(
:public
)
if
!
publik
.
nil?
&&
!
attrs
[
:visibility_level
].
present?
# Since setting the public attribute to private could mean either
# private or internal, use the more conservative option, private.
attrs
[
:visibility_level
]
=
(
publik
==
true
)
?
Gitlab
::
VisibilityLevel
::
PUBLIC
:
Gitlab
::
VisibilityLevel
::
PRIVATE
end
attrs
end
end
resource
:projects
do
...
...
@@ -165,7 +154,7 @@ module API
use
:create_params
end
post
do
attrs
=
map_public_to_visibility_level
(
declared_params
(
include_missing:
false
)
)
attrs
=
declared_params
(
include_missing:
false
)
project
=
::
Projects
::
CreateService
.
new
(
current_user
,
attrs
).
execute
if
project
.
saved?
...
...
@@ -194,7 +183,7 @@ module API
user
=
User
.
find_by
(
id:
params
.
delete
(
:user_id
))
not_found!
(
'User'
)
unless
user
attrs
=
map_public_to_visibility_level
(
declared_params
(
include_missing:
false
)
)
attrs
=
declared_params
(
include_missing:
false
)
project
=
::
Projects
::
CreateService
.
new
(
user
,
attrs
).
execute
if
project
.
saved?
...
...
@@ -272,7 +261,7 @@ module API
at_least_one_of
:name
,
:description
,
:issues_enabled
,
:merge_requests_enabled
,
:wiki_enabled
,
:builds_enabled
,
:snippets_enabled
,
:shared_runners_enabled
,
:container_registry_enabled
,
:lfs_enabled
,
:
public
,
:
visibility_level
,
:public_builds
,
:lfs_enabled
,
:visibility_level
,
:public_builds
,
:request_access_enabled
,
:only_allow_merge_if_build_succeeds
,
:only_allow_merge_if_all_discussions_are_resolved
,
:path
,
:default_branch
,
...
...
@@ -281,7 +270,7 @@ module API
end
put
':id'
do
authorize_admin_project
attrs
=
map_public_to_visibility_level
(
declared_params
(
include_missing:
false
)
)
attrs
=
declared_params
(
include_missing:
false
)
authorize!
:rename_project
,
user_project
if
attrs
[
:name
].
present?
authorize!
:change_visibility_level
,
user_project
if
attrs
[
:visibility_level
].
present?
...
...
spec/javascripts/commit/pipelines/pipelines_store_spec.js.es6
View file @
ad42c265
...
...
@@ -7,6 +7,9 @@ describe('Store', () => {
store = new gl.commits.pipelines.PipelinesStore();
});
// unregister intervals and event handlers
afterEach(() => gl.VueRealtimeListener.reset());
it('should start with a blank state', () => {
expect(store.state.pipelines.length).toBe(0);
});
...
...
spec/requests/api/projects_spec.rb
View file @
ad42c265
...
...
@@ -359,13 +359,6 @@ describe API::Projects, api: true do
expect
(
json_response
[
'visibility_level'
]).
to
eq
(
Gitlab
::
VisibilityLevel
::
PUBLIC
)
end
it
'sets a project as public using :public'
do
project
=
attributes_for
(
:project
,
{
public:
true
})
post
api
(
'/projects'
,
user
),
project
expect
(
json_response
[
'public'
]).
to
be_truthy
expect
(
json_response
[
'visibility_level'
]).
to
eq
(
Gitlab
::
VisibilityLevel
::
PUBLIC
)
end
it
'sets a project as internal'
do
project
=
attributes_for
(
:project
,
:internal
)
post
api
(
'/projects'
,
user
),
project
...
...
@@ -373,13 +366,6 @@ describe API::Projects, api: true do
expect
(
json_response
[
'visibility_level'
]).
to
eq
(
Gitlab
::
VisibilityLevel
::
INTERNAL
)
end
it
'sets a project as internal overriding :public'
do
project
=
attributes_for
(
:project
,
:internal
,
{
public:
true
})
post
api
(
'/projects'
,
user
),
project
expect
(
json_response
[
'public'
]).
to
be_falsey
expect
(
json_response
[
'visibility_level'
]).
to
eq
(
Gitlab
::
VisibilityLevel
::
INTERNAL
)
end
it
'sets a project as private'
do
project
=
attributes_for
(
:project
,
:private
)
post
api
(
'/projects'
,
user
),
project
...
...
@@ -387,13 +373,6 @@ describe API::Projects, api: true do
expect
(
json_response
[
'visibility_level'
]).
to
eq
(
Gitlab
::
VisibilityLevel
::
PRIVATE
)
end
it
'sets a project as private using :public'
do
project
=
attributes_for
(
:project
,
{
public:
false
})
post
api
(
'/projects'
,
user
),
project
expect
(
json_response
[
'public'
]).
to
be_falsey
expect
(
json_response
[
'visibility_level'
]).
to
eq
(
Gitlab
::
VisibilityLevel
::
PRIVATE
)
end
it
'sets a project as allowing merge even if build fails'
do
project
=
attributes_for
(
:project
,
{
only_allow_merge_if_build_succeeds:
false
})
post
api
(
'/projects'
,
user
),
project
...
...
@@ -431,13 +410,14 @@ describe API::Projects, api: true do
end
context
'when a visibility level is restricted'
do
let
(
:project_param
)
{
attributes_for
(
:project
,
:public
)
}
before
do
@project
=
attributes_for
(
:project
,
{
public:
true
})
stub_application_setting
(
restricted_visibility_levels:
[
Gitlab
::
VisibilityLevel
::
PUBLIC
])
end
it
'does not allow a non-admin to use a restricted visibility level'
do
post
api
(
'/projects'
,
user
),
@project
post
api
(
'/projects'
,
user
),
project_param
expect
(
response
).
to
have_http_status
(
400
)
expect
(
json_response
[
'message'
][
'visibility_level'
].
first
).
to
(
...
...
@@ -446,7 +426,8 @@ describe API::Projects, api: true do
end
it
'allows an admin to override restricted visibility settings'
do
post
api
(
'/projects'
,
admin
),
@project
post
api
(
'/projects'
,
admin
),
project_param
expect
(
json_response
[
'public'
]).
to
be_truthy
expect
(
json_response
[
'visibility_level'
]).
to
(
eq
(
Gitlab
::
VisibilityLevel
::
PUBLIC
)
...
...
@@ -499,15 +480,6 @@ describe API::Projects, api: true do
expect
(
json_response
[
'visibility_level'
]).
to
eq
(
Gitlab
::
VisibilityLevel
::
PUBLIC
)
end
it
'sets a project as public using :public'
do
project
=
attributes_for
(
:project
,
{
public:
true
})
post
api
(
"/projects/user/
#{
user
.
id
}
"
,
admin
),
project
expect
(
response
).
to
have_http_status
(
201
)
expect
(
json_response
[
'public'
]).
to
be_truthy
expect
(
json_response
[
'visibility_level'
]).
to
eq
(
Gitlab
::
VisibilityLevel
::
PUBLIC
)
end
it
'sets a project as internal'
do
project
=
attributes_for
(
:project
,
:internal
)
post
api
(
"/projects/user/
#{
user
.
id
}
"
,
admin
),
project
...
...
@@ -517,14 +489,6 @@ describe API::Projects, api: true do
expect
(
json_response
[
'visibility_level'
]).
to
eq
(
Gitlab
::
VisibilityLevel
::
INTERNAL
)
end
it
'sets a project as internal overriding :public'
do
project
=
attributes_for
(
:project
,
:internal
,
{
public:
true
})
post
api
(
"/projects/user/
#{
user
.
id
}
"
,
admin
),
project
expect
(
response
).
to
have_http_status
(
201
)
expect
(
json_response
[
'public'
]).
to
be_falsey
expect
(
json_response
[
'visibility_level'
]).
to
eq
(
Gitlab
::
VisibilityLevel
::
INTERNAL
)
end
it
'sets a project as private'
do
project
=
attributes_for
(
:project
,
:private
)
post
api
(
"/projects/user/
#{
user
.
id
}
"
,
admin
),
project
...
...
@@ -532,13 +496,6 @@ describe API::Projects, api: true do
expect
(
json_response
[
'visibility_level'
]).
to
eq
(
Gitlab
::
VisibilityLevel
::
PRIVATE
)
end
it
'sets a project as private using :public'
do
project
=
attributes_for
(
:project
,
{
public:
false
})
post
api
(
"/projects/user/
#{
user
.
id
}
"
,
admin
),
project
expect
(
json_response
[
'public'
]).
to
be_falsey
expect
(
json_response
[
'visibility_level'
]).
to
eq
(
Gitlab
::
VisibilityLevel
::
PRIVATE
)
end
it
'sets a project as allowing merge even if build fails'
do
project
=
attributes_for
(
:project
,
{
only_allow_merge_if_build_succeeds:
false
})
post
api
(
"/projects/user/
#{
user
.
id
}
"
,
admin
),
project
...
...
@@ -865,7 +822,7 @@ describe API::Projects, api: true do
it
'creates a new project snippet'
do
post
api
(
"/projects/
#{
project
.
id
}
/snippets"
,
user
),
title:
'api test'
,
file_name:
'sample.rb'
,
code:
'test'
,
visibility_level:
'0'
visibility_level:
Gitlab
::
VisibilityLevel
::
PRIVATE
expect
(
response
).
to
have_http_status
(
201
)
expect
(
json_response
[
'title'
]).
to
eq
(
'api test'
)
end
...
...
@@ -1114,7 +1071,7 @@ describe API::Projects, api: true do
end
it
'updates visibility_level'
do
project_param
=
{
visibility_level:
20
}
project_param
=
{
visibility_level:
Gitlab
::
VisibilityLevel
::
PUBLIC
}
put
api
(
"/projects/
#{
project3
.
id
}
"
,
user
),
project_param
expect
(
response
).
to
have_http_status
(
200
)
project_param
.
each_pair
do
|
k
,
v
|
...
...
@@ -1124,7 +1081,7 @@ describe API::Projects, api: true do
it
'updates visibility_level from public to private'
do
project3
.
update_attributes
({
visibility_level:
Gitlab
::
VisibilityLevel
::
PUBLIC
})
project_param
=
{
public:
false
}
project_param
=
{
visibility_level:
Gitlab
::
VisibilityLevel
::
PRIVATE
}
put
api
(
"/projects/
#{
project3
.
id
}
"
,
user
),
project_param
expect
(
response
).
to
have_http_status
(
200
)
project_param
.
each_pair
do
|
k
,
v
|
...
...
@@ -1206,7 +1163,7 @@ describe API::Projects, api: true do
end
it
'does not update visibility_level'
do
project_param
=
{
visibility_level:
20
}
project_param
=
{
visibility_level:
Gitlab
::
VisibilityLevel
::
PUBLIC
}
put
api
(
"/projects/
#{
project3
.
id
}
"
,
user4
),
project_param
expect
(
response
).
to
have_http_status
(
403
)
end
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment