Merge branch 'master' into sh-support-bitbucket-server-import
This commit is contained in:
commit
4a6ed4792f
|
@ -1 +1 @@
|
|||
0.107.0
|
||||
0.108.0
|
||||
|
|
2
Gemfile
2
Gemfile
|
@ -418,7 +418,7 @@ group :ed25519 do
|
|||
end
|
||||
|
||||
# Gitaly GRPC client
|
||||
gem 'gitaly-proto', '~> 0.102.0', require: 'gitaly'
|
||||
gem 'gitaly-proto', '~> 0.103.0', require: 'gitaly'
|
||||
gem 'grpc', '~> 1.11.0'
|
||||
|
||||
# Locked until https://github.com/google/protobuf/issues/4210 is closed
|
||||
|
|
|
@ -282,7 +282,7 @@ GEM
|
|||
gettext_i18n_rails (>= 0.7.1)
|
||||
po_to_json (>= 1.0.0)
|
||||
rails (>= 3.2.0)
|
||||
gitaly-proto (0.102.0)
|
||||
gitaly-proto (0.103.0)
|
||||
google-protobuf (~> 3.1)
|
||||
grpc (~> 1.10)
|
||||
github-linguist (5.3.3)
|
||||
|
@ -1041,7 +1041,7 @@ DEPENDENCIES
|
|||
gettext (~> 3.2.2)
|
||||
gettext_i18n_rails (~> 1.8.0)
|
||||
gettext_i18n_rails_js (~> 1.3)
|
||||
gitaly-proto (~> 0.102.0)
|
||||
gitaly-proto (~> 0.103.0)
|
||||
github-linguist (~> 5.3.3)
|
||||
gitlab-flowdock-git-hook (~> 1.0.1)
|
||||
gitlab-gollum-lib (~> 4.2)
|
||||
|
|
|
@ -285,7 +285,7 @@ GEM
|
|||
gettext_i18n_rails (>= 0.7.1)
|
||||
po_to_json (>= 1.0.0)
|
||||
rails (>= 3.2.0)
|
||||
gitaly-proto (0.102.0)
|
||||
gitaly-proto (0.103.0)
|
||||
google-protobuf (~> 3.1)
|
||||
grpc (~> 1.10)
|
||||
github-linguist (5.3.3)
|
||||
|
@ -1051,7 +1051,7 @@ DEPENDENCIES
|
|||
gettext (~> 3.2.2)
|
||||
gettext_i18n_rails (~> 1.8.0)
|
||||
gettext_i18n_rails_js (~> 1.3)
|
||||
gitaly-proto (~> 0.102.0)
|
||||
gitaly-proto (~> 0.103.0)
|
||||
github-linguist (~> 5.3.3)
|
||||
gitlab-flowdock-git-hook (~> 1.0.1)
|
||||
gitlab-gollum-lib (~> 4.2)
|
||||
|
|
19
PROCESS.md
19
PROCESS.md
|
@ -197,24 +197,7 @@ to. For example:
|
|||
If you think a merge request should go into an RC or patch even though it does not meet these requirements,
|
||||
you can ask for an exception to be made.
|
||||
|
||||
Go to [Release tasks issue tracker](https://gitlab.com/gitlab-org/release/tasks/issues/new) and create an issue
|
||||
using the `Exception-request` issue template.
|
||||
|
||||
**Do not** set the relevant `Pick into X.Y` label (see above) before request an
|
||||
exception; this should be done after the exception is approved.
|
||||
|
||||
You can find who is who on the [team page](https://about.gitlab.com/team/).
|
||||
|
||||
Whether an exception is made is determined by weighing the benefit and urgency of the change
|
||||
(how important it is to the company that this is released _right now_ instead of in a month)
|
||||
against the potential negative impact
|
||||
(things breaking without enough time to comfortably find and fix them before the release on the 22nd).
|
||||
When in doubt, we err on the side of _not_ cherry-picking.
|
||||
|
||||
For example, it is likely that an exception will be made for a trivial 1-5 line performance improvement
|
||||
(e.g. adding a database index or adding `includes` to a query), but not for a new feature, no matter how relatively small or thoroughly tested.
|
||||
|
||||
All MRs which have had exceptions granted must be merged by the 15th.
|
||||
Check [this guide](https://gitlab.com/gitlab-org/release/docs/blob/master/general/exception-request/process.md) about how to open an exception request before opening one.
|
||||
|
||||
### Regressions
|
||||
|
||||
|
|
|
@ -1,78 +1,78 @@
|
|||
<script>
|
||||
/* eslint-disable vue/require-default-prop */
|
||||
import './issue_card_inner';
|
||||
import eventHub from '../eventhub';
|
||||
/* eslint-disable vue/require-default-prop */
|
||||
import IssueCardInner from './issue_card_inner.vue';
|
||||
import eventHub from '../eventhub';
|
||||
|
||||
const Store = gl.issueBoards.BoardsStore;
|
||||
const Store = gl.issueBoards.BoardsStore;
|
||||
|
||||
export default {
|
||||
name: 'BoardsIssueCard',
|
||||
components: {
|
||||
'issue-card-inner': gl.issueBoards.IssueCardInner,
|
||||
},
|
||||
props: {
|
||||
list: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
export default {
|
||||
name: 'BoardsIssueCard',
|
||||
components: {
|
||||
IssueCardInner,
|
||||
},
|
||||
issue: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
props: {
|
||||
list: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
issue: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
issueLinkBase: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
index: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
rootPath: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
groupId: {
|
||||
type: Number,
|
||||
},
|
||||
},
|
||||
issueLinkBase: {
|
||||
type: String,
|
||||
default: '',
|
||||
data() {
|
||||
return {
|
||||
showDetail: false,
|
||||
detailIssue: Store.detail,
|
||||
};
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
computed: {
|
||||
issueDetailVisible() {
|
||||
return this.detailIssue.issue && this.detailIssue.issue.id === this.issue.id;
|
||||
},
|
||||
},
|
||||
index: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
rootPath: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
groupId: {
|
||||
type: Number,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showDetail: false,
|
||||
detailIssue: Store.detail,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
issueDetailVisible() {
|
||||
return this.detailIssue.issue && this.detailIssue.issue.id === this.issue.id;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
mouseDown() {
|
||||
this.showDetail = true;
|
||||
},
|
||||
mouseMove() {
|
||||
this.showDetail = false;
|
||||
},
|
||||
showIssue(e) {
|
||||
if (e.target.classList.contains('js-no-trigger')) return;
|
||||
|
||||
if (this.showDetail) {
|
||||
methods: {
|
||||
mouseDown() {
|
||||
this.showDetail = true;
|
||||
},
|
||||
mouseMove() {
|
||||
this.showDetail = false;
|
||||
},
|
||||
showIssue(e) {
|
||||
if (e.target.classList.contains('js-no-trigger')) return;
|
||||
|
||||
if (Store.detail.issue && Store.detail.issue.id === this.issue.id) {
|
||||
eventHub.$emit('clearDetailIssue');
|
||||
} else {
|
||||
eventHub.$emit('newDetailIssue', this.issue);
|
||||
Store.detail.list = this.list;
|
||||
if (this.showDetail) {
|
||||
this.showDetail = false;
|
||||
|
||||
if (Store.detail.issue && Store.detail.issue.id === this.issue.id) {
|
||||
eventHub.$emit('clearDetailIssue');
|
||||
} else {
|
||||
eventHub.$emit('newDetailIssue', this.issue);
|
||||
Store.detail.list = this.list;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
@ -1,196 +0,0 @@
|
|||
import $ from 'jquery';
|
||||
import Vue from 'vue';
|
||||
import UserAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
|
||||
import eventHub from '../eventhub';
|
||||
|
||||
const Store = gl.issueBoards.BoardsStore;
|
||||
|
||||
window.gl = window.gl || {};
|
||||
window.gl.issueBoards = window.gl.issueBoards || {};
|
||||
|
||||
gl.issueBoards.IssueCardInner = Vue.extend({
|
||||
components: {
|
||||
UserAvatarLink,
|
||||
},
|
||||
props: {
|
||||
issue: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
issueLinkBase: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
list: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: () => ({}),
|
||||
},
|
||||
rootPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
updateFilters: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
groupId: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
limitBeforeCounter: 3,
|
||||
maxRender: 4,
|
||||
maxCounter: 99,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
numberOverLimit() {
|
||||
return this.issue.assignees.length - this.limitBeforeCounter;
|
||||
},
|
||||
assigneeCounterTooltip() {
|
||||
return `${this.assigneeCounterLabel} more`;
|
||||
},
|
||||
assigneeCounterLabel() {
|
||||
if (this.numberOverLimit > this.maxCounter) {
|
||||
return `${this.maxCounter}+`;
|
||||
}
|
||||
|
||||
return `+${this.numberOverLimit}`;
|
||||
},
|
||||
shouldRenderCounter() {
|
||||
if (this.issue.assignees.length <= this.maxRender) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.issue.assignees.length > this.numberOverLimit;
|
||||
},
|
||||
issueId() {
|
||||
if (this.issue.iid) {
|
||||
return `#${this.issue.iid}`;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
showLabelFooter() {
|
||||
return this.issue.labels.find(l => this.showLabel(l)) !== undefined;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
isIndexLessThanlimit(index) {
|
||||
return index < this.limitBeforeCounter;
|
||||
},
|
||||
shouldRenderAssignee(index) {
|
||||
// Eg. maxRender is 4,
|
||||
// Render up to all 4 assignees if there are only 4 assigness
|
||||
// Otherwise render up to the limitBeforeCounter
|
||||
if (this.issue.assignees.length <= this.maxRender) {
|
||||
return index < this.maxRender;
|
||||
}
|
||||
|
||||
return index < this.limitBeforeCounter;
|
||||
},
|
||||
assigneeUrl(assignee) {
|
||||
return `${this.rootPath}${assignee.username}`;
|
||||
},
|
||||
assigneeUrlTitle(assignee) {
|
||||
return `Assigned to ${assignee.name}`;
|
||||
},
|
||||
avatarUrlTitle(assignee) {
|
||||
return `Avatar for ${assignee.name}`;
|
||||
},
|
||||
showLabel(label) {
|
||||
if (!label.id) return false;
|
||||
return true;
|
||||
},
|
||||
filterByLabel(label, e) {
|
||||
if (!this.updateFilters) return;
|
||||
|
||||
const filterPath = gl.issueBoards.BoardsStore.filter.path.split('&');
|
||||
const labelTitle = encodeURIComponent(label.title);
|
||||
const param = `label_name[]=${labelTitle}`;
|
||||
const labelIndex = filterPath.indexOf(param);
|
||||
$(e.currentTarget).tooltip('hide');
|
||||
|
||||
if (labelIndex === -1) {
|
||||
filterPath.push(param);
|
||||
} else {
|
||||
filterPath.splice(labelIndex, 1);
|
||||
}
|
||||
|
||||
gl.issueBoards.BoardsStore.filter.path = filterPath.join('&');
|
||||
|
||||
Store.updateFiltersUrl();
|
||||
|
||||
eventHub.$emit('updateTokens');
|
||||
},
|
||||
labelStyle(label) {
|
||||
return {
|
||||
backgroundColor: label.color,
|
||||
color: label.textColor,
|
||||
};
|
||||
},
|
||||
},
|
||||
template: `
|
||||
<div>
|
||||
<div class="board-card-header">
|
||||
<h4 class="board-card-title">
|
||||
<i
|
||||
class="fa fa-eye-slash confidential-icon"
|
||||
v-if="issue.confidential"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<a
|
||||
class="js-no-trigger"
|
||||
:href="issue.path"
|
||||
:title="issue.title">{{ issue.title }}</a>
|
||||
<span
|
||||
class="board-card-number"
|
||||
v-if="issueId"
|
||||
>
|
||||
{{ issue.referencePath }}
|
||||
</span>
|
||||
</h4>
|
||||
<div class="board-card-assignee">
|
||||
<user-avatar-link
|
||||
v-for="(assignee, index) in issue.assignees"
|
||||
:key="assignee.id"
|
||||
v-if="shouldRenderAssignee(index)"
|
||||
class="js-no-trigger"
|
||||
:link-href="assigneeUrl(assignee)"
|
||||
:img-alt="avatarUrlTitle(assignee)"
|
||||
:img-src="assignee.avatar"
|
||||
:tooltip-text="assigneeUrlTitle(assignee)"
|
||||
tooltip-placement="bottom"
|
||||
/>
|
||||
<span
|
||||
class="avatar-counter has-tooltip"
|
||||
:title="assigneeCounterTooltip"
|
||||
v-if="shouldRenderCounter"
|
||||
>
|
||||
{{ assigneeCounterLabel }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="board-card-footer"
|
||||
v-if="showLabelFooter"
|
||||
>
|
||||
<button
|
||||
class="badge color-label has-tooltip"
|
||||
v-for="label in issue.labels"
|
||||
type="button"
|
||||
v-if="showLabel(label)"
|
||||
@click="filterByLabel(label, $event)"
|
||||
:style="labelStyle(label)"
|
||||
:title="label.description"
|
||||
data-container="body">
|
||||
{{ label.title }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
});
|
|
@ -0,0 +1,196 @@
|
|||
<script>
|
||||
import $ from 'jquery';
|
||||
import UserAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
|
||||
import eventHub from '../eventhub';
|
||||
|
||||
const Store = gl.issueBoards.BoardsStore;
|
||||
|
||||
export default {
|
||||
components: {
|
||||
UserAvatarLink,
|
||||
},
|
||||
props: {
|
||||
issue: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
issueLinkBase: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
list: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: () => ({}),
|
||||
},
|
||||
rootPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
updateFilters: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
groupId: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
limitBeforeCounter: 3,
|
||||
maxRender: 4,
|
||||
maxCounter: 99,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
numberOverLimit() {
|
||||
return this.issue.assignees.length - this.limitBeforeCounter;
|
||||
},
|
||||
assigneeCounterTooltip() {
|
||||
return `${this.assigneeCounterLabel} more`;
|
||||
},
|
||||
assigneeCounterLabel() {
|
||||
if (this.numberOverLimit > this.maxCounter) {
|
||||
return `${this.maxCounter}+`;
|
||||
}
|
||||
|
||||
return `+${this.numberOverLimit}`;
|
||||
},
|
||||
shouldRenderCounter() {
|
||||
if (this.issue.assignees.length <= this.maxRender) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.issue.assignees.length > this.numberOverLimit;
|
||||
},
|
||||
issueId() {
|
||||
if (this.issue.iid) {
|
||||
return `#${this.issue.iid}`;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
showLabelFooter() {
|
||||
return this.issue.labels.find(l => this.showLabel(l)) !== undefined;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
isIndexLessThanlimit(index) {
|
||||
return index < this.limitBeforeCounter;
|
||||
},
|
||||
shouldRenderAssignee(index) {
|
||||
// Eg. maxRender is 4,
|
||||
// Render up to all 4 assignees if there are only 4 assigness
|
||||
// Otherwise render up to the limitBeforeCounter
|
||||
if (this.issue.assignees.length <= this.maxRender) {
|
||||
return index < this.maxRender;
|
||||
}
|
||||
|
||||
return index < this.limitBeforeCounter;
|
||||
},
|
||||
assigneeUrl(assignee) {
|
||||
return `${this.rootPath}${assignee.username}`;
|
||||
},
|
||||
assigneeUrlTitle(assignee) {
|
||||
return `Assigned to ${assignee.name}`;
|
||||
},
|
||||
avatarUrlTitle(assignee) {
|
||||
return `Avatar for ${assignee.name}`;
|
||||
},
|
||||
showLabel(label) {
|
||||
if (!label.id) return false;
|
||||
return true;
|
||||
},
|
||||
filterByLabel(label, e) {
|
||||
if (!this.updateFilters) return;
|
||||
|
||||
const filterPath = gl.issueBoards.BoardsStore.filter.path.split('&');
|
||||
const labelTitle = encodeURIComponent(label.title);
|
||||
const param = `label_name[]=${labelTitle}`;
|
||||
const labelIndex = filterPath.indexOf(param);
|
||||
$(e.currentTarget).tooltip('hide');
|
||||
|
||||
if (labelIndex === -1) {
|
||||
filterPath.push(param);
|
||||
} else {
|
||||
filterPath.splice(labelIndex, 1);
|
||||
}
|
||||
|
||||
gl.issueBoards.BoardsStore.filter.path = filterPath.join('&');
|
||||
|
||||
Store.updateFiltersUrl();
|
||||
|
||||
eventHub.$emit('updateTokens');
|
||||
},
|
||||
labelStyle(label) {
|
||||
return {
|
||||
backgroundColor: label.color,
|
||||
color: label.textColor,
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<div class="board-card-header">
|
||||
<h4 class="board-card-title">
|
||||
<i
|
||||
v-if="issue.confidential"
|
||||
class="fa fa-eye-slash confidential-icon"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<a
|
||||
:href="issue.path"
|
||||
:title="issue.title"
|
||||
class="js-no-trigger">{{ issue.title }}</a>
|
||||
<span
|
||||
v-if="issueId"
|
||||
class="board-card-number"
|
||||
>
|
||||
{{ issue.referencePath }}
|
||||
</span>
|
||||
</h4>
|
||||
<div class="board-card-assignee">
|
||||
<user-avatar-link
|
||||
v-for="(assignee, index) in issue.assignees"
|
||||
v-if="shouldRenderAssignee(index)"
|
||||
:key="assignee.id"
|
||||
:link-href="assigneeUrl(assignee)"
|
||||
:img-alt="avatarUrlTitle(assignee)"
|
||||
:img-src="assignee.avatar"
|
||||
:tooltip-text="assigneeUrlTitle(assignee)"
|
||||
class="js-no-trigger"
|
||||
tooltip-placement="bottom"
|
||||
/>
|
||||
<span
|
||||
v-if="shouldRenderCounter"
|
||||
:title="assigneeCounterTooltip"
|
||||
class="avatar-counter has-tooltip"
|
||||
>
|
||||
{{ assigneeCounterLabel }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="showLabelFooter"
|
||||
class="board-card-footer"
|
||||
>
|
||||
<button
|
||||
v-for="label in issue.labels"
|
||||
v-if="showLabel(label)"
|
||||
:key="label.id"
|
||||
:style="labelStyle(label)"
|
||||
:title="label.description"
|
||||
class="badge color-label has-tooltip"
|
||||
type="button"
|
||||
data-container="body"
|
||||
@click="filterByLabel(label, $event)"
|
||||
>
|
||||
{{ label.title }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
|
@ -1,79 +0,0 @@
|
|||
import Vue from 'vue';
|
||||
import modalFilters from './filters';
|
||||
import modalTabs from './tabs.vue';
|
||||
import ModalStore from '../../stores/modal_store';
|
||||
import modalMixin from '../../mixins/modal_mixins';
|
||||
|
||||
gl.issueBoards.ModalHeader = Vue.extend({
|
||||
components: {
|
||||
modalTabs,
|
||||
modalFilters,
|
||||
},
|
||||
mixins: [modalMixin],
|
||||
props: {
|
||||
projectId: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
milestonePath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
labelPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return ModalStore.store;
|
||||
},
|
||||
computed: {
|
||||
selectAllText() {
|
||||
if (ModalStore.selectedCount() !== this.issues.length || this.issues.length === 0) {
|
||||
return 'Select all';
|
||||
}
|
||||
|
||||
return 'Deselect all';
|
||||
},
|
||||
showSearch() {
|
||||
return this.activeTab === 'all' && !this.loading && this.issuesCount > 0;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
toggleAll() {
|
||||
this.$refs.selectAllBtn.blur();
|
||||
|
||||
ModalStore.toggleAll();
|
||||
},
|
||||
},
|
||||
template: `
|
||||
<div>
|
||||
<header class="add-issues-header form-actions">
|
||||
<h2>
|
||||
Add issues
|
||||
<button
|
||||
type="button"
|
||||
class="close"
|
||||
data-dismiss="modal"
|
||||
aria-label="Close"
|
||||
@click="toggleModal(false)">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</h2>
|
||||
</header>
|
||||
<modal-tabs v-if="!loading && issuesCount > 0"></modal-tabs>
|
||||
<div
|
||||
class="add-issues-search append-bottom-10"
|
||||
v-if="showSearch">
|
||||
<modal-filters :store="filter" />
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-success btn-inverted prepend-left-10"
|
||||
ref="selectAllBtn"
|
||||
@click="toggleAll">
|
||||
{{ selectAllText }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
});
|
|
@ -0,0 +1,82 @@
|
|||
<script>
|
||||
import ModalFilters from './filters';
|
||||
import ModalTabs from './tabs.vue';
|
||||
import ModalStore from '../../stores/modal_store';
|
||||
import modalMixin from '../../mixins/modal_mixins';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ModalTabs,
|
||||
ModalFilters,
|
||||
},
|
||||
mixins: [modalMixin],
|
||||
props: {
|
||||
projectId: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
milestonePath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
labelPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return ModalStore.store;
|
||||
},
|
||||
computed: {
|
||||
selectAllText() {
|
||||
if (ModalStore.selectedCount() !== this.issues.length || this.issues.length === 0) {
|
||||
return 'Select all';
|
||||
}
|
||||
|
||||
return 'Deselect all';
|
||||
},
|
||||
showSearch() {
|
||||
return this.activeTab === 'all' && !this.loading && this.issuesCount > 0;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
toggleAll() {
|
||||
this.$refs.selectAllBtn.blur();
|
||||
|
||||
ModalStore.toggleAll();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<header class="add-issues-header form-actions">
|
||||
<h2>
|
||||
Add issues
|
||||
<button
|
||||
type="button"
|
||||
class="close"
|
||||
data-dismiss="modal"
|
||||
aria-label="Close"
|
||||
@click="toggleModal(false)"
|
||||
>
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</h2>
|
||||
</header>
|
||||
<modal-tabs v-if="!loading && issuesCount > 0"/>
|
||||
<div
|
||||
v-if="showSearch"
|
||||
class="add-issues-search append-bottom-10">
|
||||
<modal-filters :store="filter" />
|
||||
<button
|
||||
ref="selectAllBtn"
|
||||
type="button"
|
||||
class="btn btn-success btn-inverted prepend-left-10"
|
||||
@click="toggleAll"
|
||||
>
|
||||
{{ selectAllText }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
|
@ -1,171 +0,0 @@
|
|||
/* global ListIssue */
|
||||
|
||||
import Vue from 'vue';
|
||||
import queryData from '~/boards/utils/query_data';
|
||||
import loadingIcon from '~/vue_shared/components/loading_icon.vue';
|
||||
import './header';
|
||||
import './list';
|
||||
import ModalFooter from './footer.vue';
|
||||
import EmptyState from './empty_state.vue';
|
||||
import ModalStore from '../../stores/modal_store';
|
||||
|
||||
gl.issueBoards.IssuesModal = Vue.extend({
|
||||
components: {
|
||||
EmptyState,
|
||||
'modal-header': gl.issueBoards.ModalHeader,
|
||||
'modal-list': gl.issueBoards.ModalList,
|
||||
ModalFooter,
|
||||
loadingIcon,
|
||||
},
|
||||
props: {
|
||||
newIssuePath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
emptyStateSvg: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
issueLinkBase: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
rootPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
projectId: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
milestonePath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
labelPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return ModalStore.store;
|
||||
},
|
||||
computed: {
|
||||
showList() {
|
||||
if (this.activeTab === 'selected') {
|
||||
return this.selectedIssues.length > 0;
|
||||
}
|
||||
|
||||
return this.issuesCount > 0;
|
||||
},
|
||||
showEmptyState() {
|
||||
if (!this.loading && this.issuesCount === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.activeTab === 'selected' && this.selectedIssues.length === 0;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
page() {
|
||||
this.loadIssues();
|
||||
},
|
||||
showAddIssuesModal() {
|
||||
if (this.showAddIssuesModal && !this.issues.length) {
|
||||
this.loading = true;
|
||||
const loadingDone = () => {
|
||||
this.loading = false;
|
||||
};
|
||||
|
||||
this.loadIssues()
|
||||
.then(loadingDone)
|
||||
.catch(loadingDone);
|
||||
} else if (!this.showAddIssuesModal) {
|
||||
this.issues = [];
|
||||
this.selectedIssues = [];
|
||||
this.issuesCount = false;
|
||||
}
|
||||
},
|
||||
filter: {
|
||||
handler() {
|
||||
if (this.$el.tagName) {
|
||||
this.page = 1;
|
||||
this.filterLoading = true;
|
||||
const loadingDone = () => {
|
||||
this.filterLoading = false;
|
||||
};
|
||||
|
||||
this.loadIssues(true)
|
||||
.then(loadingDone)
|
||||
.catch(loadingDone);
|
||||
}
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.page = 1;
|
||||
},
|
||||
methods: {
|
||||
loadIssues(clearIssues = false) {
|
||||
if (!this.showAddIssuesModal) return false;
|
||||
|
||||
return gl.boardService.getBacklog(queryData(this.filter.path, {
|
||||
page: this.page,
|
||||
per: this.perPage,
|
||||
}))
|
||||
.then(res => res.data)
|
||||
.then((data) => {
|
||||
if (clearIssues) {
|
||||
this.issues = [];
|
||||
}
|
||||
|
||||
data.issues.forEach((issueObj) => {
|
||||
const issue = new ListIssue(issueObj);
|
||||
const foundSelectedIssue = ModalStore.findSelectedIssue(issue);
|
||||
issue.selected = !!foundSelectedIssue;
|
||||
|
||||
this.issues.push(issue);
|
||||
});
|
||||
|
||||
this.loadingNewPage = false;
|
||||
|
||||
if (!this.issuesCount) {
|
||||
this.issuesCount = data.size;
|
||||
}
|
||||
}).catch(() => {
|
||||
// TODO: handle request error
|
||||
});
|
||||
},
|
||||
},
|
||||
template: `
|
||||
<div
|
||||
class="add-issues-modal"
|
||||
v-if="showAddIssuesModal">
|
||||
<div class="add-issues-container">
|
||||
<modal-header
|
||||
:project-id="projectId"
|
||||
:milestone-path="milestonePath"
|
||||
:label-path="labelPath">
|
||||
</modal-header>
|
||||
<modal-list
|
||||
:issue-link-base="issueLinkBase"
|
||||
:root-path="rootPath"
|
||||
:empty-state-svg="emptyStateSvg"
|
||||
v-if="!loading && showList && !filterLoading"></modal-list>
|
||||
<empty-state
|
||||
v-if="showEmptyState"
|
||||
:new-issue-path="newIssuePath"
|
||||
:empty-state-svg="emptyStateSvg"></empty-state>
|
||||
<section
|
||||
class="add-issues-list text-center"
|
||||
v-if="loading || filterLoading">
|
||||
<div class="add-issues-list-loading">
|
||||
<loading-icon />
|
||||
</div>
|
||||
</section>
|
||||
<modal-footer></modal-footer>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
});
|
|
@ -0,0 +1,178 @@
|
|||
<script>
|
||||
/* global ListIssue */
|
||||
import queryData from '~/boards/utils/query_data';
|
||||
import loadingIcon from '~/vue_shared/components/loading_icon.vue';
|
||||
import ModalHeader from './header.vue';
|
||||
import ModalList from './list.vue';
|
||||
import ModalFooter from './footer.vue';
|
||||
import EmptyState from './empty_state.vue';
|
||||
import ModalStore from '../../stores/modal_store';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
EmptyState,
|
||||
ModalHeader,
|
||||
ModalList,
|
||||
ModalFooter,
|
||||
loadingIcon,
|
||||
},
|
||||
props: {
|
||||
newIssuePath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
emptyStateSvg: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
issueLinkBase: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
rootPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
projectId: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
milestonePath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
labelPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return ModalStore.store;
|
||||
},
|
||||
computed: {
|
||||
showList() {
|
||||
if (this.activeTab === 'selected') {
|
||||
return this.selectedIssues.length > 0;
|
||||
}
|
||||
|
||||
return this.issuesCount > 0;
|
||||
},
|
||||
showEmptyState() {
|
||||
if (!this.loading && this.issuesCount === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.activeTab === 'selected' && this.selectedIssues.length === 0;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
page() {
|
||||
this.loadIssues();
|
||||
},
|
||||
showAddIssuesModal() {
|
||||
if (this.showAddIssuesModal && !this.issues.length) {
|
||||
this.loading = true;
|
||||
const loadingDone = () => {
|
||||
this.loading = false;
|
||||
};
|
||||
|
||||
this.loadIssues()
|
||||
.then(loadingDone)
|
||||
.catch(loadingDone);
|
||||
} else if (!this.showAddIssuesModal) {
|
||||
this.issues = [];
|
||||
this.selectedIssues = [];
|
||||
this.issuesCount = false;
|
||||
}
|
||||
},
|
||||
filter: {
|
||||
handler() {
|
||||
if (this.$el.tagName) {
|
||||
this.page = 1;
|
||||
this.filterLoading = true;
|
||||
const loadingDone = () => {
|
||||
this.filterLoading = false;
|
||||
};
|
||||
|
||||
this.loadIssues(true)
|
||||
.then(loadingDone)
|
||||
.catch(loadingDone);
|
||||
}
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.page = 1;
|
||||
},
|
||||
methods: {
|
||||
loadIssues(clearIssues = false) {
|
||||
if (!this.showAddIssuesModal) return false;
|
||||
|
||||
return gl.boardService
|
||||
.getBacklog(
|
||||
queryData(this.filter.path, {
|
||||
page: this.page,
|
||||
per: this.perPage,
|
||||
}),
|
||||
)
|
||||
.then(res => res.data)
|
||||
.then(data => {
|
||||
if (clearIssues) {
|
||||
this.issues = [];
|
||||
}
|
||||
|
||||
data.issues.forEach(issueObj => {
|
||||
const issue = new ListIssue(issueObj);
|
||||
const foundSelectedIssue = ModalStore.findSelectedIssue(issue);
|
||||
issue.selected = !!foundSelectedIssue;
|
||||
|
||||
this.issues.push(issue);
|
||||
});
|
||||
|
||||
this.loadingNewPage = false;
|
||||
|
||||
if (!this.issuesCount) {
|
||||
this.issuesCount = data.size;
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
// TODO: handle request error
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div
|
||||
v-if="showAddIssuesModal"
|
||||
class="add-issues-modal">
|
||||
<div class="add-issues-container">
|
||||
<modal-header
|
||||
:project-id="projectId"
|
||||
:milestone-path="milestonePath"
|
||||
:label-path="labelPath"
|
||||
/>
|
||||
<modal-list
|
||||
v-if="!loading && showList && !filterLoading"
|
||||
:issue-link-base="issueLinkBase"
|
||||
:root-path="rootPath"
|
||||
:empty-state-svg="emptyStateSvg"
|
||||
/>
|
||||
<empty-state
|
||||
v-if="showEmptyState"
|
||||
:new-issue-path="newIssuePath"
|
||||
:empty-state-svg="emptyStateSvg"
|
||||
/>
|
||||
<section
|
||||
v-if="loading || filterLoading"
|
||||
class="add-issues-list text-center"
|
||||
>
|
||||
<div class="add-issues-list-loading">
|
||||
<loading-icon />
|
||||
</div>
|
||||
</section>
|
||||
<modal-footer/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
|
@ -1,159 +0,0 @@
|
|||
import Vue from 'vue';
|
||||
import bp from '../../../breakpoints';
|
||||
import ModalStore from '../../stores/modal_store';
|
||||
|
||||
gl.issueBoards.ModalList = Vue.extend({
|
||||
components: {
|
||||
'issue-card-inner': gl.issueBoards.IssueCardInner,
|
||||
},
|
||||
props: {
|
||||
issueLinkBase: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
rootPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
emptyStateSvg: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return ModalStore.store;
|
||||
},
|
||||
computed: {
|
||||
loopIssues() {
|
||||
if (this.activeTab === 'all') {
|
||||
return this.issues;
|
||||
}
|
||||
|
||||
return this.selectedIssues;
|
||||
},
|
||||
groupedIssues() {
|
||||
const groups = [];
|
||||
this.loopIssues.forEach((issue, i) => {
|
||||
const index = i % this.columns;
|
||||
|
||||
if (!groups[index]) {
|
||||
groups.push([]);
|
||||
}
|
||||
|
||||
groups[index].push(issue);
|
||||
});
|
||||
|
||||
return groups;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
activeTab() {
|
||||
if (this.activeTab === 'all') {
|
||||
ModalStore.purgeUnselectedIssues();
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.scrollHandlerWrapper = this.scrollHandler.bind(this);
|
||||
this.setColumnCountWrapper = this.setColumnCount.bind(this);
|
||||
this.setColumnCount();
|
||||
|
||||
this.$refs.list.addEventListener('scroll', this.scrollHandlerWrapper);
|
||||
window.addEventListener('resize', this.setColumnCountWrapper);
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.$refs.list.removeEventListener('scroll', this.scrollHandlerWrapper);
|
||||
window.removeEventListener('resize', this.setColumnCountWrapper);
|
||||
},
|
||||
methods: {
|
||||
scrollHandler() {
|
||||
const currentPage = Math.floor(this.issues.length / this.perPage);
|
||||
|
||||
if (
|
||||
this.scrollTop() > this.scrollHeight() - 100 &&
|
||||
!this.loadingNewPage &&
|
||||
currentPage === this.page
|
||||
) {
|
||||
this.loadingNewPage = true;
|
||||
this.page += 1;
|
||||
}
|
||||
},
|
||||
toggleIssue(e, issue) {
|
||||
if (e.target.tagName !== 'A') {
|
||||
ModalStore.toggleIssue(issue);
|
||||
}
|
||||
},
|
||||
listHeight() {
|
||||
return this.$refs.list.getBoundingClientRect().height;
|
||||
},
|
||||
scrollHeight() {
|
||||
return this.$refs.list.scrollHeight;
|
||||
},
|
||||
scrollTop() {
|
||||
return this.$refs.list.scrollTop + this.listHeight();
|
||||
},
|
||||
showIssue(issue) {
|
||||
if (this.activeTab === 'all') return true;
|
||||
|
||||
const index = ModalStore.selectedIssueIndex(issue);
|
||||
|
||||
return index !== -1;
|
||||
},
|
||||
setColumnCount() {
|
||||
const breakpoint = bp.getBreakpointSize();
|
||||
|
||||
if (breakpoint === 'lg' || breakpoint === 'md') {
|
||||
this.columns = 3;
|
||||
} else if (breakpoint === 'sm') {
|
||||
this.columns = 2;
|
||||
} else {
|
||||
this.columns = 1;
|
||||
}
|
||||
},
|
||||
},
|
||||
template: `
|
||||
<section
|
||||
class="add-issues-list add-issues-list-columns"
|
||||
ref="list">
|
||||
<div
|
||||
class="empty-state add-issues-empty-state-filter text-center"
|
||||
v-if="issuesCount > 0 && issues.length === 0">
|
||||
<div
|
||||
class="svg-content">
|
||||
<img :src="emptyStateSvg"/>
|
||||
</div>
|
||||
<div class="text-content">
|
||||
<h4>
|
||||
There are no issues to show.
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-for="group in groupedIssues"
|
||||
class="add-issues-list-column">
|
||||
<div
|
||||
v-for="issue in group"
|
||||
v-if="showIssue(issue)"
|
||||
class="board-card-parent">
|
||||
<div
|
||||
class="board-card"
|
||||
:class="{ 'is-active': issue.selected }"
|
||||
@click="toggleIssue($event, issue)">
|
||||
<issue-card-inner
|
||||
:issue="issue"
|
||||
:issue-link-base="issueLinkBase"
|
||||
:root-path="rootPath">
|
||||
</issue-card-inner>
|
||||
<span
|
||||
:aria-label="'Issue #' + issue.id + ' selected'"
|
||||
aria-checked="true"
|
||||
v-if="issue.selected"
|
||||
class="issue-card-selected text-center">
|
||||
<i class="fa fa-check"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
`,
|
||||
});
|
|
@ -0,0 +1,162 @@
|
|||
<script>
|
||||
import bp from '../../../breakpoints';
|
||||
import ModalStore from '../../stores/modal_store';
|
||||
import IssueCardInner from '../issue_card_inner.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
IssueCardInner,
|
||||
},
|
||||
props: {
|
||||
issueLinkBase: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
rootPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
emptyStateSvg: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return ModalStore.store;
|
||||
},
|
||||
computed: {
|
||||
loopIssues() {
|
||||
if (this.activeTab === 'all') {
|
||||
return this.issues;
|
||||
}
|
||||
|
||||
return this.selectedIssues;
|
||||
},
|
||||
groupedIssues() {
|
||||
const groups = [];
|
||||
this.loopIssues.forEach((issue, i) => {
|
||||
const index = i % this.columns;
|
||||
|
||||
if (!groups[index]) {
|
||||
groups.push([]);
|
||||
}
|
||||
|
||||
groups[index].push(issue);
|
||||
});
|
||||
|
||||
return groups;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
activeTab() {
|
||||
if (this.activeTab === 'all') {
|
||||
ModalStore.purgeUnselectedIssues();
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.scrollHandlerWrapper = this.scrollHandler.bind(this);
|
||||
this.setColumnCountWrapper = this.setColumnCount.bind(this);
|
||||
this.setColumnCount();
|
||||
|
||||
this.$refs.list.addEventListener('scroll', this.scrollHandlerWrapper);
|
||||
window.addEventListener('resize', this.setColumnCountWrapper);
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.$refs.list.removeEventListener('scroll', this.scrollHandlerWrapper);
|
||||
window.removeEventListener('resize', this.setColumnCountWrapper);
|
||||
},
|
||||
methods: {
|
||||
scrollHandler() {
|
||||
const currentPage = Math.floor(this.issues.length / this.perPage);
|
||||
|
||||
if (
|
||||
this.scrollTop() > this.scrollHeight() - 100 &&
|
||||
!this.loadingNewPage &&
|
||||
currentPage === this.page
|
||||
) {
|
||||
this.loadingNewPage = true;
|
||||
this.page += 1;
|
||||
}
|
||||
},
|
||||
toggleIssue(e, issue) {
|
||||
if (e.target.tagName !== 'A') {
|
||||
ModalStore.toggleIssue(issue);
|
||||
}
|
||||
},
|
||||
listHeight() {
|
||||
return this.$refs.list.getBoundingClientRect().height;
|
||||
},
|
||||
scrollHeight() {
|
||||
return this.$refs.list.scrollHeight;
|
||||
},
|
||||
scrollTop() {
|
||||
return this.$refs.list.scrollTop + this.listHeight();
|
||||
},
|
||||
showIssue(issue) {
|
||||
if (this.activeTab === 'all') return true;
|
||||
|
||||
const index = ModalStore.selectedIssueIndex(issue);
|
||||
|
||||
return index !== -1;
|
||||
},
|
||||
setColumnCount() {
|
||||
const breakpoint = bp.getBreakpointSize();
|
||||
|
||||
if (breakpoint === 'lg' || breakpoint === 'md') {
|
||||
this.columns = 3;
|
||||
} else if (breakpoint === 'sm') {
|
||||
this.columns = 2;
|
||||
} else {
|
||||
this.columns = 1;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<section
|
||||
ref="list"
|
||||
class="add-issues-list add-issues-list-columns">
|
||||
<div
|
||||
v-if="issuesCount > 0 && issues.length === 0"
|
||||
class="empty-state add-issues-empty-state-filter text-center">
|
||||
<div
|
||||
class="svg-content">
|
||||
<img :src="emptyStateSvg" />
|
||||
</div>
|
||||
<div class="text-content">
|
||||
<h4>
|
||||
There are no issues to show.
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-for="(group, index) in groupedIssues"
|
||||
:key="index"
|
||||
class="add-issues-list-column">
|
||||
<div
|
||||
v-for="issue in group"
|
||||
v-if="showIssue(issue)"
|
||||
:key="issue.id"
|
||||
class="board-card-parent">
|
||||
<div
|
||||
:class="{ 'is-active': issue.selected }"
|
||||
class="board-card"
|
||||
@click="toggleIssue($event, issue)">
|
||||
<issue-card-inner
|
||||
:issue="issue"
|
||||
:issue-link-base="issueLinkBase"
|
||||
:root-path="rootPath"/>
|
||||
<span
|
||||
v-if="issue.selected"
|
||||
:aria-label="'Issue #' + issue.id + ' selected'"
|
||||
aria-checked="true"
|
||||
class="issue-card-selected text-center">
|
||||
<i class="fa fa-check"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
|
@ -25,7 +25,7 @@ import './filters/due_date_filters';
|
|||
import './components/board';
|
||||
import './components/board_sidebar';
|
||||
import './components/new_list_dropdown';
|
||||
import './components/modal/index';
|
||||
import BoardAddIssuesModal from './components/modal/index.vue';
|
||||
import '~/vue_shared/vue_resource_interceptor'; // eslint-disable-line import/first
|
||||
|
||||
export default () => {
|
||||
|
@ -49,7 +49,7 @@ export default () => {
|
|||
components: {
|
||||
'board': gl.issueBoards.Board,
|
||||
'board-sidebar': gl.issueBoards.BoardSidebar,
|
||||
'board-add-issues-modal': gl.issueBoards.IssuesModal,
|
||||
BoardAddIssuesModal,
|
||||
},
|
||||
data: {
|
||||
state: Store.state,
|
||||
|
|
|
@ -189,12 +189,25 @@ export const getParameterByName = (name, urlToParse) => {
|
|||
return decodeURIComponent(results[2].replace(/\+/g, ' '));
|
||||
};
|
||||
|
||||
const handleSelectedRange = (range) => {
|
||||
const container = range.commonAncestorContainer;
|
||||
// add context to fragment if needed
|
||||
if (container.tagName === 'OL') {
|
||||
const parentContainer = document.createElement(container.tagName);
|
||||
parentContainer.appendChild(range.cloneContents());
|
||||
return parentContainer;
|
||||
}
|
||||
return range.cloneContents();
|
||||
};
|
||||
|
||||
export const getSelectedFragment = () => {
|
||||
const selection = window.getSelection();
|
||||
if (selection.rangeCount === 0) return null;
|
||||
const documentFragment = document.createDocumentFragment();
|
||||
|
||||
for (let i = 0; i < selection.rangeCount; i += 1) {
|
||||
documentFragment.appendChild(selection.getRangeAt(i).cloneContents());
|
||||
const range = selection.getRangeAt(i);
|
||||
documentFragment.appendChild(handleSelectedRange(range));
|
||||
}
|
||||
if (documentFragment.textContent.length === 0) return null;
|
||||
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
import $ from 'jquery';
|
||||
import _ from 'underscore';
|
||||
import ProtectedBranchAccessDropdown from './protected_branch_access_dropdown';
|
||||
import CreateItemDropdown from '../create_item_dropdown';
|
||||
import AccessorUtilities from '../lib/utils/accessor';
|
||||
|
||||
const PB_LOCAL_STORAGE_KEY = 'protected-branches-defaults';
|
||||
|
||||
export default class ProtectedBranchCreate {
|
||||
constructor() {
|
||||
this.$form = $('.js-new-protected-branch');
|
||||
|
@ -43,8 +40,6 @@ export default class ProtectedBranchCreate {
|
|||
onSelect: this.onSelectCallback,
|
||||
getData: ProtectedBranchCreate.getProtectedBranches,
|
||||
});
|
||||
|
||||
this.loadPreviousSelection($allowedToMergeDropdown.data('glDropdown'), $allowedToPushDropdown.data('glDropdown'));
|
||||
}
|
||||
|
||||
// This will run after clicked callback
|
||||
|
@ -59,39 +54,10 @@ export default class ProtectedBranchCreate {
|
|||
$allowedToPushInput.length
|
||||
);
|
||||
|
||||
this.savePreviousSelection($allowedToMergeInput.val(), $allowedToPushInput.val());
|
||||
this.$form.find('input[type="submit"]').prop('disabled', completedForm);
|
||||
}
|
||||
|
||||
static getProtectedBranches(term, callback) {
|
||||
callback(gon.open_branches);
|
||||
}
|
||||
|
||||
loadPreviousSelection(mergeDropdown, pushDropdown) {
|
||||
let mergeIndex = 0;
|
||||
let pushIndex = 0;
|
||||
if (this.isLocalStorageAvailable) {
|
||||
const savedDefaults = JSON.parse(window.localStorage.getItem(PB_LOCAL_STORAGE_KEY));
|
||||
if (savedDefaults != null) {
|
||||
mergeIndex = _.findLastIndex(mergeDropdown.fullData.roles, {
|
||||
id: parseInt(savedDefaults.mergeSelection, 0),
|
||||
});
|
||||
pushIndex = _.findLastIndex(pushDropdown.fullData.roles, {
|
||||
id: parseInt(savedDefaults.pushSelection, 0),
|
||||
});
|
||||
}
|
||||
}
|
||||
mergeDropdown.selectRowAtIndex(mergeIndex);
|
||||
pushDropdown.selectRowAtIndex(pushIndex);
|
||||
}
|
||||
|
||||
savePreviousSelection(mergeSelection, pushSelection) {
|
||||
if (this.isLocalStorageAvailable) {
|
||||
const branchDefaults = {
|
||||
mergeSelection,
|
||||
pushSelection,
|
||||
};
|
||||
window.localStorage.setItem(PB_LOCAL_STORAGE_KEY, JSON.stringify(branchDefaults));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -289,7 +289,7 @@ export default class SearchAutocomplete {
|
|||
}
|
||||
|
||||
// If the dropdown is closed, we'll open it
|
||||
if (!this.dropdown.hasClass('open')) {
|
||||
if (!this.dropdown.hasClass('show')) {
|
||||
this.loadingSuggestions = false;
|
||||
this.dropdownToggle.dropdown('toggle');
|
||||
return this.searchInput.removeClass('disabled');
|
||||
|
@ -424,9 +424,9 @@ export default class SearchAutocomplete {
|
|||
}
|
||||
|
||||
disableAutocomplete() {
|
||||
if (!this.searchInput.hasClass('disabled') && this.dropdown.hasClass('open')) {
|
||||
if (!this.searchInput.hasClass('disabled') && this.dropdown.hasClass('show')) {
|
||||
this.searchInput.addClass('disabled');
|
||||
this.dropdown.removeClass('open').trigger('hidden.bs.dropdown');
|
||||
this.dropdown.removeClass('show').trigger('hidden.bs.dropdown');
|
||||
this.restoreMenu();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ class HealthController < ActionController::Base
|
|||
Gitlab::HealthChecks::Redis::CacheCheck,
|
||||
Gitlab::HealthChecks::Redis::QueuesCheck,
|
||||
Gitlab::HealthChecks::Redis::SharedStateCheck,
|
||||
Gitlab::HealthChecks::FsShardsCheck,
|
||||
Gitlab::HealthChecks::GitalyCheck
|
||||
].freeze
|
||||
|
||||
|
|
|
@ -270,7 +270,7 @@ module ApplicationHelper
|
|||
{
|
||||
members: members_project_autocomplete_sources_path(object, type: noteable_type, type_id: params[:id]),
|
||||
issues: issues_project_autocomplete_sources_path(object),
|
||||
merge_requests: merge_requests_project_autocomplete_sources_path(object),
|
||||
mergeRequests: merge_requests_project_autocomplete_sources_path(object),
|
||||
labels: labels_project_autocomplete_sources_path(object, type: noteable_type, type_id: params[:id]),
|
||||
milestones: milestones_project_autocomplete_sources_path(object),
|
||||
commands: commands_project_autocomplete_sources_path(object, type: noteable_type, type_id: params[:id])
|
||||
|
|
|
@ -6,7 +6,8 @@ class MetricsService
|
|||
Gitlab::HealthChecks::Redis::RedisCheck,
|
||||
Gitlab::HealthChecks::Redis::CacheCheck,
|
||||
Gitlab::HealthChecks::Redis::QueuesCheck,
|
||||
Gitlab::HealthChecks::Redis::SharedStateCheck
|
||||
Gitlab::HealthChecks::Redis::SharedStateCheck,
|
||||
Gitlab::HealthChecks::GitalyCheck
|
||||
].freeze
|
||||
|
||||
def prometheus_metrics_text
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AdminEmailWorker
|
||||
include ApplicationWorker
|
||||
include CronjobQueue
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ArchiveTraceWorker
|
||||
include ApplicationWorker
|
||||
include PipelineBackgroundQueue
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AuthorizedProjectsWorker
|
||||
include ApplicationWorker
|
||||
prepend WaitableWorker
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class BackgroundMigrationWorker
|
||||
include ApplicationWorker
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class BuildCoverageWorker
|
||||
include ApplicationWorker
|
||||
include PipelineQueue
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class BuildFinishedWorker
|
||||
include ApplicationWorker
|
||||
include PipelineQueue
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class BuildHooksWorker
|
||||
include ApplicationWorker
|
||||
include PipelineQueue
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class BuildQueueWorker
|
||||
include ApplicationWorker
|
||||
include PipelineQueue
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class BuildSuccessWorker
|
||||
include ApplicationWorker
|
||||
include PipelineQueue
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class BuildTraceSectionsWorker
|
||||
include ApplicationWorker
|
||||
include PipelineQueue
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Ci
|
||||
class ArchiveTracesCronWorker
|
||||
include ApplicationWorker
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Ci
|
||||
class BuildTraceChunkFlushWorker
|
||||
include ApplicationWorker
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ClusterInstallAppWorker
|
||||
include ApplicationWorker
|
||||
include ClusterQueue
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ClusterProvisionWorker
|
||||
include ApplicationWorker
|
||||
include ClusterQueue
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ClusterWaitForAppInstallationWorker
|
||||
include ApplicationWorker
|
||||
include ClusterQueue
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ClusterWaitForIngressIpAddressWorker
|
||||
include ApplicationWorker
|
||||
include ClusterQueue
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
Sidekiq::Worker.extend ActiveSupport::Concern
|
||||
|
||||
module ApplicationWorker
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ClusterApplications
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
##
|
||||
# Concern for setting Sidekiq settings for the various Gcp clusters workers.
|
||||
#
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Concern that sets various Sidekiq settings for workers executed using a
|
||||
# cronjob.
|
||||
module CronjobQueue
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Concern for enabling a few lines of exception backtraces in Sidekiq
|
||||
module ExceptionBacktrace
|
||||
extend ActiveSupport::Concern
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module GithubImport
|
||||
module Queue
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module MailSchedulerQueue
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module NewIssuable
|
||||
attr_reader :issuable, :user
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Concern for setting Sidekiq settings for the various GitLab ObjectStorage workers.
|
||||
module ObjectStorageQueue
|
||||
extend ActiveSupport::Concern
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
##
|
||||
# Concern for setting Sidekiq settings for the low priority CI pipeline workers.
|
||||
#
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
##
|
||||
# Concern for setting Sidekiq settings for the various CI pipeline workers.
|
||||
#
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ProjectImportOptions
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Used in EE by mirroring
|
||||
module ProjectStartImport
|
||||
def start(project)
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Concern for setting Sidekiq settings for the various repository check workers.
|
||||
module RepositoryCheckQueue
|
||||
extend ActiveSupport::Concern
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module WaitableWorker
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CreateGpgSignatureWorker
|
||||
include ApplicationWorker
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CreateNoteDiffFileWorker
|
||||
include ApplicationWorker
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CreatePipelineWorker
|
||||
include ApplicationWorker
|
||||
include PipelineQueue
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class DeleteMergedBranchesWorker
|
||||
include ApplicationWorker
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class DeleteUserWorker
|
||||
include ApplicationWorker
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class EmailReceiverWorker
|
||||
include ApplicationWorker
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class EmailsOnPushWorker
|
||||
include ApplicationWorker
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ExpireBuildArtifactsWorker
|
||||
include ApplicationWorker
|
||||
include CronjobQueue
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ExpireBuildInstanceArtifactsWorker
|
||||
include ApplicationWorker
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ExpireJobCacheWorker
|
||||
include ApplicationWorker
|
||||
include PipelineQueue
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ExpirePipelineCacheWorker
|
||||
include ApplicationWorker
|
||||
include PipelineQueue
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class GitGarbageCollectWorker
|
||||
include ApplicationWorker
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class GitlabShellWorker
|
||||
include ApplicationWorker
|
||||
include Gitlab::ShellAdapter
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class GitlabUsagePingWorker
|
||||
LEASE_TIMEOUT = 86400
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class GroupDestroyWorker
|
||||
include ApplicationWorker
|
||||
include ExceptionBacktrace
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ImportExportProjectCleanupWorker
|
||||
include ApplicationWorker
|
||||
include CronjobQueue
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class InvalidGpgSignatureUpdateWorker
|
||||
include ApplicationWorker
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'json'
|
||||
require 'socket'
|
||||
|
||||
|
@ -69,8 +71,8 @@ class IrkerWorker
|
|||
newbranch = "#{Gitlab.config.gitlab.url}/#{repo_path}/branches"
|
||||
newbranch = "\x0302\x1f#{newbranch}\x0f" if @colors
|
||||
|
||||
privmsg = "[#{repo_name}] #{committer} has created a new branch "
|
||||
privmsg += "#{branch}: #{newbranch}"
|
||||
privmsg = "[#{repo_name}] #{committer} has created a new branch " \
|
||||
"#{branch}: #{newbranch}"
|
||||
sendtoirker privmsg
|
||||
end
|
||||
|
||||
|
@ -112,9 +114,7 @@ class IrkerWorker
|
|||
url = compare_url data, project.full_path
|
||||
commits = colorize_commits data['total_commits_count']
|
||||
|
||||
new_commits = 'new commit'
|
||||
new_commits += 's' if data['total_commits_count'] > 1
|
||||
|
||||
new_commits = 'new commit'.pluralize(data['total_commits_count'])
|
||||
sendtoirker "[#{repo}] #{committer} pushed #{commits} #{new_commits} " \
|
||||
"to #{branch}: #{url}"
|
||||
end
|
||||
|
@ -122,8 +122,8 @@ class IrkerWorker
|
|||
def compare_url(data, repo_path)
|
||||
sha1 = Commit.truncate_sha(data['before'])
|
||||
sha2 = Commit.truncate_sha(data['after'])
|
||||
compare_url = "#{Gitlab.config.gitlab.url}/#{repo_path}/compare"
|
||||
compare_url += "/#{sha1}...#{sha2}"
|
||||
compare_url = "#{Gitlab.config.gitlab.url}/#{repo_path}/compare" \
|
||||
"/#{sha1}...#{sha2}"
|
||||
colorize_url compare_url
|
||||
end
|
||||
|
||||
|
@ -144,8 +144,7 @@ class IrkerWorker
|
|||
def files_count(commit)
|
||||
diff_size = commit.raw_deltas.size
|
||||
|
||||
files = "#{diff_size} file"
|
||||
files += 's' if diff_size > 1
|
||||
files = "#{diff_size} file".pluralize(diff_size)
|
||||
files
|
||||
end
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class IssueDueSchedulerWorker
|
||||
include ApplicationWorker
|
||||
include CronjobQueue
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module MailScheduler
|
||||
class IssueDueWorker
|
||||
include ApplicationWorker
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'active_job/arguments'
|
||||
|
||||
module MailScheduler
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class MergeWorker
|
||||
include ApplicationWorker
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Worker to destroy projects that do not have a namespace
|
||||
#
|
||||
# It destroys everything it can without having the info about the namespace it
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class NewIssueWorker
|
||||
include ApplicationWorker
|
||||
include NewIssuable
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class NewMergeRequestWorker
|
||||
include ApplicationWorker
|
||||
include NewIssuable
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class NewNoteWorker
|
||||
include ApplicationWorker
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ObjectStorage
|
||||
class BackgroundMoveWorker
|
||||
include ApplicationWorker
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# @Deprecated - remove once the `object_storage_upload` queue is empty
|
||||
# The queue has been renamed `object_storage:object_storage_background_upload`
|
||||
#
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class PagesDomainVerificationCronWorker
|
||||
include ApplicationWorker
|
||||
include CronjobQueue
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class PagesDomainVerificationWorker
|
||||
include ApplicationWorker
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class PagesWorker
|
||||
include ApplicationWorker
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class PipelineHooksWorker
|
||||
include ApplicationWorker
|
||||
include PipelineQueue
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class PipelineMetricsWorker
|
||||
include ApplicationWorker
|
||||
include PipelineQueue
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class PipelineNotificationWorker
|
||||
include ApplicationWorker
|
||||
include PipelineQueue
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class PipelineProcessWorker
|
||||
include ApplicationWorker
|
||||
include PipelineQueue
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class PipelineScheduleWorker
|
||||
include ApplicationWorker
|
||||
include CronjobQueue
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class PipelineSuccessWorker
|
||||
include ApplicationWorker
|
||||
include PipelineQueue
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class PipelineUpdateWorker
|
||||
include ApplicationWorker
|
||||
include PipelineQueue
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class PluginWorker
|
||||
include ApplicationWorker
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class PostReceive
|
||||
include ApplicationWorker
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Worker for processing individiual commit messages pushed to a repository.
|
||||
#
|
||||
# Jobs for this worker are scheduled for every commit that is being pushed. As a
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Worker for updating any project specific caches.
|
||||
class ProjectCacheWorker
|
||||
include ApplicationWorker
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ProjectDestroyWorker
|
||||
include ApplicationWorker
|
||||
include ExceptionBacktrace
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ProjectExportWorker
|
||||
include ApplicationWorker
|
||||
include ExceptionBacktrace
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ProjectMigrateHashedStorageWorker
|
||||
include ApplicationWorker
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ProjectServiceWorker
|
||||
include ApplicationWorker
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Worker for updating any project specific caches.
|
||||
class PropagateServiceTemplateWorker
|
||||
include ApplicationWorker
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class PruneOldEventsWorker
|
||||
include ApplicationWorker
|
||||
include CronjobQueue
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue