Skip to content
Snippets Groups Projects
Unverified Commit 160157a9 authored by Mike Greiling's avatar Mike Greiling
Browse files

Prettify remaining files with differences in CE and EE

parent ed816c3d
No related branches found
No related tags found
No related merge requests found
Showing
with 610 additions and 509 deletions
Loading
Loading
@@ -234,11 +234,11 @@ class List {
});
}
 
getTypeInfo (type) {
getTypeInfo(type) {
return TYPES[type] || {};
}
 
onNewIssueResponse (issue, data) {
onNewIssueResponse(issue, data) {
issue.id = data.id;
issue.iid = data.iid;
issue.project = data.project;
Loading
Loading
Loading
Loading
@@ -19,7 +19,9 @@ export default class BoardService {
}
 
static generateIssuePath(boardId, id) {
return `${gon.relative_url_root}/-/boards/${boardId ? `${boardId}` : ''}/issues${id ? `/${id}` : ''}`;
return `${gon.relative_url_root}/-/boards/${boardId ? `${boardId}` : ''}/issues${
id ? `/${id}` : ''
}`;
}
 
all() {
Loading
Loading
@@ -54,7 +56,9 @@ export default class BoardService {
 
getIssuesForList(id, filter = {}) {
const data = { id };
Object.keys(filter).forEach((key) => { data[key] = filter[key]; });
Object.keys(filter).forEach(key => {
data[key] = filter[key];
});
 
return axios.get(mergeUrlParams(data, this.generateIssuesPath(id)));
}
Loading
Loading
@@ -75,7 +79,9 @@ export default class BoardService {
}
 
getBacklog(data) {
return axios.get(mergeUrlParams(data, `${gon.relative_url_root}/-/boards/${this.boardId}/issues.json`));
return axios.get(
mergeUrlParams(data, `${gon.relative_url_root}/-/boards/${this.boardId}/issues.json`),
);
}
 
bulkUpdate(issueIds, extraData = {}) {
Loading
Loading
Loading
Loading
@@ -20,20 +20,20 @@ const boardsStore = {
issue: {},
list: {},
},
create () {
create() {
this.state.lists = [];
this.filter.path = getUrlParamsArray().join('&');
this.detail = {
issue: {},
};
},
addList (listObj, defaultAvatar) {
addList(listObj, defaultAvatar) {
const list = new List(listObj, defaultAvatar);
this.state.lists.push(list);
 
return list;
},
new (listObj) {
new(listObj) {
const list = this.addList(listObj);
const backlogList = this.findList('type', 'backlog', 'backlog');
 
Loading
Loading
@@ -50,44 +50,44 @@ const boardsStore = {
});
this.removeBlankState();
},
updateNewListDropdown (listId) {
updateNewListDropdown(listId) {
$(`.js-board-list-${listId}`).removeClass('is-active');
},
shouldAddBlankState () {
shouldAddBlankState() {
// Decide whether to add the blank state
return !(this.state.lists.filter(list => list.type !== 'backlog' && list.type !== 'closed')[0]);
return !this.state.lists.filter(list => list.type !== 'backlog' && list.type !== 'closed')[0];
},
addBlankState () {
addBlankState() {
if (!this.shouldAddBlankState() || this.welcomeIsHidden() || this.disabled) return;
 
this.addList({
id: 'blank',
list_type: 'blank',
title: 'Welcome to your Issue Board!',
position: 0
position: 0,
});
 
this.state.lists = _.sortBy(this.state.lists, 'position');
},
removeBlankState () {
removeBlankState() {
this.removeList('blank');
 
Cookies.set('issue_board_welcome_hidden', 'true', {
expires: 365 * 10,
path: ''
path: '',
});
},
welcomeIsHidden () {
welcomeIsHidden() {
return Cookies.get('issue_board_welcome_hidden') === 'true';
},
removeList (id, type = 'blank') {
removeList(id, type = 'blank') {
const list = this.findList('id', id, type);
 
if (!list) return;
 
this.state.lists = this.state.lists.filter(list => list.id !== id);
},
moveList (listFrom, orderLists) {
moveList(listFrom, orderLists) {
orderLists.forEach((id, i) => {
const list = this.findList('id', parseInt(id, 10));
 
Loading
Loading
@@ -95,22 +95,25 @@ const boardsStore = {
});
listFrom.update();
},
moveIssueToList (listFrom, listTo, issue, newIndex) {
moveIssueToList(listFrom, listTo, issue, newIndex) {
const issueTo = listTo.findIssue(issue.id);
const issueLists = issue.getLists();
const listLabels = issueLists.map(listIssue => listIssue.label);
 
if (!issueTo) {
// Check if target list assignee is already present in this issue
if ((listTo.type === 'assignee' && listFrom.type === 'assignee') &&
issue.findAssignee(listTo.assignee)) {
if (
listTo.type === 'assignee' &&
listFrom.type === 'assignee' &&
issue.findAssignee(listTo.assignee)
) {
const targetIssue = listTo.findIssue(issue.id);
targetIssue.removeAssignee(listFrom.assignee);
} else if (listTo.type === 'milestone') {
const currentMilestone = issue.milestone;
const currentLists = this.state.lists
.filter(list => (list.type === 'milestone' && list.id !== listTo.id))
.filter(list => list.issues.some(listIssue => issue.id === listIssue.id));
.filter(list => list.type === 'milestone' && list.id !== listTo.id)
.filter(list => list.issues.some(listIssue => issue.id === listIssue.id));
 
issue.removeMilestone(currentMilestone);
issue.addMilestone(listTo.milestone);
Loading
Loading
@@ -126,7 +129,7 @@ const boardsStore = {
}
 
if (listTo.type === 'closed' && listFrom.type !== 'backlog') {
issueLists.forEach((list) => {
issueLists.forEach(list => {
list.removeIssue(issue);
});
issue.removeLabels(listLabels);
Loading
Loading
@@ -144,26 +147,28 @@ const boardsStore = {
return (
(listTo.type !== 'label' && listFrom.type === 'assignee') ||
(listTo.type !== 'assignee' && listFrom.type === 'label') ||
(listFrom.type === 'backlog')
listFrom.type === 'backlog'
);
},
moveIssueInList (list, issue, oldIndex, newIndex, idArray) {
moveIssueInList(list, issue, oldIndex, newIndex, idArray) {
const beforeId = parseInt(idArray[newIndex - 1], 10) || null;
const afterId = parseInt(idArray[newIndex + 1], 10) || null;
 
list.moveIssue(issue, oldIndex, newIndex, beforeId, afterId);
},
findList (key, val, type = 'label') {
const filteredList = this.state.lists.filter((list) => {
const byType = type ? (list.type === type) || (list.type === 'assignee') || (list.type === 'milestone') : true;
findList(key, val, type = 'label') {
const filteredList = this.state.lists.filter(list => {
const byType = type
? list.type === type || list.type === 'assignee' || list.type === 'milestone'
: true;
 
return list[key] === val && byType;
});
return filteredList[0];
},
updateFiltersUrl () {
updateFiltersUrl() {
window.history.pushState(null, null, `?${this.filter.path}`);
}
},
};
 
// hacks added in order to allow milestone_select to function properly
Loading
Loading
Loading
Loading
@@ -40,7 +40,7 @@ class ModalStore {
toggleAll() {
const select = this.selectedCount() !== this.store.issues.length;
 
this.store.issues.forEach((issue) => {
this.store.issues.forEach(issue => {
const issueUpdate = issue;
 
if (issueUpdate.selected !== select) {
Loading
Loading
@@ -69,13 +69,14 @@ class ModalStore {
 
removeSelectedIssue(issue, forcePurge = false) {
if (this.store.activeTab === 'all' || forcePurge) {
this.store.selectedIssues = this.store.selectedIssues
.filter(fIssue => fIssue.id !== issue.id);
this.store.selectedIssues = this.store.selectedIssues.filter(
fIssue => fIssue.id !== issue.id,
);
}
}
 
purgeUnselectedIssues() {
this.store.selectedIssues.forEach((issue) => {
this.store.selectedIssues.forEach(issue => {
if (!issue.selected) {
this.removeSelectedIssue(issue, true);
}
Loading
Loading
@@ -87,8 +88,7 @@ class ModalStore {
}
 
findSelectedIssue(issue) {
return this.store.selectedIssues
.filter(filteredIssue => filteredIssue.id === issue.id)[0];
return this.store.selectedIssues.filter(filteredIssue => filteredIssue.id === issue.id)[0];
}
}
 
Loading
Loading
import Vue from 'vue';
import {
GlProgressBar,
GlLoadingIcon,
GlTooltipDirective,
} from '@gitlab-org/gitlab-ui';
import { GlProgressBar, GlLoadingIcon, GlTooltipDirective } from '@gitlab-org/gitlab-ui';
 
Vue.component('gl-progress-bar', GlProgressBar);
Vue.component('gl-loading-icon', GlLoadingIcon);
Loading
Loading
Loading
Loading
@@ -18,8 +18,8 @@ export default {
},
data() {
const treeListStored = localStorage.getItem(treeListStorageKey);
const renderTreeList = treeListStored !== null ?
convertPermissionToBoolean(treeListStored) : true;
const renderTreeList =
treeListStored !== null ? convertPermissionToBoolean(treeListStored) : true;
 
return {
search: '',
Loading
Loading
<script>
import Flash from '../../flash';
import { s__ } from '../../locale';
import emptyState from './empty_state.vue';
import eventHub from '../event_hub';
import environmentsMixin from '../mixins/environments_mixin';
import CIPaginationMixin from '../../vue_shared/mixins/ci_pagination_api_mixin';
import StopEnvironmentModal from './stop_environment_modal.vue';
import Flash from '../../flash';
import { s__ } from '../../locale';
import emptyState from './empty_state.vue';
import eventHub from '../event_hub';
import environmentsMixin from '../mixins/environments_mixin';
import CIPaginationMixin from '../../vue_shared/mixins/ci_pagination_api_mixin';
import StopEnvironmentModal from './stop_environment_modal.vue';
 
export default {
components: {
emptyState,
StopEnvironmentModal,
},
export default {
components: {
emptyState,
StopEnvironmentModal,
},
 
mixins: [
CIPaginationMixin,
environmentsMixin,
],
mixins: [CIPaginationMixin, environmentsMixin],
 
props: {
endpoint: {
type: String,
required: true,
},
canCreateEnvironment: {
type: Boolean,
required: true,
},
canCreateDeployment: {
type: Boolean,
required: true,
},
canReadEnvironment: {
type: Boolean,
required: true,
},
cssContainerClass: {
type: String,
required: true,
},
newEnvironmentPath: {
type: String,
required: true,
},
helpPagePath: {
type: String,
required: true,
},
props: {
endpoint: {
type: String,
required: true,
},
created() {
eventHub.$on('toggleFolder', this.toggleFolder);
canCreateEnvironment: {
type: Boolean,
required: true,
},
beforeDestroy() {
eventHub.$off('toggleFolder');
canCreateDeployment: {
type: Boolean,
required: true,
},
canReadEnvironment: {
type: Boolean,
required: true,
},
cssContainerClass: {
type: String,
required: true,
},
newEnvironmentPath: {
type: String,
required: true,
},
helpPagePath: {
type: String,
required: true,
},
},
created() {
eventHub.$on('toggleFolder', this.toggleFolder);
},
 
methods: {
toggleFolder(folder) {
this.store.toggleFolder(folder);
beforeDestroy() {
eventHub.$off('toggleFolder');
},
 
if (!folder.isOpen) {
this.fetchChildEnvironments(folder, true);
}
},
methods: {
toggleFolder(folder) {
this.store.toggleFolder(folder);
 
fetchChildEnvironments(folder, showLoader = false) {
this.store.updateEnvironmentProp(folder, 'isLoadingFolderContent', showLoader);
if (!folder.isOpen) {
this.fetchChildEnvironments(folder, true);
}
},
 
this.service.getFolderContent(folder.folder_path)
.then(response => this.store.setfolderContent(folder, response.data.environments))
.then(() => this.store.updateEnvironmentProp(folder, 'isLoadingFolderContent', false))
.catch(() => {
Flash(s__('Environments|An error occurred while fetching the environments.'));
this.store.updateEnvironmentProp(folder, 'isLoadingFolderContent', false);
});
},
fetchChildEnvironments(folder, showLoader = false) {
this.store.updateEnvironmentProp(folder, 'isLoadingFolderContent', showLoader);
this.service
.getFolderContent(folder.folder_path)
.then(response => this.store.setfolderContent(folder, response.data.environments))
.then(() => this.store.updateEnvironmentProp(folder, 'isLoadingFolderContent', false))
.catch(() => {
Flash(s__('Environments|An error occurred while fetching the environments.'));
this.store.updateEnvironmentProp(folder, 'isLoadingFolderContent', false);
});
},
 
successCallback(resp) {
this.saveData(resp);
successCallback(resp) {
this.saveData(resp);
 
// We need to verify if any folder is open to also update it
const openFolders = this.store.getOpenFolders();
if (openFolders.length) {
openFolders.forEach(folder => this.fetchChildEnvironments(folder));
}
},
// We need to verify if any folder is open to also update it
const openFolders = this.store.getOpenFolders();
if (openFolders.length) {
openFolders.forEach(folder => this.fetchChildEnvironments(folder));
}
},
};
},
};
</script>
<template>
<div :class="cssContainerClass">
Loading
Loading
Loading
Loading
@@ -34,14 +34,14 @@ export default class EnvironmentsStore {
* @returns {Array}
*/
storeEnvironments(environments = []) {
const filteredEnvironments = environments.map((env) => {
const oldEnvironmentState = this.state.environments
.find((element) => {
if (env.latest) {
return element.id === env.latest.id;
}
return element.id === env.id;
}) || {};
const filteredEnvironments = environments.map(env => {
const oldEnvironmentState =
this.state.environments.find(element => {
if (env.latest) {
return element.id === env.latest.id;
}
return element.id === env.id;
}) || {};
 
let filtered = {};
 
Loading
Loading
@@ -101,11 +101,11 @@ export default class EnvironmentsStore {
}
 
/**
* Toggles folder open property for the given folder.
*
* @param {Object} folder
* @return {Array}
*/
* Toggles folder open property for the given folder.
*
* @param {Object} folder
* @return {Array}
*/
toggleFolder(folder) {
return this.updateEnvironmentProp(folder, 'isOpen', !folder.isOpen);
}
Loading
Loading
@@ -119,7 +119,7 @@ export default class EnvironmentsStore {
* @return {Object}
*/
setfolderContent(folder, environments) {
const updatedEnvironments = environments.map((env) => {
const updatedEnvironments = environments.map(env => {
let updated = env;
 
if (env.latest) {
Loading
Loading
@@ -148,7 +148,7 @@ export default class EnvironmentsStore {
updateEnvironmentProp(environment, prop, newValue) {
const { environments } = this.state;
 
const updatedEnvironments = environments.map((env) => {
const updatedEnvironments = environments.map(env => {
const updateEnv = Object.assign({}, env);
if (env.id === environment.id) {
updateEnv[prop] = newValue;
Loading
Loading
Loading
Loading
@@ -39,8 +39,9 @@ export default class DropdownUser extends FilteredSearchDropdown {
}
 
itemClicked(e) {
super.itemClicked(e,
selected => selected.querySelector('.dropdown-light-content').innerText.trim());
super.itemClicked(e, selected =>
selected.querySelector('.dropdown-light-content').innerText.trim(),
);
}
 
renderContent(forceShowList = false) {
Loading
Loading
@@ -68,7 +69,7 @@ export default class DropdownUser extends FilteredSearchDropdown {
 
// Removes the first character if it is a quotation so that we can search
// with multiple words
if (value[0] === '"' || value[0] === '\'') {
if (value[0] === '"' || value[0] === "'") {
value = value.slice(1);
}
 
Loading
Loading
Loading
Loading
@@ -108,7 +108,7 @@ export default class FilteredSearchDropdownManager {
},
};
 
supportedTokens.forEach((type) => {
supportedTokens.forEach(type => {
if (availableMappings[type]) {
allowedMappings[type] = availableMappings[type];
}
Loading
Loading
@@ -142,10 +142,7 @@ export default class FilteredSearchDropdownManager {
}
 
static addWordToInput(tokenName, tokenValue = '', clicked = false, options = {}) {
const {
uppercaseTokenName = false,
capitalizeTokenValue = false,
} = options;
const { uppercaseTokenName = false, capitalizeTokenValue = false } = options;
const input = FilteredSearchContainer.container.querySelector('.filtered-search');
FilteredSearchVisualTokens.addFilterVisualToken(tokenName, tokenValue, {
uppercaseTokenName,
Loading
Loading
@@ -164,13 +161,16 @@ export default class FilteredSearchDropdownManager {
 
updateDropdownOffset(key) {
// Always align dropdown with the input field
let offset = this.filteredSearchInput.getBoundingClientRect().left - this.container.querySelector('.scroll-container').getBoundingClientRect().left;
let offset =
this.filteredSearchInput.getBoundingClientRect().left -
this.container.querySelector('.scroll-container').getBoundingClientRect().left;
 
const maxInputWidth = 240;
const currentDropdownWidth = this.mapping[key].element.clientWidth || maxInputWidth;
 
// Make sure offset never exceeds the input container
const offsetMaxWidth = this.container.querySelector('.scroll-container').clientWidth - currentDropdownWidth;
const offsetMaxWidth =
this.container.querySelector('.scroll-container').clientWidth - currentDropdownWidth;
if (offsetMaxWidth < offset) {
offset = offsetMaxWidth;
}
Loading
Loading
@@ -196,8 +196,7 @@ export default class FilteredSearchDropdownManager {
const glArguments = Object.assign({}, defaultArguments, extraArguments);
 
// Passing glArguments to `new glClass(<arguments>)`
mappingKey.reference =
new (Function.prototype.bind.apply(glClass, [null, glArguments]))();
mappingKey.reference = new (Function.prototype.bind.apply(glClass, [null, glArguments]))();
}
 
if (firstLoad) {
Loading
Loading
@@ -224,8 +223,8 @@ export default class FilteredSearchDropdownManager {
}
 
const match = this.filteredSearchTokenKeys.searchByKey(dropdownName.toLowerCase());
const shouldOpenFilterDropdown = match && this.currentDropdown !== match.key
&& this.mapping[match.key];
const shouldOpenFilterDropdown =
match && this.currentDropdown !== match.key && this.mapping[match.key];
const shouldOpenHintDropdown = !match && this.currentDropdown !== 'hint';
 
if (shouldOpenFilterDropdown || shouldOpenHintDropdown) {
Loading
Loading
@@ -236,8 +235,10 @@ export default class FilteredSearchDropdownManager {
 
setDropdown() {
const query = DropdownUtils.getSearchQuery(true);
const { lastToken, searchToken } =
this.tokenizer.processTokens(query, this.filteredSearchTokenKeys.getKeys());
const { lastToken, searchToken } = this.tokenizer.processTokens(
query,
this.filteredSearchTokenKeys.getKeys(),
);
 
if (this.currentDropdown) {
this.updateCurrentDropdownOffset();
Loading
Loading
import _ from 'underscore';
import {
getParameterByName,
getUrlParamsArray,
} from '~/lib/utils/common_utils';
import { getParameterByName, getUrlParamsArray } from '~/lib/utils/common_utils';
import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys';
import { visitUrl } from '../lib/utils/url_utility';
import Flash from '../flash';
Loading
Loading
@@ -48,24 +45,28 @@ export default class FilteredSearchManager {
isLocalStorageAvailable: RecentSearchesService.isAvailable(),
allowedKeys: this.filteredSearchTokenKeys.getKeys(),
});
this.searchHistoryDropdownElement = document.querySelector('.js-filtered-search-history-dropdown');
const fullPath = this.searchHistoryDropdownElement ?
this.searchHistoryDropdownElement.dataset.fullPath : 'project';
this.searchHistoryDropdownElement = document.querySelector(
'.js-filtered-search-history-dropdown',
);
const fullPath = this.searchHistoryDropdownElement
? this.searchHistoryDropdownElement.dataset.fullPath
: 'project';
const recentSearchesKey = `${fullPath}-${this.recentsStorageKeyNames[this.page]}`;
this.recentSearchesService = new RecentSearchesService(recentSearchesKey);
}
 
setup() {
// Fetch recent searches from localStorage
this.fetchingRecentSearchesPromise = this.recentSearchesService.fetch()
.catch((error) => {
this.fetchingRecentSearchesPromise = this.recentSearchesService
.fetch()
.catch(error => {
if (error.name === 'RecentSearchesServiceError') return undefined;
// eslint-disable-next-line no-new
new Flash('An error occurred while parsing recent searches');
// Gracefully fail to empty array
return [];
})
.then((searches) => {
.then(searches => {
if (!searches) {
return;
}
Loading
Loading
@@ -120,7 +121,7 @@ export default class FilteredSearchManager {
if (this.stateFilters) {
this.searchStateWrapper = this.searchState.bind(this);
 
this.applyToStateFilters((filterEl) => {
this.applyToStateFilters(filterEl => {
filterEl.addEventListener('click', this.searchStateWrapper);
});
}
Loading
Loading
@@ -128,14 +129,14 @@ export default class FilteredSearchManager {
 
unbindStateEvents() {
if (this.stateFilters) {
this.applyToStateFilters((filterEl) => {
this.applyToStateFilters(filterEl => {
filterEl.removeEventListener('click', this.searchStateWrapper);
});
}
}
 
applyToStateFilters(callback) {
this.stateFilters.querySelectorAll('a[data-state]').forEach((filterEl) => {
this.stateFilters.querySelectorAll('a[data-state]').forEach(filterEl => {
if (this.states.indexOf(filterEl.dataset.state) > -1) {
callback(filterEl);
}
Loading
Loading
@@ -207,7 +208,7 @@ export default class FilteredSearchManager {
let backspaceCount = 0;
 
// closure for keeping track of the number of backspace keystrokes
return (e) => {
return e => {
// 8 = Backspace Key
// 46 = Delete Key
if (e.keyCode === 8 || e.keyCode === 46) {
Loading
Loading
@@ -274,8 +275,12 @@ export default class FilteredSearchManager {
const isElementInDynamicFilterDropdown = e.target.closest('.filter-dropdown') !== null;
const isElementInStaticFilterDropdown = e.target.closest('ul[data-dropdown]') !== null;
 
if (!isElementInFilteredSearch && !isElementInDynamicFilterDropdown &&
!isElementInStaticFilterDropdown && inputContainer) {
if (
!isElementInFilteredSearch &&
!isElementInDynamicFilterDropdown &&
!isElementInStaticFilterDropdown &&
inputContainer
) {
inputContainer.classList.remove('focus');
}
}
Loading
Loading
@@ -368,7 +373,7 @@ export default class FilteredSearchManager {
 
const removeElements = [];
 
[].forEach.call(this.tokensContainer.children, (t) => {
[].forEach.call(this.tokensContainer.children, t => {
let canClearToken = t.classList.contains('js-visual-token');
 
if (canClearToken) {
Loading
Loading
@@ -381,7 +386,7 @@ export default class FilteredSearchManager {
}
});
 
removeElements.forEach((el) => {
removeElements.forEach(el => {
el.parentElement.removeChild(el);
});
 
Loading
Loading
@@ -397,13 +402,14 @@ export default class FilteredSearchManager {
 
handleInputVisualToken() {
const input = this.filteredSearchInput;
const { tokens, searchToken }
= this.tokenizer.processTokens(input.value, this.filteredSearchTokenKeys.getKeys());
const { isLastVisualTokenValid }
= FilteredSearchVisualTokens.getLastVisualTokenBeforeInput();
const { tokens, searchToken } = this.tokenizer.processTokens(
input.value,
this.filteredSearchTokenKeys.getKeys(),
);
const { isLastVisualTokenValid } = FilteredSearchVisualTokens.getLastVisualTokenBeforeInput();
 
if (isLastVisualTokenValid) {
tokens.forEach((t) => {
tokens.forEach(t => {
input.value = input.value.replace(`${t.key}:${t.symbol}${t.value}`, '');
FilteredSearchVisualTokens.addFilterVisualToken(t.key, `${t.symbol}${t.value}`, {
uppercaseTokenName: this.filteredSearchTokenKeys.shouldUppercaseTokenName(t.key),
Loading
Loading
@@ -453,15 +459,17 @@ export default class FilteredSearchManager {
 
saveCurrentSearchQuery() {
// Don't save before we have fetched the already saved searches
this.fetchingRecentSearchesPromise.then(() => {
const searchQuery = DropdownUtils.getSearchQuery();
if (searchQuery.length > 0) {
const resultantSearches = this.recentSearchesStore.addRecentSearch(searchQuery);
this.recentSearchesService.save(resultantSearches);
}
}).catch(() => {
// https://gitlab.com/gitlab-org/gitlab-ce/issues/30821
});
this.fetchingRecentSearchesPromise
.then(() => {
const searchQuery = DropdownUtils.getSearchQuery();
if (searchQuery.length > 0) {
const resultantSearches = this.recentSearchesStore.addRecentSearch(searchQuery);
this.recentSearchesService.save(resultantSearches);
}
})
.catch(() => {
// https://gitlab.com/gitlab-org/gitlab-ce/issues/30821
});
}
 
// allows for modifying params array when a param can't be included in the URL (e.g. Service Desk)
Loading
Loading
@@ -475,7 +483,7 @@ export default class FilteredSearchManager {
const usernameParams = this.getUsernameParams();
let hasFilteredSearch = false;
 
params.forEach((p) => {
params.forEach(p => {
const split = p.split('=');
const keyParam = decodeURIComponent(split[0]);
const value = split[1];
Loading
Loading
@@ -486,11 +494,9 @@ export default class FilteredSearchManager {
if (condition) {
hasFilteredSearch = true;
const canEdit = this.canEdit && this.canEdit(condition.tokenKey);
FilteredSearchVisualTokens.addFilterVisualToken(
condition.tokenKey,
condition.value,
{ canEdit },
);
FilteredSearchVisualTokens.addFilterVisualToken(condition.tokenKey, condition.value, {
canEdit,
});
} else {
// Sanitize value since URL converts spaces into +
// Replace before decode so that we know what was originally + versus the encoded +
Loading
Loading
@@ -510,7 +516,7 @@ export default class FilteredSearchManager {
 
if (sanitizedValue.indexOf(' ') !== -1) {
// Prefer ", but use ' if required
quotationsToUse = sanitizedValue.indexOf('"') === -1 ? '"' : '\'';
quotationsToUse = sanitizedValue.indexOf('"') === -1 ? '"' : "'";
}
 
hasFilteredSearch = true;
Loading
Loading
@@ -531,7 +537,9 @@ export default class FilteredSearchManager {
hasFilteredSearch = true;
const tokenName = 'assignee';
const canEdit = this.canEdit && this.canEdit(tokenName);
FilteredSearchVisualTokens.addFilterVisualToken(tokenName, `@${usernameParams[id]}`, { canEdit });
FilteredSearchVisualTokens.addFilterVisualToken(tokenName, `@${usernameParams[id]}`, {
canEdit,
});
}
} else if (!match && keyParam === 'author_id') {
const id = parseInt(value, 10);
Loading
Loading
@@ -539,7 +547,9 @@ export default class FilteredSearchManager {
hasFilteredSearch = true;
const tokenName = 'author';
const canEdit = this.canEdit && this.canEdit(tokenName);
FilteredSearchVisualTokens.addFilterVisualToken(tokenName, `@${usernameParams[id]}`, { canEdit });
FilteredSearchVisualTokens.addFilterVisualToken(tokenName, `@${usernameParams[id]}`, {
canEdit,
});
}
} else if (!match && keyParam === 'search') {
hasFilteredSearch = true;
Loading
Loading
@@ -580,9 +590,11 @@ export default class FilteredSearchManager {
const currentState = state || getParameterByName('state') || 'opened';
paths.push(`state=${currentState}`);
 
tokens.forEach((token) => {
const condition = this.filteredSearchTokenKeys
.searchByConditionKeyValue(token.key, token.value.toLowerCase());
tokens.forEach(token => {
const condition = this.filteredSearchTokenKeys.searchByConditionKeyValue(
token.key,
token.value.toLowerCase(),
);
const tokenConfig = this.filteredSearchTokenKeys.searchByKey(token.key) || {};
const { param } = tokenConfig;
 
Loading
Loading
@@ -601,8 +613,10 @@ export default class FilteredSearchManager {
tokenValue = tokenValue.toLowerCase();
}
 
if ((tokenValue[0] === '\'' && tokenValue[tokenValue.length - 1] === '\'') ||
(tokenValue[0] === '"' && tokenValue[tokenValue.length - 1] === '"')) {
if (
(tokenValue[0] === "'" && tokenValue[tokenValue.length - 1] === "'") ||
(tokenValue[0] === '"' && tokenValue[tokenValue.length - 1] === '"')
) {
tokenValue = tokenValue.slice(1, tokenValue.length - 1);
}
 
Loading
Loading
@@ -613,7 +627,10 @@ export default class FilteredSearchManager {
});
 
if (searchToken) {
const sanitized = searchToken.split(' ').map(t => encodeURIComponent(t)).join('+');
const sanitized = searchToken
.split(' ')
.map(t => encodeURIComponent(t))
.join('+');
paths.push(`search=${sanitized}`);
}
 
Loading
Loading
@@ -630,7 +647,7 @@ export default class FilteredSearchManager {
const usernamesById = {};
try {
const attribute = this.filteredSearchInput.getAttribute('data-username-params');
JSON.parse(attribute).forEach((user) => {
JSON.parse(attribute).forEach(user => {
usernamesById[user.id] = user.username;
});
} catch (e) {
Loading
Loading
Loading
Loading
@@ -40,7 +40,9 @@ const createFlashEl = (message, type, isFixedLayout = false) => `
class="flash-${type}"
>
<div
class="flash-text ${isFixedLayout ? 'container-fluid container-limited limit-container-width' : ''}"
class="flash-text ${
isFixedLayout ? 'container-fluid container-limited limit-container-width' : ''
}"
>
${_.escape(message)}
</div>
Loading
Loading
@@ -78,7 +80,9 @@ const createFlash = function createFlash(
 
if (!flashContainer) return null;
 
const isFixedLayout = navigation ? navigation.parentNode.classList.contains('container-limited') : true;
const isFixedLayout = navigation
? navigation.parentNode.classList.contains('container-limited')
: true;
 
flashContainer.innerHTML = createFlashEl(message, type, isFixedLayout);
 
Loading
Loading
Loading
Loading
@@ -94,7 +94,7 @@ class GfmAutoComplete {
...this.getDefaultCallbacks(),
beforeSave(commands) {
if (GfmAutoComplete.isLoading(commands)) return commands;
return $.map(commands, (c) => {
return $.map(commands, c => {
let search = c.name;
if (c.aliases.length > 0) {
search = `${search} ${c.aliases.join(' ')}`;
Loading
Loading
@@ -167,7 +167,7 @@ class GfmAutoComplete {
callbacks: {
...this.getDefaultCallbacks(),
beforeSave(members) {
return $.map(members, (m) => {
return $.map(members, m => {
let title = '';
if (m.username == null) {
return m;
Loading
Loading
@@ -178,7 +178,9 @@ class GfmAutoComplete {
}
 
const autoCompleteAvatar = m.avatar_url || m.username.charAt(0).toUpperCase();
const imgAvatar = `<img src="${m.avatar_url}" alt="${m.username}" class="avatar avatar-inline center s26"/>`;
const imgAvatar = `<img src="${m.avatar_url}" alt="${
m.username
}" class="avatar avatar-inline center s26"/>`;
const txtAvatar = `<div class="avatar center avatar-inline s26">${autoCompleteAvatar}</div>`;
 
return {
Loading
Loading
@@ -211,7 +213,7 @@ class GfmAutoComplete {
callbacks: {
...this.getDefaultCallbacks(),
beforeSave(issues) {
return $.map(issues, (i) => {
return $.map(issues, i => {
if (i.title == null) {
return i;
}
Loading
Loading
@@ -244,7 +246,7 @@ class GfmAutoComplete {
callbacks: {
...this.getDefaultCallbacks(),
beforeSave(milestones) {
return $.map(milestones, (m) => {
return $.map(milestones, m => {
if (m.title == null) {
return m;
}
Loading
Loading
@@ -277,7 +279,7 @@ class GfmAutoComplete {
callbacks: {
...this.getDefaultCallbacks(),
beforeSave(merges) {
return $.map(merges, (m) => {
return $.map(merges, m => {
if (m.title == null) {
return m;
}
Loading
Loading
@@ -324,13 +326,20 @@ class GfmAutoComplete {
},
matcher(flag, subtext) {
const match = GfmAutoComplete.defaultMatcher(flag, subtext, this.app.controllers);
const subtextNodes = subtext.split(/\n+/g).pop().split(GfmAutoComplete.regexSubtext);
const subtextNodes = subtext
.split(/\n+/g)
.pop()
.split(GfmAutoComplete.regexSubtext);
 
// Check if ~ is followed by '/label', '/relabel' or '/unlabel' commands.
command = subtextNodes.find((node) => {
if (node === LABEL_COMMAND.LABEL ||
node === LABEL_COMMAND.RELABEL ||
node === LABEL_COMMAND.UNLABEL) { return node; }
command = subtextNodes.find(node => {
if (
node === LABEL_COMMAND.LABEL ||
node === LABEL_COMMAND.RELABEL ||
node === LABEL_COMMAND.UNLABEL
) {
return node;
}
return null;
});
 
Loading
Loading
@@ -380,7 +389,7 @@ class GfmAutoComplete {
callbacks: {
...this.getDefaultCallbacks(),
beforeSave(snippets) {
return $.map(snippets, (m) => {
return $.map(snippets, m => {
if (m.title == null) {
return m;
}
Loading
Loading
@@ -458,13 +467,17 @@ class GfmAutoComplete {
this.loadData($input, at, validEmojiNames);
GfmAutoComplete.glEmojiTag = glEmojiTag;
})
.catch(() => { this.isLoadingData[at] = false; });
.catch(() => {
this.isLoadingData[at] = false;
});
} else if (dataSource) {
AjaxCache.retrieve(dataSource, true)
.then((data) => {
.then(data => {
this.loadData($input, at, data);
})
.catch(() => { this.isLoadingData[at] = false; });
.catch(() => {
this.isLoadingData[at] = false;
});
} else {
this.isLoadingData[at] = false;
}
Loading
Loading
@@ -497,15 +510,16 @@ class GfmAutoComplete {
}
 
const loadingState = GfmAutoComplete.defaultLoadingData[0];
return dataToInspect &&
(dataToInspect === loadingState || dataToInspect.name === loadingState);
return dataToInspect && (dataToInspect === loadingState || dataToInspect.name === loadingState);
}
 
static defaultMatcher(flag, subtext, controllers) {
// The below is taken from At.js source
// Tweaked to commands to start without a space only if char before is a non-word character
// https://github.com/ichord/At.js
const atSymbolsWithBar = Object.keys(controllers).join('|').replace(/[$]/, '\\$&');
const atSymbolsWithBar = Object.keys(controllers)
.join('|')
.replace(/[$]/, '\\$&');
const atSymbolsWithoutBar = Object.keys(controllers).join('');
const targetSubtext = subtext.split(GfmAutoComplete.regexSubtext).pop();
const resultantFlag = flag.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&');
Loading
Loading
@@ -513,7 +527,10 @@ class GfmAutoComplete {
const accentAChar = decodeURI('%C3%80');
const accentYChar = decodeURI('%C3%BF');
 
const regexp = new RegExp(`^(?:\\B|[^a-zA-Z0-9_\`${atSymbolsWithoutBar}]|\\s)${resultantFlag}(?!${atSymbolsWithBar})((?:[A-Za-z${accentAChar}-${accentYChar}0-9_'.+-]|[^\\x00-\\x7a])*)$`, 'gi');
const regexp = new RegExp(
`^(?:\\B|[^a-zA-Z0-9_\`${atSymbolsWithoutBar}]|\\s)${resultantFlag}(?!${atSymbolsWithBar})((?:[A-Za-z${accentAChar}-${accentYChar}0-9_'.+-]|[^\\x00-\\x7a])*)$`,
'gi',
);
 
return regexp.exec(targetSubtext);
}
Loading
Loading
@@ -553,7 +570,8 @@ GfmAutoComplete.Members = {
};
GfmAutoComplete.Labels = {
// eslint-disable-next-line no-template-curly-in-string
template: '<li><span class="dropdown-label-box" style="background: ${color}"></span> ${title}</li>',
template:
'<li><span class="dropdown-label-box" style="background: ${color}"></span> ${title}</li>',
};
// Issues, MergeRequests and Snippets
GfmAutoComplete.Issues = {
Loading
Loading
@@ -567,7 +585,8 @@ GfmAutoComplete.Milestones = {
template: '<li>${title}</li>',
};
GfmAutoComplete.Loading = {
template: '<li style="pointer-events: none;"><i class="fa fa-spinner fa-spin"></i> Loading...</li>',
template:
'<li style="pointer-events: none;"><i class="fa fa-spinner fa-spin"></i> Loading...</li>',
};
 
export default GfmAutoComplete;
<script>
import _ from 'underscore';
import { mapGetters, mapState, mapActions } from 'vuex';
import { isScrolledToBottom } from '~/lib/utils/scroll_utils';
import bp from '~/breakpoints';
import CiHeader from '~/vue_shared/components/header_ci_component.vue';
import Callout from '~/vue_shared/components/callout.vue';
import createStore from '../store';
import EmptyState from './empty_state.vue';
import EnvironmentsBlock from './environments_block.vue';
import ErasedBlock from './erased_block.vue';
import Log from './job_log.vue';
import LogTopBar from './job_log_controllers.vue';
import StuckBlock from './stuck_block.vue';
import Sidebar from './sidebar.vue';
import _ from 'underscore';
import { mapGetters, mapState, mapActions } from 'vuex';
import { isScrolledToBottom } from '~/lib/utils/scroll_utils';
import bp from '~/breakpoints';
import CiHeader from '~/vue_shared/components/header_ci_component.vue';
import Callout from '~/vue_shared/components/callout.vue';
import createStore from '../store';
import EmptyState from './empty_state.vue';
import EnvironmentsBlock from './environments_block.vue';
import ErasedBlock from './erased_block.vue';
import Log from './job_log.vue';
import LogTopBar from './job_log_controllers.vue';
import StuckBlock from './stuck_block.vue';
import Sidebar from './sidebar.vue';
 
export default {
name: 'JobPageApp',
store: createStore(),
components: {
CiHeader,
Callout,
EmptyState,
EnvironmentsBlock,
ErasedBlock,
Log,
LogTopBar,
StuckBlock,
Sidebar,
export default {
name: 'JobPageApp',
store: createStore(),
components: {
CiHeader,
Callout,
EmptyState,
EnvironmentsBlock,
ErasedBlock,
Log,
LogTopBar,
StuckBlock,
Sidebar,
},
props: {
runnerSettingsUrl: {
type: String,
required: false,
default: null,
},
props: {
runnerSettingsUrl: {
type: String,
required: false,
default: null,
},
runnerHelpUrl: {
type: String,
required: false,
default: null,
},
endpoint: {
type: String,
required: true,
},
terminalPath: {
type: String,
required: false,
default: null,
},
pagePath: {
type: String,
required: true,
},
logState: {
type: String,
required: true,
},
runnerHelpUrl: {
type: String,
required: false,
default: null,
},
computed: {
...mapState([
'isLoading',
'job',
'isSidebarOpen',
'trace',
'isTraceComplete',
'traceSize',
'isTraceSizeVisible',
'isScrollBottomDisabled',
'isScrollTopDisabled',
'isScrolledToBottomBeforeReceivingTrace',
'hasError',
]),
...mapGetters([
'headerActions',
'headerTime',
'shouldRenderCalloutMessage',
'shouldRenderTriggeredLabel',
'hasEnvironment',
'hasTrace',
'emptyStateIllustration',
'isScrollingDown',
'emptyStateAction',
'hasRunnersForProject',
]),
endpoint: {
type: String,
required: true,
},
terminalPath: {
type: String,
required: false,
default: null,
},
pagePath: {
type: String,
required: true,
},
logState: {
type: String,
required: true,
},
},
computed: {
...mapState([
'isLoading',
'job',
'isSidebarOpen',
'trace',
'isTraceComplete',
'traceSize',
'isTraceSizeVisible',
'isScrollBottomDisabled',
'isScrollTopDisabled',
'isScrolledToBottomBeforeReceivingTrace',
'hasError',
]),
...mapGetters([
'headerActions',
'headerTime',
'shouldRenderCalloutMessage',
'shouldRenderTriggeredLabel',
'hasEnvironment',
'hasTrace',
'emptyStateIllustration',
'isScrollingDown',
'emptyStateAction',
'hasRunnersForProject',
]),
 
shouldRenderContent() {
return !this.isLoading && !this.hasError;
}
shouldRenderContent() {
return !this.isLoading && !this.hasError;
},
watch: {
// Once the job log is loaded,
// fetch the stages for the dropdown on the sidebar
job(newVal, oldVal) {
if (_.isEmpty(oldVal) && !_.isEmpty(newVal.pipeline)) {
this.fetchStages();
}
},
},
watch: {
// Once the job log is loaded,
// fetch the stages for the dropdown on the sidebar
job(newVal, oldVal) {
if (_.isEmpty(oldVal) && !_.isEmpty(newVal.pipeline)) {
this.fetchStages();
}
},
created() {
this.throttled = _.throttle(this.toggleScrollButtons, 100);
},
created() {
this.throttled = _.throttle(this.toggleScrollButtons, 100);
 
this.setJobEndpoint(this.endpoint);
this.setTraceOptions({
logState: this.logState,
pagePath: this.pagePath,
});
this.setJobEndpoint(this.endpoint);
this.setTraceOptions({
logState: this.logState,
pagePath: this.pagePath,
});
 
this.fetchJob();
this.fetchTrace();
this.fetchJob();
this.fetchTrace();
 
window.addEventListener('resize', this.onResize);
window.addEventListener('scroll', this.updateScroll);
},
window.addEventListener('resize', this.onResize);
window.addEventListener('scroll', this.updateScroll);
},
 
mounted() {
mounted() {
this.updateSidebar();
},
destroyed() {
window.removeEventListener('resize', this.onResize);
window.removeEventListener('scroll', this.updateScroll);
},
methods: {
...mapActions([
'setJobEndpoint',
'setTraceOptions',
'fetchJob',
'fetchStages',
'hideSidebar',
'showSidebar',
'toggleSidebar',
'fetchTrace',
'scrollBottom',
'scrollTop',
'toggleScrollButtons',
'toggleScrollAnimation',
]),
onResize() {
this.updateSidebar();
this.updateScroll();
},
destroyed() {
window.removeEventListener('resize', this.onResize);
window.removeEventListener('scroll', this.updateScroll);
updateSidebar() {
if (bp.getBreakpointSize() === 'xs') {
this.hideSidebar();
} else if (!this.isSidebarOpen) {
this.showSidebar();
}
},
updateScroll() {
if (!isScrolledToBottom()) {
this.toggleScrollAnimation(false);
} else if (this.isScrollingDown) {
this.toggleScrollAnimation(true);
}
 
methods: {
...mapActions([
'setJobEndpoint',
'setTraceOptions',
'fetchJob',
'fetchStages',
'hideSidebar',
'showSidebar',
'toggleSidebar',
'fetchTrace',
'scrollBottom',
'scrollTop',
'toggleScrollButtons',
'toggleScrollAnimation',
]),
onResize() {
this.updateSidebar();
this.updateScroll();
},
updateSidebar() {
if (bp.getBreakpointSize() === 'xs') {
this.hideSidebar();
} else if (!this.isSidebarOpen) {
this.showSidebar();
}
},
updateScroll() {
if (!isScrolledToBottom()) {
this.toggleScrollAnimation(false);
} else if (this.isScrollingDown) {
this.toggleScrollAnimation(true);
}
this.throttled();
},
this.throttled();
},
};
},
};
</script>
<template>
<div>
Loading
Loading
<script>
import { mapState, mapActions } from 'vuex';
import { mapState, mapActions } from 'vuex';
 
export default {
name: 'JobLog',
props: {
trace: {
type: String,
required: true,
},
isComplete: {
type: Boolean,
required: true,
},
export default {
name: 'JobLog',
props: {
trace: {
type: String,
required: true,
},
computed: {
...mapState(['isScrolledToBottomBeforeReceivingTrace']),
isComplete: {
type: Boolean,
required: true,
},
updated() {
this.$nextTick(() => this.handleScrollDown());
},
computed: {
...mapState(['isScrolledToBottomBeforeReceivingTrace']),
},
updated() {
this.$nextTick(() => this.handleScrollDown());
},
mounted() {
this.$nextTick(() => this.handleScrollDown());
},
methods: {
...mapActions(['scrollBottom']),
/**
* The job log is sent in HTML, which means we need to use `v-html` to render it
* Using the updated hook with $nextTick is not enough to wait for the DOM to be updated
* in this case because it runs before `v-html` has finished running, since there's no
* Vue binding.
* In order to scroll the page down after `v-html` has finished, we need to use setTimeout
*/
handleScrollDown() {
if (this.isScrolledToBottomBeforeReceivingTrace) {
setTimeout(() => {
this.scrollBottom();
}, 0);
}
},
mounted() {
this.$nextTick(() => this.handleScrollDown());
},
methods: {
...mapActions(['scrollBottom']),
/**
* The job log is sent in HTML, which means we need to use `v-html` to render it
* Using the updated hook with $nextTick is not enough to wait for the DOM to be updated
* in this case because it runs before `v-html` has finished running, since there's no
* Vue binding.
* In order to scroll the page down after `v-html` has finished, we need to use setTimeout
*/
handleScrollDown() {
if (this.isScrolledToBottomBeforeReceivingTrace) {
setTimeout(() => {
this.scrollBottom();
}, 0);
}
},
},
};
},
};
</script>
<template>
<pre class="js-build-trace build-trace qa-build-trace">
Loading
Loading
Loading
Loading
@@ -23,4 +23,3 @@ export default () => {
},
});
};
Loading
Loading
@@ -35,16 +35,19 @@ export const hasEnvironment = state => !_.isEmpty(state.job.deployment_status);
* Used to check if it should render the job log or the empty state
* @returns {Boolean}
*/
export const hasTrace = state => state.job.has_trace || (!_.isEmpty(state.job.status) && state.job.status.group === 'running');
export const hasTrace = state =>
state.job.has_trace || (!_.isEmpty(state.job.status) && state.job.status.group === 'running');
 
export const emptyStateIllustration = state =>
(state.job && state.job.status && state.job.status.illustration) || {};
 
export const emptyStateAction = state => (state.job && state.job.status && state.job.status.action) || {};
export const emptyStateAction = state =>
(state.job && state.job.status && state.job.status.action) || {};
 
export const isScrollingDown = state => isScrolledToBottom() && !state.isTraceComplete;
 
export const hasRunnersForProject = state => state.job.runners.available && !state.job.runners.online;
export const hasRunnersForProject = state =>
state.job.runners.available && !state.job.runners.online;
 
// prevent babel-plugin-rewire from generating an invalid default during karma tests
export default () => {};
Loading
Loading
@@ -25,7 +25,35 @@ export default class LabelsSelect {
}
 
$els.each(function(i, dropdown) {
var $block, $colorPreview, $dropdown, $form, $loading, $selectbox, $sidebarCollapsedValue, $value, abilityName, defaultLabel, enableLabelCreateButton, issueURLSplit, issueUpdateURL, labelUrl, namespacePath, projectPath, saveLabelData, selectedLabel, showAny, showNo, $sidebarLabelTooltip, initialSelected, $toggleText, fieldName, useId, propertyName, showMenuAbove, $container, $dropdownContainer;
var $block,
$colorPreview,
$dropdown,
$form,
$loading,
$selectbox,
$sidebarCollapsedValue,
$value,
abilityName,
defaultLabel,
enableLabelCreateButton,
issueURLSplit,
issueUpdateURL,
labelUrl,
namespacePath,
projectPath,
saveLabelData,
selectedLabel,
showAny,
showNo,
$sidebarLabelTooltip,
initialSelected,
$toggleText,
fieldName,
useId,
propertyName,
showMenuAbove,
$container,
$dropdownContainer;
$dropdown = $(dropdown);
$dropdownContainer = $dropdown.closest('.labels-filter');
$toggleText = $dropdown.find('.dropdown-toggle-text');
Loading
Loading
@@ -34,7 +62,7 @@ export default class LabelsSelect {
labelUrl = $dropdown.data('labels');
issueUpdateURL = $dropdown.data('issueUpdate');
selectedLabel = $dropdown.data('selected');
if ((selectedLabel != null) && !$dropdown.hasClass('js-multiselect')) {
if (selectedLabel != null && !$dropdown.hasClass('js-multiselect')) {
selectedLabel = selectedLabel.split(',');
}
showNo = $dropdown.data('showNo');
Loading
Loading
@@ -50,26 +78,37 @@ export default class LabelsSelect {
$value = $block.find('.value');
$loading = $block.find('.block-loading').fadeOut();
fieldName = $dropdown.data('fieldName');
useId = $dropdown.is('.js-issuable-form-dropdown, .js-filter-bulk-update, .js-label-sidebar-dropdown');
useId = $dropdown.is(
'.js-issuable-form-dropdown, .js-filter-bulk-update, .js-label-sidebar-dropdown',
);
propertyName = useId ? 'id' : 'title';
initialSelected = $selectbox
.find('input[name="' + $dropdown.data('fieldName') + '"]')
.map(function () {
.map(function() {
return this.value;
}).get();
})
.get();
const { handleClick } = options;
 
$sidebarLabelTooltip.tooltip();
 
if ($dropdown.closest('.dropdown').find('.dropdown-new-label').length) {
new CreateLabelDropdown($dropdown.closest('.dropdown').find('.dropdown-new-label'), namespacePath, projectPath);
new CreateLabelDropdown(
$dropdown.closest('.dropdown').find('.dropdown-new-label'),
namespacePath,
projectPath,
);
}
 
saveLabelData = function() {
var data, selected;
selected = $dropdown.closest('.selectbox').find("input[name='" + fieldName + "']").map(function() {
return this.value;
}).get();
selected = $dropdown
.closest('.selectbox')
.find("input[name='" + fieldName + "']")
.map(function() {
return this.value;
})
.get();
 
if (_.isEqual(initialSelected, selected)) return;
initialSelected = selected;
Loading
Loading
@@ -82,7 +121,8 @@ export default class LabelsSelect {
}
$loading.removeClass('hidden').fadeIn();
$dropdown.trigger('loading.gl.dropdown');
axios.put(issueUpdateURL, data)
axios
.put(issueUpdateURL, data)
.then(({ data }) => {
var labelCount, template, labelTooltipTitle, labelTitles, formattedLabels;
$loading.fadeOut();
Loading
Loading
@@ -96,8 +136,7 @@ export default class LabelsSelect {
issueUpdateURL,
});
labelCount = data.labels.length;
}
else {
} else {
template = '<span class="no-value">None</span>';
}
$value.removeAttr('style').html(template);
Loading
Loading
@@ -114,17 +153,14 @@ export default class LabelsSelect {
}
 
labelTooltipTitle = labelTitles.join(', ');
}
else {
} else {
labelTooltipTitle = __('Labels');
}
 
$sidebarLabelTooltip
.attr('title', labelTooltipTitle)
.tooltip('_fixTitle');
$sidebarLabelTooltip.attr('title', labelTooltipTitle).tooltip('_fixTitle');
 
$('.has-tooltip', $value).tooltip({
container: 'body'
container: 'body',
});
})
.catch(() => flash(__('Error saving label update.')));
Loading
Loading
@@ -132,34 +168,38 @@ export default class LabelsSelect {
$dropdown.glDropdown({
showMenuAbove: showMenuAbove,
data: function(term, callback) {
axios.get(labelUrl)
.then((res) => {
let data = _.chain(res.data).groupBy(function(label) {
return label.title;
}).map(function(label) {
var color;
color = _.map(label, function(dup) {
return dup.color;
});
return {
id: label[0].id,
title: label[0].title,
color: color,
duplicate: color.length > 1
};
}).value();
axios
.get(labelUrl)
.then(res => {
let data = _.chain(res.data)
.groupBy(function(label) {
return label.title;
})
.map(function(label) {
var color;
color = _.map(label, function(dup) {
return dup.color;
});
return {
id: label[0].id,
title: label[0].title,
color: color,
duplicate: color.length > 1,
};
})
.value();
if ($dropdown.hasClass('js-extra-options')) {
var extraData = [];
if (showNo) {
extraData.unshift({
id: 0,
title: 'No Label'
title: 'No Label',
});
}
if (showAny) {
extraData.unshift({
isAny: true,
title: 'Any Label'
title: 'Any Label',
});
}
if (extraData.length) {
Loading
Loading
@@ -176,11 +216,22 @@ export default class LabelsSelect {
.catch(() => flash(__('Error fetching labels.')));
},
renderRow: function(label, instance) {
var $a, $li, color, colorEl, indeterminate, removesAll, selectedClass, spacing, i, marked, dropdownName, dropdownValue;
var $a,
$li,
color,
colorEl,
indeterminate,
removesAll,
selectedClass,
spacing,
i,
marked,
dropdownName,
dropdownValue;
$li = $('<li>');
$a = $('<a href="#">');
selectedClass = [];
removesAll = label.id <= 0 || (label.id == null);
removesAll = label.id <= 0 || label.id == null;
if ($dropdown.hasClass('js-filter-bulk-update')) {
indeterminate = $dropdown.data('indeterminate') || [];
marked = $dropdown.data('marked') || [];
Loading
Loading
@@ -200,9 +251,19 @@ export default class LabelsSelect {
} else {
if (this.id(label)) {
dropdownName = $dropdown.data('fieldName');
dropdownValue = this.id(label).toString().replace(/'/g, '\\\'');
if ($form.find("input[type='hidden'][name='" + dropdownName + "'][value='" + dropdownValue + "']").length) {
dropdownValue = this.id(label)
.toString()
.replace(/'/g, "\\'");
if (
$form.find(
"input[type='hidden'][name='" +
dropdownName +
"'][value='" +
dropdownValue +
"']",
).length
) {
selectedClass.push('is-active');
}
}
Loading
Loading
@@ -213,16 +274,14 @@ export default class LabelsSelect {
}
if (label.duplicate) {
color = DropdownUtils.duplicateLabelColor(label.color);
}
else {
} else {
if (label.color != null) {
[color] = label.color;
}
}
if (color) {
colorEl = "<span class='dropdown-label-box' style='background: " + color + "'></span>";
}
else {
} else {
colorEl = '';
}
// We need to identify which items are actually labels
Loading
Loading
@@ -235,7 +294,7 @@ export default class LabelsSelect {
return $li.html($a).prop('outerHTML');
},
search: {
fields: ['title']
fields: ['title'],
},
selectable: true,
filterable: true,
Loading
Loading
@@ -255,25 +314,21 @@ export default class LabelsSelect {
if (selected && selected.id === 0) {
this.selected = [];
return 'No Label';
}
else if (isSelected) {
} else if (isSelected) {
this.selected.push(title);
}
else if (!isSelected && title) {
} else if (!isSelected && title) {
var index = this.selected.indexOf(title);
this.selected.splice(index, 1);
}
 
if (selectedLabels.length === 1) {
return selectedLabels;
}
else if (selectedLabels.length) {
} else if (selectedLabels.length) {
return sprintf(__('%{firstLabel} +%{labelCount} more'), {
firstLabel: selectedLabels[0],
labelCount: selectedLabels.length - 1
labelCount: selectedLabels.length - 1,
});
}
else {
} else {
return defaultLabel;
}
},
Loading
Loading
@@ -285,10 +340,9 @@ export default class LabelsSelect {
return label.id;
}
 
if ($dropdown.hasClass("js-filter-submit") && (label.isAny == null)) {
if ($dropdown.hasClass('js-filter-submit') && label.isAny == null) {
return label.title;
}
else {
} else {
return label.id;
}
},
Loading
Loading
@@ -310,13 +364,13 @@ export default class LabelsSelect {
}
if ($dropdown.hasClass('js-multiselect')) {
if ($dropdown.hasClass('js-filter-submit') && (isIssueIndex || isMRIndex)) {
selectedLabels = $dropdown.closest('form').find("input:hidden[name='" + ($dropdown.data('fieldName')) + "']");
selectedLabels = $dropdown
.closest('form')
.find("input:hidden[name='" + $dropdown.data('fieldName') + "']");
Issuable.filterResults($dropdown.closest('form'));
}
else if ($dropdown.hasClass('js-filter-submit')) {
} else if ($dropdown.hasClass('js-filter-submit')) {
$dropdown.closest('form').submit();
}
else {
} else {
if (!$dropdown.hasClass('js-filter-bulk-update')) {
saveLabelData();
}
Loading
Loading
@@ -325,7 +379,7 @@ export default class LabelsSelect {
},
multiSelect: $dropdown.hasClass('js-multiselect'),
vue: $dropdown.hasClass('js-issue-board-sidebar'),
clicked: function (clickEvent) {
clicked: function(clickEvent) {
const { $el, e, isMarking } = clickEvent;
const label = clickEvent.selectedObj;
 
Loading
Loading
@@ -339,7 +393,8 @@ export default class LabelsSelect {
isMRIndex = page === 'projects:merge_requests:index';
 
if ($dropdown.parent().find('.is-active:not(.dropdown-clear-active)').length) {
$dropdown.parent()
$dropdown
.parent()
.find('.dropdown-clear-active')
.removeClass('is-active');
}
Loading
Loading
@@ -367,28 +422,26 @@ export default class LabelsSelect {
 
e.preventDefault();
return;
}
else if ($dropdown.hasClass('js-filter-submit') && (isIssueIndex || isMRIndex)) {
} else if ($dropdown.hasClass('js-filter-submit') && (isIssueIndex || isMRIndex)) {
if (!$dropdown.hasClass('js-multiselect')) {
selectedLabel = label.title;
return Issuable.filterResults($dropdown.closest('form'));
}
}
else if ($dropdown.hasClass('js-filter-submit')) {
} else if ($dropdown.hasClass('js-filter-submit')) {
return $dropdown.closest('form').submit();
}
else if ($dropdown.hasClass('js-issue-board-sidebar')) {
} else if ($dropdown.hasClass('js-issue-board-sidebar')) {
if ($el.hasClass('is-active')) {
boardsStore.detail.issue.labels.push(new ListLabel({
id: label.id,
title: label.title,
color: label.color[0],
textColor: '#fff'
}));
}
else {
boardsStore.detail.issue.labels.push(
new ListLabel({
id: label.id,
title: label.title,
color: label.color[0],
textColor: '#fff',
}),
);
} else {
var { labels } = boardsStore.detail.issue;
labels = labels.filter(function (selectedLabel) {
labels = labels.filter(function(selectedLabel) {
return selectedLabel.id !== label.id;
});
boardsStore.detail.issue.labels = labels;
Loading
Loading
@@ -396,19 +449,16 @@ export default class LabelsSelect {
 
$loading.fadeIn();
 
boardsStore.detail.issue.update($dropdown.attr('data-issue-update'))
boardsStore.detail.issue
.update($dropdown.attr('data-issue-update'))
.then(fadeOutLoader)
.catch(fadeOutLoader);
}
else if (handleClick) {
} else if (handleClick) {
e.preventDefault();
handleClick(label);
}
else {
} else {
if ($dropdown.hasClass('js-multiselect')) {
}
else {
} else {
return saveLabelData();
}
}
Loading
Loading
@@ -436,15 +486,17 @@ export default class LabelsSelect {
// so best approach is to use traditional way of
// concatenation
// see: http://2ality.com/2016/05/template-literal-whitespace.html#joining-arrays
const tpl = _.template([
'<% _.each(labels, function(label){ %>',
'<a href="<%- issueUpdateURL.slice(0, issueUpdateURL.lastIndexOf("/")) %>?label_name[]=<%- encodeURIComponent(label.title) %>">',
'<span class="badge label has-tooltip color-label" title="<%- label.description %>" style="background-color: <%- label.color %>; color: <%- label.text_color %>;">',
'<%- label.title %>',
'</span>',
'</a>',
'<% }); %>',
].join(''));
const tpl = _.template(
[
'<% _.each(labels, function(label){ %>',
'<a href="<%- issueUpdateURL.slice(0, issueUpdateURL.lastIndexOf("/")) %>?label_name[]=<%- encodeURIComponent(label.title) %>">',
'<span class="badge label has-tooltip color-label" title="<%- label.description %>" style="background-color: <%- label.color %>; color: <%- label.text_color %>;">',
'<%- label.title %>',
'</span>',
'</a>',
'<% }); %>',
].join(''),
);
 
return tpl(tplData);
}
Loading
Loading
/* global ace */
 
export default function getModeByFileExtension(path) {
const modelist = ace.require("ace/ext/modelist");
const modelist = ace.require('ace/ext/modelist');
return modelist.getModeForPath(path).mode;
};
}
Loading
Loading
@@ -7,7 +7,7 @@ import { BYTES_IN_KIB } from './constants';
* * * Show 3 digits to the right
* * For 2 digits to the left of the decimal point and X digits to the right of it
* * * Show 2 digits to the right
*/
*/
export function formatRelevantDigits(number) {
let digitsLeft = '';
let relevantDigits = 0;
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