Commit 7cce2c28 authored by GitLab Bot's avatar GitLab Bot

Merge remote-tracking branch 'upstream/master' into ce-to-ee-2018-10-10

# Conflicts:
#	app/assets/javascripts/boards/index.js
#	app/assets/javascripts/boards/models/list.js
#	app/assets/javascripts/boards/stores/boards_store.js
#	spec/javascripts/boards/mock_data.js

[ci skip]
parents efe49ae6 6947890e
...@@ -216,6 +216,7 @@ the stable branch are: ...@@ -216,6 +216,7 @@ the stable branch are:
* Fixes or improvements to automated QA scenarios * Fixes or improvements to automated QA scenarios
* [Documentation updates](https://docs.gitlab.com/ee/development/documentation/workflow.html#documentation-shipped-late) for changes in the same release * [Documentation updates](https://docs.gitlab.com/ee/development/documentation/workflow.html#documentation-shipped-late) for changes in the same release
* New or updated translations (as long as they do not touch application code) * New or updated translations (as long as they do not touch application code)
* Changes that are behind a feature flag and have the ~"feature flag" label
During the feature freeze all merge requests that are meant to go into the During the feature freeze all merge requests that are meant to go into the
upcoming release should have the correct milestone assigned _and_ the upcoming release should have the correct milestone assigned _and_ the
......
...@@ -16,6 +16,7 @@ import boardsStore from './stores/boards_store'; ...@@ -16,6 +16,7 @@ import boardsStore from './stores/boards_store';
import ModalStore from './stores/modal_store'; import ModalStore from './stores/modal_store';
import modalMixin from './mixins/modal_mixins'; import modalMixin from './mixins/modal_mixins';
import './filters/due_date_filters'; import './filters/due_date_filters';
<<<<<<< HEAD
import Board from 'ee/boards/components/board'; import Board from 'ee/boards/components/board';
import BoardSidebar from 'ee/boards/components/board_sidebar'; import BoardSidebar from 'ee/boards/components/board_sidebar';
import initNewListDropdown from './components/new_list_dropdown'; import initNewListDropdown from './components/new_list_dropdown';
...@@ -32,11 +33,23 @@ import collapseIcon from 'ee/boards/icons/fullscreen_collapse.svg'; ...@@ -32,11 +33,23 @@ import collapseIcon from 'ee/boards/icons/fullscreen_collapse.svg';
import expandIcon from 'ee/boards/icons/fullscreen_expand.svg'; import expandIcon from 'ee/boards/icons/fullscreen_expand.svg';
import tooltip from '~/vue_shared/directives/tooltip'; import tooltip from '~/vue_shared/directives/tooltip';
=======
import Board from './components/board';
import BoardSidebar from './components/board_sidebar';
import initNewListDropdown from './components/new_list_dropdown';
import BoardAddIssuesModal from './components/modal/index.vue';
import '~/vue_shared/vue_resource_interceptor';
import { NavigationType } from '~/lib/utils/common_utils';
>>>>>>> upstream/master
let issueBoardsApp; let issueBoardsApp;
export default () => { export default () => {
const $boardApp = document.getElementById('board-app'); const $boardApp = document.getElementById('board-app');
<<<<<<< HEAD
const issueBoardsContent = document.querySelector('.content-wrapper > .js-focus-mode-board'); const issueBoardsContent = document.querySelector('.content-wrapper > .js-focus-mode-board');
=======
>>>>>>> upstream/master
// check for browser back and trigger a hard reload to circumvent browser caching. // check for browser back and trigger a hard reload to circumvent browser caching.
window.addEventListener('pageshow', (event) => { window.addEventListener('pageshow', (event) => {
...@@ -121,7 +134,10 @@ export default () => { ...@@ -121,7 +134,10 @@ export default () => {
this.state.lists = _.sortBy(this.state.lists, 'position'); this.state.lists = _.sortBy(this.state.lists, 'position');
boardsStore.addBlankState(); boardsStore.addBlankState();
<<<<<<< HEAD
boardsStore.addPromotionState(); boardsStore.addPromotionState();
=======
>>>>>>> upstream/master
this.loading = false; this.loading = false;
}) })
.catch(() => { .catch(() => {
...@@ -187,7 +203,10 @@ export default () => { ...@@ -187,7 +203,10 @@ export default () => {
el: document.getElementById('js-add-list'), el: document.getElementById('js-add-list'),
data: { data: {
filters: boardsStore.state.filters, filters: boardsStore.state.filters,
<<<<<<< HEAD
milestoneTitle: $boardApp.dataset.boardMilestoneTitle, milestoneTitle: $boardApp.dataset.boardMilestoneTitle,
=======
>>>>>>> upstream/master
}, },
mounted() { mounted() {
initNewListDropdown(); initNewListDropdown();
...@@ -248,8 +267,11 @@ export default () => { ...@@ -248,8 +267,11 @@ export default () => {
return { return {
modal: ModalStore.store, modal: ModalStore.store,
store: boardsStore.state, store: boardsStore.state,
<<<<<<< HEAD
isFullscreen: false, isFullscreen: false,
focusModeAvailable: $boardApp.hasAttribute('data-focus-mode-available'), focusModeAvailable: $boardApp.hasAttribute('data-focus-mode-available'),
=======
>>>>>>> upstream/master
canAdminList: this.$options.el.hasAttribute('data-can-admin-list'), canAdminList: this.$options.el.hasAttribute('data-can-admin-list'),
}; };
}, },
......
...@@ -6,7 +6,10 @@ import ListLabel from '~/vue_shared/models/label'; ...@@ -6,7 +6,10 @@ import ListLabel from '~/vue_shared/models/label';
import ListAssignee from '~/vue_shared/models/assignee'; import ListAssignee from '~/vue_shared/models/assignee';
import { urlParamsToObject } from '~/lib/utils/common_utils'; import { urlParamsToObject } from '~/lib/utils/common_utils';
import boardsStore from '../stores/boards_store'; import boardsStore from '../stores/boards_store';
<<<<<<< HEAD
import ListMilestone from './milestone'; import ListMilestone from './milestone';
=======
>>>>>>> upstream/master
const PER_PAGE = 20; const PER_PAGE = 20;
......
...@@ -184,8 +184,11 @@ const boardsStore = { ...@@ -184,8 +184,11 @@ const boardsStore = {
} }
}; };
<<<<<<< HEAD
BoardsStoreEE.initEESpecific(boardsStore); BoardsStoreEE.initEESpecific(boardsStore);
=======
>>>>>>> upstream/master
// hacks added in order to allow milestone_select to function properly // hacks added in order to allow milestone_select to function properly
// TODO: remove these // TODO: remove these
......
...@@ -38,14 +38,18 @@ export default { ...@@ -38,14 +38,18 @@ export default {
return this.modifiedFilesLength ? 'multi-file-modified' : ''; return this.modifiedFilesLength ? 'multi-file-modified' : '';
}, },
additionsTooltip() { additionsTooltip() {
return sprintf(n__('1 %{type} addition', '%{count} %{type} additions', this.addedFilesLength), { return sprintf(
n__('1 %{type} addition', '%{count} %{type} additions', this.addedFilesLength),
{
type: this.title.toLowerCase(), type: this.title.toLowerCase(),
count: this.addedFilesLength, count: this.addedFilesLength,
}); },
);
}, },
modifiedTooltip() { modifiedTooltip() {
return sprintf( return sprintf(
n__('1 %{type} modification', '%{count} %{type} modifications', this.modifiedFilesLength), { n__('1 %{type} modification', '%{count} %{type} modifications', this.modifiedFilesLength),
{
type: this.title.toLowerCase(), type: this.title.toLowerCase(),
count: this.modifiedFilesLength, count: this.modifiedFilesLength,
}, },
......
...@@ -25,10 +25,7 @@ export default { ...@@ -25,10 +25,7 @@ export default {
return `discard-file-${this.path}`; return `discard-file-${this.path}`;
}, },
modalTitle() { modalTitle() {
return sprintf( return sprintf(__('Discard changes to %{path}?'), { path: this.path });
__('Discard changes to %{path}?'),
{ path: this.path },
);
}, },
}, },
methods: { methods: {
......
...@@ -24,13 +24,7 @@ export default { ...@@ -24,13 +24,7 @@ export default {
IdeProjectHeader, IdeProjectHeader,
}, },
computed: { computed: {
...mapState([ ...mapState(['loading', 'currentActivityView', 'changedFiles', 'stagedFiles', 'lastCommitMsg']),
'loading',
'currentActivityView',
'changedFiles',
'stagedFiles',
'lastCommitMsg',
]),
...mapGetters(['currentProject', 'someUncommitedChanges']), ...mapGetters(['currentProject', 'someUncommitedChanges']),
showSuccessMessage() { showSuccessMessage() {
return ( return (
......
...@@ -37,14 +37,10 @@ export default { ...@@ -37,14 +37,10 @@ export default {
return this.hasSearchFocus && !this.search && !this.currentSearchType; return this.hasSearchFocus && !this.search && !this.currentSearchType;
}, },
type() { type() {
return this.currentSearchType return this.currentSearchType ? this.currentSearchType.type : '';
? this.currentSearchType.type
: '';
}, },
searchTokens() { searchTokens() {
return this.currentSearchType return this.currentSearchType ? [this.currentSearchType] : [];
? [this.currentSearchType]
: [];
}, },
}, },
watch: { watch: {
......
...@@ -13,9 +13,7 @@ export default { ...@@ -13,9 +13,7 @@ export default {
computed: { computed: {
...mapState(['currentBranchId', 'currentMergeRequestId']), ...mapState(['currentBranchId', 'currentMergeRequestId']),
mergeRequestLabel() { mergeRequestLabel() {
return this.currentMergeRequestId return this.currentMergeRequestId ? `!${this.currentMergeRequestId}` : EMPTY_LABEL;
? `!${this.currentMergeRequestId}`
: EMPTY_LABEL;
}, },
branchLabel() { branchLabel() {
return this.currentBranchId || EMPTY_LABEL; return this.currentBranchId || EMPTY_LABEL;
......
...@@ -43,34 +43,25 @@ export default { ...@@ -43,34 +43,25 @@ export default {
{ {
show: this.currentMergeRequestId, show: this.currentMergeRequestId,
title: __('Merge Request'), title: __('Merge Request'),
views: [ views: [rightSidebarViews.mergeRequestInfo],
rightSidebarViews.mergeRequestInfo,
],
icon: 'text-description', icon: 'text-description',
}, },
{ {
show: true, show: true,
title: __('Pipelines'), title: __('Pipelines'),
views: [ views: [rightSidebarViews.pipelines, rightSidebarViews.jobsDetail],
rightSidebarViews.pipelines,
rightSidebarViews.jobsDetail,
],
icon: 'rocket', icon: 'rocket',
}, },
{ {
show: this.showLivePreview, show: this.showLivePreview,
title: __('Live preview'), title: __('Live preview'),
views: [ views: [rightSidebarViews.clientSidePreview],
rightSidebarViews.clientSidePreview,
],
icon: 'live-preview', icon: 'live-preview',
}, },
]; ];
}, },
tabs() { tabs() {
return this.defaultTabs return this.defaultTabs.concat(this.extensionTabs).filter(tab => tab.show);
.concat(this.extensionTabs)
.filter(tab => tab.show);
}, },
tabViews() { tabViews() {
return _.flatten(this.tabs.map(tab => tab.views)); return _.flatten(this.tabs.map(tab => tab.views));
......
...@@ -25,12 +25,7 @@ export default { ...@@ -25,12 +25,7 @@ export default {
...mapState('rightPane', { ...mapState('rightPane', {
rightPaneIsOpen: 'isOpen', rightPaneIsOpen: 'isOpen',
}), }),
...mapState([ ...mapState(['rightPanelCollapsed', 'viewer', 'panelResizing', 'currentActivityView']),
'rightPanelCollapsed',
'viewer',
'panelResizing',
'currentActivityView',
]),
...mapGetters([ ...mapGetters([
'currentMergeRequest', 'currentMergeRequest',
'getStagedFile', 'getStagedFile',
......
...@@ -30,9 +30,7 @@ export default { ...@@ -30,9 +30,7 @@ export default {
}, },
computed: { computed: {
placeholderText() { placeholderText() {
return this.tokens.length return this.tokens.length ? '' : this.placeholder;
? ''
: this.placeholder;
}, },
}, },
watch: { watch: {
......
...@@ -21,10 +21,7 @@ Vue.use(Translate); ...@@ -21,10 +21,7 @@ Vue.use(Translate);
export function initIde(el, options = {}) { export function initIde(el, options = {}) {
if (!el) return null; if (!el) return null;
const { const { extraInitialData = () => ({}), rootComponent = ide } = options;
extraInitialData = () => ({}),
rootComponent = ide,
} = options;
return new Vue({ return new Vue({
el, el,
......
...@@ -11,14 +11,16 @@ export const computeDiff = (originalContent, newContent) => { ...@@ -11,14 +11,16 @@ export const computeDiff = (originalContent, newContent) => {
if (findOnLine) { if (findOnLine) {
Object.assign(findOnLine, change, { Object.assign(findOnLine, change, {
modified: true, modified: true,
endLineNumber: (lineNumber + change.count) - 1, endLineNumber: lineNumber + change.count - 1,
}); });
} else if ('added' in change || 'removed' in change) { } else if ('added' in change || 'removed' in change) {
acc.push(Object.assign({}, change, { acc.push(
Object.assign({}, change, {
lineNumber, lineNumber,
modified: undefined, modified: undefined,
endLineNumber: (lineNumber + change.count) - 1, endLineNumber: lineNumber + change.count - 1,
})); }),
);
} }
if (!change.removed) { if (!change.removed) {
......
import { computeDiff } from './diff'; import { computeDiff } from './diff';
// eslint-disable-next-line no-restricted-globals // eslint-disable-next-line no-restricted-globals
self.addEventListener('message', (e) => { self.addEventListener('message', e => {
const { data } = e; const { data } = e;
// eslint-disable-next-line no-restricted-globals // eslint-disable-next-line no-restricted-globals
......
...@@ -125,10 +125,7 @@ export const showBranchNotFoundError = ({ dispatch }, branchId) => { ...@@ -125,10 +125,7 @@ export const showBranchNotFoundError = ({ dispatch }, branchId) => {
}); });
}; };
export const openBranch = ( export const openBranch = ({ dispatch, state }, { projectId, branchId, basePath }) => {
{ dispatch, state },
{ projectId, branchId, basePath },
) => {
dispatch('setCurrentBranchId', branchId); dispatch('setCurrentBranchId', branchId);
dispatch('getBranchData', { dispatch('getBranchData', {
...@@ -136,12 +133,10 @@ export const openBranch = ( ...@@ -136,12 +133,10 @@ export const openBranch = (
branchId, branchId,
}); });
return ( return dispatch('getFiles', {
dispatch('getFiles', {
projectId, projectId,
branchId, branchId,
}) }).then(() => {
.then(() => {
if (basePath) { if (basePath) {
const path = basePath.slice(-1) === '/' ? basePath.slice(0, -1) : basePath; const path = basePath.slice(-1) === '/' ? basePath.slice(0, -1) : basePath;
const treeEntryKey = Object.keys(state.entries).find( const treeEntryKey = Object.keys(state.entries).find(
...@@ -153,6 +148,5 @@ export const openBranch = ( ...@@ -153,6 +148,5 @@ export const openBranch = (
dispatch('handleTreeEntryAction', treeEntry); dispatch('handleTreeEntryAction', treeEntry);
} }
} }
}) });
);
}; };
...@@ -3,8 +3,7 @@ import Api from '../../../../api'; ...@@ -3,8 +3,7 @@ import Api from '../../../../api';
import { scopes } from './constants'; import { scopes } from './constants';
import * as types from './mutation_types'; import * as types from './mutation_types';
export const requestMergeRequests = ({ commit }) => export const requestMergeRequests = ({ commit }) => commit(types.REQUEST_MERGE_REQUESTS);
commit(types.REQUEST_MERGE_REQUESTS);
export const receiveMergeRequestsError = ({ commit, dispatch }, { type, search }) => { export const receiveMergeRequestsError = ({ commit, dispatch }, { type, search }) => {
dispatch( dispatch(
'setErrorMessage', 'setErrorMessage',
......
<script> <script>
import Visibility from 'visibilityjs'; import Visibility from 'visibilityjs';
import { visitUrl } from '../../lib/utils/url_utility'; import { visitUrl } from '../../lib/utils/url_utility';
import Poll from '../../lib/utils/poll'; import Poll from '../../lib/utils/poll';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import Service from '../services/index'; import Service from '../services/index';
import Store from '../stores'; import Store from '../stores';
import titleComponent from './title.vue'; import titleComponent from './title.vue';
import descriptionComponent from './description.vue'; import descriptionComponent from './description.vue';
import editedComponent from './edited.vue'; import editedComponent from './edited.vue';
import formComponent from './form.vue'; import formComponent from './form.vue';
import recaptchaModalImplementor from '../../vue_shared/mixins/recaptcha_modal_implementor'; import recaptchaModalImplementor from '../../vue_shared/mixins/recaptcha_modal_implementor';
export default { export default {
components: { components: {
descriptionComponent, descriptionComponent,
titleComponent, titleComponent,
editedComponent, editedComponent,
formComponent, formComponent,
}, },
mixins: [ mixins: [recaptchaModalImplementor],
recaptchaModalImplementor,
],
props: { props: {
endpoint: { endpoint: {
required: true, required: true,
...@@ -158,10 +156,8 @@ ...@@ -158,10 +156,8 @@
return !!this.state.updatedAt; return !!this.state.updatedAt;
}, },
issueChanged() { issueChanged() {
const descriptionChanged = const descriptionChanged = this.initialDescriptionText !== this.store.formState.description;
this.initialDescriptionText !== this.store.formState.description; const titleChanged = this.initialTitleText !== this.store.formState.title;
const titleChanged =
this.initialTitleText !== this.store.formState.title;
return descriptionChanged || titleChanged; return descriptionChanged || titleChanged;
}, },
}, },
...@@ -227,10 +223,11 @@ ...@@ -227,10 +223,11 @@
}, },
updateIssuable() { updateIssuable() {
return this.service.updateIssuable(this.store.formState) return this.service
.updateIssuable(this.store.formState)
.then(res => res.data) .then(res => res.data)
.then(data => this.checkForSpam(data)) .then(data => this.checkForSpam(data))
.then((data) => { .then(data => {
if (window.location.pathname !== data.web_url) { if (window.location.pathname !== data.web_url) {
visitUrl(data.web_url); visitUrl(data.web_url);
} }
...@@ -238,11 +235,11 @@ ...@@ -238,11 +235,11 @@
return this.service.getData(); return this.service.getData();
}) })
.then(res => res.data) .then(res => res.data)
.then((data) => { .then(data => {
this.store.updateState(data); this.store.updateState(data);
eventHub.$emit('close.form'); eventHub.$emit('close.form');
}) })
.catch((error) => { .catch(error => {
if (error && error.name === 'SpamError') { if (error && error.name === 'SpamError') {
this.openRecaptcha(); this.openRecaptcha();
} else { } else {
...@@ -261,9 +258,10 @@ ...@@ -261,9 +258,10 @@
}, },
deleteIssuable() { deleteIssuable() {
this.service.deleteIssuable() this.service
.deleteIssuable()
.then(res => res.data) .then(res => res.data)
.then((data) => { .then(data => {
// Stop the poll so we don't get 404's with the issuable not existing // Stop the poll so we don't get 404's with the issuable not existing
this.poll.stop(); this.poll.stop();
...@@ -275,7 +273,7 @@ ...@@ -275,7 +273,7 @@
}); });
}, },
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
import $ from 'jquery'; import $ from 'jquery';
import animateMixin from '../mixins/animate'; import animateMixin from '../mixins/animate';
import TaskList from '../../task_list'; import TaskList from '../../task_list';
import recaptchaModalImplementor from '../../vue_shared/mixins/recaptcha_modal_implementor'; import recaptchaModalImplementor from '../../vue_shared/mixins/recaptcha_modal_implementor';
export default { export default {
mixins: [ mixins: [animateMixin, recaptchaModalImplementor],
animateMixin,
recaptchaModalImplementor,
],
props: { props: {
canUpdate: { canUpdate: {
...@@ -94,9 +91,7 @@ ...@@ -94,9 +91,7 @@
if (taskRegexMatches) { if (taskRegexMatches) {
$tasks.text(this.taskStatus); $tasks.text(this.taskStatus);
$tasksShort.text( $tasksShort.text(
`${taskRegexMatches[1]}/${taskRegexMatches[2]} task${taskRegexMatches[2] > 1 ? `${taskRegexMatches[1]}/${taskRegexMatches[2]} task${taskRegexMatches[2] > 1 ? 's' : ''}`,
's' :
''}`,
); );
} else { } else {
$tasks.text(''); $tasks.text('');
...@@ -104,7 +99,7 @@ ...@@ -104,7 +99,7 @@
} }
}, },
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
import { __, sprintf } from '~/locale'; import { __, sprintf } from '~/locale';
import updateMixin from '../mixins/update'; import updateMixin from '../mixins/update';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
const issuableTypes = { const issuableTypes = {
issue: __('Issue'), issue: __('Issue'),
epic: __('Epic'), epic: __('Epic'),
}; };
export default { export default {
mixins: [updateMixin], mixins: [updateMixin],
props: { props: {
canDestroy: { canDestroy: {
...@@ -58,7 +58,7 @@ ...@@ -58,7 +58,7 @@
} }
}, },
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
import timeAgoTooltip from '../../vue_shared/components/time_ago_tooltip.vue'; import timeAgoTooltip from '../../vue_shared/components/time_ago_tooltip.vue';
export default { export default {
components: { components: {
timeAgoTooltip, timeAgoTooltip,
}, },
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
return this.updatedByName && this.updatedByPath; return this.updatedByName && this.updatedByPath;
}, },
}, },
}; };
</script> </script>
<template> <template>
...@@ -53,4 +53,3 @@ ...@@ -53,4 +53,3 @@
</span> </span>
</small> </small>
</template> </template>
<script> <script>
import updateMixin from '../../mixins/update'; import updateMixin from '../../mixins/update';
import markdownField from '../../../vue_shared/components/markdown/field.vue'; import markdownField from '../../../vue_shared/components/markdown/field.vue';
export default { export default {
components: { components: {
markdownField, markdownField,
}, },
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
mounted() { mounted() {
this.$refs.textarea.focus(); this.$refs.textarea.focus();
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
import $ from 'jquery'; import $ from 'jquery';
import IssuableTemplateSelectors from '../../../templates/issuable_template_selectors'; import IssuableTemplateSelectors from '../../../templates/issuable_template_selectors';
export default { export default {
props: { props: {
formState: { formState: {
type: Object, type: Object,
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
mounted() { mounted() {
// Create the editor for the template // Create the editor for the template
const editor = document.querySelector('.detail-page-description .note-textarea') || {}; const editor = document.querySelector('.detail-page-description .note-textarea') || {};
editor.setValue = (val) => { editor.setValue = val => {
this.formState.description = val; this.formState.description = val;
}; };
editor.getValue = () => this.formState.description; editor.getValue = () => this.formState.description;
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
editor, editor,
}); });
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
import updateMixin from '../../mixins/update'; import updateMixin from '../../mixins/update';
export default { export default {
mixins: [updateMixin], mixins: [updateMixin],
props: { props: {
formState: { formState: {
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
required: true, required: true,
}, },
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
import lockedWarning from './locked_warning.vue'; import lockedWarning from './locked_warning.vue';
import titleField from './fields/title.vue'; import titleField from './fields/title.vue';
import descriptionField from './fields/description.vue'; import descriptionField from './fields/description.vue';
import editActions from './edit_actions.vue'; import editActions from './edit_actions.vue';
import descriptionTemplate from './fields/description_template.vue'; import descriptionTemplate from './fields/description_template.vue';
export default { export default {
components: { components: {
lockedWarning, lockedWarning,
titleField, titleField,
...@@ -73,7 +73,7 @@ ...@@ -73,7 +73,7 @@
return this.issuableTemplates.length; return this.issuableTemplates.length;
}, },
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
export default { export default {
computed: { computed: {
currentPath() { currentPath() {
return window.location.pathname; return window.location.pathname;
}, },
}, },
}; };
</script> </script>
<template> <template>
......
...@@ -25,8 +25,10 @@ export default class Store { ...@@ -25,8 +25,10 @@ export default class Store {
} }
stateShouldUpdate(data) { stateShouldUpdate(data) {
return this.state.titleText !== data.title_text || return (
this.state.descriptionText !== data.description_text; this.state.titleText !== data.title_text ||
this.state.descriptionText !== data.description_text
);
} }
setFormState(state) { setFormState(state) {
......
<script> <script>
import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import timeagoMixin from '~/vue_shared/mixins/timeago'; import timeagoMixin from '~/vue_shared/mixins/timeago';
export default { export default {
components: { components: {
TimeagoTooltip, TimeagoTooltip,
}, },
mixins: [ mixins: [timeagoMixin],
timeagoMixin,
],
props: { props: {
artifact: { artifact: {
type: Object, type: Object,
...@@ -24,7 +22,7 @@ ...@@ -24,7 +22,7 @@
return this.artifact.expired === false; return this.artifact.expired === false;
}, },
}, },
}; };
</script> </script>
<template> <template>
<div class="block"> <div class="block">
......
<script> <script>
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
export default { export default {
components: { components: {
ClipboardButton, ClipboardButton,
}, },
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
required: true, required: true,
}, },
}, },
}; };
</script> </script>
<template> <template>
<div <div
......
<script> <script>
export default { export default {
props: { props: {
illustrationPath: { illustrationPath: {
type: String, type: String,
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
}, },
}, },
}, },
}; };
</script> </script>
<template> <template>
<div class="row empty-state"> <div class="row empty-state">
......
<script> <script>
import _ from 'underscore'; import _ from 'underscore';
import CiIcon from '~/vue_shared/components/ci_icon.vue'; import CiIcon from '~/vue_shared/components/ci_icon.vue';
import { sprintf, __ } from '../../locale'; import { sprintf, __ } from '../../locale';
export default { export default {
components: { components: {
CiIcon, CiIcon,
}, },
...@@ -107,7 +107,9 @@ ...@@ -107,7 +107,9 @@
return !_.isEmpty(this.deploymentStatus.environment); return !_.isEmpty(this.deploymentStatus.environment);
}, },
lastDeploymentPath() { lastDeploymentPath() {
return !_.isEmpty(this.lastDeployment.deployable) ? this.lastDeployment.deployable.build_path : ''; return !_.isEmpty(this.lastDeployment.deployable)
? this.lastDeployment.deployable.build_path
: '';
}, },
}, },
methods: { methods: {
...@@ -123,7 +125,7 @@ ...@@ -123,7 +125,7 @@
); );
}, },
}, },
}; };
</script> </script>
<template> <template>
<div class="prepend-top-default js-environment-container"> <div class="prepend-top-default js-environment-container">
......
<script> <script>
import _ from 'underscore'; import _ from 'underscore';
import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
export default { export default {
components: { components: {
TimeagoTooltip, TimeagoTooltip,
}, },
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
return !_.isEmpty(this.user); return !_.isEmpty(this.user);
}, },
}, },
}; };
</script> </script>
<template> <template>
<div class="prepend-top-default js-build-erased"> <div class="prepend-top-default js-build-erased">
......
<script> <script>
export default { export default {
name: 'JobLog', name: 'JobLog',
props: { props: {
trace: { trace: {
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
required: true, required: true,
}, },
}, },
}; };
</script> </script>
<template> <template>
<pre class="build-trace"> <pre class="build-trace">
......
<script> <script>
import { polyfillSticky } from '~/lib/utils/sticky'; import { polyfillSticky } from '~/lib/utils/sticky';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import tooltip from '~/vue_shared/directives/tooltip'; import tooltip from '~/vue_shared/directives/tooltip';
import { numberToHumanSize } from '~/lib/utils/number_utils'; import { numberToHumanSize } from '~/lib/utils/number_utils';
import { sprintf } from '~/locale'; import { sprintf } from '~/locale';
export default { export default {
components: { components: {
Icon, Icon,
}, },
...@@ -62,8 +62,7 @@ ...@@ -62,8 +62,7 @@
this.$emit('scrollJobLogBottom'); this.$emit('scrollJobLogBottom');
}, },
}, },
};
};
</script> </script>
<template> <template>
<div class="top-bar"> <div class="top-bar">
......
<script> <script>
import _ from 'underscore'; import _ from 'underscore';
import CiIcon from '~/vue_shared/components/ci_icon.vue'; import CiIcon from '~/vue_shared/components/ci_icon.vue';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import tooltip from '~/vue_shared/directives/tooltip'; import tooltip from '~/vue_shared/directives/tooltip';
export default { export default {
components: { components: {
CiIcon, CiIcon,
Icon, Icon,
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
return `${_.escape(job.name)} - ${job.status.tooltip}`; return `${_.escape(job.name)} - ${job.status.tooltip}`;
}, },
}, },
}; };
</script> </script>
<template> <template>
<div class="js-jobs-container builds-container"> <div class="js-jobs-container builds-container">
......
<script> <script>
import _ from 'underscore'; import _ from 'underscore';
import { mapActions, mapState } from 'vuex'; import { mapActions, mapState } from 'vuex';
import timeagoMixin from '~/vue_shared/mixins/timeago'; import timeagoMixin from '~/vue_shared/mixins/timeago';
import { timeIntervalInWords } from '~/lib/utils/datetime_utility'; import { timeIntervalInWords } from '~/lib/utils/datetime_utility';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import DetailRow from './sidebar_detail_row.vue'; import DetailRow from './sidebar_detail_row.vue';
import ArtifactsBlock from './artifacts_block.vue'; import ArtifactsBlock from './artifacts_block.vue';
import TriggerBlock from './trigger_block.vue'; import TriggerBlock from './trigger_block.vue';
import CommitBlock from './commit_block.vue'; import CommitBlock from './commit_block.vue';
import StagesDropdown from './stages_dropdown.vue'; import StagesDropdown from './stages_dropdown.vue';
import JobsContainer from './jobs_container.vue'; import JobsContainer from './jobs_container.vue';
export default { export default {
name: 'JobSidebar', name: 'JobSidebar',
components: { components: {
ArtifactsBlock, ArtifactsBlock,
...@@ -106,7 +106,7 @@ ...@@ -106,7 +106,7 @@
methods: { methods: {
...mapActions(['fetchJobsForStage']), ...mapActions(['fetchJobsForStage']),
}, },
}; };
</script> </script>
<template> <template>
<aside <aside
......
<script> <script>
export default { export default {
name: 'SidebarDetailRow', name: 'SidebarDetailRow',
props: { props: {
title: { title: {
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
return this.helpUrl.length > 0; return this.helpUrl.length > 0;
}, },
}, },
}; };
</script> </script>
<template> <template>
<p class="build-detail-row"> <p class="build-detail-row">
......
<script> <script>
import _ from 'underscore'; import _ from 'underscore';
import CiIcon from '~/vue_shared/components/ci_icon.vue'; import CiIcon from '~/vue_shared/components/ci_icon.vue';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import { __ } from '~/locale'; import { __ } from '~/locale';
export default { export default {
components: { components: {
CiIcon, CiIcon,
Icon, Icon,
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
this.selectedStage = stage.name; this.selectedStage = stage.name;
}, },
}, },
}; };
</script> </script>
<template> <template>
<div class="block-last dropdown"> <div class="block-last dropdown">
......
<script> <script>
export default { export default {
props: { props: {
trigger: { trigger: {
type: Object, type: Object,
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
this.areVariablesVisible = true; this.areVariablesVisible = true;
}, },
}, },
}; };
</script> </script>
<template> <template>
......
...@@ -7,9 +7,10 @@ import mutations from './mutations'; ...@@ -7,9 +7,10 @@ import mutations from './mutations';
Vue.use(Vuex); Vue.use(Vuex);
export default () => new Vuex.Store({ export default () =>
new Vuex.Store({
actions, actions,
mutations, mutations,
getters, getters,
state: state(), state: state(),
}); });
...@@ -4,7 +4,7 @@ import Cache from './cache'; ...@@ -4,7 +4,7 @@ import Cache from './cache';
class AjaxCache extends Cache { class AjaxCache extends Cache {
constructor() { constructor() {
super(); super();
this.pendingRequests = { }; this.pendingRequests = {};
} }
override(endpoint, data) { override(endpoint, data) {
...@@ -19,12 +19,13 @@ class AjaxCache extends Cache { ...@@ -19,12 +19,13 @@ class AjaxCache extends Cache {
let pendingRequest = this.pendingRequests[endpoint]; let pendingRequest = this.pendingRequests[endpoint];
if (!pendingRequest) { if (!pendingRequest) {
pendingRequest = axios.get(endpoint) pendingRequest = axios
.get(endpoint)
.then(({ data }) => { .then(({ data }) => {
this.internalStorage[endpoint] = data; this.internalStorage[endpoint] = data;
delete this.pendingRequests[endpoint]; delete this.pendingRequests[endpoint];
}) })
.catch((e) => { .catch(e => {
const error = new Error(`${endpoint}: ${e.message}`); const error = new Error(`${endpoint}: ${e.message}`);
error.textStatus = e.message; error.textStatus = e.message;
......
...@@ -7,7 +7,7 @@ axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; ...@@ -7,7 +7,7 @@ axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
// Maintain a global counter for active requests // Maintain a global counter for active requests
// see: spec/support/wait_for_requests.rb // see: spec/support/wait_for_requests.rb
axios.interceptors.request.use((config) => { axios.interceptors.request.use(config => {
window.activeVueResources = window.activeVueResources || 0; window.activeVueResources = window.activeVueResources || 0;
window.activeVueResources += 1; window.activeVueResources += 1;
...@@ -15,15 +15,18 @@ axios.interceptors.request.use((config) => { ...@@ -15,15 +15,18 @@ axios.interceptors.request.use((config) => {
}); });
// Remove the global counter // Remove the global counter
axios.interceptors.response.use((config) => { axios.interceptors.response.use(
config => {
window.activeVueResources -= 1; window.activeVueResources -= 1;
return config; return config;
}, (e) => { },
e => {
window.activeVueResources -= 1; window.activeVueResources -= 1;
return Promise.reject(e); return Promise.reject(e);
}); },
);
export default axios; export default axios;
......
...@@ -93,9 +93,13 @@ export default class LinkedTabs { ...@@ -93,9 +93,13 @@ export default class LinkedTabs {
const newState = `${copySource}${this.currentLocation.search}${this.currentLocation.hash}`; const newState = `${copySource}${this.currentLocation.search}${this.currentLocation.hash}`;
window.history.replaceState({ window.history.replaceState(
{
url: newState, url: newState,
}, document.title, newState); },
document.title,
newState,
);
return newState; return newState;
} }
......
export default class Cache { export default class Cache {
constructor() { constructor() {
this.internalStorage = { }; this.internalStorage = {};
} }
get(key) { get(key) {
......
export const pad = (val, len = 2) => `0${val}`.slice(-len);
export const pad = (val, len = 2) => (`0${val}`).slice(-len);
/** /**
* Formats dates in Pickaday * Formats dates in Pickaday
* @param {String} dateString Date in yyyy-mm-dd format * @param {String} dateString Date in yyyy-mm-dd format
* @return {Date} UTC format * @return {Date} UTC format
*/ */
export const parsePikadayDate = (dateString) => { export const parsePikadayDate = dateString => {
const parts = dateString.split('-'); const parts = dateString.split('-');
const year = parseInt(parts[0], 10); const year = parseInt(parts[0], 10);
const month = parseInt(parts[1] - 1, 10); const month = parseInt(parts[1] - 1, 10);
...@@ -20,7 +19,7 @@ export const parsePikadayDate = (dateString) => { ...@@ -20,7 +19,7 @@ export const parsePikadayDate = (dateString) => {
* @param {Date} date UTC format * @param {Date} date UTC format
* @return {String} Date formated in yyyy-mm-dd * @return {String} Date formated in yyyy-mm-dd
*/ */
export const pikadayToString = (date) => { export const pikadayToString = date => {
const day = pad(date.getDate()); const day = pad(date.getDate());
const month = pad(date.getMonth() + 1); const month = pad(date.getMonth() + 1);
const year = date.getFullYear(); const year = date.getFullYear();
......
...@@ -8,7 +8,7 @@ function notificationGranted(message, opts, onclick) { ...@@ -8,7 +8,7 @@ function notificationGranted(message, opts, onclick) {
return notification.close(); return notification.close();
}, 8000); }, 8000);
return notification.onclick = onclick || notification.close; return (notification.onclick = onclick || notification.close);
} }
function notifyPermissions() { function notifyPermissions() {
...@@ -21,7 +21,7 @@ function notifyMe(message, body, icon, onclick) { ...@@ -21,7 +21,7 @@ function notifyMe(message, body, icon, onclick) {
var opts; var opts;
opts = { opts = {
body: body, body: body,
icon: icon icon: icon,
}; };
// Let's check if the browser supports notifications // Let's check if the browser supports notifications
if (!('Notification' in window)) { if (!('Notification' in window)) {
......
...@@ -27,10 +27,10 @@ export function parseSeconds(seconds, { daysPerWeek = 5, hoursPerDay = 8 } = {}) ...@@ -27,10 +27,10 @@ export function parseSeconds(seconds, { daysPerWeek = 5, hoursPerDay = 8 } = {})
let unorderedMinutes = Math.abs(seconds / MINUTES_PER_HOUR); let unorderedMinutes = Math.abs(seconds / MINUTES_PER_HOUR);
return _.mapObject(timePeriodConstraints, (minutesPerPeriod) => { return _.mapObject(timePeriodConstraints, minutesPerPeriod => {
const periodCount = Math.floor(unorderedMinutes / minutesPerPeriod); const periodCount = Math.floor(unorderedMinutes / minutesPerPeriod);
unorderedMinutes -= (periodCount * minutesPerPeriod); unorderedMinutes -= periodCount * minutesPerPeriod;
return periodCount; return periodCount;
}); });
...@@ -42,10 +42,14 @@ export function parseSeconds(seconds, { daysPerWeek = 5, hoursPerDay = 8 } = {}) ...@@ -42,10 +42,14 @@ export function parseSeconds(seconds, { daysPerWeek = 5, hoursPerDay = 8 } = {})
*/ */
export function stringifyTime(timeObject) { export function stringifyTime(timeObject) {
const reducedTime = _.reduce(timeObject, (memo, unitValue, unitName) => { const reducedTime = _.reduce(
timeObject,
(memo, unitValue, unitName) => {
const isNonZero = !!unitValue; const isNonZero = !!unitValue;
return isNonZero ? `${memo} ${unitValue}${unitName.charAt(0)}` : memo; return isNonZero ? `${memo} ${unitValue}${unitName.charAt(0)}` : memo;
}, '').trim(); },
'',
).trim();
return reducedTime.length ? reducedTime : '0m'; return reducedTime.length ? reducedTime : '0m';
} }
...@@ -55,7 +59,5 @@ export function stringifyTime(timeObject) { ...@@ -55,7 +59,5 @@ export function stringifyTime(timeObject) {
*/ */
export function abbreviateTime(timeStr) { export function abbreviateTime(timeStr) {
return timeStr.split(' ') return timeStr.split(' ').filter(unitStr => unitStr.charAt(0) !== '0')[0];
.filter(unitStr => unitStr.charAt(0) !== '0')[0];
} }
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
// Inspired by https://github.com/mishoo/UglifyJS/blob/2bc1d02363db3798d5df41fb5059a19edca9b7eb/lib/parse-js.js#L203 // Inspired by https://github.com/mishoo/UglifyJS/blob/2bc1d02363db3798d5df41fb5059a19edca9b7eb/lib/parse-js.js#L203
// Unicode 6.1 // Unicode 6.1
const unicodeLetters = '\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u0527\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0620-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0800-\\u0815\\u081A\\u0824\\u0828\\u0840-\\u0858\\u08A0\\u08A2-\\u08AC\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971-\\u0977\\u0979-\\u097F\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C33\\u0C35-\\u0C39\\u0C3D\\u0C58\\u0C59\\u0C60\\u0C61\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0CF1\\u0CF2\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D3A\\u0D3D\\u0D4E\\u0D60\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC-\\u0EDF\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8C\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10C7\\u10CD\\u10D0-\\u10FA\\u10FC-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F4\\u1401-\\u166C\\u166F-\\u167F\\u1681-\\u169A\\u16A0-\\u16EA\\u16EE-\\u16F0\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u18B0-\\u18F5\\u1900-\\u191C\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19AB\\u19C1-\\u19C7\\u1A00-\\u1A16\\u1A20-\\u1A54\\u1AA7\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1BBA-\\u1BE5\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1CE9-\\u1CEC\\u1CEE-\\u1CF1\\u1CF5\\u1CF6\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u209C\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2160-\\u2188\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2CE4\\u2CEB-\\u2CEE\\u2CF2\\u2CF3\\u2D00-\\u2D25\\u2D27\\u2D2D\\u2D30-\\u2D67\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005-\\u3007\\u3021-\\u3029\\u3031-\\u3035\\u3038-\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31BA\\u31F0-\\u31FF\\u3400-\\u4DB5\\u4E00-\\u9FCC\\uA000-\\uA48C\\uA4D0-\\uA4FD\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA66E\\uA67F-\\uA697\\uA6A0-\\uA6EF\\uA717-\\uA71F\\uA722-\\uA788\\uA78B-\\uA78E\\uA790-\\uA793\\uA7A0-\\uA7AA\\uA7F8-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA8F2-\\uA8F7\\uA8FB\\uA90A-\\uA925\\uA930-\\uA946\\uA960-\\uA97C\\uA984-\\uA9B2\\uA9CF\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAA60-\\uAA76\\uAA7A\\uAA80-\\uAAAF\\uAAB1\\uAAB5\\uAAB6\\uAAB9-\\uAABD\\uAAC0\\uAAC2\\uAADB-\\uAADD\\uAAE0-\\uAAEA\\uAAF2-\\uAAF4\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uABC0-\\uABE2\\uAC00-\\uD7A3\\uD7B0-\\uD7C6\\uD7CB-\\uD7FB\\uF900-\\uFA6D\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC'; const unicodeLetters =
'\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u0527\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0620-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0800-\\u0815\\u081A\\u0824\\u0828\\u0840-\\u0858\\u08A0\\u08A2-\\u08AC\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971-\\u0977\\u0979-\\u097F\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C33\\u0C35-\\u0C39\\u0C3D\\u0C58\\u0C59\\u0C60\\u0C61\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0CF1\\u0CF2\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D3A\\u0D3D\\u0D4E\\u0D60\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC-\\u0EDF\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8C\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10C7\\u10CD\\u10D0-\\u10FA\\u10FC-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F4\\u1401-\\u166C\\u166F-\\u167F\\u1681-\\u169A\\u16A0-\\u16EA\\u16EE-\\u16F0\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u18B0-\\u18F5\\u1900-\\u191C\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19AB\\u19C1-\\u19C7\\u1A00-\\u1A16\\u1A20-\\u1A54\\u1AA7\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1BBA-\\u1BE5\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1CE9-\\u1CEC\\u1CEE-\\u1CF1\\u1CF5\\u1CF6\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u209C\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2160-\\u2188\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2CE4\\u2CEB-\\u2CEE\\u2CF2\\u2CF3\\u2D00-\\u2D25\\u2D27\\u2D2D\\u2D30-\\u2D67\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005-\\u3007\\u3021-\\u3029\\u3031-\\u3035\\u3038-\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31BA\\u31F0-\\u31FF\\u3400-\\u4DB5\\u4E00-\\u9FCC\\uA000-\\uA48C\\uA4D0-\\uA4FD\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA66E\\uA67F-\\uA697\\uA6A0-\\uA6EF\\uA717-\\uA71F\\uA722-\\uA788\\uA78B-\\uA78E\\uA790-\\uA793\\uA7A0-\\uA7AA\\uA7F8-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA8F2-\\uA8F7\\uA8FB\\uA90A-\\uA925\\uA930-\\uA946\\uA960-\\uA97C\\uA984-\\uA9B2\\uA9CF\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAA60-\\uAA76\\uAA7A\\uAA80-\\uAAAF\\uAAB1\\uAAB5\\uAAB6\\uAAB9-\\uAABD\\uAAC0\\uAAC2\\uAADB-\\uAADD\\uAAE0-\\uAAEA\\uAAF2-\\uAAF4\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uABC0-\\uABE2\\uAC00-\\uD7A3\\uD7B0-\\uD7C6\\uD7CB-\\uD7FB\\uF900-\\uFA6D\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC';
export default { unicodeLetters }; export default { unicodeLetters };
...@@ -2,7 +2,7 @@ export default (fn, interval = 2000, timeout = 60000) => { ...@@ -2,7 +2,7 @@ export default (fn, interval = 2000, timeout = 60000) => {
const startTime = Date.now(); const startTime = Date.now();
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const stop = arg => ((arg instanceof Error) ? reject(arg) : resolve(arg)); const stop = arg => (arg instanceof Error ? reject(arg) : resolve(arg));
const next = () => { const next = () => {
if (Date.now() - startTime < timeout) { if (Date.now() - startTime < timeout) {
setTimeout(fn.bind(null, next, stop), interval); setTimeout(fn.bind(null, next, stop), interval);
......
...@@ -24,7 +24,11 @@ export const isSticky = (el, scrollY, stickyTop, insertPlaceholder) => { ...@@ -24,7 +24,11 @@ export const isSticky = (el, scrollY, stickyTop, insertPlaceholder) => {
} else if (top > stickyTop && el.classList.contains('is-stuck')) { } else if (top > stickyTop && el.classList.contains('is-stuck')) {
el.classList.remove('is-stuck'); el.classList.remove('is-stuck');
if (insertPlaceholder && el.nextElementSibling && el.nextElementSibling.classList.contains('sticky-placeholder')) { if (
insertPlaceholder &&
el.nextElementSibling &&
el.nextElementSibling.classList.contains('sticky-placeholder')
) {
el.nextElementSibling.remove(); el.nextElementSibling.remove();
} }
} }
...@@ -42,11 +46,19 @@ export const isSticky = (el, scrollY, stickyTop, insertPlaceholder) => { ...@@ -42,11 +46,19 @@ export const isSticky = (el, scrollY, stickyTop, insertPlaceholder) => {
export const stickyMonitor = (el, stickyTop, insertPlaceholder = true) => { export const stickyMonitor = (el, stickyTop, insertPlaceholder = true) => {
if (!el) return; if (!el) return;
if (typeof CSS === 'undefined' || !(CSS.supports('(position: -webkit-sticky) or (position: sticky)'))) return; if (
typeof CSS === 'undefined' ||
!CSS.supports('(position: -webkit-sticky) or (position: sticky)')
)
return;
document.addEventListener('scroll', () => isSticky(el, window.scrollY, stickyTop, insertPlaceholder), { document.addEventListener(
'scroll',
() => isSticky(el, window.scrollY, stickyTop, insertPlaceholder),
{
passive: true, passive: true,
}); },
);
}; };
/** /**
...@@ -55,6 +67,6 @@ export const stickyMonitor = (el, stickyTop, insertPlaceholder = true) => { ...@@ -55,6 +67,6 @@ export const stickyMonitor = (el, stickyTop, insertPlaceholder = true) => {
* - If the current environment supports `position: sticky`, do nothing. * - If the current environment supports `position: sticky`, do nothing.
* - Can receive an iterable element list (NodeList, jQuery collection, etc.) or single HTMLElement. * - Can receive an iterable element list (NodeList, jQuery collection, etc.) or single HTMLElement.
*/ */
export const polyfillSticky = (el) => { export const polyfillSticky = el => {
StickyFill.add(el); StickyFill.add(el);
}; };
...@@ -8,12 +8,18 @@ function selectedText(text, textarea) { ...@@ -8,12 +8,18 @@ function selectedText(text, textarea) {
function lineBefore(text, textarea) { function lineBefore(text, textarea) {
var split; var split;
split = text.substring(0, textarea.selectionStart).trim().split('\n'); split = text
.substring(0, textarea.selectionStart)
.trim()
.split('\n');
return split[split.length - 1]; return split[split.length - 1];
} }
function lineAfter(text, textarea) { function lineAfter(text, textarea) {
return text.substring(textarea.selectionEnd).trim().split('\n')[0]; return text
.substring(textarea.selectionEnd)
.trim()
.split('\n')[0];
} }
function blockTagText(text, textArea, blockTag, selected) { function blockTagText(text, textArea, blockTag, selected) {
...@@ -27,7 +33,7 @@ function blockTagText(text, textArea, blockTag, selected) { ...@@ -27,7 +33,7 @@ function blockTagText(text, textArea, blockTag, selected) {
} }
return selected; return selected;
} else { } else {
return blockTag + "\n" + selected + "\n" + blockTag; return blockTag + '\n' + selected + '\n' + blockTag;
} }
} }
...@@ -58,7 +64,14 @@ function moveCursor({ textArea, tag, wrapped, removedLastNewLine, select }) { ...@@ -58,7 +64,14 @@ function moveCursor({ textArea, tag, wrapped, removedLastNewLine, select }) {
} }
export function insertMarkdownText({ textArea, text, tag, blockTag, selected, wrap, select }) { export function insertMarkdownText({ textArea, text, tag, blockTag, selected, wrap, select }) {
var textToInsert, inserted, selectedSplit, startChar, removedLastNewLine, removedFirstNewLine, currentLineEmpty, lastNewLine; var textToInsert,
inserted,
selectedSplit,
startChar,
removedLastNewLine,
removedFirstNewLine,
currentLineEmpty,
lastNewLine;
removedLastNewLine = false; removedLastNewLine = false;
removedFirstNewLine = false; removedFirstNewLine = false;
currentLineEmpty = false; currentLineEmpty = false;
...@@ -94,21 +107,23 @@ export function insertMarkdownText({ textArea, text, tag, blockTag, selected, wr ...@@ -94,21 +107,23 @@ export function insertMarkdownText({ textArea, text, tag, blockTag, selected, wr
if (blockTag != null && blockTag !== '') { if (blockTag != null && blockTag !== '') {
textToInsert = blockTagText(text, textArea, blockTag, selected); textToInsert = blockTagText(text, textArea, blockTag, selected);
} else { } else {
textToInsert = selectedSplit.map(function(val) { textToInsert = selectedSplit
.map(function(val) {
if (tag.indexOf(textPlaceholder) > -1) { if (tag.indexOf(textPlaceholder) > -1) {
return tag.replace(textPlaceholder, val); return tag.replace(textPlaceholder, val);
} }
if (val.indexOf(tag) === 0) { if (val.indexOf(tag) === 0) {
return "" + (val.replace(tag, '')); return '' + val.replace(tag, '');
} else { } else {
return "" + tag + val; return '' + tag + val;
} }
}).join('\n'); })
.join('\n');
} }
} else if (tag.indexOf(textPlaceholder) > -1) { } else if (tag.indexOf(textPlaceholder) > -1) {
textToInsert = tag.replace(textPlaceholder, selected); textToInsert = tag.replace(textPlaceholder, selected);
} else { } else {
textToInsert = "" + startChar + tag + selected + (wrap ? tag : ' '); textToInsert = '' + startChar + tag + selected + (wrap ? tag : ' ');
} }
if (removedFirstNewLine) { if (removedFirstNewLine) {
...@@ -120,7 +135,13 @@ export function insertMarkdownText({ textArea, text, tag, blockTag, selected, wr ...@@ -120,7 +135,13 @@ export function insertMarkdownText({ textArea, text, tag, blockTag, selected, wr
} }
insertText(textArea, textToInsert); insertText(textArea, textToInsert);
return moveCursor({ textArea, tag: tag.replace(textPlaceholder, selected), wrap, removedLastNewLine, select }); return moveCursor({
textArea,
tag: tag.replace(textPlaceholder, selected),
wrap,
removedLastNewLine,
select,
});
} }
function updateText({ textArea, tag, blockTag, wrap, select }) { function updateText({ textArea, tag, blockTag, wrap, select }) {
...@@ -138,14 +159,17 @@ function replaceRange(s, start, end, substitute) { ...@@ -138,14 +159,17 @@ function replaceRange(s, start, end, substitute) {
} }
export function addMarkdownListeners(form) { export function addMarkdownListeners(form) {
return $('.js-md', form).off('click').on('click', function() { return $('.js-md', form)
.off('click')
.on('click', function() {
const $this = $(this); const $this = $(this);
return updateText({ return updateText({
textArea: $this.closest('.md-area').find('textarea'), textArea: $this.closest('.md-area').find('textarea'),
tag: $this.data('mdTag'), tag: $this.data('mdTag'),
blockTag: $this.data('mdBlock'), blockTag: $this.data('mdBlock'),
wrap: !$this.data('mdPrepend'), wrap: !$this.data('mdPrepend'),
select: $this.data('mdSelect') }); select: $this.data('mdSelect'),
});
}); });
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* @returns {String} * @returns {String}
*/ */
export const addDelimiter = text => export const addDelimiter = text =>
(text ? text.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',') : text); text ? text.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',') : text;
/** /**
* Returns '99+' for numbers bigger than 99. * Returns '99+' for numbers bigger than 99.
...@@ -94,9 +94,7 @@ export function capitalizeFirstCharacter(text) { ...@@ -94,9 +94,7 @@ export function capitalizeFirstCharacter(text) {
* @return {String} * @return {String}
*/ */
export function getFirstCharacterCapitalized(text) { export function getFirstCharacterCapitalized(text) {
return text return text ? text.charAt(0).toUpperCase() : '';
? text.charAt(0).toUpperCase()
: '';
} }
/** /**
...@@ -136,10 +134,9 @@ export const convertToSentenceCase = string => { ...@@ -136,10 +134,9 @@ export const convertToSentenceCase = string => {
* e.g. HelloWorld => Hello World * e.g. HelloWorld => Hello World
* *
* @param {*} string * @param {*} string
*/ */
export const splitCamelCase = string => ( export const splitCamelCase = string =>
string string
.replace(/([A-Z]+)([A-Z][a-z])/g, ' $1 $2') .replace(/([A-Z]+)([A-Z][a-z])/g, ' $1 $2')
.replace(/([a-z\d])([A-Z])/g, '$1 $2') .replace(/([a-z\d])([A-Z])/g, '$1 $2')
.trim() .trim();
);
...@@ -26,7 +26,7 @@ initDateFormats(); ...@@ -26,7 +26,7 @@ initDateFormats();
see also https://github.com/d3/d3-3.x-api-reference/blob/master/SVG-Axes.md#tickFormat see also https://github.com/d3/d3-3.x-api-reference/blob/master/SVG-Axes.md#tickFormat
*/ */
export const dateTickFormat = (date) => { export const dateTickFormat = date => {
if (date.getDate() !== 1) { if (date.getDate() !== 1) {
return dateTimeFormats.dayFormat.format(date); return dateTimeFormats.dayFormat.format(date);
} }
......
...@@ -7,8 +7,7 @@ class UsersCache extends Cache { ...@@ -7,8 +7,7 @@ class UsersCache extends Cache {
return Promise.resolve(this.get(username)); return Promise.resolve(this.get(username));
} }
return Api.users('', { username }) return Api.users('', { username }).then(({ data }) => {
.then(({ data }) => {
if (!data.length) { if (!data.length) {
throw new Error(`User "${username}" could not be found!`); throw new Error(`User "${username}" could not be found!`);
} }
......
...@@ -6,7 +6,7 @@ import axios from '~/lib/utils/axios_utils'; ...@@ -6,7 +6,7 @@ import axios from '~/lib/utils/axios_utils';
import flash from '~/flash'; import flash from '~/flash';
import { __ } from '~/locale'; import { __ } from '~/locale';
((global) => { (global => {
global.mergeConflicts = global.mergeConflicts || {}; global.mergeConflicts = global.mergeConflicts || {};
global.mergeConflicts.diffFileEditor = Vue.extend({ global.mergeConflicts.diffFileEditor = Vue.extend({
...@@ -35,10 +35,10 @@ import { __ } from '~/locale'; ...@@ -35,10 +35,10 @@ import { __ } from '~/locale';
computed: { computed: {
classObject() { classObject() {
return { return {
'saved': this.saved, saved: this.saved,
'is-loading': this.loading 'is-loading': this.loading,
}; };
} },
}, },
watch: { watch: {
['file.showEditor'](val) { ['file.showEditor'](val) {
...@@ -49,7 +49,7 @@ import { __ } from '~/locale'; ...@@ -49,7 +49,7 @@ import { __ } from '~/locale';
} }
this.loadEditor(); this.loadEditor();
} },
}, },
mounted() { mounted() {
if (this.file.loadEditor) { if (this.file.loadEditor) {
...@@ -60,7 +60,8 @@ import { __ } from '~/locale'; ...@@ -60,7 +60,8 @@ import { __ } from '~/locale';
loadEditor() { loadEditor() {
this.loading = true; this.loading = true;
axios.get(this.file.content_path) axios
.get(this.file.content_path)
.then(({ data }) => { .then(({ data }) => {
const content = this.$el.querySelector('pre'); const content = this.$el.querySelector('pre');
const fileContent = document.createTextNode(data.content); const fileContent = document.createTextNode(data.content);
...@@ -101,7 +102,7 @@ import { __ } from '~/locale'; ...@@ -101,7 +102,7 @@ import { __ } from '~/locale';
}, },
acceptDiscardConfirmation(file) { acceptDiscardConfirmation(file) {
this.onAcceptDiscardConfirmation(file); this.onAcceptDiscardConfirmation(file);
} },
} },
}); });
})(window.gl || (window.gl = {})); })(window.gl || (window.gl = {}));
...@@ -4,7 +4,7 @@ import Vue from 'vue'; ...@@ -4,7 +4,7 @@ import Vue from 'vue';
import actionsMixin from '../mixins/line_conflict_actions'; import actionsMixin from '../mixins/line_conflict_actions';
import utilsMixin from '../mixins/line_conflict_utils'; import utilsMixin from '../mixins/line_conflict_utils';
((global) => { (global => {
global.mergeConflicts = global.mergeConflicts || {}; global.mergeConflicts = global.mergeConflicts || {};
global.mergeConflicts.parallelConflictLines = Vue.extend({ global.mergeConflicts.parallelConflictLines = Vue.extend({
......
...@@ -4,7 +4,7 @@ import $ from 'jquery'; ...@@ -4,7 +4,7 @@ import $ from 'jquery';
import Vue from 'vue'; import Vue from 'vue';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
((global) => { (global => {
global.mergeConflicts = global.mergeConflicts || {}; global.mergeConflicts = global.mergeConflicts || {};
const diffViewType = Cookies.get('diff_view'); const diffViewType = Cookies.get('diff_view');
...@@ -17,11 +17,11 @@ import Cookies from 'js-cookie'; ...@@ -17,11 +17,11 @@ import Cookies from 'js-cookie';
const DEFAULT_RESOLVE_MODE = INTERACTIVE_RESOLVE_MODE; const DEFAULT_RESOLVE_MODE = INTERACTIVE_RESOLVE_MODE;
const VIEW_TYPES = { const VIEW_TYPES = {
INLINE: 'inline', INLINE: 'inline',
PARALLEL: 'parallel' PARALLEL: 'parallel',
}; };
const CONFLICT_TYPES = { const CONFLICT_TYPES = {
TEXT: 'text', TEXT: 'text',
TEXT_EDITOR: 'text-editor' TEXT_EDITOR: 'text-editor',
}; };
global.mergeConflicts.mergeConflictsStore = { global.mergeConflicts.mergeConflictsStore = {
...@@ -31,7 +31,7 @@ import Cookies from 'js-cookie'; ...@@ -31,7 +31,7 @@ import Cookies from 'js-cookie';
isSubmitting: false, isSubmitting: false,
isParallel: diffViewType === VIEW_TYPES.PARALLEL, isParallel: diffViewType === VIEW_TYPES.PARALLEL,
diffViewType: diffViewType, diffViewType: diffViewType,
conflictsData: {} conflictsData: {},
}, },
setConflictsData(data) { setConflictsData(data) {
...@@ -47,7 +47,7 @@ import Cookies from 'js-cookie'; ...@@ -47,7 +47,7 @@ import Cookies from 'js-cookie';
}, },
decorateFiles(files) { decorateFiles(files) {
files.forEach((file) => { files.forEach(file => {
file.content = ''; file.content = '';
file.resolutionData = {}; file.resolutionData = {};
file.promptDiscardConfirmation = false; file.promptDiscardConfirmation = false;
...@@ -72,7 +72,7 @@ import Cookies from 'js-cookie'; ...@@ -72,7 +72,7 @@ import Cookies from 'js-cookie';
setInlineLine(file) { setInlineLine(file) {
file.inlineLines = []; file.inlineLines = [];
file.sections.forEach((section) => { file.sections.forEach(section => {
let currentLineType = 'new'; let currentLineType = 'new';
const { conflict, lines, id } = section; const { conflict, lines, id } = section;
...@@ -80,7 +80,7 @@ import Cookies from 'js-cookie'; ...@@ -80,7 +80,7 @@ import Cookies from 'js-cookie';
file.inlineLines.push(this.getHeadHeaderLine(id)); file.inlineLines.push(this.getHeadHeaderLine(id));
} }
lines.forEach((line) => { lines.forEach(line => {
const { type } = line; const { type } = line;
if ((type === 'new' || type === 'old') && currentLineType !== type) { if ((type === 'new' || type === 'old') && currentLineType !== type) {
...@@ -102,7 +102,7 @@ import Cookies from 'js-cookie'; ...@@ -102,7 +102,7 @@ import Cookies from 'js-cookie';
file.parallelLines = []; file.parallelLines = [];
const linesObj = { left: [], right: [] }; const linesObj = { left: [], right: [] };
file.sections.forEach((section) => { file.sections.forEach(section => {
const { conflict, lines, id } = section; const { conflict, lines, id } = section;
if (conflict) { if (conflict) {
...@@ -110,7 +110,7 @@ import Cookies from 'js-cookie'; ...@@ -110,7 +110,7 @@ import Cookies from 'js-cookie';
linesObj.right.push(this.getHeadHeaderLine(id)); linesObj.right.push(this.getHeadHeaderLine(id));
} }
lines.forEach((line) => { lines.forEach(line => {
const { type } = line; const { type } = line;
if (conflict) { if (conflict) {
...@@ -131,10 +131,7 @@ import Cookies from 'js-cookie'; ...@@ -131,10 +131,7 @@ import Cookies from 'js-cookie';
}); });
for (let i = 0, len = linesObj.left.length; i < len; i += 1) { for (let i = 0, len = linesObj.left.length; i < len; i += 1) {
file.parallelLines.push([ file.parallelLines.push([linesObj.right[i], linesObj.left[i]]);
linesObj.right[i],
linesObj.left[i]
]);
} }
}, },
...@@ -159,9 +156,9 @@ import Cookies from 'js-cookie'; ...@@ -159,9 +156,9 @@ import Cookies from 'js-cookie';
const { files } = this.state.conflictsData; const { files } = this.state.conflictsData;
let count = 0; let count = 0;
files.forEach((file) => { files.forEach(file => {
if (file.type === CONFLICT_TYPES.TEXT) { if (file.type === CONFLICT_TYPES.TEXT) {
file.sections.forEach((section) => { file.sections.forEach(section => {
if (section.conflict) { if (section.conflict) {
count += 1; count += 1;
} }
...@@ -198,7 +195,7 @@ import Cookies from 'js-cookie'; ...@@ -198,7 +195,7 @@ import Cookies from 'js-cookie';
isHeader: true, isHeader: true,
isHead: true, isHead: true,
isSelected: false, isSelected: false,
isUnselected: false isUnselected: false,
}; };
}, },
...@@ -229,7 +226,7 @@ import Cookies from 'js-cookie'; ...@@ -229,7 +226,7 @@ import Cookies from 'js-cookie';
section: isHead ? 'head' : 'origin', section: isHead ? 'head' : 'origin',
richText: rich_text, richText: rich_text,
isSelected: false, isSelected: false,
isUnselected: false isUnselected: false,
}; };
}, },
...@@ -243,7 +240,7 @@ import Cookies from 'js-cookie'; ...@@ -243,7 +240,7 @@ import Cookies from 'js-cookie';
isHeader: true, isHeader: true,
isOrigin: true, isOrigin: true,
isSelected: false, isSelected: false,
isUnselected: false isUnselected: false,
}; };
}, },
...@@ -290,14 +287,14 @@ import Cookies from 'js-cookie'; ...@@ -290,14 +287,14 @@ import Cookies from 'js-cookie';
}, },
restoreFileLinesState(file) { restoreFileLinesState(file) {
file.inlineLines.forEach((line) => { file.inlineLines.forEach(line => {
if (line.hasConflict || line.isHeader) { if (line.hasConflict || line.isHeader) {
line.isSelected = false; line.isSelected = false;
line.isUnselected = false; line.isUnselected = false;
} }
}); });
file.parallelLines.forEach((lines) => { file.parallelLines.forEach(lines => {
const left = lines[0]; const left = lines[0];
const right = lines[1]; const right = lines[1];
const isLeftMatch = left.hasConflict || left.isHeader; const isLeftMatch = left.hasConflict || left.isHeader;
...@@ -354,7 +351,7 @@ import Cookies from 'js-cookie'; ...@@ -354,7 +351,7 @@ import Cookies from 'js-cookie';
const initial = 'Commit to source branch'; const initial = 'Commit to source branch';
const inProgress = 'Committing...'; const inProgress = 'Committing...';
return this.state ? this.state.isSubmitting ? inProgress : initial : initial; return this.state ? (this.state.isSubmitting ? inProgress : initial) : initial;
}, },
getCommitData() { getCommitData() {
...@@ -362,13 +359,13 @@ import Cookies from 'js-cookie'; ...@@ -362,13 +359,13 @@ import Cookies from 'js-cookie';
commitData = { commitData = {
commit_message: this.state.conflictsData.commitMessage, commit_message: this.state.conflictsData.commitMessage,
files: [] files: [],
}; };
this.state.conflictsData.files.forEach((file) => { this.state.conflictsData.files.forEach(file => {
const addFile = { const addFile = {
old_path: file.old_path, old_path: file.old_path,
new_path: file.new_path new_path: file.new_path,
}; };
if (file.type === CONFLICT_TYPES.TEXT) { if (file.type === CONFLICT_TYPES.TEXT) {
...@@ -391,13 +388,13 @@ import Cookies from 'js-cookie'; ...@@ -391,13 +388,13 @@ import Cookies from 'js-cookie';
handleSelected(file, sectionId, selection) { handleSelected(file, sectionId, selection) {
Vue.set(file.resolutionData, sectionId, selection); Vue.set(file.resolutionData, sectionId, selection);
file.inlineLines.forEach((line) => { file.inlineLines.forEach(line => {
if (line.id === sectionId && (line.hasConflict || line.isHeader)) { if (line.id === sectionId && (line.hasConflict || line.isHeader)) {
this.markLine(line, selection); this.markLine(line, selection);
} }
}); });
file.parallelLines.forEach((lines) => { file.parallelLines.forEach(lines => {
const left = lines[0]; const left = lines[0];
const right = lines[1]; const right = lines[1];
const hasSameId = right.id === sectionId || left.id === sectionId; const hasSameId = right.id === sectionId || left.id === sectionId;
...@@ -430,6 +427,6 @@ import Cookies from 'js-cookie'; ...@@ -430,6 +427,6 @@ import Cookies from 'js-cookie';
fileTextTypePresent() { fileTextTypePresent() {
return this.state.conflictsData.files.some(f => f.type === CONFLICT_TYPES.TEXT); return this.state.conflictsData.files.some(f => f.type === CONFLICT_TYPES.TEXT);
} },
}; };
})(window.gl || (window.gl = {})); })(window.gl || (window.gl = {}));
...@@ -148,7 +148,7 @@ export default { ...@@ -148,7 +148,7 @@ export default {
point = point.matrixTransform(this.$refs.graphData.getScreenCTM().inverse()); point = point.matrixTransform(this.$refs.graphData.getScreenCTM().inverse());
point.x += 7; point.x += 7;
this.seriesUnderMouse = this.timeSeries.filter((series) => { this.seriesUnderMouse = this.timeSeries.filter(series => {
const mouseX = series.timeSeriesScaleX.invert(point.x); const mouseX = series.timeSeriesScaleX.invert(point.x);
let minDistance = Infinity; let minDistance = Infinity;
...@@ -221,21 +221,18 @@ export default { ...@@ -221,21 +221,18 @@ export default {
.scale(axisYScale) .scale(axisYScale)
.ticks(measurements.yTicks); .ticks(measurements.yTicks);
d3 d3.select(this.$refs.baseSvg)
.select(this.$refs.baseSvg)
.select('.x-axis') .select('.x-axis')
.call(xAxis); .call(xAxis);
const width = this.graphWidth; const width = this.graphWidth;
d3 d3.select(this.$refs.baseSvg)
.select(this.$refs.baseSvg)
.select('.y-axis') .select('.y-axis')
.call(yAxis) .call(yAxis)
.selectAll('.tick') .selectAll('.tick')
.each(function createTickLines(d, i) { .each(function createTickLines(d, i) {
if (i > 0) { if (i > 0) {
d3 d3.select(this)
.select(this)
.select('line') .select('line')
.attr('x2', width) .attr('x2', width)
.attr('class', 'axis-tick'); .attr('class', 'axis-tick');
......
...@@ -38,38 +38,25 @@ export default { ...@@ -38,38 +38,25 @@ export default {
computed: { computed: {
textTransform() { textTransform() {
const yCoordinate = const yCoordinate =
(this.graphHeight - (this.graphHeight - this.margin.top + this.measurements.axisLabelLineOffset) / 2 || 0;
this.margin.top +
this.measurements.axisLabelLineOffset) /
2 || 0;
return `translate(15, ${yCoordinate}) rotate(-90)`; return `translate(15, ${yCoordinate}) rotate(-90)`;
}, },
rectTransform() { rectTransform() {
const yCoordinate = const yCoordinate =
(this.graphHeight - (this.graphHeight - this.margin.top + this.measurements.axisLabelLineOffset) / 2 +
this.margin.top +
this.measurements.axisLabelLineOffset) /
2 +
this.yLabelWidth / 2 || 0; this.yLabelWidth / 2 || 0;
return `translate(0, ${yCoordinate}) rotate(-90)`; return `translate(0, ${yCoordinate}) rotate(-90)`;
}, },
xPosition() { xPosition() {
return ( return (this.graphWidth + this.measurements.axisLabelLineOffset) / 2 - this.margin.right || 0;
(this.graphWidth + this.measurements.axisLabelLineOffset) / 2 -
this.margin.right || 0
);
}, },
yPosition() { yPosition() {
return ( return this.graphHeight - this.margin.top + this.measurements.axisLabelLineOffset || 0;
this.graphHeight -
this.margin.top +
this.measurements.axisLabelLineOffset || 0
);
}, },
yAxisLabelSentenceCase() { yAxisLabelSentenceCase() {
......
...@@ -92,7 +92,8 @@ export default { ...@@ -92,7 +92,8 @@ export default {
methods: { methods: {
seriesMetricValue(seriesIndex, series) { seriesMetricValue(seriesIndex, series) {
const indexFromCoordinates = this.currentCoordinates[series.metricTag] const indexFromCoordinates = this.currentCoordinates[series.metricTag]
? this.currentCoordinates[series.metricTag].currentDataIndex : 0; ? this.currentCoordinates[series.metricTag].currentDataIndex
: 0;
const index = this.deploymentFlagData const index = this.deploymentFlagData
? this.deploymentFlagData.seriesIndex ? this.deploymentFlagData.seriesIndex
: indexFromCoordinates; : indexFromCoordinates;
......
...@@ -26,4 +26,3 @@ export default { ...@@ -26,4 +26,3 @@ export default {
{{ summaryMetrics }} {{ summaryMetrics }}
</span> </span>
</template> </template>
...@@ -33,4 +33,3 @@ export default { ...@@ -33,4 +33,3 @@ export default {
</svg> </svg>
</td> </td>
</template> </template>
...@@ -6,7 +6,7 @@ const mixins = { ...@@ -6,7 +6,7 @@ const mixins = {
if (!this.reducedDeploymentData) return false; if (!this.reducedDeploymentData) return false;
let dataFound = false; let dataFound = false;
this.reducedDeploymentData = this.reducedDeploymentData.map((d) => { this.reducedDeploymentData = this.reducedDeploymentData.map(d => {
const deployment = d; const deployment = d;
if (d.xPos >= mouseXPos - 10 && d.xPos <= mouseXPos + 10 && !dataFound) { if (d.xPos >= mouseXPos - 10 && d.xPos <= mouseXPos + 10 && !dataFound) {
dataFound = d.xPos + 1; dataFound = d.xPos + 1;
...@@ -61,7 +61,7 @@ const mixins = { ...@@ -61,7 +61,7 @@ const mixins = {
this.currentCoordinates = {}; this.currentCoordinates = {};
this.seriesUnderMouse.forEach((series) => { this.seriesUnderMouse.forEach(series => {
const currentDataIndex = bisectDate(series.values, this.hoverData.hoveredDate); const currentDataIndex = bisectDate(series.values, this.hoverData.hoveredDate);
const currentData = series.values[currentDataIndex]; const currentData = series.values[currentDataIndex];
const currentX = Math.floor(series.timeSeriesScaleX(currentData.time)); const currentX = Math.floor(series.timeSeriesScaleX(currentData.time));
......
...@@ -8,7 +8,8 @@ const MAX_REQUESTS = 3; ...@@ -8,7 +8,8 @@ const MAX_REQUESTS = 3;
function backOffRequest(makeRequestCallback) { function backOffRequest(makeRequestCallback) {
let requestCounter = 0; let requestCounter = 0;
return backOff((next, stop) => { return backOff((next, stop) => {
makeRequestCallback().then((resp) => { makeRequestCallback()
.then(resp => {
if (resp.status === statusCodes.NO_CONTENT) { if (resp.status === statusCodes.NO_CONTENT) {
requestCounter += 1; requestCounter += 1;
if (requestCounter < MAX_REQUESTS) { if (requestCounter < MAX_REQUESTS) {
...@@ -19,7 +20,8 @@ function backOffRequest(makeRequestCallback) { ...@@ -19,7 +20,8 @@ function backOffRequest(makeRequestCallback) {
} else { } else {
stop(resp); stop(resp);
} }
}).catch(stop); })
.catch(stop);
}); });
} }
...@@ -33,7 +35,7 @@ export default class MonitoringService { ...@@ -33,7 +35,7 @@ export default class MonitoringService {
getGraphsData() { getGraphsData() {
return backOffRequest(() => axios.get(this.metricsEndpoint)) return backOffRequest(() => axios.get(this.metricsEndpoint))
.then(resp => resp.data) .then(resp => resp.data)
.then((response) => { .then(response => {
if (!response || !response.data) { if (!response || !response.data) {
throw new Error(s__('Metrics|Unexpected metrics data response from prometheus endpoint')); throw new Error(s__('Metrics|Unexpected metrics data response from prometheus endpoint'));
} }
...@@ -47,20 +49,25 @@ export default class MonitoringService { ...@@ -47,20 +49,25 @@ export default class MonitoringService {
} }
return backOffRequest(() => axios.get(this.deploymentEndpoint)) return backOffRequest(() => axios.get(this.deploymentEndpoint))
.then(resp => resp.data) .then(resp => resp.data)
.then((response) => { .then(response => {
if (!response || !response.deployments) { if (!response || !response.deployments) {
throw new Error(s__('Metrics|Unexpected deployment data response from prometheus endpoint')); throw new Error(
s__('Metrics|Unexpected deployment data response from prometheus endpoint'),
);
} }
return response.deployments; return response.deployments;
}); });
} }
getEnvironmentsData() { getEnvironmentsData() {
return axios.get(this.environmentsEndpoint) return axios
.get(this.environmentsEndpoint)
.then(resp => resp.data) .then(resp => resp.data)
.then((response) => { .then(response => {
if (!response || !response.environments) { if (!response || !response.environments) {
throw new Error(s__('Metrics|There was an error fetching the environments data, please try again')); throw new Error(
s__('Metrics|There was an error fetching the environments data, please try again'),
);
} }
return response.environments; return response.environments;
}); });
......
export default { export default {
small: { // Covers both xs and sm screen sizes small: {
// Covers both xs and sm screen sizes
margin: { margin: {
top: 40, top: 40,
right: 40, right: 40,
...@@ -18,7 +19,8 @@ export default { ...@@ -18,7 +19,8 @@ export default {
}, },
axisLabelLineOffset: -20, axisLabelLineOffset: -20,
}, },
large: { // This covers both md and lg screen sizes large: {
// This covers both md and lg screen sizes
margin: { margin: {
top: 80, top: 80,
right: 80, right: 80,
......
...@@ -66,7 +66,8 @@ function queryTimeSeries(query, graphDrawData, lineStyle) { ...@@ -66,7 +66,8 @@ function queryTimeSeries(query, graphDrawData, lineStyle) {
// offset the same amount as the original data // offset the same amount as the original data
const [minX, maxX] = graphDrawData.xDom; const [minX, maxX] = graphDrawData.xDom;
const offset = d3.timeMinute(minX) - Number(minX); const offset = d3.timeMinute(minX) - Number(minX);
const datesWithoutGaps = d3.timeSecond.every(60) const datesWithoutGaps = d3.timeSecond
.every(60)
.range(d3.timeMinute.offset(minX, -1), maxX) .range(d3.timeMinute.offset(minX, -1), maxX)
.map(d => d - offset); .map(d => d - offset);
...@@ -208,9 +209,7 @@ export default function createTimeSeries(queries, graphWidth, graphHeight, graph ...@@ -208,9 +209,7 @@ export default function createTimeSeries(queries, graphWidth, graphHeight, graph
const timeSeries = queries.reduce((series, query, index) => { const timeSeries = queries.reduce((series, query, index) => {
const lineStyle = defaultStyleOrder[index % defaultStyleOrder.length]; const lineStyle = defaultStyleOrder[index % defaultStyleOrder.length];
return series.concat( return series.concat(queryTimeSeries(query, graphDrawData, lineStyle));
queryTimeSeries(query, graphDrawData, lineStyle),
);
}, []); }, []);
return { return {
......
<script> <script>
import Prism from '../../lib/highlight'; import Prism from '../../lib/highlight';
import Prompt from '../prompt.vue'; import Prompt from '../prompt.vue';
export default { export default {
components: { components: {
prompt: Prompt, prompt: Prompt,
}, },
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
mounted() { mounted() {
Prism.highlightElement(this.$refs.code); Prism.highlightElement(this.$refs.code);
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
/* global katex */ /* global katex */
import marked from 'marked'; import marked from 'marked';
import sanitize from 'sanitize-html'; import sanitize from 'sanitize-html';
import Prompt from './prompt.vue'; import Prompt from './prompt.vue';
const renderer = new marked.Renderer(); const renderer = new marked.Renderer();
/* /*
Regex to match KaTex blocks. Regex to match KaTex blocks.
Supports the following: Supports the following:
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
The matched text then goes through the KaTex renderer & then outputs the HTML The matched text then goes through the KaTex renderer & then outputs the HTML
*/ */
const katexRegexString = `( const katexRegexString = `(
^\\\\begin{[a-zA-Z]+}\\s ^\\\\begin{[a-zA-Z]+}\\s
| |
^\\$\\$ ^\\$\\$
...@@ -32,14 +32,17 @@ ...@@ -32,14 +32,17 @@
| |
\\$ \\$
) )
`.replace(/\s/g, '').trim(); `
.replace(/\s/g, '')
.trim();
renderer.paragraph = (t) => { renderer.paragraph = t => {
let text = t; let text = t;
let inline = false; let inline = false;
if (typeof katex !== 'undefined') { if (typeof katex !== 'undefined') {
const katexString = text.replace(/&amp;/g, '&') const katexString = text
.replace(/&amp;/g, '&')
.replace(/&=&/g, '\\space=\\space') .replace(/&=&/g, '\\space=\\space')
.replace(/<(\/?)em>/g, '_'); .replace(/<(\/?)em>/g, '_');
const regex = new RegExp(katexRegexString, 'gi'); const regex = new RegExp(katexRegexString, 'gi');
...@@ -64,14 +67,14 @@ ...@@ -64,14 +67,14 @@
} }
return `<p class="${inline ? 'inline-katex' : ''}">${text}</p>`; return `<p class="${inline ? 'inline-katex' : ''}">${text}</p>`;
}; };
marked.setOptions({ marked.setOptions({
sanitize: true, sanitize: true,
renderer, renderer,
}); });
export default { export default {
components: { components: {
prompt: Prompt, prompt: Prompt,
}, },
...@@ -91,7 +94,7 @@ ...@@ -91,7 +94,7 @@
}); });
}, },
}, },
}; };
</script> </script>
<template> <template>
...@@ -105,13 +108,13 @@ ...@@ -105,13 +108,13 @@
</template> </template>
<style> <style>
.markdown .katex { .markdown .katex {
display: block; display: block;
text-align: center; text-align: center;
} }
.markdown .inline-katex .katex { .markdown .inline-katex .katex {
display: inline; display: inline;
text-align: initial; text-align: initial;
} }
</style> </style>
<script> <script>
import sanitize from 'sanitize-html'; import sanitize from 'sanitize-html';
import Prompt from '../prompt.vue'; import Prompt from '../prompt.vue';
export default { export default {
components: { components: {
prompt: Prompt, prompt: Prompt,
}, },
...@@ -15,16 +15,14 @@ ...@@ -15,16 +15,14 @@
computed: { computed: {
sanitizedOutput() { sanitizedOutput() {
return sanitize(this.rawCode, { return sanitize(this.rawCode, {
allowedTags: sanitize.defaults.allowedTags.concat([ allowedTags: sanitize.defaults.allowedTags.concat(['img', 'svg']),
'img', 'svg',
]),
allowedAttributes: { allowedAttributes: {
img: ['src'], img: ['src'],
}, },
}); });
}, },
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
import Prompt from '../prompt.vue'; import Prompt from '../prompt.vue';
export default { export default {
components: { components: {
prompt: Prompt, prompt: Prompt,
}, },
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
required: true, required: true,
}, },
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
import CodeCell from '../code/index.vue'; import CodeCell from '../code/index.vue';
import Html from './html.vue'; import Html from './html.vue';
import Image from './image.vue'; import Image from './image.vue';
export default { export default {
components: { components: {
'code-cell': CodeCell, 'code-cell': CodeCell,
'html-output': Html, 'html-output': Html,
...@@ -72,7 +72,7 @@ ...@@ -72,7 +72,7 @@
return data; return data;
}, },
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
export default { export default {
props: { props: {
type: { type: {
type: String, type: String,
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
return this.type !== '' && this.count; return this.type !== '' && this.count;
}, },
}, },
}; };
</script> </script>
<template> <template>
...@@ -29,9 +29,9 @@ ...@@ -29,9 +29,9 @@
</template> </template>
<style scoped> <style scoped>
.prompt { .prompt {
padding: 0 10px; padding: 0 10px;
min-width: 7em; min-width: 7em;
font-family: monospace; font-family: monospace;
} }
</style> </style>
<script> <script>
import { import { MarkdownCell, CodeCell } from './cells';
MarkdownCell,
CodeCell,
} from './cells';
export default { export default {
components: { components: {
'code-cell': CodeCell, 'code-cell': CodeCell,
'markdown-cell': MarkdownCell, 'markdown-cell': MarkdownCell,
...@@ -45,7 +42,7 @@ ...@@ -45,7 +42,7 @@
return `${type}-cell`; return `${type}-cell`;
}, },
}, },
}; };
</script> </script>
<template> <template>
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
*/ */
@import "../../../node_modules/pikaday/scss/pikaday"; @import "../../../node_modules/pikaday/scss/pikaday";
@import "../../../node_modules/dropzone/dist/basic.css"; @import "../../../node_modules/dropzone/dist/basic";
/* /*
* GitLab UI framework * GitLab UI framework
......
...@@ -5,22 +5,22 @@ ...@@ -5,22 +5,22 @@
= devise_error_messages! = devise_error_messages!
.form-group .form-group
= f.label :name, 'Full name', class: 'label-bold' = f.label :name, 'Full name', class: 'label-bold'
= f.text_field :name, class: "form-control top", required: true, title: "This field is required." = f.text_field :name, class: "form-control top qa-new-user-name", required: true, title: "This field is required."
.username.form-group .username.form-group
= f.label :username, class: 'label-bold' = f.label :username, class: 'label-bold'
= f.text_field :username, class: "form-control middle", pattern: Gitlab::PathRegex::NAMESPACE_FORMAT_REGEX_JS, required: true, title: 'Please create a username with only alphanumeric characters.' = f.text_field :username, class: "form-control middle qa-new-user-username", pattern: Gitlab::PathRegex::NAMESPACE_FORMAT_REGEX_JS, required: true, title: 'Please create a username with only alphanumeric characters.'
%p.validation-error.hide Username is already taken. %p.validation-error.hide Username is already taken.
%p.validation-success.hide Username is available. %p.validation-success.hide Username is available.
%p.validation-pending.hide Checking username availability... %p.validation-pending.hide Checking username availability...
.form-group .form-group
= f.label :email, class: 'label-bold' = f.label :email, class: 'label-bold'
= f.email_field :email, class: "form-control middle", required: true, title: "Please provide a valid email address." = f.email_field :email, class: "form-control middle qa-new-user-email", required: true, title: "Please provide a valid email address."
.form-group .form-group
= f.label :email_confirmation, class: 'label-bold' = f.label :email_confirmation, class: 'label-bold'
= f.email_field :email_confirmation, class: "form-control middle", required: true, title: "Please retype the email address." = f.email_field :email_confirmation, class: "form-control middle qa-new-user-email-confirmation", required: true, title: "Please retype the email address."
.form-group.append-bottom-20#password-strength .form-group.append-bottom-20#password-strength
= f.label :password, class: 'label-bold' = f.label :password, class: 'label-bold'
= f.password_field :password, class: "form-control bottom", required: true, pattern: ".{#{@minimum_password_length},}", title: "Minimum length is #{@minimum_password_length} characters." = f.password_field :password, class: "form-control bottom qa-new-user-password", required: true, pattern: ".{#{@minimum_password_length},}", title: "Minimum length is #{@minimum_password_length} characters."
%p.gl-field-hint.text-secondary Minimum length is #{@minimum_password_length} characters %p.gl-field-hint.text-secondary Minimum length is #{@minimum_password_length} characters
- if Gitlab::CurrentSettings.current_application_settings.enforce_terms? - if Gitlab::CurrentSettings.current_application_settings.enforce_terms?
.form-group .form-group
...@@ -34,4 +34,4 @@ ...@@ -34,4 +34,4 @@
- if Gitlab::Recaptcha.enabled? - if Gitlab::Recaptcha.enabled?
= recaptcha_tags = recaptcha_tags
.submit-container .submit-container
= f.submit "Register", class: "btn-register btn" = f.submit "Register", class: "btn-register btn qa-new-user-register-button"
...@@ -32,6 +32,21 @@ module QA ...@@ -32,6 +32,21 @@ module QA
false false
end end
def with_retry(max_attempts: 3, reload: false)
attempts = 0
while attempts < max_attempts
result = yield
return result if result
refresh if reload
attempts += 1
end
false
end
def scroll_to(selector, text: nil) def scroll_to(selector, text: nil)
page.execute_script <<~JS page.execute_script <<~JS
var elements = Array.from(document.querySelectorAll('#{selector}')); var elements = Array.from(document.querySelectorAll('#{selector}'));
......
...@@ -68,10 +68,6 @@ module QA ...@@ -68,10 +68,6 @@ module QA
end end
end end
def assert_has_personal_area
raise "Failed to sign in" unless has_personal_area?
end
private private
def within_top_menu def within_top_menu
......
# frozen_string_literal: true
module QA module QA
module Page module Page
module Main module Main
class SignUp < Page::Base class SignUp < Page::Base
view 'app/views/devise/shared/_signup_box.html.haml' do view 'app/views/devise/shared/_signup_box.html.haml' do
element :name, 'text_field :name' element :new_user_name
element :username, 'text_field :username' element :new_user_username
element :email_field, 'email_field :email' element :new_user_email
element :email_confirmation, 'email_field :email_confirmation' element :new_user_email_confirmation
element :password, 'password_field :password' element :new_user_password
element :register_button, 'submit "Register"' element :new_user_register_button
end end
def sign_up!(user) def sign_up!(user)
fill_in :new_user_name, with: user.name fill_element :new_user_name, user.name
fill_in :new_user_username, with: user.username fill_element :new_user_username, user.username
fill_in :new_user_email, with: user.email fill_element :new_user_email, user.email
fill_in :new_user_email_confirmation, with: user.email fill_element :new_user_email_confirmation, user.email
fill_in :new_user_password, with: user.password fill_element :new_user_password, user.password
click_button 'Register'
signed_in = with_retry do
click_element :new_user_register_button
Page::Main::Menu.act { has_personal_area? }
end
Page::Main::Menu.act { assert_has_personal_area } raise "Failed to register and sign in" unless signed_in
end end
end end
end end
......
...@@ -68,11 +68,11 @@ module Trigger ...@@ -68,11 +68,11 @@ module Trigger
def base_variables def base_variables
{ {
'TOP_UPSTREAM_TRIGGER_PROJECT' => ENV['TOP_UPSTREAM_TRIGGER_PROJECT'] || ENV['CI_PROJECT_PATH'],
'UPSTREAM_TRIGGER_PROJECT' => ENV['CI_PROJECT_PATH'],
'UPSTREAM_TRIGGER_SOURCE' => ENV['TRIGGER_SOURCE'],
'TRIGGERED_USER' => ENV['TRIGGERED_USER'] || ENV['GITLAB_USER_NAME'], 'TRIGGERED_USER' => ENV['TRIGGERED_USER'] || ENV['GITLAB_USER_NAME'],
'TRIGGER_SOURCE' => ENV['CI_JOB_URL'] 'TRIGGER_SOURCE' => ENV['CI_JOB_URL'],
'TOP_UPSTREAM_SOURCE_PROJECT' => ENV['CI_PROJECT_PATH'],
'TOP_UPSTREAM_SOURCE_JOB' => ENV['CI_JOB_URL'],
'TOP_UPSTREAM_SOURCE_SHA' => ENV['CI_COMMIT_SHA']
} }
end end
......
...@@ -20,12 +20,35 @@ ...@@ -20,12 +20,35 @@
"name" "name"
], ],
"properties": { "properties": {
"name": { "type": "string" } "name": { "type": "string" },
"ref_path": { "type": "string" }
}, },
"additionalProperties": false "additionalProperties": false
}, },
"sha": { "type": "string" }, "sha": { "type": "string" },
"tag": { "type": "boolean" } "tag": { "type": "boolean" },
"user": {
"oneOf": [
{ "type": "null" },
{ "$ref": "entities/user.json" }
]
},
"commit": {
"oneOf": [
{ "type": "null" },
{ "$ref": "entities/commit.json" }
]
},
"deployable": {
"oneOf": [
{ "type": "null" },
{ "$ref": "job/job.json" }
]
},
"manual_actions": {
"type": "array",
"items": { "$ref": "job/job.json" }
}
}, },
"additionalProperties": false "additionalProperties": false
} }
...@@ -17,11 +17,10 @@ ...@@ -17,11 +17,10 @@
"author": { "author": {
"oneOf": [ "oneOf": [
{ "type": "null" }, { "type": "null" },
{ "type": "user.json" } { "$ref": "user.json" }
] ]
} }
}, }
"additionalProperties": false
} }
] ]
} }
import BoardService from '~/boards/services/board_service'; import BoardService from '~/boards/services/board_service';
<<<<<<< HEAD
export const boardObj = { export const boardObj = {
id: 1, id: 1,
name: 'test', name: 'test',
milestone_id: null, milestone_id: null,
}; };
=======
>>>>>>> upstream/master
export const listObj = { export const listObj = {
id: 300, id: 300,
position: 0, position: 0,
......
# frozen_string_literal: true
require 'spec_helper'
describe DeploymentSerializer do
set(:project) { create(:project, :repository) }
set(:user) { create(:user, email: project.commit.author_email) }
let(:resource) { create(:deployment, project: project, sha: project.commit.id) }
let(:serializer) { described_class.new(request) }
shared_examples 'json schema' do
let(:json_entity) { subject.as_json }
it 'matches deployment entity schema' do
expect(json_entity).to match_schema('deployment')
end
end
describe '#represent' do
subject { serializer.represent(resource) }
let(:request) { { project: project, current_user: user } }
it_behaves_like 'json schema'
end
describe '#represent_concise' do
subject { serializer.represent_concise(resource) }
let(:request) { { project: project } }
it_behaves_like 'json schema'
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