Skip to content
Snippets Groups Projects
Commit a706b373 authored by Douwe Maan's avatar Douwe Maan
Browse files

Merge branch 'master' into 'dm-document-role-maintainer'

# Conflicts:
#   doc/development/code_review.md
parents 90056ed2 68eafa50
No related branches found
No related tags found
1 merge request!10495Merge Requests - Assignee
Showing
with 143 additions and 136 deletions
Loading
Loading
@@ -14,13 +14,9 @@ import IssuableContext from '../../issuable_context';
import LabelsSelect from '../../labels_select';
import Subscriptions from '../../sidebar/components/subscriptions/subscriptions.vue';
import MilestoneSelect from '../../milestone_select';
import boardsStore from '../stores/boards_store';
 
const Store = gl.issueBoards.BoardsStore;
window.gl = window.gl || {};
window.gl.issueBoards = window.gl.issueBoards || {};
gl.issueBoards.BoardSidebar = Vue.extend({
export default Vue.extend({
components: {
AssigneeTitle,
Assignees,
Loading
Loading
@@ -35,7 +31,7 @@ gl.issueBoards.BoardSidebar = Vue.extend({
},
data() {
return {
detail: Store.detail,
detail: boardsStore.detail,
issue: {},
list: {},
loadingAssignees: false,
Loading
Loading
@@ -117,18 +113,18 @@ gl.issueBoards.BoardSidebar = Vue.extend({
this.saveAssignees();
},
removeAssignee (a) {
gl.issueBoards.BoardsStore.detail.issue.removeAssignee(a);
boardsStore.detail.issue.removeAssignee(a);
},
addAssignee (a) {
gl.issueBoards.BoardsStore.detail.issue.addAssignee(a);
boardsStore.detail.issue.addAssignee(a);
},
removeAllAssignees () {
gl.issueBoards.BoardsStore.detail.issue.removeAllAssignees();
boardsStore.detail.issue.removeAllAssignees();
},
saveAssignees () {
this.loadingAssignees = true;
 
gl.issueBoards.BoardsStore.detail.issue.update()
boardsStore.detail.issue.update()
.then(() => {
this.loadingAssignees = false;
})
Loading
Loading
<script>
import $ from 'jquery';
import Icon from '~/vue_shared/components/icon.vue';
import UserAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
import eventHub from '../eventhub';
import tooltip from '../../vue_shared/directives/tooltip';
const Store = gl.issueBoards.BoardsStore;
import boardsStore from '../stores/boards_store';
 
export default {
components: {
UserAvatarLink,
Icon,
},
directives: {
tooltip,
Loading
Loading
@@ -110,7 +111,7 @@
filterByLabel(label, e) {
if (!this.updateFilters) return;
 
const filterPath = gl.issueBoards.BoardsStore.filter.path.split('&');
const filterPath = boardsStore.filter.path.split('&');
const labelTitle = encodeURIComponent(label.title);
const param = `label_name[]=${labelTitle}`;
const labelIndex = filterPath.indexOf(param);
Loading
Loading
@@ -122,9 +123,9 @@
filterPath.splice(labelIndex, 1);
}
 
gl.issueBoards.BoardsStore.filter.path = filterPath.join('&');
boardsStore.filter.path = filterPath.join('&');
 
Store.updateFiltersUrl();
boardsStore.updateFiltersUrl();
 
eventHub.$emit('updateTokens');
},
Loading
Loading
@@ -141,11 +142,11 @@
<div>
<div class="board-card-header">
<h4 class="board-card-title">
<i
<icon
v-if="issue.confidential"
class="fa fa-eye-slash confidential-icon"
aria-hidden="true"
></i>
name="eye-slash"
class="confidential-icon"
/>
<a
:href="issue.path"
:title="issue.title"
Loading
Loading
Loading
Loading
@@ -5,6 +5,7 @@ import ListsDropdown from './lists_dropdown.vue';
import { pluralize } from '../../../lib/utils/text_utility';
import ModalStore from '../../stores/modal_store';
import modalMixin from '../../mixins/modal_mixins';
import boardsStore from '../../stores/boards_store';
 
export default {
components: {
Loading
Loading
@@ -14,7 +15,7 @@ export default {
data() {
return {
modal: ModalStore.store,
state: gl.issueBoards.BoardsStore.state,
state: boardsStore.state,
};
},
computed: {
Loading
Loading
<script>
import Icon from '~/vue_shared/components/icon.vue';
import bp from '../../../breakpoints';
import ModalStore from '../../stores/modal_store';
import IssueCardInner from '../issue_card_inner.vue';
Loading
Loading
@@ -6,6 +7,7 @@
export default {
components: {
IssueCardInner,
Icon,
},
props: {
issueLinkBase: {
Loading
Loading
@@ -147,13 +149,13 @@
:issue="issue"
:issue-link-base="issueLinkBase"
:root-path="rootPath"/>
<span
<icon
v-if="issue.selected"
:aria-label="'Issue #' + issue.id + ' selected'"
name="mobile-issue-close"
aria-checked="true"
class="issue-card-selected text-center">
<i class="fa fa-check"></i>
</span>
class="issue-card-selected text-center"
/>
</div>
</div>
</div>
Loading
Loading
<script>
import { Link } from '@gitlab-org/gitlab-ui';
import Icon from '~/vue_shared/components/icon.vue';
import ModalStore from '../../stores/modal_store';
import boardsStore from '../../stores/boards_store';
 
export default {
components: {
'gl-link': Link,
Icon,
},
data() {
return {
modal: ModalStore.store,
state: gl.issueBoards.BoardsStore.state,
state: boardsStore.state,
};
},
computed: {
Loading
Loading
@@ -34,7 +37,9 @@ export default {
class="dropdown-label-box">
</span>
{{ selected.title }}
<i class="fa fa-chevron-down"></i>
<icon
name="chevron-down"
/>
</button>
<div class="dropdown-menu dropdown-menu-selectable dropdown-menu-drop-up">
<ul>
Loading
Loading
Loading
Loading
@@ -4,16 +4,12 @@ import $ from 'jquery';
import axios from '~/lib/utils/axios_utils';
import _ from 'underscore';
import CreateLabelDropdown from '../../create_label';
window.gl = window.gl || {};
window.gl.issueBoards = window.gl.issueBoards || {};
const Store = gl.issueBoards.BoardsStore;
import boardsStore from '../stores/boards_store';
 
$(document).off('created.label').on('created.label', (e, label) => {
Store.new({
boardsStore.new({
title: label.title,
position: Store.state.lists.length - 2,
position: boardsStore.state.lists.length - 2,
list_type: 'label',
label: {
id: label.id,
Loading
Loading
@@ -23,7 +19,7 @@ $(document).off('created.label').on('created.label', (e, label) => {
});
});
 
gl.issueBoards.newListDropdownInit = () => {
export default function initNewListDropdown() {
$('.js-new-board-list').each(function () {
const $this = $(this);
new CreateLabelDropdown($this.closest('.dropdown').find('.dropdown-new-label'), $this.data('namespacePath'), $this.data('projectPath'));
Loading
Loading
@@ -36,7 +32,7 @@ gl.issueBoards.newListDropdownInit = () => {
});
},
renderRow (label) {
const active = Store.findList('title', label.title);
const active = boardsStore.findList('title', label.title);
const $li = $('<li />');
const $a = $('<a />', {
class: (active ? `is-active js-board-list-${active.id}` : ''),
Loading
Loading
@@ -62,10 +58,10 @@ gl.issueBoards.newListDropdownInit = () => {
const label = options.selectedObj;
e.preventDefault();
 
if (!Store.findList('title', label.title)) {
Store.new({
if (!boardsStore.findList('title', label.title)) {
boardsStore.new({
title: label.title,
position: Store.state.lists.length - 2,
position: boardsStore.state.lists.length - 2,
list_type: 'label',
label: {
id: label.id,
Loading
Loading
@@ -74,9 +70,9 @@ gl.issueBoards.newListDropdownInit = () => {
},
});
 
Store.state.lists = _.sortBy(Store.state.lists, 'position');
boardsStore.state.lists = _.sortBy(boardsStore.state.lists, 'position');
}
},
});
});
};
}
<script>
import $ from 'jquery';
import _ from 'underscore';
import Icon from '~/vue_shared/components/icon.vue';
import eventHub from '../eventhub';
import Api from '../../api';
 
export default {
name: 'BoardProjectSelect',
components: {
Icon,
},
props: {
groupId: {
type: Number,
Loading
Loading
@@ -78,11 +82,9 @@ export default {
aria-expanded="false"
>
{{ selectedProjectName }}
<i
class="fa fa-chevron-down"
aria-hidden="true"
>
</i>
<icon
name="chevron-down"
/>
</button>
<div class="dropdown-menu dropdown-menu-selectable dropdown-menu-full-width">
<div class="dropdown-title">
Loading
Loading
@@ -92,12 +94,11 @@ export default {
type="button"
class="dropdown-title-button dropdown-menu-close"
>
<i
aria-hidden="true"
<icon
name="merge-request-close-m"
data-hidden="true"
class="fa fa-times dropdown-menu-close-icon"
>
</i>
class="dropdown-menu-close-icon"
/>
</button>
</div>
<div class="dropdown-input">
Loading
Loading
@@ -106,12 +107,11 @@ export default {
type="search"
placeholder="Search projects"
/>
<i
aria-hidden="true"
<icon
name="search"
class="dropdown-input-search"
data-hidden="true"
class="fa fa-search dropdown-input-search"
>
</i>
/>
</div>
<div class="dropdown-content"></div>
<div class="dropdown-loading">
Loading
Loading
Loading
Loading
@@ -2,8 +2,7 @@
import Vue from 'vue';
import Flash from '../../../flash';
import { __ } from '../../../locale';
const Store = gl.issueBoards.BoardsStore;
import boardsStore from '../../stores/boards_store';
 
export default Vue.extend({
props: {
Loading
Loading
@@ -49,7 +48,7 @@
list.removeIssue(issue);
});
 
Store.detail.issue = {};
boardsStore.detail.issue = {};
},
/**
* Build the default patch request.
Loading
Loading
import FilteredSearchContainer from '../filtered_search/container';
import FilteredSearchManager from '../filtered_search/filtered_search_manager';
import boardsStore from './stores/boards_store';
 
export default class FilteredSearchBoards extends FilteredSearchManager {
constructor(store, updateUrl = false, cantEdit = []) {
Loading
Loading
@@ -23,7 +24,7 @@ export default class FilteredSearchBoards extends FilteredSearchManager {
this.store.path = path.substr(1);
 
if (this.updateUrl) {
gl.issueBoards.BoardsStore.updateFiltersUrl();
boardsStore.updateFiltersUrl();
}
}
 
Loading
Loading
Loading
Loading
@@ -14,24 +14,22 @@ import './models/issue';
import './models/list';
import './models/milestone';
import './models/project';
import './stores/boards_store';
import boardsStore from './stores/boards_store';
import ModalStore from './stores/modal_store';
import BoardService from './services/board_service';
import modalMixin from './mixins/modal_mixins';
import './mixins/sortable_default_options';
import './filters/due_date_filters';
import './components/board';
import './components/board_sidebar';
import './components/new_list_dropdown';
import Board from './components/board';
import BoardSidebar from './components/board_sidebar';
import initNewListDropdown from './components/new_list_dropdown';
import BoardAddIssuesModal from './components/modal/index.vue';
import '~/vue_shared/vue_resource_interceptor';
import { NavigationType } from '~/lib/utils/common_utils';
 
let issueBoardsApp;
export default () => {
const $boardApp = document.getElementById('board-app');
const Store = gl.issueBoards.BoardsStore;
window.gl = window.gl || {};
 
// check for browser back and trigger a hard reload to circumvent browser caching.
window.addEventListener('pageshow', (event) => {
Loading
Loading
@@ -43,25 +41,21 @@ export default () => {
}
});
 
if (gl.IssueBoardsApp) {
gl.IssueBoardsApp.$destroy(true);
if (issueBoardsApp) {
issueBoardsApp.$destroy(true);
}
 
Store.create();
// hack to allow sidebar scripts like milestone_select manipulate the BoardsStore
gl.issueBoards.boardStoreIssueSet = (...args) => Vue.set(Store.detail.issue, ...args);
gl.issueBoards.boardStoreIssueDelete = (...args) => Vue.delete(Store.detail.issue, ...args);
boardsStore.create();
 
gl.IssueBoardsApp = new Vue({
issueBoardsApp = new Vue({
el: $boardApp,
components: {
board: gl.issueBoards.Board,
'board-sidebar': gl.issueBoards.BoardSidebar,
Board,
BoardSidebar,
BoardAddIssuesModal,
},
data: {
state: Store.state,
state: boardsStore.state,
loading: true,
boardsEndpoint: $boardApp.dataset.boardsEndpoint,
listsEndpoint: $boardApp.dataset.listsEndpoint,
Loading
Loading
@@ -70,7 +64,7 @@ export default () => {
issueLinkBase: $boardApp.dataset.issueLinkBase,
rootPath: $boardApp.dataset.rootPath,
bulkUpdatePath: $boardApp.dataset.bulkUpdatePath,
detailIssue: Store.detail,
detailIssue: boardsStore.detail,
defaultAvatar: $boardApp.dataset.defaultAvatar,
},
computed: {
Loading
Loading
@@ -85,7 +79,7 @@ export default () => {
bulkUpdatePath: this.bulkUpdatePath,
boardId: this.boardId,
});
Store.rootPath = this.boardsEndpoint;
boardsStore.rootPath = this.boardsEndpoint;
 
eventHub.$on('updateTokens', this.updateTokens);
eventHub.$on('newDetailIssue', this.updateDetailIssue);
Loading
Loading
@@ -99,16 +93,16 @@ export default () => {
sidebarEventHub.$off('toggleSubscription', this.toggleSubscription);
},
mounted() {
this.filterManager = new FilteredSearchBoards(Store.filter, true, Store.cantEdit);
this.filterManager = new FilteredSearchBoards(boardsStore.filter, true, boardsStore.cantEdit);
this.filterManager.setup();
 
Store.disabled = this.disabled;
boardsStore.disabled = this.disabled;
gl.boardService
.all()
.then(res => res.data)
.then(data => {
data.forEach(board => {
const list = Store.addList(board, this.defaultAvatar);
const list = boardsStore.addList(board, this.defaultAvatar);
 
if (list.type === 'closed') {
list.position = Infinity;
Loading
Loading
@@ -119,7 +113,7 @@ export default () => {
 
this.state.lists = _.sortBy(this.state.lists, 'position');
 
Store.addBlankState();
boardsStore.addBlankState();
this.loading = false;
})
.catch(() => {
Loading
Loading
@@ -148,13 +142,13 @@ export default () => {
});
}
 
Store.detail.issue = newIssue;
boardsStore.detail.issue = newIssue;
},
clearDetailIssue() {
Store.detail.issue = {};
boardsStore.detail.issue = {};
},
toggleSubscription(id) {
const { issue } = Store.detail;
const { issue } = boardsStore.detail;
if (issue.id === id && issue.toggleSubscriptionEndpoint) {
issue.setFetchingState('subscriptions', true);
BoardService.toggleIssueSubscription(issue.toggleSubscriptionEndpoint)
Loading
Loading
@@ -173,26 +167,28 @@ export default () => {
},
});
 
gl.IssueBoardsSearch = new Vue({
// eslint-disable-next-line no-new
new Vue({
el: document.getElementById('js-add-list'),
data: {
filters: Store.state.filters,
filters: boardsStore.state.filters,
},
mounted() {
gl.issueBoards.newListDropdownInit();
initNewListDropdown();
},
});
 
const issueBoardsModal = document.getElementById('js-add-issues-btn');
 
if (issueBoardsModal) {
gl.IssueBoardsModalAddBtn = new Vue({
// eslint-disable-next-line no-new
new Vue({
el: issueBoardsModal,
mixins: [modalMixin],
data() {
return {
modal: ModalStore.store,
store: Store.state,
store: boardsStore.state,
canAdminList: this.$options.el.hasAttribute('data-can-admin-list'),
};
},
Loading
Loading
Loading
Loading
@@ -3,32 +3,29 @@
import $ from 'jquery';
import sortableConfig from '../../sortable/sortable_config';
 
window.gl = window.gl || {};
window.gl.issueBoards = window.gl.issueBoards || {};
gl.issueBoards.onStart = () => {
export function sortableStart() {
$('.has-tooltip').tooltip('hide')
.tooltip('disable');
document.body.classList.add('is-dragging');
};
}
 
gl.issueBoards.onEnd = () => {
export function sortableEnd() {
$('.has-tooltip').tooltip('enable');
document.body.classList.remove('is-dragging');
};
}
 
gl.issueBoards.touchEnabled = ('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch;
export function getBoardSortableDefaultOptions(obj) {
const touchEnabled = ('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch;
 
gl.issueBoards.getBoardSortableDefaultOptions = (obj) => {
const defaultSortOptions = Object.assign({}, sortableConfig, {
filter: '.board-delete, .btn',
delay: gl.issueBoards.touchEnabled ? 100 : 0,
scrollSensitivity: gl.issueBoards.touchEnabled ? 60 : 100,
delay: touchEnabled ? 100 : 0,
scrollSensitivity: touchEnabled ? 60 : 100,
scrollSpeed: 20,
onStart: gl.issueBoards.onStart,
onEnd: gl.issueBoards.onEnd,
onStart: sortableStart,
onEnd: sortableEnd,
});
 
Object.keys(obj).forEach((key) => { defaultSortOptions[key] = obj[key]; });
return defaultSortOptions;
};
}
Loading
Loading
@@ -6,6 +6,7 @@
import Vue from 'vue';
import '~/vue_shared/models/label';
import IssueProject from './project';
import boardsStore from '../stores/boards_store';
 
class ListIssue {
constructor (obj, defaultAvatar) {
Loading
Loading
@@ -86,7 +87,7 @@ class ListIssue {
}
 
getLists () {
return gl.issueBoards.BoardsStore.state.lists.filter(list => list.findIssue(this.id));
return boardsStore.state.lists.filter(list => list.findIssue(this.id));
}
 
updateData(newData) {
Loading
Loading
Loading
Loading
@@ -5,6 +5,7 @@ import { __ } from '~/locale';
import ListLabel from '~/vue_shared/models/label';
import ListAssignee from '~/vue_shared/models/assignee';
import { urlParamsToObject } from '~/lib/utils/common_utils';
import boardsStore from '../stores/boards_store';
 
const PER_PAGE = 20;
 
Loading
Loading
@@ -89,9 +90,9 @@ class List {
}
 
destroy() {
const index = gl.issueBoards.BoardsStore.state.lists.indexOf(this);
gl.issueBoards.BoardsStore.state.lists.splice(index, 1);
gl.issueBoards.BoardsStore.updateNewListDropdown(this.id);
const index = boardsStore.state.lists.indexOf(this);
boardsStore.state.lists.splice(index, 1);
boardsStore.updateNewListDropdown(this.id);
 
gl.boardService.destroyList(this.id).catch(() => {
// TODO: handle request error
Loading
Loading
@@ -116,7 +117,7 @@ class List {
 
getIssues(emptyIssues = true) {
const data = {
...urlParamsToObject(gl.issueBoards.BoardsStore.filter.path),
...urlParamsToObject(boardsStore.filter.path),
page: this.page,
};
 
Loading
Loading
Loading
Loading
@@ -3,13 +3,11 @@
 
import $ from 'jquery';
import _ from 'underscore';
import Vue from 'vue';
import Cookies from 'js-cookie';
import { getUrlParamsArray } from '~/lib/utils/common_utils';
 
window.gl = window.gl || {};
window.gl.issueBoards = window.gl.issueBoards || {};
gl.issueBoards.BoardsStore = {
const boardsStore = {
disabled: false,
filter: {
path: '',
Loading
Loading
@@ -167,3 +165,16 @@ gl.issueBoards.BoardsStore = {
window.history.pushState(null, null, `?${this.filter.path}`);
}
};
// hacks added in order to allow milestone_select to function properly
// TODO: remove these
export function boardStoreIssueSet(...args) {
Vue.set(boardsStore.detail.issue, ...args);
}
export function boardStoreIssueDelete(...args) {
Vue.delete(boardsStore.detail.issue, ...args);
}
export default boardsStore;
import Visibility from 'visibilityjs';
import Vue from 'vue';
import PersistentUserCallout from '../persistent_user_callout';
import initDismissableCallout from '~/dismissable_callout';
import { s__, sprintf } from '../locale';
import Flash from '../flash';
import Poll from '../lib/utils/poll';
Loading
Loading
@@ -62,7 +62,7 @@ export default class Clusters {
this.showTokenButton = document.querySelector('.js-show-cluster-token');
this.tokenField = document.querySelector('.js-cluster-token');
 
Clusters.initDismissableCallout();
initDismissableCallout('.js-cluster-security-warning');
initSettingsPanels();
setupToggleButtons(document.querySelector('.js-cluster-enable-toggle-area'));
this.initApplications();
Loading
Loading
@@ -105,12 +105,6 @@ export default class Clusters {
});
}
 
static initDismissableCallout() {
const callout = document.querySelector('.js-cluster-security-warning');
if (callout) new PersistentUserCallout(callout); // eslint-disable-line no-new
}
addListeners() {
if (this.showTokenButton) this.showTokenButton.addEventListener('click', this.showToken);
eventHub.$on('installApplication', this.installApplication);
Loading
Loading
import createFlash from '~/flash';
import { __ } from '~/locale';
import setupToggleButtons from '~/toggle_buttons';
import PersistentUserCallout from '../persistent_user_callout';
import initDismissableCallout from '~/dismissable_callout';
 
import ClustersService from './services/clusters_service';
 
export default () => {
const clusterList = document.querySelector('.js-clusters-list');
 
const callout = document.querySelector('.gcp-signup-offer');
if (callout) new PersistentUserCallout(callout); // eslint-disable-line no-new
initDismissableCallout('.gcp-signup-offer');
 
// The empty state won't have a clusterList
if (clusterList) {
Loading
Loading
<script>
import _ from 'underscore';
import helmInstallIllustration from '@gitlab-org/gitlab-svgs/illustrations/kubernetes-installation.svg';
import helmInstallIllustration from '@gitlab-org/gitlab-svgs/dist/illustrations/kubernetes-installation.svg';
import elasticsearchLogo from 'images/cluster_app_logos/elasticsearch.png';
import gitlabLogo from 'images/cluster_app_logos/gitlab.png';
import helmLogo from 'images/cluster_app_logos/helm.png';
Loading
Loading
<script>
import Icon from '~/vue_shared/components/icon.vue';
import iconCycleAnalyticsSplash from 'icons/_icon_cycle_analytics_splash.svg';
 
export default {
components: {
Icon,
},
props: {
documentationLink: {
type: String,
Loading
Loading
@@ -28,10 +32,9 @@
type="button"
@click="dismissOverviewDialog"
>
<i
class="fa fa-times"
aria-hidden="true">
</i>
<icon
name="close"
/>
</button>
<div
class="svg-container"
Loading
Loading
Loading
Loading
@@ -115,7 +115,7 @@ export default {
<span>
{{ selectedVersionName }}
</span>
<Icon
<icon
:size="12"
name="angle-down"
class="position-absolute"
Loading
Loading
Loading
Loading
@@ -20,6 +20,11 @@ export default {
Tooltip,
},
props: {
discussionPath: {
type: String,
required: false,
default: '',
},
diffFile: {
type: Object,
required: true,
Loading
Loading
@@ -65,8 +70,7 @@ export default {
if (this.diffFile.submodule) {
return this.diffFile.submoduleTreeUrl || this.diffFile.submoduleLink;
}
return `#${this.diffFile.fileHash}`;
return this.discussionPath;
},
filePath() {
if (this.diffFile.submodule) {
Loading
Loading
@@ -152,7 +156,7 @@ export default {
v-once
ref="titleWrapper"
:href="titleLink"
class="append-right-4"
class="append-right-4 js-title-wrapper"
>
<file-icon
:file-name="filePath"
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment