Commit 1d99c775 authored by Phil Hughes's avatar Phil Hughes

Merge branch 'master' into notebooklab-in-repo

parents a8b7a4b7 7d7dfee4
......@@ -7,13 +7,12 @@ import boardBlankState from './board_blank_state';
require('./board_delete');
require('./board_list');
(() => {
const Store = gl.issueBoards.BoardsStore;
const Store = gl.issueBoards.BoardsStore;
window.gl = window.gl || {};
window.gl.issueBoards = window.gl.issueBoards || {};
window.gl = window.gl || {};
window.gl.issueBoards = window.gl.issueBoards || {};
gl.issueBoards.Board = Vue.extend({
gl.issueBoards.Board = Vue.extend({
template: '#js-board-template',
components: {
boardList,
......@@ -102,5 +101,4 @@ require('./board_list');
this.sortable = Sortable.create(this.$el.parentNode, this.sortableOptions);
},
});
})();
});
......@@ -2,11 +2,10 @@
import Vue from 'vue';
(() => {
window.gl = window.gl || {};
window.gl.issueBoards = window.gl.issueBoards || {};
window.gl = window.gl || {};
window.gl.issueBoards = window.gl.issueBoards || {};
gl.issueBoards.BoardDelete = Vue.extend({
gl.issueBoards.BoardDelete = Vue.extend({
props: {
list: Object
},
......@@ -19,5 +18,4 @@ import Vue from 'vue';
}
}
}
});
})();
});
......@@ -8,13 +8,12 @@ import Vue from 'vue';
require('./sidebar/remove_issue');
(() => {
const Store = gl.issueBoards.BoardsStore;
const Store = gl.issueBoards.BoardsStore;
window.gl = window.gl || {};
window.gl.issueBoards = window.gl.issueBoards || {};
window.gl = window.gl || {};
window.gl.issueBoards = window.gl.issueBoards || {};
gl.issueBoards.BoardSidebar = Vue.extend({
gl.issueBoards.BoardSidebar = Vue.extend({
props: {
currentUser: Object
},
......@@ -69,5 +68,4 @@ require('./sidebar/remove_issue');
components: {
removeBtn: gl.issueBoards.RemoveIssueBtn,
},
});
})();
});
import Vue from 'vue';
import eventHub from '../eventhub';
(() => {
const Store = gl.issueBoards.BoardsStore;
const Store = gl.issueBoards.BoardsStore;
window.gl = window.gl || {};
window.gl.issueBoards = window.gl.issueBoards || {};
window.gl = window.gl || {};
window.gl.issueBoards = window.gl.issueBoards || {};
gl.issueBoards.IssueCardInner = Vue.extend({
gl.issueBoards.IssueCardInner = Vue.extend({
props: {
issue: {
type: Object,
......@@ -137,5 +136,4 @@ import eventHub from '../eventhub';
</div>
</div>
`,
});
})();
});
import Vue from 'vue';
(() => {
const ModalStore = gl.issueBoards.ModalStore;
const ModalStore = gl.issueBoards.ModalStore;
gl.issueBoards.ModalEmptyState = Vue.extend({
gl.issueBoards.ModalEmptyState = Vue.extend({
mixins: [gl.issueBoards.ModalMixins],
data() {
return ModalStore.store;
......@@ -67,5 +66,4 @@ import Vue from 'vue';
</div>
</section>
`,
});
})();
});
......@@ -5,10 +5,9 @@ import Vue from 'vue';
require('./lists_dropdown');
(() => {
const ModalStore = gl.issueBoards.ModalStore;
const ModalStore = gl.issueBoards.ModalStore;
gl.issueBoards.ModalFooter = Vue.extend({
gl.issueBoards.ModalFooter = Vue.extend({
mixins: [gl.issueBoards.ModalMixins],
data() {
return {
......@@ -80,5 +79,4 @@ require('./lists_dropdown');
</button>
</footer>
`,
});
})();
});
......@@ -3,10 +3,9 @@ import modalFilters from './filters';
require('./tabs');
(() => {
const ModalStore = gl.issueBoards.ModalStore;
const ModalStore = gl.issueBoards.ModalStore;
gl.issueBoards.ModalHeader = Vue.extend({
gl.issueBoards.ModalHeader = Vue.extend({
mixins: [gl.issueBoards.ModalMixins],
props: {
projectId: {
......@@ -78,5 +77,4 @@ require('./tabs');
</div>
</div>
`,
});
})();
});
......@@ -8,10 +8,9 @@ require('./list');
require('./footer');
require('./empty_state');
(() => {
const ModalStore = gl.issueBoards.ModalStore;
const ModalStore = gl.issueBoards.ModalStore;
gl.issueBoards.IssuesModal = Vue.extend({
gl.issueBoards.IssuesModal = Vue.extend({
props: {
blankStateImage: {
type: String,
......@@ -163,5 +162,4 @@ require('./empty_state');
</div>
</div>
`,
});
})();
});
......@@ -3,10 +3,9 @@
import Vue from 'vue';
(() => {
const ModalStore = gl.issueBoards.ModalStore;
const ModalStore = gl.issueBoards.ModalStore;
gl.issueBoards.ModalList = Vue.extend({
gl.issueBoards.ModalList = Vue.extend({
props: {
issueLinkBase: {
type: String,
......@@ -157,5 +156,4 @@ import Vue from 'vue';
</div>
</section>
`,
});
})();
});
import Vue from 'vue';
(() => {
const ModalStore = gl.issueBoards.ModalStore;
const ModalStore = gl.issueBoards.ModalStore;
gl.issueBoards.ModalFooterListsDropdown = Vue.extend({
gl.issueBoards.ModalFooterListsDropdown = Vue.extend({
data() {
return {
modal: ModalStore.store,
......@@ -53,5 +52,4 @@ import Vue from 'vue';
</div>
</div>
`,
});
})();
});
import Vue from 'vue';
(() => {
const ModalStore = gl.issueBoards.ModalStore;
const ModalStore = gl.issueBoards.ModalStore;
gl.issueBoards.ModalTabs = Vue.extend({
gl.issueBoards.ModalTabs = Vue.extend({
mixins: [gl.issueBoards.ModalMixins],
data() {
return ModalStore.store;
......@@ -44,5 +43,4 @@ import Vue from 'vue';
</ul>
</div>
`,
});
})();
});
/* eslint-disable comma-dangle, func-names, no-new, space-before-function-paren, one-var */
(() => {
window.gl = window.gl || {};
window.gl.issueBoards = window.gl.issueBoards || {};
window.gl = window.gl || {};
window.gl.issueBoards = window.gl.issueBoards || {};
const Store = gl.issueBoards.BoardsStore;
const Store = gl.issueBoards.BoardsStore;
$(document).off('created.label').on('created.label', (e, label) => {
$(document).off('created.label').on('created.label', (e, label) => {
Store.new({
title: label.title,
position: Store.state.lists.length - 2,
......@@ -17,9 +16,9 @@
color: label.color
}
});
});
});
gl.issueBoards.newListDropdownInit = () => {
gl.issueBoards.newListDropdownInit = () => {
$('.js-new-board-list').each(function () {
const $this = $(this);
new gl.CreateLabelDropdown($this.closest('.dropdown').find('.dropdown-new-label'), $this.data('namespace-path'), $this.data('project-path'));
......@@ -72,5 +71,4 @@
}
});
});
};
})();
};
......@@ -3,13 +3,12 @@
import Vue from 'vue';
(() => {
const Store = gl.issueBoards.BoardsStore;
const Store = gl.issueBoards.BoardsStore;
window.gl = window.gl || {};
window.gl.issueBoards = window.gl.issueBoards || {};
window.gl = window.gl || {};
window.gl.issueBoards = window.gl.issueBoards || {};
gl.issueBoards.RemoveIssueBtn = Vue.extend({
gl.issueBoards.RemoveIssueBtn = Vue.extend({
props: {
issue: {
type: Object,
......@@ -57,5 +56,4 @@ import Vue from 'vue';
</button>
</div>
`,
});
})();
});
(() => {
const ModalStore = gl.issueBoards.ModalStore;
const ModalStore = gl.issueBoards.ModalStore;
gl.issueBoards.ModalMixins = {
gl.issueBoards.ModalMixins = {
methods: {
toggleModal(toggle) {
ModalStore.store.showAddIssuesModal = toggle;
......@@ -10,5 +9,4 @@
ModalStore.store.activeTab = tab;
},
},
};
})();
};
/* eslint-disable no-unused-vars, no-mixed-operators, comma-dangle */
/* global DocumentTouch */
((w) => {
window.gl = window.gl || {};
window.gl.issueBoards = window.gl.issueBoards || {};
window.gl = window.gl || {};
window.gl.issueBoards = window.gl.issueBoards || {};
gl.issueBoards.onStart = () => {
gl.issueBoards.onStart = () => {
$('.has-tooltip').tooltip('hide')
.tooltip('disable');
document.body.classList.add('is-dragging');
};
};
gl.issueBoards.onEnd = () => {
gl.issueBoards.onEnd = () => {
$('.has-tooltip').tooltip('enable');
document.body.classList.remove('is-dragging');
};
};
gl.issueBoards.touchEnabled = ('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch;
gl.issueBoards.touchEnabled = ('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch;
gl.issueBoards.getBoardSortableDefaultOptions = (obj) => {
gl.issueBoards.getBoardSortableDefaultOptions = (obj) => {
const defaultSortOptions = {
animation: 200,
forceFallback: true,
......@@ -35,5 +34,4 @@
Object.keys(obj).forEach((key) => { defaultSortOptions[key] = obj[key]; });
return defaultSortOptions;
};
})(window);
};
......@@ -3,11 +3,10 @@
import Cookies from 'js-cookie';
(() => {
window.gl = window.gl || {};
window.gl.issueBoards = window.gl.issueBoards || {};
window.gl = window.gl || {};
window.gl.issueBoards = window.gl.issueBoards || {};
gl.issueBoards.BoardsStore = {
gl.issueBoards.BoardsStore = {
disabled: false,
filter: {
path: '',
......@@ -123,5 +122,4 @@ import Cookies from 'js-cookie';
updateFiltersUrl () {
history.pushState(null, null, `?${this.filter.path}`);
}
};
})();
};
(() => {
window.gl = window.gl || {};
window.gl.issueBoards = window.gl.issueBoards || {};
window.gl = window.gl || {};
window.gl.issueBoards = window.gl.issueBoards || {};
class ModalStore {
class ModalStore {
constructor() {
this.store = {
columns: 3,
......@@ -94,7 +93,6 @@
return this.store.selectedIssues
.filter(filteredIssue => filteredIssue.id === issue.id)[0];
}
}
}
gl.issueBoards.ModalStore = new ModalStore();
})();
gl.issueBoards.ModalStore = new ModalStore();
......@@ -2,10 +2,10 @@
import Vue from 'vue';
((global) => {
global.cycleAnalytics = global.cycleAnalytics || {};
const global = window.gl || (window.gl = {});
global.cycleAnalytics = global.cycleAnalytics || {};
global.cycleAnalytics.StageCodeComponent = Vue.extend({
global.cycleAnalytics.StageCodeComponent = Vue.extend({
props: {
items: Array,
stage: Object,
......@@ -43,5 +43,4 @@ import Vue from 'vue';
</ul>
</div>
`,
});
})(window.gl || (window.gl = {}));
});
......@@ -2,10 +2,10 @@
import Vue from 'vue';
((global) => {
global.cycleAnalytics = global.cycleAnalytics || {};
const global = window.gl || (window.gl = {});
global.cycleAnalytics = global.cycleAnalytics || {};
global.cycleAnalytics.StageIssueComponent = Vue.extend({
global.cycleAnalytics.StageIssueComponent = Vue.extend({
props: {
items: Array,
stage: Object,
......@@ -45,5 +45,4 @@ import Vue from 'vue';
</ul>
</div>
`,
});
})(window.gl || (window.gl = {}));
});
......@@ -2,10 +2,10 @@
import Vue from 'vue';
import iconCommit from '../svg/icon_commit.svg';
((global) => {
global.cycleAnalytics = global.cycleAnalytics || {};
const global = window.gl || (window.gl = {});
global.cycleAnalytics = global.cycleAnalytics || {};
global.cycleAnalytics.StagePlanComponent = Vue.extend({
global.cycleAnalytics.StagePlanComponent = Vue.extend({
props: {
items: Array,
stage: Object,
......@@ -47,5 +47,4 @@ import iconCommit from '../svg/icon_commit.svg';
</ul>
</div>
`,
});
})(window.gl || (window.gl = {}));
});
......@@ -2,10 +2,10 @@
import Vue from 'vue';
((global) => {
global.cycleAnalytics = global.cycleAnalytics || {};
const global = window.gl || (window.gl = {});
global.cycleAnalytics = global.cycleAnalytics || {};
global.cycleAnalytics.StageProductionComponent = Vue.extend({
global.cycleAnalytics.StageProductionComponent = Vue.extend({
props: {
items: Array,
stage: Object,
......@@ -45,5 +45,4 @@ import Vue from 'vue';
</ul>
</div>
`,
});
})(window.gl || (window.gl = {}));
});
......@@ -2,10 +2,10 @@
import Vue from 'vue';
((global) => {
global.cycleAnalytics = global.cycleAnalytics || {};
const global = window.gl || (window.gl = {});
global.cycleAnalytics = global.cycleAnalytics || {};
global.cycleAnalytics.StageReviewComponent = Vue.extend({
global.cycleAnalytics.StageReviewComponent = Vue.extend({
props: {
items: Array,
stage: Object,
......@@ -55,5 +55,4 @@ import Vue from 'vue';
</ul>
</div>
`,
});
})(window.gl || (window.gl = {}));
});
......@@ -2,10 +2,10 @@
import Vue from 'vue';
import iconBranch from '../svg/icon_branch.svg';
((global) => {
global.cycleAnalytics = global.cycleAnalytics || {};
const global = window.gl || (window.gl = {});
global.cycleAnalytics = global.cycleAnalytics || {};
global.cycleAnalytics.StageStagingComponent = Vue.extend({
global.cycleAnalytics.StageStagingComponent = Vue.extend({
props: {
items: Array,
stage: Object,
......@@ -45,5 +45,4 @@ import iconBranch from '../svg/icon_branch.svg';
</ul>
</div>
`,
});
})(window.gl || (window.gl = {}));
});
......@@ -3,10 +3,10 @@ import Vue from 'vue';
import iconBuildStatus from '../svg/icon_build_status.svg';
import iconBranch from '../svg/icon_branch.svg';
((global) => {
global.cycleAnalytics = global.cycleAnalytics || {};
const global = window.gl || (window.gl = {});
global.cycleAnalytics = global.cycleAnalytics || {};
global.cycleAnalytics.StageTestComponent = Vue.extend({
global.cycleAnalytics.StageTestComponent = Vue.extend({
props: {
items: Array,
stage: Object,
......@@ -46,5 +46,4 @@ import iconBranch from '../svg/icon_branch.svg';
</ul>
</div>
`,
});
})(window.gl || (window.gl = {}));
});
......@@ -2,10 +2,10 @@
import Vue from 'vue';
((global) => {
global.cycleAnalytics = global.cycleAnalytics || {};
const global = window.gl || (window.gl = {});
global.cycleAnalytics = global.cycleAnalytics || {};
global.cycleAnalytics.TotalTimeComponent = Vue.extend({
global.cycleAnalytics.TotalTimeComponent = Vue.extend({
props: {
time: Object,
},
......@@ -22,5 +22,4 @@ import Vue from 'vue';
</template>
</span>
`,
});
})(window.gl || (window.gl = {}));
});
/* eslint-disable no-param-reassign */
((global) => {
global.cycleAnalytics = global.cycleAnalytics || {};
class CycleAnalyticsService {
const global = window.gl || (window.gl = {});
global.cycleAnalytics = global.cycleAnalytics || {};
class CycleAnalyticsService {
constructor(options) {
this.requestPath = options.requestPath;
}
......@@ -35,7 +36,6 @@
},
});
}
}
}
global.cycleAnalytics.CycleAnalyticsService = CycleAnalyticsService;
})(window.gl || (window.gl = {}));
global.cycleAnalytics.CycleAnalyticsService = CycleAnalyticsService;
......@@ -3,10 +3,10 @@
require('../lib/utils/text_utility');
const DEFAULT_EVENT_OBJECTS = require('./default_event_objects');
((global) => {
global.cycleAnalytics = global.cycleAnalytics || {};
const global = window.gl || (window.gl = {});
global.cycleAnalytics = global.cycleAnalytics || {};
const EMPTY_STAGE_TEXTS = {
const EMPTY_STAGE_TEXTS = {
issue: 'The issue stage shows the time it takes from creating an issue to assigning the issue to a milestone, or add the issue to a list on your Issue Board. Begin creating issues to see data for this stage.',
plan: 'The planning stage shows the time from the previous step to pushing your first commit. This time will be added automatically once you push your first commit.',
code: 'The coding stage shows the time from the first commit to creating the merge request. The data will automatically be added here once you create your first merge request.',
......@@ -14,9 +14,9 @@ const DEFAULT_EVENT_OBJECTS = require('./default_event_objects');
review: 'The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request.',
staging: 'The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time.',
production: 'The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle.',
};
};
global.cycleAnalytics.CycleAnalyticsStore = {
global.cycleAnalytics.CycleAnalyticsStore = {
state: {
summary: '',
stats: '',
......@@ -100,5 +100,4 @@ const DEFAULT_EVENT_OBJECTS = require('./default_event_objects');
currentActiveStage() {
return this.state.stages.find(stage => stage.active);
},
};
})(window.gl || (window.gl = {}));
};
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-param-reassign, no-cond-assign, quotes, one-var, one-var-declaration-per-line, operator-assignment, no-else-return, prefer-template, prefer-arrow-callback, no-empty, max-len, consistent-return, no-unused-vars, no-return-assign, max-len */
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-param-reassign, no-cond-assign, quotes, one-var, one-var-declaration-per-line, operator-assignment, no-else-return, prefer-template, prefer-arrow-callback, no-empty, max-len, consistent-return, no-unused-vars, no-return-assign, max-len, vars-on-top */
require('vendor/latinise');
(function() {
(function(w) {
var base;
if (w.gl == null) {
var base;
var w = window;
if (w.gl == null) {
w.gl = {};
}
if ((base = w.gl).text == null) {
}
if ((base = w.gl).text == null) {
base.text = {};
}
gl.text.addDelimiter = function(text) {
}
gl.text.addDelimiter = function(text) {
return text ? text.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") : text;
};
gl.text.highCountTrim = function(count) {
};
gl.text.highCountTrim = function(count) {
return count > 99 ? '99+' : count;
};
gl.text.randomString = function() {
};
gl.text.randomString = function() {
return Math.random().toString(36).substring(7);
};
gl.text.replaceRange = function(s, start, end, substitute) {
};
gl.text.replaceRange = function(s, start, end, substitute) {
return s.substring(0, start) + substitute + s.substring(end);
};
gl.text.getTextWidth = function(text, font) {
};
gl.text.getTextWidth = function(text, font) {
/**
* Uses canvas.measureText to compute and return the width of the given text of given font in pixels.
*
......@@ -37,19 +35,19 @@ require('vendor/latinise');
var context = canvas.getContext('2d');
context.font = font;
return context.measureText(text).width;
};
gl.text.selectedText = function(text, textarea) {
};
gl.text.selectedText = function(text, textarea) {
return text.substring(textarea.selectionStart, textarea.selectionEnd);
};
gl.text.lineBefore = function(text, textarea) {
};
gl.text.lineBefore = function(text, textarea) {
var split;
split = text.substring(0, textarea.selectionStart).trim().split('\n');
return split[split.length - 1];
};
gl.text.lineAfter = function(text, textarea) {
};
gl.text.lineAfter = function(text, textarea) {
return text.substring(textarea.selectionEnd).trim().split('\n')[0];
};
gl.text.blockTagText = function(text, textArea, blockTag, selected) {
};
gl.text.blockTagText = function(text, textArea, blockTag, selected) {
var lineAfter, lineBefore;
lineBefore = this.lineBefore(text, textArea);
lineAfter = this.lineAfter(text, textArea);
......@@ -63,8 +61,8 @@ require('vendor/latinise');
} else {
return blockTag + "\n" + selected + "\n" + blockTag;
}
};
gl.text.insertText = function(textArea, text, tag, blockTag, selected, wrap) {
};
gl.text.insertText = function(textArea, text, tag, blockTag, selected, wrap) {
var insertText, inserted, selectedSplit, startChar, removedLastNewLine, removedFirstNewLine, currentLineEmpty, lastNewLine;
removedLastNewLine = false;
removedFirstNewLine = false;
......@@ -132,8 +130,8 @@ require('vendor/latinise');
} catch (error) {}
}
return this.moveCursor(textArea, tag, wrap, removedLastNewLine);
};
gl.text.moveCursor = function(textArea, tag, wrapped, removedLastNewLine) {
};
gl.text.moveCursor = function(textArea, tag, wrapped, removedLastNewLine) {
var pos;
if (!textArea.setSelectionRange) {
return;
......@@ -151,8 +149,8 @@ require('vendor/latinise');
return textArea.setSelectionRange(pos, pos);
}
};
gl.text.updateText = function(textArea, tag, blockTag, wrap) {
};
gl.text.updateText = function(textArea, tag, blockTag, wrap) {
var $textArea, selected, text;
$textArea = $(textArea);
textArea = $textArea.get(0);
......@@ -160,8 +158,8 @@ require('vendor/latinise');
selected = this.selectedText(text, textArea);
$textArea.focus();
return this.insertText(textArea, text, tag, blockTag, selected, wrap);
};
gl.text.init = function(form) {
};
gl.text.init = function(form) {
var self;
self = this;
return $('.js-md', form).off('click').on('click', function() {
......@@ -169,24 +167,22 @@ require('vendor/latinise');
$this = $(this);
return self.updateText($this.closest('.md-area').find('textarea'), $this.data('md-tag'), $this.data('md-block'), !$this.data('md-prepend'));
});
};
gl.text.removeListeners = function(form) {
};
gl.text.removeListeners = function(form) {
return $('.js-md', form).off();
};
gl.text.humanize = function(string) {
};
gl.text.humanize = function(string) {
return string.charAt(0).toUpperCase() + string.replace(/_/g, ' ').slice(1);
};
gl.text.pluralize = function(str, count) {
};
gl.text.pluralize = function(str, count) {
return str + (count > 1 || count === 0 ? 's' : '');
};
gl.text.truncate = function(string, maxLength) {
};
gl.text.truncate = function(string, maxLength) {
return string.substr(0, (maxLength - 3)) + '...';
};
gl.text.dasherize = function(str) {
};
gl.text.dasherize = function(str) {
return str.replace(/[_\s]+/g, '-');
};
gl.text.slugify = function(str) {
};
gl.text.slugify = function(str) {
return str.trim().toLowerCase().latinise();
};
})(window);
}).call(window);
};
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-param-reassign, no-cond-assign, one-var, one-var-declaration-per-line, no-void, guard-for-in, no-restricted-syntax, prefer-template, quotes, max-len */
(function() {
(function(w) {
var base;
if (w.gl == null) {
var base;
var w = window;
if (w.gl == null) {
w.gl = {};
}
if ((base = w.gl).utils == null) {
}
if ((base = w.gl).utils == null) {
base.utils = {};
}
// Returns an array containing the value(s) of the
// of the key passed as an argument
w.gl.utils.getParameterValues = function(sParam) {
}
// Returns an array containing the value(s) of the
// of the key passed as an argument
w.gl.utils.getParameterValues = function(sParam) {
var i, sPageURL, sParameterName, sURLVariables, values;
sPageURL = decodeURIComponent(window.location.search.substring(1));
sURLVariables = sPageURL.split('&');
......@@ -25,10 +24,10 @@
i += 1;
}
return values;
};
// @param {Object} params - url keys and value to merge
// @param {String} url
w.gl.utils.mergeUrlParams = function(params, url) {
};
// @param {Object} params - url keys and value to merge
// @param {String} url
w.gl.utils.mergeUrlParams = function(params, url) {
var lastChar, newUrl, paramName, paramValue, pattern;
newUrl = decodeURIComponent(url);
for (paramName in params) {
......@@ -48,9 +47,9 @@
newUrl = newUrl.slice(0, -1);
}
return newUrl;
};
// removes parameter query string from url. returns the modified url
w.gl.utils.removeParamQueryString = function(url, param) {
};
// removes parameter query string from url. returns the modified url
w.gl.utils.removeParamQueryString = function(url, param) {
var urlVariables, variables;
url = decodeURIComponent(url);
urlVariables = url.split('&');
......@@ -65,15 +64,15 @@
}
return results;
})()).join('&');
};
w.gl.utils.removeParams = (params) => {
};
w.gl.utils.removeParams = (params) => {
const url = new URL(window.location.href);
params.forEach((param) => {
url.search = w.gl.utils.removeParamQueryString(url.search, param);
});
return url.href;
};
w.gl.utils.getLocationHash = function(url) {
};
w.gl.utils.getLocationHash = function(url) {
var hashIndex;
if (typeof url === 'undefined') {
// Note: We can't use window.location.hash here because it's
......@@ -82,12 +81,10 @@
}
hashIndex = url.indexOf('#');
return hashIndex === -1 ? null : url.substring(hashIndex + 1);
};
};
w.gl.utils.refreshCurrentPage = () => gl.utils.visitUrl(document.location.href);
w.gl.utils.refreshCurrentPage = () => gl.utils.visitUrl(document.location.href);
w.gl.utils.visitUrl = (url) => {
w.gl.utils.visitUrl = (url) => {
document.location.href = url;
};
})(window);
}).call(window);
};
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, max-len */
(function() {
var bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; };
import '~/lib/utils/url_utility';
(function() {
this.MergedButtons = (function() {
function MergedButtons() {
this.removeSourceBranch = bind(this.removeSourceBranch, this);
this.removeSourceBranch = this.removeSourceBranch.bind(this);
this.removeBranchSuccess = this.removeBranchSuccess.bind(this);
this.removeBranchError = this.removeBranchError.bind(this);
this.$removeBranchWidget = $('.remove_source_branch_widget');
this.$removeBranchProgress = $('.remove_source_branch_in_progress');
this.$removeBranchFailed = $('.remove_source_branch_widget.failed');
......@@ -22,7 +24,7 @@
MergedButtons.prototype.initEventListeners = function() {
$(document).on('click', '.remove_source_branch', this.removeSourceBranch);
$(document).on('ajax:success', '.remove_source_branch', this.removeBranchSuccess);
return $(document).on('ajax:error', '.remove_source_branch', this.removeBranchError);
$(document).on('ajax:error', '.remove_source_branch', this.removeBranchError);
};
MergedButtons.prototype.removeSourceBranch = function() {
......@@ -31,7 +33,7 @@
};
MergedButtons.prototype.removeBranchSuccess = function() {
return location.reload();
gl.utils.refreshCurrentPage();
};
MergedButtons.prototype.removeBranchError = function() {
......
......@@ -158,6 +158,7 @@
li.task-list-item {
list-style-type: none;
position: relative;
min-height: 22px;
padding-left: 28px;
margin-left: 0 !important;
......
......@@ -627,7 +627,6 @@ ul.notes {
}
&:not(.is-disabled):hover,
&:not(.is-disabled):focus,
&.is-active {
color: $gl-text-green;
......@@ -641,6 +640,11 @@ ul.notes {
height: 15px;
width: 15px;
}
.loading {
margin: 0;
height: auto;
}
}
.discussion-next-btn {
......
......@@ -20,7 +20,8 @@ class ContainerRepository < ActiveRecord::Base
end
def path
@path ||= [project.full_path, name].select(&:present?).join('/')
@path ||= [project.full_path, name]
.select(&:present?).join('/').downcase
end
def location
......
......@@ -23,7 +23,7 @@
Registry
- if project_nav_tab? :issues
= nav_link(controller: [:issues, :labels, :milestones, :boards]) do
= nav_link(controller: @project.default_issues_tracker? ? [:issues, :labels, :milestones, :boards] : :issues) do
= link_to namespace_project_issues_path(@project.namespace, @project), title: 'Issues', class: 'shortcuts-issues' do
%span
Issues
......@@ -31,7 +31,7 @@
%span.badge.count.issue_counter= number_with_delimiter(IssuesFinder.new(current_user, project_id: @project.id).execute.opened.count)
- if project_nav_tab? :merge_requests
= nav_link(controller: :merge_requests) do
= nav_link(controller: @project.default_issues_tracker? ? :merge_requests : [:merge_requests, :labels, :milestones]) do
= link_to namespace_project_merge_requests_path(@project.namespace, @project), title: 'Merge Requests', class: 'shortcuts-merge_requests' do
%span
Merge Requests
......
- @no_container = true
- page_title "Edit", @label.name, "Labels"
= render "projects/issues/head"
= render "shared/mr_head"
%div{ class: container_class }
%h3.page-title
......
- @no_container = true
- page_title "Labels"
- hide_class = ''
= render "projects/issues/head"
= render "shared/mr_head"
- if @labels.exists? || @prioritized_labels.exists?
%div{ class: container_class }
......
- @no_container = true
- page_title "New Label"
= render "projects/issues/head"
= render "shared/mr_head"
%div{ class: container_class }
%h3.page-title
......
= content_for :sub_nav do
.scrolling-tabs-container.sub-nav-scroll
= render 'shared/nav_scroll'
.nav-links.sub-nav.scrolling-tabs
%ul{ class: (container_class) }
= nav_link(controller: :merge_requests) do
= link_to namespace_project_merge_requests_path(@project.namespace, @project), title: 'Merge Requests' do
%span
List
- if project_nav_tab? :labels
= nav_link(controller: :labels) do
= link_to namespace_project_labels_path(@project.namespace, @project), title: 'Labels' do
%span
Labels
- if project_nav_tab? :milestones
= nav_link(controller: :milestones) do
= link_to namespace_project_milestones_path(@project.namespace, @project), title: 'Milestones' do
%span
Milestones
......@@ -2,6 +2,9 @@
- @bulk_edit = can?(current_user, :admin_merge_request, @project)
- page_title "Merge Requests"
- unless @project.default_issues_tracker?
= content_for :sub_nav do
= render "projects/merge_requests/head"
= render 'projects/last_push'
- content_for :page_specific_javascripts do
......
- @no_container = true
- page_title "Edit", @milestone.title, "Milestones"
= render "projects/issues/head"
= render "shared/mr_head"
%div{ class: container_class }
......
- @no_container = true
- page_title 'Milestones'
= render 'projects/issues/head'
= render "shared/mr_head"
%div{ class: container_class }
.top-area
......
- @no_container = true
- page_title "New Milestone"
= render "projects/issues/head"
= render "shared/mr_head"
%div{ class: container_class }
%h3.page-title
......
- @no_container = true
- page_title @milestone.title, "Milestones"
- page_description @milestone.description
= render "projects/issues/head"
= render "shared/mr_head"
%div{ class: container_class }
.detail-page-header.milestone-page-header
......
......@@ -52,11 +52,10 @@
":aria-label" => "buttonText",
"@click" => "resolve",
":title" => "buttonText",
"v-show" => "!loading",
":ref" => "'button'" }
= icon("spin spinner", "v-show" => "loading")
= render "shared/icons/icon_status_success.svg"
= icon("spin spinner", "v-show" => "loading", class: 'loading')
%div{ 'v-show' => '!loading' }= render "shared/icons/icon_status_success.svg"
- if current_user
- if note.emoji_awardable?
......
- if @project.default_issues_tracker?
= render "projects/issues/head"
- else
= render "projects/merge_requests/head"
---
title: Show sub-nav under Merge Requests when issue tracker is non-default.
merge_request: 10658
author:
---
title: Fixed alignment of empty task list items
merge_request:
author:
---
title: Fix invalid encoding when showing some traces
merge_request: 10681
author:
......@@ -13,8 +13,8 @@ module Banzai
issuables = extractor.extract([doc])
issuables.each do |node, issuable|
if VISIBLE_STATES.include?(issuable.state)
node.children.last.content += " [#{issuable.state}]"
if VISIBLE_STATES.include?(issuable.state) && node.children.present?
node.add_child(Nokogiri::XML::Text.new(" [#{issuable.state}]", doc))
end
end
......
......@@ -15,7 +15,7 @@ module ContainerRegistry
LEVELS_SUPPORTED = 3
def initialize(path)
@path = path
@path = path.to_s.downcase
end
def valid?
......@@ -25,7 +25,7 @@ module ContainerRegistry
end
def components
@components ||= @path.to_s.split('/')
@components ||= @path.split('/')
end
def nodes
......
......@@ -25,11 +25,10 @@ module Gitlab
end
def limit(last_bytes = LIMIT_SIZE)
stream_size = size
if stream_size < last_bytes
last_bytes = stream_size
end
if last_bytes < size
stream.seek(-last_bytes, IO::SEEK_END)
stream.readline
end
end
def append(data, offset)
......
......@@ -198,6 +198,8 @@ feature 'Diff notes resolve', feature: true, js: true do
it 'does not mark discussion as resolved when resolving single note' do
page.first '.diff-content .note' do
first('.line-resolve-btn').click
expect(page).to have_selector('.note-action-button .loading')
expect(first('.line-resolve-btn')['data-original-title']).to eq("Resolved by #{user.name}")
end
......
.
..
😺
ヾ(´༎ຶД༎ຶ`)ノ
許功蓋
......@@ -7,6 +7,7 @@ describe Projects::MergeRequestsController, '(JavaScript fixtures)', type: :cont
let(:namespace) { create(:namespace, name: 'frontend-fixtures' )}
let(:project) { create(:project, namespace: namespace, path: 'merge-requests-project') }
let(:merge_request) { create(:merge_request, :with_diffs, source_project: project, target_project: project, description: '- [ ] Task List Item') }
let(:merged_merge_request) { create(:merge_request, :merged, source_project: project, target_project: project) }
let(:pipeline) do
create(
:ci_pipeline,
......@@ -32,6 +33,12 @@ describe Projects::MergeRequestsController, '(JavaScript fixtures)', type: :cont
render_merge_request(example.description, merge_request)
end
it 'merge_requests/merged_merge_request.html.raw' do |example|
allow_any_instance_of(MergeRequest).to receive(:source_branch_exists?).and_return(true)
allow_any_instance_of(MergeRequest).to receive(:can_remove_source_branch?).and_return(true)
render_merge_request(example.description, merged_merge_request)
end
private
def render_merge_request(fixture_file_name, merge_request)
......
require('~/lib/utils/text_utility');
(() => {
describe('text_utility', () => {
describe('text_utility', () => {
describe('gl.text.getTextWidth', () => {
it('returns zero width when no text is passed', () => {
expect(gl.text.getTextWidth('')).toBe(0);
......@@ -106,5 +105,4 @@ require('~/lib/utils/text_utility');
});
});
});
});
})();
});
/* global MergedButtons */
import '~/merged_buttons';
describe('MergedButtons', () => {
const fixturesPath = 'merge_requests/merged_merge_request.html.raw';
preloadFixtures(fixturesPath);
beforeEach(() => {
loadFixtures(fixturesPath);
this.mergedButtons = new MergedButtons();
this.$removeBranchWidget = $('.remove_source_branch_widget:not(.failed)');
this.$removeBranchProgress = $('.remove_source_branch_in_progress');
this.$removeBranchFailed = $('.remove_source_branch_widget.failed');
this.$removeBranchButton = $('.remove_source_branch');
});
describe('removeSourceBranch', () => {
it('shows loader', () => {
$('.remove_source_branch').trigger('click');
expect(this.$removeBranchProgress).toBeVisible();
expect(this.$removeBranchWidget).not.toBeVisible();
});
});
describe('removeBranchSuccess', () => {
it('refreshes page when branch removed', () => {
spyOn(gl.utils, 'refreshCurrentPage').and.stub();
const response = { status: 200 };
this.$removeBranchButton.trigger('ajax:success', response, 'xhr');
expect(gl.utils.refreshCurrentPage).toHaveBeenCalled();
});
});
describe('removeBranchError', () => {
it('shows error message', () => {
const response = { status: 500 };
this.$removeBranchButton.trigger('ajax:error', response, 'xhr');
expect(this.$removeBranchFailed).toBeVisible();
expect(this.$removeBranchProgress).not.toBeVisible();
expect(this.$removeBranchWidget).not.toBeVisible();
});
});
});
......@@ -6,8 +6,8 @@ describe Banzai::Filter::IssuableStateFilter, lib: true do
let(:user) { create(:user) }
def create_link(data)
link_to('text', '', class: 'gfm has-tooltip', data: data)
def create_link(text, data)
link_to(text, '', class: 'gfm has-tooltip', data: data)
end
it 'ignores non-GFM links' do
......@@ -19,16 +19,37 @@ describe Banzai::Filter::IssuableStateFilter, lib: true do
it 'ignores non-issuable links' do
project = create(:empty_project, :public)
link = create_link(project: project, reference_type: 'issue')
link = create_link('text', project: project, reference_type: 'issue')
doc = filter(link, current_user: user)
expect(doc.css('a').last.text).to eq('text')
end
it 'ignores issuable links with empty content' do
issue = create(:issue, :closed)
link = create_link('', issue: issue.id, reference_type: 'issue')
doc = filter(link, current_user: user)
expect(doc.css('a').last.text).to eq('')
end
it 'adds text with standard formatting' do
issue = create(:issue, :closed)
link = create_link(
'something <strong>else</strong>'.html_safe,
issue: issue.id,
reference_type: 'issue'
)
doc = filter(link, current_user: user)
expect(doc.css('a').last.inner_html).
to eq('something <strong>else</strong> [closed]')
end
context 'for issue references' do
it 'ignores open issue references' do
issue = create(:issue)
link = create_link(issue: issue.id, reference_type: 'issue')
link = create_link('text', issue: issue.id, reference_type: 'issue')
doc = filter(link, current_user: user)
expect(doc.css('a').last.text).to eq('text')
......@@ -36,7 +57,7 @@ describe Banzai::Filter::IssuableStateFilter, lib: true do
it 'ignores reopened issue references' do
reopened_issue = create(:issue, :reopened)
link = create_link(issue: reopened_issue.id, reference_type: 'issue')
link = create_link('text', issue: reopened_issue.id, reference_type: 'issue')
doc = filter(link, current_user: user)
expect(doc.css('a').last.text).to eq('text')
......@@ -44,7 +65,7 @@ describe Banzai::Filter::IssuableStateFilter, lib: true do
it 'appends [closed] to closed issue references' do
closed_issue = create(:issue, :closed)
link = create_link(issue: closed_issue.id, reference_type: 'issue')
link = create_link('text', issue: closed_issue.id, reference_type: 'issue')
doc = filter(link, current_user: user)
expect(doc.css('a').last.text).to eq('text [closed]')
......@@ -54,7 +75,7 @@ describe Banzai::Filter::IssuableStateFilter, lib: true do
context 'for merge request references' do
it 'ignores open merge request references' do
mr = create(:merge_request)
link = create_link(merge_request: mr.id, reference_type: 'merge_request')
link = create_link('text', merge_request: mr.id, reference_type: 'merge_request')
doc = filter(link, current_user: user)
expect(doc.css('a').last.text).to eq('text')
......@@ -62,7 +83,7 @@ describe Banzai::Filter::IssuableStateFilter, lib: true do
it 'ignores reopened merge request references' do
mr = create(:merge_request, :reopened)
link = create_link(merge_request: mr.id, reference_type: 'merge_request')
link = create_link('text', merge_request: mr.id, reference_type: 'merge_request')
doc = filter(link, current_user: user)
expect(doc.css('a').last.text).to eq('text')
......@@ -70,7 +91,7 @@ describe Banzai::Filter::IssuableStateFilter, lib: true do
it 'ignores locked merge request references' do
mr = create(:merge_request, :locked)
link = create_link(merge_request: mr.id, reference_type: 'merge_request')
link = create_link('text', merge_request: mr.id, reference_type: 'merge_request')
doc = filter(link, current_user: user)
expect(doc.css('a').last.text).to eq('text')
......@@ -78,7 +99,7 @@ describe Banzai::Filter::IssuableStateFilter, lib: true do
it 'appends [closed] to closed merge request references' do
mr = create(:merge_request, :closed)
link = create_link(merge_request: mr.id, reference_type: 'merge_request')
link = create_link('text', merge_request: mr.id, reference_type: 'merge_request')
doc = filter(link, current_user: user)
expect(doc.css('a').last.text).to eq('text [closed]')
......@@ -86,7 +107,7 @@ describe Banzai::Filter::IssuableStateFilter, lib: true do
it 'appends [merged] to merged merge request references' do
mr = create(:merge_request, :merged)
link = create_link(merge_request: mr.id, reference_type: 'merge_request')
link = create_link('text', merge_request: mr.id, reference_type: 'merge_request')
doc = filter(link, current_user: user)
expect(doc.css('a').last.text).to eq('text [merged]')
......
......@@ -33,10 +33,20 @@ describe ContainerRegistry::Path do
end
describe '#to_s' do
context 'when path does not have uppercase characters' do
let(:path) { 'some/image' }
it 'return a string with a repository path' do
expect(subject.to_s).to eq path
expect(subject.to_s).to eq 'some/image'
end
end
context 'when path has uppercase characters' do
let(:path) { 'SoMe/ImAgE' }
it 'return a string with a repository path' do
expect(subject.to_s).to eq 'some/image'
end
end
end
......@@ -70,6 +80,12 @@ describe ContainerRegistry::Path do
it { is_expected.to be_valid }
end
context 'when path contains uppercase letters' do
let(:path) { 'Some/Registry' }
it { is_expected.to be_valid }
end
end
describe '#has_repository?' do
......
......@@ -17,12 +17,12 @@ describe Gitlab::Ci::Trace::Stream do
describe '#limit' do
let(:stream) do
described_class.new do
StringIO.new("12345678")
StringIO.new((1..8).to_a.join("\n"))
end
end
it 'if size is larger we start from beggining' do
stream.limit(10)
it 'if size is larger we start from beginning' do
stream.limit(20)
expect(stream.tell).to eq(0)
end
......@@ -30,7 +30,27 @@ describe Gitlab::Ci::Trace::Stream do
it 'if size is smaller we start from the end' do
stream.limit(2)
expect(stream.tell).to eq(6)
expect(stream.raw).to eq("8")
end
context 'when the trace contains ANSI sequence and Unicode' do
let(:stream) do
described_class.new do
File.open(expand_fixture_path('trace/ansi-sequence-and-unicode'))
end
end
it 'forwards to the next linefeed, case 1' do
stream.limit(7)
expect(stream.raw).to eq('')
end
it 'forwards to the next linefeed, case 2' do
stream.limit(29)
expect(stream.raw).to eq("\e[01;32m許功蓋\e[0m\n")
end
end
end
......
......@@ -34,11 +34,21 @@ describe ContainerRepository do
end
describe '#path' do
context 'when project path does not contain uppercase letters' do
it 'returns a full path to the repository' do
expect(repository.path).to eq('group/test/my_image')
end
end
context 'when path contains uppercase letters' do
let(:project) { create(:project, path: 'MY_PROJECT', group: group) }
it 'returns a full path without capital letters' do
expect(repository.path).to eq('group/my_project/my_image')
end
end
end
describe '#manifest' do
it 'returns non-empty manifest' do
expect(repository.manifest).not_to be_nil
......
module FixtureHelpers
def fixture_file(filename)
return '' if filename.blank?
file_path = File.expand_path(Rails.root.join('spec/fixtures/', filename))
File.read(file_path)
File.read(expand_fixture_path(filename))
end
def expand_fixture_path(filename)
File.expand_path(Rails.root.join('spec/fixtures/', filename))
end
end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment