diff options
Diffstat (limited to 'app/assets')
44 files changed, 923 insertions, 752 deletions
diff --git a/app/assets/images/icon-merge-request-unmerged.svg b/app/assets/images/icon-merge-request-unmerged.svg new file mode 100644 index 00000000000..c4d8e65122d --- /dev/null +++ b/app/assets/images/icon-merge-request-unmerged.svg @@ -0,0 +1 @@ +<svg width="12" height="15" viewBox="0 0 12 15" xmlns="http://www.w3.org/2000/svg"><path d="M10.267 11.028V5.167c-.028-.728-.318-1.372-.878-1.923-.56-.55-1.194-.85-1.922-.877h-.934V.5l-2.8 2.8 2.8 2.8V4.233h.934a.976.976 0 0 1 .644.29.88.88 0 0 1 .289.644v5.861a1.86 1.86 0 0 0 .933 3.472 1.86 1.86 0 0 0 .934-3.472zM3.733 3.3a1.86 1.86 0 0 0-1.866-1.867 1.86 1.86 0 0 0-.934 3.472v6.123a1.86 1.86 0 0 0 .933 3.472 1.86 1.86 0 0 0 .934-3.472V4.905c.55-.317.933-.914.933-1.605z" fill-rule="nonzero"/></svg> diff --git a/app/assets/images/mailers/gitlab_footer_logo.gif b/app/assets/images/mailers/gitlab_footer_logo.gif Binary files differnew file mode 100644 index 00000000000..3f4ef31947b --- /dev/null +++ b/app/assets/images/mailers/gitlab_footer_logo.gif diff --git a/app/assets/images/mailers/gitlab_header_logo.gif b/app/assets/images/mailers/gitlab_header_logo.gif Binary files differnew file mode 100644 index 00000000000..387628f831c --- /dev/null +++ b/app/assets/images/mailers/gitlab_header_logo.gif diff --git a/app/assets/javascripts/ajax_loading_spinner.js b/app/assets/javascripts/ajax_loading_spinner.js new file mode 100644 index 00000000000..38a8317dbd7 --- /dev/null +++ b/app/assets/javascripts/ajax_loading_spinner.js @@ -0,0 +1,35 @@ +class AjaxLoadingSpinner { + static init() { + const $elements = $('.js-ajax-loading-spinner'); + + $elements.on('ajax:beforeSend', AjaxLoadingSpinner.ajaxBeforeSend); + $elements.on('ajax:complete', AjaxLoadingSpinner.ajaxComplete); + } + + static ajaxBeforeSend(e) { + e.target.setAttribute('disabled', ''); + const iconElement = e.target.querySelector('i'); + // get first fa- icon + const originalIcon = iconElement.className.match(/(fa-)([^\s]+)/g).first(); + iconElement.dataset.icon = originalIcon; + AjaxLoadingSpinner.toggleLoadingIcon(iconElement); + $(e.target).off('ajax:beforeSend', AjaxLoadingSpinner.ajaxBeforeSend); + } + + static ajaxComplete(e) { + e.target.removeAttribute('disabled'); + const iconElement = e.target.querySelector('i'); + AjaxLoadingSpinner.toggleLoadingIcon(iconElement); + $(e.target).off('ajax:complete', AjaxLoadingSpinner.ajaxComplete); + } + + static toggleLoadingIcon(iconElement) { + const classList = iconElement.classList; + classList.toggle(iconElement.dataset.icon); + classList.toggle('fa-spinner'); + classList.toggle('fa-spin'); + } +} + +window.gl = window.gl || {}; +gl.AjaxLoadingSpinner = AjaxLoadingSpinner; diff --git a/app/assets/javascripts/boards/boards_bundle.js.es6 b/app/assets/javascripts/boards/boards_bundle.js.es6 index 878ad1b6031..55d13be6e5f 100644 --- a/app/assets/javascripts/boards/boards_bundle.js.es6 +++ b/app/assets/javascripts/boards/boards_bundle.js.es6 @@ -1,16 +1,20 @@ -/* eslint-disable one-var, quote-props, comma-dangle, space-before-function-paren, import/newline-after-import, no-multi-spaces, max-len */ +/* eslint-disable one-var, quote-props, comma-dangle, space-before-function-paren */ /* global Vue */ /* global BoardService */ -function requireAll(context) { return context.keys().map(context); } - window.Vue = require('vue'); window.Vue.use(require('vue-resource')); -requireAll(require.context('./models', true, /^\.\/.*\.(js|es6)$/)); -requireAll(require.context('./stores', true, /^\.\/.*\.(js|es6)$/)); -requireAll(require.context('./services', true, /^\.\/.*\.(js|es6)$/)); -requireAll(require.context('./mixins', true, /^\.\/.*\.(js|es6)$/)); -requireAll(require.context('./filters', true, /^\.\/.*\.(js|es6)$/)); +require('./models/issue'); +require('./models/label'); +require('./models/list'); +require('./models/milestone'); +require('./models/user'); +require('./stores/boards_store'); +require('./stores/modal_store'); +require('./services/board_service'); +require('./mixins/modal_mixins'); +require('./mixins/sortable_default_options'); +require('./filters/due_date_filters'); require('./components/board'); require('./components/board_sidebar'); require('./components/new_list_dropdown'); @@ -93,17 +97,53 @@ $(() => { modal: ModalStore.store, store: Store.state, }, + watch: { + disabled() { + this.updateTooltip(); + }, + }, computed: { disabled() { return !this.store.lists.filter(list => list.type !== 'blank' && list.type !== 'done').length; }, + tooltipTitle() { + if (this.disabled) { + return 'Please add a list to your board first'; + } + + return ''; + }, + }, + methods: { + updateTooltip() { + const $tooltip = $(this.$el); + + this.$nextTick(() => { + if (this.disabled) { + $tooltip.tooltip(); + } else { + $tooltip.tooltip('destroy'); + } + }); + }, + openModal() { + if (!this.disabled) { + this.toggleModal(true); + } + }, + }, + mounted() { + this.updateTooltip(); }, template: ` <button - class="btn btn-create pull-right prepend-left-10 has-tooltip" + class="btn btn-create pull-right prepend-left-10" type="button" - :disabled="disabled" - @click="toggleModal(true)"> + data-placement="bottom" + :class="{ 'disabled': disabled }" + :title="tooltipTitle" + :aria-disabled="disabled" + @click="openModal"> Add issues </button> `, diff --git a/app/assets/javascripts/boards/components/board_card.js b/app/assets/javascripts/boards/components/board_card.js new file mode 100644 index 00000000000..52f61d84517 --- /dev/null +++ b/app/assets/javascripts/boards/components/board_card.js @@ -0,0 +1,69 @@ +/* global Vue */ +require('./issue_card_inner'); + +const Store = gl.issueBoards.BoardsStore; + +module.exports = { + name: 'BoardsIssueCard', + template: ` + <li class="card" + :class="{ 'user-can-drag': !disabled && issue.id, 'is-disabled': disabled || !issue.id, 'is-active': issueDetailVisible }" + :index="index" + :data-issue-id="issue.id" + @mousedown="mouseDown" + @mousemove="mouseMove" + @mouseup="showIssue($event)"> + <issue-card-inner + :list="list" + :issue="issue" + :issue-link-base="issueLinkBase" + :root-path="rootPath" /> + </li> + `, + components: { + 'issue-card-inner': gl.issueBoards.IssueCardInner, + }, + props: { + list: Object, + issue: Object, + issueLinkBase: String, + disabled: Boolean, + index: Number, + rootPath: String, + }, + data() { + return { + showDetail: false, + detailIssue: Store.detail, + }; + }, + computed: { + issueDetailVisible() { + return this.detailIssue.issue && this.detailIssue.issue.id === this.issue.id; + }, + }, + methods: { + mouseDown() { + this.showDetail = true; + }, + mouseMove() { + this.showDetail = false; + }, + showIssue(e) { + const targetTagName = e.target.tagName.toLowerCase(); + + if (targetTagName === 'a' || targetTagName === 'button') return; + + if (this.showDetail) { + this.showDetail = false; + + if (Store.detail.issue && Store.detail.issue.id === this.issue.id) { + Store.detail.issue = {}; + } else { + Store.detail.issue = this.issue; + Store.detail.list = this.list; + } + } + }, + }, +}; diff --git a/app/assets/javascripts/boards/components/board_card.js.es6 b/app/assets/javascripts/boards/components/board_card.js.es6 deleted file mode 100644 index 0ea66bd027c..00000000000 --- a/app/assets/javascripts/boards/components/board_card.js.es6 +++ /dev/null @@ -1,61 +0,0 @@ -/* eslint-disable comma-dangle, space-before-function-paren, dot-notation */ -/* global Vue */ - -require('./issue_card_inner'); - -(() => { - const Store = gl.issueBoards.BoardsStore; - - window.gl = window.gl || {}; - window.gl.issueBoards = window.gl.issueBoards || {}; - - gl.issueBoards.BoardCard = Vue.extend({ - template: '#js-board-list-card', - components: { - 'issue-card-inner': gl.issueBoards.IssueCardInner, - }, - props: { - list: Object, - issue: Object, - issueLinkBase: String, - disabled: Boolean, - index: Number, - rootPath: String, - }, - data () { - return { - showDetail: false, - detailIssue: Store.detail - }; - }, - computed: { - issueDetailVisible () { - return this.detailIssue.issue && this.detailIssue.issue.id === this.issue.id; - } - }, - methods: { - mouseDown () { - this.showDetail = true; - }, - mouseMove() { - this.showDetail = false; - }, - showIssue (e) { - const targetTagName = e.target.tagName.toLowerCase(); - - if (targetTagName === 'a' || targetTagName === 'button') return; - - if (this.showDetail) { - this.showDetail = false; - - if (Store.detail.issue && Store.detail.issue.id === this.issue.id) { - Store.detail.issue = {}; - } else { - Store.detail.issue = this.issue; - Store.detail.list = this.list; - } - } - } - } - }); -})(); diff --git a/app/assets/javascripts/boards/components/board_list.js.es6 b/app/assets/javascripts/boards/components/board_list.js.es6 index 60b0a30af3f..d92047cc0f8 100644 --- a/app/assets/javascripts/boards/components/board_list.js.es6 +++ b/app/assets/javascripts/boards/components/board_list.js.es6 @@ -2,7 +2,7 @@ /* global Vue */ /* global Sortable */ -require('./board_card'); +const boardCard = require('./board_card'); require('./board_new_issue'); (() => { @@ -14,7 +14,7 @@ require('./board_new_issue'); gl.issueBoards.BoardList = Vue.extend({ template: '#js-board-list-template', components: { - 'board-card': gl.issueBoards.BoardCard, + boardCard, 'board-new-issue': gl.issueBoards.BoardNewIssue }, props: { diff --git a/app/assets/javascripts/create_label.js.es6 b/app/assets/javascripts/create_label.js.es6 index 947c129d5b5..85384d98126 100644 --- a/app/assets/javascripts/create_label.js.es6 +++ b/app/assets/javascripts/create_label.js.es6 @@ -107,9 +107,9 @@ if (typeof label.message === 'string') { errors = label.message; } else { - errors = label.message.map(function (value, key) { - return key + " " + value[0]; - }).join("<br/>"); + errors = Object.keys(label.message).map(key => + `${gl.text.humanize(key)} ${label.message[key].join(', ')}` + ).join("<br/>"); } this.$newLabelError diff --git a/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js.es6 b/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js.es6 index 1ac715aab77..411ac7b24b2 100644 --- a/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js.es6 +++ b/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js.es6 @@ -4,10 +4,20 @@ window.Vue = require('vue'); window.Cookies = require('js-cookie'); - -function requireAll(context) { return context.keys().map(context); } -requireAll(require.context('./svg', false, /^\.\/.*\.(js|es6)$/)); -requireAll(require.context('.', true, /^\.\/(?!cycle_analytics_bundle).*\.(js|es6)$/)); +require('./svg/icon_branch'); +require('./svg/icon_build_status'); +require('./svg/icon_commit'); +require('./components/stage_code_component'); +require('./components/stage_issue_component'); +require('./components/stage_plan_component'); +require('./components/stage_production_component'); +require('./components/stage_review_component'); +require('./components/stage_staging_component'); +require('./components/stage_test_component'); +require('./components/total_time_component'); +require('./cycle_analytics_service'); +require('./cycle_analytics_store'); +require('./default_event_objects'); $(() => { const OVERVIEW_DIALOG_COOKIE = 'cycle_analytics_help_dismissed'; diff --git a/app/assets/javascripts/diff_notes/diff_notes_bundle.js.es6 b/app/assets/javascripts/diff_notes/diff_notes_bundle.js.es6 index 190461451d5..cadf8b96b87 100644 --- a/app/assets/javascripts/diff_notes/diff_notes_bundle.js.es6 +++ b/app/assets/javascripts/diff_notes/diff_notes_bundle.js.es6 @@ -1,14 +1,18 @@ -/* eslint-disable func-names, comma-dangle, new-cap, no-new, import/newline-after-import, no-multi-spaces, max-len */ +/* eslint-disable func-names, comma-dangle, new-cap, no-new, max-len */ /* global Vue */ /* global ResolveCount */ -function requireAll(context) { return context.keys().map(context); } const Vue = require('vue'); -requireAll(require.context('./models', false, /^\.\/.*\.(js|es6)$/)); -requireAll(require.context('./stores', false, /^\.\/.*\.(js|es6)$/)); -requireAll(require.context('./services', false, /^\.\/.*\.(js|es6)$/)); -requireAll(require.context('./mixins', false, /^\.\/.*\.(js|es6)$/)); -requireAll(require.context('./components', false, /^\.\/.*\.(js|es6)$/)); +require('./models/discussion'); +require('./models/note'); +require('./stores/comments'); +require('./services/resolve'); +require('./mixins/discussion'); +require('./components/comment_resolve_btn'); +require('./components/jump_to_discussion'); +require('./components/resolve_btn'); +require('./components/resolve_count'); +require('./components/resolve_discussion_btn'); $(() => { const projectPath = document.querySelector('.merge-request').dataset.projectPath; diff --git a/app/assets/javascripts/dispatcher.js.es6 b/app/assets/javascripts/dispatcher.js.es6 index 45aa6050aed..089ecedeb78 100644 --- a/app/assets/javascripts/dispatcher.js.es6 +++ b/app/assets/javascripts/dispatcher.js.es6 @@ -74,7 +74,7 @@ const ShortcutsBlob = require('./shortcuts_blob'); case 'projects:merge_requests:index': case 'projects:issues:index': if (gl.FilteredSearchManager) { - new gl.FilteredSearchManager(); + new gl.FilteredSearchManager(page === 'projects:issues:index' ? 'issues' : 'merge_requests'); } Issuable.init(); new gl.IssuableBulkActions({ @@ -108,6 +108,9 @@ const ShortcutsBlob = require('./shortcuts_blob'); case 'projects:compare:show': new gl.Diff(); break; + case 'projects:branches:index': + gl.AjaxLoadingSpinner.init(); + break; case 'projects:issues:new': case 'projects:issues:edit': shortcut_handler = new ShortcutsNavigation(); diff --git a/app/assets/javascripts/dropzone_input.js b/app/assets/javascripts/dropzone_input.js index 64a7a9eaf37..646f836aff0 100644 --- a/app/assets/javascripts/dropzone_input.js +++ b/app/assets/javascripts/dropzone_input.js @@ -126,13 +126,14 @@ require('./preview_markdown'); }; pasteText = function(text) { var afterSelection, beforeSelection, caretEnd, caretStart, textEnd; + var formattedText = text + "\n\n"; caretStart = $(child)[0].selectionStart; caretEnd = $(child)[0].selectionEnd; textEnd = $(child).val().length; beforeSelection = $(child).val().substring(0, caretStart); afterSelection = $(child).val().substring(caretEnd, textEnd); - $(child).val(beforeSelection + text + afterSelection); - child.get(0).setSelectionRange(caretStart + text.length, caretEnd + text.length); + $(child).val(beforeSelection + formattedText + afterSelection); + child.get(0).setSelectionRange(caretStart + formattedText.length, caretEnd + formattedText.length); return form_textarea.trigger("input"); }; getFilename = function(e) { diff --git a/app/assets/javascripts/environments/components/environment_actions.js.es6 b/app/assets/javascripts/environments/components/environment_actions.js.es6 index c5a714d9673..978d4dd8b6b 100644 --- a/app/assets/javascripts/environments/components/environment_actions.js.es6 +++ b/app/assets/javascripts/environments/components/environment_actions.js.es6 @@ -15,29 +15,29 @@ module.exports = Vue.component('actions-component', { }, template: ` - <div class="inline"> - <div class="dropdown"> - <a class="dropdown-new btn btn-default" data-toggle="dropdown"> + <div class="btn-group" role="group"> + <button class="dropdown btn btn-default dropdown-new" data-toggle="dropdown"> + <span> <span class="js-dropdown-play-icon-container" v-html="playIconSvg"></span> <i class="fa fa-caret-down"></i> - </a> + </span> - <ul class="dropdown-menu dropdown-menu-align-right"> - <li v-for="action in actions"> - <a :href="action.play_path" - data-method="post" - rel="nofollow" - class="js-manual-action-link"> + <ul class="dropdown-menu dropdown-menu-align-right"> + <li v-for="action in actions"> + <a :href="action.play_path" + data-method="post" + rel="nofollow" + class="js-manual-action-link"> - <span class="js-action-play-icon-container" v-html="playIconSvg"></span> + <span class="js-action-play-icon-container" v-html="playIconSvg"></span> - <span> - {{action.name}} - </span> - </a> - </li> - </ul> - </div> - </div> + <span> + {{action.name}} + </span> + </a> + </li> + </ul> + </button> + </div> `, }); diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6 index 24fd58a301a..ad9d1d21a79 100644 --- a/app/assets/javascripts/environments/components/environment_item.js.es6 +++ b/app/assets/javascripts/environments/components/environment_item.js.es6 @@ -505,39 +505,26 @@ module.exports = Vue.component('environment-item', { <td class="hidden-xs"> <div v-if="!model.isFolder"> - <div v-if="hasManualActions && canCreateDeployment" - class="inline js-manual-actions-container"> - <actions-component + <div class="btn-group" role="group"> + <actions-component v-if="hasManualActions && canCreateDeployment" :play-icon-svg="playIconSvg" :actions="manualActions"> </actions-component> - </div> - <div v-if="externalURL && canReadEnvironment" - class="inline js-external-url-container"> - <external-url-component + <external-url-component v-if="externalURL && canReadEnvironment" :external-url="externalURL"> </external-url-component> - </div> - <div v-if="hasStopAction && canCreateDeployment" - class="inline js-stop-component-container"> - <stop-component + <stop-component v-if="hasStopAction && canCreateDeployment" :stop-url="model.stop_path"> </stop-component> - </div> - <div v-if="model && model.terminal_path" - class="inline js-terminal-button-container"> - <terminal-button-component + <terminal-button-component v-if="model && model.terminal_path" :terminal-icon-svg="terminalIconSvg" :terminal-path="model.terminal_path"> </terminal-button-component> - </div> - <div v-if="canRetry && canCreateDeployment" - class="inline js-rollback-component-container"> - <rollback-component + <rollback-component v-if="canRetry && canCreateDeployment" :is-last-deployment="isLastDeployment" :retry-url="retryUrl"> </rollback-component> diff --git a/app/assets/javascripts/filtered_search/dropdown_hint.js.es6 b/app/assets/javascripts/filtered_search/dropdown_hint.js.es6 index 572c221929a..9e92d544bef 100644 --- a/app/assets/javascripts/filtered_search/dropdown_hint.js.es6 +++ b/app/assets/javascripts/filtered_search/dropdown_hint.js.es6 @@ -37,23 +37,18 @@ require('./filtered_search_dropdown'); } renderContent() { - const dropdownData = [{ - icon: 'fa-pencil', - hint: 'author:', - tag: '<@author>', - }, { - icon: 'fa-user', - hint: 'assignee:', - tag: '<@assignee>', - }, { - icon: 'fa-clock-o', - hint: 'milestone:', - tag: '<%milestone>', - }, { - icon: 'fa-tag', - hint: 'label:', - tag: '<~label>', - }]; + const dropdownData = []; + + [].forEach.call(this.input.parentElement.querySelectorAll('.dropdown-menu'), (dropdownMenu) => { + const { icon, hint, tag } = dropdownMenu.dataset; + if (icon && hint && tag) { + dropdownData.push({ + icon: `fa-${icon}`, + hint, + tag: `<${tag}>`, + }); + } + }); this.droplab.changeHookList(this.hookId, this.dropdown, [droplabFilter], this.config); this.droplab.setData(this.hookId, dropdownData); diff --git a/app/assets/javascripts/filtered_search/filtered_search_bundle.js b/app/assets/javascripts/filtered_search/filtered_search_bundle.js index 392f1835966..faaba994f46 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_bundle.js +++ b/app/assets/javascripts/filtered_search/filtered_search_bundle.js @@ -1,3 +1,9 @@ -function requireAll(context) { return context.keys().map(context); } - -requireAll(require.context('./', true, /^\.\/(?!filtered_search_bundle).*\.(js|es6)$/)); +require('./dropdown_hint'); +require('./dropdown_non_user'); +require('./dropdown_user'); +require('./dropdown_utils'); +require('./filtered_search_dropdown_manager'); +require('./filtered_search_dropdown'); +require('./filtered_search_manager'); +require('./filtered_search_token_keys'); +require('./filtered_search_tokenizer'); diff --git a/app/assets/javascripts/filtered_search/filtered_search_dropdown.js.es6 b/app/assets/javascripts/filtered_search/filtered_search_dropdown.js.es6 index e8c2df03a46..fbc72a3001a 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_dropdown.js.es6 +++ b/app/assets/javascripts/filtered_search/filtered_search_dropdown.js.es6 @@ -52,8 +52,9 @@ } renderContent(forceShowList = false) { - if (forceShowList && this.getCurrentHook().list.hidden) { - this.getCurrentHook().list.show(); + const currentHook = this.getCurrentHook(); + if (forceShowList && currentHook && currentHook.list.hidden) { + currentHook.list.show(); } } @@ -92,18 +93,24 @@ } hideDropdown() { - this.getCurrentHook().list.hide(); + const currentHook = this.getCurrentHook(); + if (currentHook) { + currentHook.list.hide(); + } } resetFilters() { const hook = this.getCurrentHook(); - const data = hook.list.data; - const results = data.map((o) => { - const updated = o; - updated.droplab_hidden = false; - return updated; - }); - hook.list.render(results); + + if (hook) { + const data = hook.list.data; + const results = data.map((o) => { + const updated = o; + updated.droplab_hidden = false; + return updated; + }); + hook.list.render(results); + } } } diff --git a/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js.es6 b/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js.es6 index 8ce4cf4fc36..cecd3518ce3 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js.es6 +++ b/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js.es6 @@ -2,10 +2,12 @@ (() => { class FilteredSearchDropdownManager { - constructor(baseEndpoint = '') { + constructor(baseEndpoint = '', page) { this.baseEndpoint = baseEndpoint.replace(/\/$/, ''); this.tokenizer = gl.FilteredSearchTokenizer; + this.filteredSearchTokenKeys = gl.FilteredSearchTokenKeys; this.filteredSearchInput = document.querySelector('.filtered-search'); + this.page = page; this.setupMapping(); @@ -150,7 +152,7 @@ this.droplab = new DropLab(); } - const match = gl.FilteredSearchTokenKeys.searchByKey(dropdownName.toLowerCase()); + const match = this.filteredSearchTokenKeys.searchByKey(dropdownName.toLowerCase()); const shouldOpenFilterDropdown = match && this.currentDropdown !== match.key && this.mapping[match.key]; const shouldOpenHintDropdown = !match && this.currentDropdown !== 'hint'; diff --git a/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6 b/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6 index ffc7d29e4c5..bbafead0305 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6 +++ b/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6 @@ -1,12 +1,13 @@ (() => { class FilteredSearchManager { - constructor() { + constructor(page) { this.filteredSearchInput = document.querySelector('.filtered-search'); this.clearSearchButton = document.querySelector('.clear-search'); + this.filteredSearchTokenKeys = gl.FilteredSearchTokenKeys; if (this.filteredSearchInput) { this.tokenizer = gl.FilteredSearchTokenizer; - this.dropdownManager = new gl.FilteredSearchDropdownManager(this.filteredSearchInput.getAttribute('data-base-endpoint') || ''); + this.dropdownManager = new gl.FilteredSearchDropdownManager(this.filteredSearchInput.getAttribute('data-base-endpoint') || '', page); this.bindEvents(); this.loadSearchParamsFromURL(); @@ -117,8 +118,8 @@ const keyParam = decodeURIComponent(split[0]); const value = split[1]; - // Check if it matches edge conditions listed in gl.FilteredSearchTokenKeys - const condition = gl.FilteredSearchTokenKeys.searchByConditionUrl(p); + // Check if it matches edge conditions listed in this.filteredSearchTokenKeys + const condition = this.filteredSearchTokenKeys.searchByConditionUrl(p); if (condition) { inputValues.push(`${condition.tokenKey}:${condition.value}`); @@ -126,7 +127,7 @@ // Sanitize value since URL converts spaces into + // Replace before decode so that we know what was originally + versus the encoded + const sanitizedValue = value ? decodeURIComponent(value.replace(/\+/g, ' ')) : value; - const match = gl.FilteredSearchTokenKeys.searchByKeyParam(keyParam); + const match = this.filteredSearchTokenKeys.searchByKeyParam(keyParam); if (match) { const indexOf = keyParam.indexOf('_'); @@ -171,9 +172,9 @@ paths.push(`state=${currentState}`); tokens.forEach((token) => { - const condition = gl.FilteredSearchTokenKeys + const condition = this.filteredSearchTokenKeys .searchByConditionKeyValue(token.key, token.value.toLowerCase()); - const { param } = gl.FilteredSearchTokenKeys.searchByKey(token.key); + const { param } = this.filteredSearchTokenKeys.searchByKey(token.key) || {}; const keyParam = param ? `${token.key}_${param}` : token.key; let tokenPath = ''; diff --git a/app/assets/javascripts/filtered_search/filtered_search_tokenizer.js.es6 b/app/assets/javascripts/filtered_search/filtered_search_tokenizer.js.es6 index cf53845a48b..9bf1b1ced88 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_tokenizer.js.es6 +++ b/app/assets/javascripts/filtered_search/filtered_search_tokenizer.js.es6 @@ -1,9 +1,12 @@ +require('./filtered_search_token_keys'); + (() => { class FilteredSearchTokenizer { static processTokens(input) { + const allowedKeys = gl.FilteredSearchTokenKeys.get().map(i => i.key); // Regex extracts `(token):(symbol)(value)` // Values that start with a double quote must end in a double quote (same for single) - const tokenRegex = /(\w+):([~%@]?)(?:('[^']*'{0,1})|("[^"]*"{0,1})|(\S+))/g; + const tokenRegex = new RegExp(`(${allowedKeys.join('|')}):([~%@]?)(?:('[^']*'{0,1})|("[^"]*"{0,1})|(\\S+))`, 'g'); const tokens = []; let lastToken = null; const searchToken = input.replace(tokenRegex, (match, key, symbol, v1, v2, v3) => { diff --git a/app/assets/javascripts/gl_dropdown.js b/app/assets/javascripts/gl_dropdown.js index bf3da8528f0..a01662e2f9e 100644 --- a/app/assets/javascripts/gl_dropdown.js +++ b/app/assets/javascripts/gl_dropdown.js @@ -47,9 +47,10 @@ } // Only filter asynchronously only if option remote is set if (this.options.remote) { - $inputContainer.parent().addClass('is-loading'); clearTimeout(timeout); return timeout = setTimeout(function() { + $inputContainer.parent().addClass('is-loading'); + return this.options.query(this.input.val(), function(data) { $inputContainer.parent().removeClass('is-loading'); return this.options.callback(data); diff --git a/app/assets/javascripts/graphs/graphs_bundle.js b/app/assets/javascripts/graphs/graphs_bundle.js index 4f7777aa5bc..ea5afbd9d29 100644 --- a/app/assets/javascripts/graphs/graphs_bundle.js +++ b/app/assets/javascripts/graphs/graphs_bundle.js @@ -1,3 +1,4 @@ -// require everything else in this directory -function requireAll(context) { return context.keys().map(context); } -requireAll(require.context('.', false, /^\.\/(?!graphs_bundle).*\.(js|es6)$/)); +import ContributorsStatGraph from './stat_graph_contributors'; + +// export to global scope +window.ContributorsStatGraph = ContributorsStatGraph; diff --git a/app/assets/javascripts/graphs/stat_graph.js b/app/assets/javascripts/graphs/stat_graph.js deleted file mode 100644 index 75a53aae33c..00000000000 --- a/app/assets/javascripts/graphs/stat_graph.js +++ /dev/null @@ -1,18 +0,0 @@ -/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-return-assign, max-len */ -(function() { - this.StatGraph = (function() { - function StatGraph() {} - - StatGraph.log = {}; - - StatGraph.get_log = function() { - return this.log; - }; - - StatGraph.set_log = function(data) { - return this.log = data; - }; - - return StatGraph; - })(); -}).call(window); diff --git a/app/assets/javascripts/graphs/stat_graph_contributors.js b/app/assets/javascripts/graphs/stat_graph_contributors.js index bbfb467ad50..c6be4c9e8fe 100644 --- a/app/assets/javascripts/graphs/stat_graph_contributors.js +++ b/app/assets/javascripts/graphs/stat_graph_contributors.js @@ -1,116 +1,111 @@ -/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, one-var, camelcase, one-var-declaration-per-line, quotes, no-param-reassign, quote-props, comma-dangle, prefer-template, max-len, no-return-assign */ -/* global ContributorsGraph */ -/* global ContributorsAuthorGraph */ -/* global ContributorsMasterGraph */ -/* global ContributorsStatGraphUtil */ -/* global d3 */ +/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, one-var, camelcase, one-var-declaration-per-line, quotes, no-param-reassign, quote-props, comma-dangle, prefer-template, max-len, no-return-assign, no-shadow */ -window.d3 = require('d3'); +import d3 from 'd3'; +import { ContributorsGraph, ContributorsAuthorGraph, ContributorsMasterGraph } from './stat_graph_contributors_graph'; +import ContributorsStatGraphUtil from './stat_graph_contributors_util'; -(function() { - this.ContributorsStatGraph = (function() { - function ContributorsStatGraph() {} +export default (function() { + function ContributorsStatGraph() {} - ContributorsStatGraph.prototype.init = function(log) { - var author_commits, total_commits; - this.parsed_log = ContributorsStatGraphUtil.parse_log(log); - this.set_current_field("commits"); - total_commits = ContributorsStatGraphUtil.get_total_data(this.parsed_log, this.field); - author_commits = ContributorsStatGraphUtil.get_author_data(this.parsed_log, this.field); - this.add_master_graph(total_commits); - this.add_authors_graph(author_commits); - return this.change_date_header(); - }; + ContributorsStatGraph.prototype.init = function(log) { + var author_commits, total_commits; + this.parsed_log = ContributorsStatGraphUtil.parse_log(log); + this.set_current_field("commits"); + total_commits = ContributorsStatGraphUtil.get_total_data(this.parsed_log, this.field); + author_commits = ContributorsStatGraphUtil.get_author_data(this.parsed_log, this.field); + this.add_master_graph(total_commits); + this.add_authors_graph(author_commits); + return this.change_date_header(); + }; - ContributorsStatGraph.prototype.add_master_graph = function(total_data) { - this.master_graph = new ContributorsMasterGraph(total_data); - return this.master_graph.draw(); - }; + ContributorsStatGraph.prototype.add_master_graph = function(total_data) { + this.master_graph = new ContributorsMasterGraph(total_data); + return this.master_graph.draw(); + }; - ContributorsStatGraph.prototype.add_authors_graph = function(author_data) { - var limited_author_data; - this.authors = []; - limited_author_data = author_data.slice(0, 100); - return _.each(limited_author_data, (function(_this) { - return function(d) { - var author_graph, author_header; - author_header = _this.create_author_header(d); - $(".contributors-list").append(author_header); - _this.authors[d.author_name] = author_graph = new ContributorsAuthorGraph(d.dates); - return author_graph.draw(); - }; - })(this)); - }; + ContributorsStatGraph.prototype.add_authors_graph = function(author_data) { + var limited_author_data; + this.authors = []; + limited_author_data = author_data.slice(0, 100); + return _.each(limited_author_data, (function(_this) { + return function(d) { + var author_graph, author_header; + author_header = _this.create_author_header(d); + $(".contributors-list").append(author_header); + _this.authors[d.author_name] = author_graph = new ContributorsAuthorGraph(d.dates); + return author_graph.draw(); + }; + })(this)); + }; - ContributorsStatGraph.prototype.format_author_commit_info = function(author) { - var commits; - commits = $('<span/>', { - "class": 'graph-author-commits-count' - }); - commits.text(author.commits + " commits"); - return $('<span/>').append(commits); - }; + ContributorsStatGraph.prototype.format_author_commit_info = function(author) { + var commits; + commits = $('<span/>', { + "class": 'graph-author-commits-count' + }); + commits.text(author.commits + " commits"); + return $('<span/>').append(commits); + }; - ContributorsStatGraph.prototype.create_author_header = function(author) { - var author_commit_info, author_commit_info_span, author_email, author_name, list_item; - list_item = $('<li/>', { - "class": 'person', - style: 'display: block;' - }); - author_name = $('<h4>' + author.author_name + '</h4>'); - author_email = $('<p class="graph-author-email">' + author.author_email + '</p>'); - author_commit_info_span = $('<span/>', { - "class": 'commits' - }); - author_commit_info = this.format_author_commit_info(author); - author_commit_info_span.html(author_commit_info); - list_item.append(author_name); - list_item.append(author_email); - list_item.append(author_commit_info_span); - return list_item; - }; + ContributorsStatGraph.prototype.create_author_header = function(author) { + var author_commit_info, author_commit_info_span, author_email, author_name, list_item; + list_item = $('<li/>', { + "class": 'person', + style: 'display: block;' + }); + author_name = $('<h4>' + author.author_name + '</h4>'); + author_email = $('<p class="graph-author-email">' + author.author_email + '</p>'); + author_commit_info_span = $('<span/>', { + "class": 'commits' + }); + author_commit_info = this.format_author_commit_info(author); + author_commit_info_span.html(author_commit_info); + list_item.append(author_name); + list_item.append(author_email); + list_item.append(author_commit_info_span); + return list_item; + }; - ContributorsStatGraph.prototype.redraw_master = function() { - var total_data; - total_data = ContributorsStatGraphUtil.get_total_data(this.parsed_log, this.field); - this.master_graph.set_data(total_data); - return this.master_graph.redraw(); - }; + ContributorsStatGraph.prototype.redraw_master = function() { + var total_data; + total_data = ContributorsStatGraphUtil.get_total_data(this.parsed_log, this.field); + this.master_graph.set_data(total_data); + return this.master_graph.redraw(); + }; - ContributorsStatGraph.prototype.redraw_authors = function() { - var author_commits, x_domain; - $("ol").html(""); - x_domain = ContributorsGraph.prototype.x_domain; - author_commits = ContributorsStatGraphUtil.get_author_data(this.parsed_log, this.field, x_domain); - return _.each(author_commits, (function(_this) { - return function(d) { - _this.redraw_author_commit_info(d); - $(_this.authors[d.author_name].list_item).appendTo("ol"); - _this.authors[d.author_name].set_data(d.dates); - return _this.authors[d.author_name].redraw(); - }; - })(this)); - }; + ContributorsStatGraph.prototype.redraw_authors = function() { + var author_commits, x_domain; + $("ol").html(""); + x_domain = ContributorsGraph.prototype.x_domain; + author_commits = ContributorsStatGraphUtil.get_author_data(this.parsed_log, this.field, x_domain); + return _.each(author_commits, (function(_this) { + return function(d) { + _this.redraw_author_commit_info(d); + $(_this.authors[d.author_name].list_item).appendTo("ol"); + _this.authors[d.author_name].set_data(d.dates); + return _this.authors[d.author_name].redraw(); + }; + })(this)); + }; - ContributorsStatGraph.prototype.set_current_field = function(field) { - return this.field = field; - }; + ContributorsStatGraph.prototype.set_current_field = function(field) { + return this.field = field; + }; - ContributorsStatGraph.prototype.change_date_header = function() { - var print, print_date_format, x_domain; - x_domain = ContributorsGraph.prototype.x_domain; - print_date_format = d3.time.format("%B %e %Y"); - print = print_date_format(x_domain[0]) + " - " + print_date_format(x_domain[1]); - return $("#date_header").text(print); - }; + ContributorsStatGraph.prototype.change_date_header = function() { + var print, print_date_format, x_domain; + x_domain = ContributorsGraph.prototype.x_domain; + print_date_format = d3.time.format("%B %e %Y"); + print = print_date_format(x_domain[0]) + " - " + print_date_format(x_domain[1]); + return $("#date_header").text(print); + }; - ContributorsStatGraph.prototype.redraw_author_commit_info = function(author) { - var author_commit_info, author_list_item; - author_list_item = $(this.authors[author.author_name].list_item); - author_commit_info = this.format_author_commit_info(author); - return author_list_item.find("span").html(author_commit_info); - }; + ContributorsStatGraph.prototype.redraw_author_commit_info = function(author) { + var author_commit_info, author_list_item; + author_list_item = $(this.authors[author.author_name].list_item); + author_commit_info = this.format_author_commit_info(author); + return author_list_item.find("span").html(author_commit_info); + }; - return ContributorsStatGraph; - })(); -}).call(window); + return ContributorsStatGraph; +})(); diff --git a/app/assets/javascripts/graphs/stat_graph_contributors_graph.js b/app/assets/javascripts/graphs/stat_graph_contributors_graph.js index 228771da4ee..521bc77db66 100644 --- a/app/assets/javascripts/graphs/stat_graph_contributors_graph.js +++ b/app/assets/javascripts/graphs/stat_graph_contributors_graph.js @@ -1,276 +1,272 @@ -/* eslint-disable func-names, space-before-function-paren, one-var, no-var, prefer-rest-params, max-len, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, comma-dangle, no-return-assign, prefer-arrow-callback, quotes, prefer-template, newline-per-chained-call, no-else-return */ -/* global d3 */ -/* global ContributorsGraph */ - -window.d3 = require('d3'); - -(function() { - var bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; }, - extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, - hasProp = {}.hasOwnProperty; - - this.ContributorsGraph = (function() { - function ContributorsGraph() {} - - ContributorsGraph.prototype.MARGIN = { - top: 20, - right: 20, - bottom: 30, - left: 50 - }; - - ContributorsGraph.prototype.x_domain = null; - - ContributorsGraph.prototype.y_domain = null; - - ContributorsGraph.prototype.dates = []; - - ContributorsGraph.set_x_domain = function(data) { - return ContributorsGraph.prototype.x_domain = data; - }; - - ContributorsGraph.set_y_domain = function(data) { - return ContributorsGraph.prototype.y_domain = [ - 0, d3.max(data, function(d) { - return d.commits = d.commits || d.additions || d.deletions; - }) - ]; - }; - - ContributorsGraph.init_x_domain = function(data) { - return ContributorsGraph.prototype.x_domain = d3.extent(data, function(d) { - return d.date; - }); - }; - - ContributorsGraph.init_y_domain = function(data) { - return ContributorsGraph.prototype.y_domain = [ - 0, d3.max(data, function(d) { - return d.commits = d.commits || d.additions || d.deletions; - }) - ]; - }; - - ContributorsGraph.init_domain = function(data) { - ContributorsGraph.init_x_domain(data); - return ContributorsGraph.init_y_domain(data); - }; - - ContributorsGraph.set_dates = function(data) { - return ContributorsGraph.prototype.dates = data; - }; - - ContributorsGraph.prototype.set_x_domain = function() { - return this.x.domain(this.x_domain); - }; - - ContributorsGraph.prototype.set_y_domain = function() { - return this.y.domain(this.y_domain); - }; - - ContributorsGraph.prototype.set_domain = function() { - this.set_x_domain(); - return this.set_y_domain(); - }; - - ContributorsGraph.prototype.create_scale = function(width, height) { - this.x = d3.time.scale().range([0, width]).clamp(true); - return this.y = d3.scale.linear().range([height, 0]).nice(); - }; - - ContributorsGraph.prototype.draw_x_axis = function() { - return this.svg.append("g").attr("class", "x axis").attr("transform", "translate(0, " + this.height + ")").call(this.x_axis); - }; - - ContributorsGraph.prototype.draw_y_axis = function() { - return this.svg.append("g").attr("class", "y axis").call(this.y_axis); - }; - - ContributorsGraph.prototype.set_data = function(data) { - return this.data = data; - }; - - return ContributorsGraph; - })(); - - this.ContributorsMasterGraph = (function(superClass) { - extend(ContributorsMasterGraph, superClass); - - function ContributorsMasterGraph(data1) { - this.data = data1; - this.update_content = bind(this.update_content, this); - this.width = $('.content').width() - 70; - this.height = 200; - this.x = null; - this.y = null; - this.x_axis = null; - this.y_axis = null; - this.area = null; - this.svg = null; - this.brush = null; - this.x_max_domain = null; +/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, max-len, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, comma-dangle, no-return-assign, prefer-arrow-callback, quotes, prefer-template, newline-per-chained-call, no-else-return, no-shadow */ + +import d3 from 'd3'; + +const bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; }; +const extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; +const hasProp = {}.hasOwnProperty; + +export const ContributorsGraph = (function() { + function ContributorsGraph() {} + + ContributorsGraph.prototype.MARGIN = { + top: 20, + right: 20, + bottom: 30, + left: 50 + }; + + ContributorsGraph.prototype.x_domain = null; + + ContributorsGraph.prototype.y_domain = null; + + ContributorsGraph.prototype.dates = []; + + ContributorsGraph.set_x_domain = function(data) { + return ContributorsGraph.prototype.x_domain = data; + }; + + ContributorsGraph.set_y_domain = function(data) { + return ContributorsGraph.prototype.y_domain = [ + 0, d3.max(data, function(d) { + return d.commits = d.commits || d.additions || d.deletions; + }) + ]; + }; + + ContributorsGraph.init_x_domain = function(data) { + return ContributorsGraph.prototype.x_domain = d3.extent(data, function(d) { + return d.date; + }); + }; + + ContributorsGraph.init_y_domain = function(data) { + return ContributorsGraph.prototype.y_domain = [ + 0, d3.max(data, function(d) { + return d.commits = d.commits || d.additions || d.deletions; + }) + ]; + }; + + ContributorsGraph.init_domain = function(data) { + ContributorsGraph.init_x_domain(data); + return ContributorsGraph.init_y_domain(data); + }; + + ContributorsGraph.set_dates = function(data) { + return ContributorsGraph.prototype.dates = data; + }; + + ContributorsGraph.prototype.set_x_domain = function() { + return this.x.domain(this.x_domain); + }; + + ContributorsGraph.prototype.set_y_domain = function() { + return this.y.domain(this.y_domain); + }; + + ContributorsGraph.prototype.set_domain = function() { + this.set_x_domain(); + return this.set_y_domain(); + }; + + ContributorsGraph.prototype.create_scale = function(width, height) { + this.x = d3.time.scale().range([0, width]).clamp(true); + return this.y = d3.scale.linear().range([height, 0]).nice(); + }; + + ContributorsGraph.prototype.draw_x_axis = function() { + return this.svg.append("g").attr("class", "x axis").attr("transform", "translate(0, " + this.height + ")").call(this.x_axis); + }; + + ContributorsGraph.prototype.draw_y_axis = function() { + return this.svg.append("g").attr("class", "y axis").call(this.y_axis); + }; + + ContributorsGraph.prototype.set_data = function(data) { + return this.data = data; + }; + + return ContributorsGraph; +})(); + +export const ContributorsMasterGraph = (function(superClass) { + extend(ContributorsMasterGraph, superClass); + + function ContributorsMasterGraph(data1) { + this.data = data1; + this.update_content = bind(this.update_content, this); + this.width = $('.content').width() - 70; + this.height = 200; + this.x = null; + this.y = null; + this.x_axis = null; + this.y_axis = null; + this.area = null; + this.svg = null; + this.brush = null; + this.x_max_domain = null; + } + + ContributorsMasterGraph.prototype.process_dates = function(data) { + var dates; + dates = this.get_dates(data); + this.parse_dates(data); + return ContributorsGraph.set_dates(dates); + }; + + ContributorsMasterGraph.prototype.get_dates = function(data) { + return _.pluck(data, 'date'); + }; + + ContributorsMasterGraph.prototype.parse_dates = function(data) { + var parseDate; + parseDate = d3.time.format("%Y-%m-%d").parse; + return data.forEach(function(d) { + return d.date = parseDate(d.date); + }); + }; + + ContributorsMasterGraph.prototype.create_scale = function() { + return ContributorsMasterGraph.__super__.create_scale.call(this, this.width, this.height); + }; + + ContributorsMasterGraph.prototype.create_axes = function() { + this.x_axis = d3.svg.axis().scale(this.x).orient("bottom"); + return this.y_axis = d3.svg.axis().scale(this.y).orient("left").ticks(5); + }; + + ContributorsMasterGraph.prototype.create_svg = function() { + return this.svg = d3.select("#contributors-master").append("svg").attr("width", this.width + this.MARGIN.left + this.MARGIN.right).attr("height", this.height + this.MARGIN.top + this.MARGIN.bottom).attr("class", "tint-box").append("g").attr("transform", "translate(" + this.MARGIN.left + "," + this.MARGIN.top + ")"); + }; + + ContributorsMasterGraph.prototype.create_area = function(x, y) { + return this.area = d3.svg.area().x(function(d) { + return x(d.date); + }).y0(this.height).y1(function(d) { + d.commits = d.commits || d.additions || d.deletions; + return y(d.commits); + }).interpolate("basis"); + }; + + ContributorsMasterGraph.prototype.create_brush = function() { + return this.brush = d3.svg.brush().x(this.x).on("brushend", this.update_content); + }; + + ContributorsMasterGraph.prototype.draw_path = function(data) { + return this.svg.append("path").datum(data).attr("class", "area").attr("d", this.area); + }; + + ContributorsMasterGraph.prototype.add_brush = function() { + return this.svg.append("g").attr("class", "selection").call(this.brush).selectAll("rect").attr("height", this.height); + }; + + ContributorsMasterGraph.prototype.update_content = function() { + ContributorsGraph.set_x_domain(this.brush.empty() ? this.x_max_domain : this.brush.extent()); + return $("#brush_change").trigger('change'); + }; + + ContributorsMasterGraph.prototype.draw = function() { + this.process_dates(this.data); + this.create_scale(); + this.create_axes(); + ContributorsGraph.init_domain(this.data); + this.x_max_domain = this.x_domain; + this.set_domain(); + this.create_area(this.x, this.y); + this.create_svg(); + this.create_brush(); + this.draw_path(this.data); + this.draw_x_axis(); + this.draw_y_axis(); + return this.add_brush(); + }; + + ContributorsMasterGraph.prototype.redraw = function() { + this.process_dates(this.data); + ContributorsGraph.set_y_domain(this.data); + this.set_y_domain(); + this.svg.select("path").datum(this.data); + this.svg.select("path").attr("d", this.area); + return this.svg.select(".y.axis").call(this.y_axis); + }; + + return ContributorsMasterGraph; +})(ContributorsGraph); + +export const ContributorsAuthorGraph = (function(superClass) { + extend(ContributorsAuthorGraph, superClass); + + function ContributorsAuthorGraph(data1) { + this.data = data1; + // Don't split graph size in half for mobile devices. + if ($(window).width() < 768) { + this.width = $('.content').width() - 80; + } else { + this.width = ($('.content').width() / 2) - 100; } - - ContributorsMasterGraph.prototype.process_dates = function(data) { - var dates; - dates = this.get_dates(data); - this.parse_dates(data); - return ContributorsGraph.set_dates(dates); - }; - - ContributorsMasterGraph.prototype.get_dates = function(data) { - return _.pluck(data, 'date'); - }; - - ContributorsMasterGraph.prototype.parse_dates = function(data) { + this.height = 200; + this.x = null; + this.y = null; + this.x_axis = null; + this.y_axis = null; + this.area = null; + this.svg = null; + this.list_item = null; + } + + ContributorsAuthorGraph.prototype.create_scale = function() { + return ContributorsAuthorGraph.__super__.create_scale.call(this, this.width, this.height); + }; + + ContributorsAuthorGraph.prototype.create_axes = function() { + this.x_axis = d3.svg.axis().scale(this.x).orient("bottom").ticks(8); + return this.y_axis = d3.svg.axis().scale(this.y).orient("left").ticks(5); + }; + + ContributorsAuthorGraph.prototype.create_area = function(x, y) { + return this.area = d3.svg.area().x(function(d) { var parseDate; parseDate = d3.time.format("%Y-%m-%d").parse; - return data.forEach(function(d) { - return d.date = parseDate(d.date); - }); - }; - - ContributorsMasterGraph.prototype.create_scale = function() { - return ContributorsMasterGraph.__super__.create_scale.call(this, this.width, this.height); - }; - - ContributorsMasterGraph.prototype.create_axes = function() { - this.x_axis = d3.svg.axis().scale(this.x).orient("bottom"); - return this.y_axis = d3.svg.axis().scale(this.y).orient("left").ticks(5); - }; - - ContributorsMasterGraph.prototype.create_svg = function() { - return this.svg = d3.select("#contributors-master").append("svg").attr("width", this.width + this.MARGIN.left + this.MARGIN.right).attr("height", this.height + this.MARGIN.top + this.MARGIN.bottom).attr("class", "tint-box").append("g").attr("transform", "translate(" + this.MARGIN.left + "," + this.MARGIN.top + ")"); - }; - - ContributorsMasterGraph.prototype.create_area = function(x, y) { - return this.area = d3.svg.area().x(function(d) { - return x(d.date); - }).y0(this.height).y1(function(d) { - d.commits = d.commits || d.additions || d.deletions; - return y(d.commits); - }).interpolate("basis"); - }; - - ContributorsMasterGraph.prototype.create_brush = function() { - return this.brush = d3.svg.brush().x(this.x).on("brushend", this.update_content); - }; - - ContributorsMasterGraph.prototype.draw_path = function(data) { - return this.svg.append("path").datum(data).attr("class", "area").attr("d", this.area); - }; - - ContributorsMasterGraph.prototype.add_brush = function() { - return this.svg.append("g").attr("class", "selection").call(this.brush).selectAll("rect").attr("height", this.height); - }; - - ContributorsMasterGraph.prototype.update_content = function() { - ContributorsGraph.set_x_domain(this.brush.empty() ? this.x_max_domain : this.brush.extent()); - return $("#brush_change").trigger('change'); - }; - - ContributorsMasterGraph.prototype.draw = function() { - this.process_dates(this.data); - this.create_scale(); - this.create_axes(); - ContributorsGraph.init_domain(this.data); - this.x_max_domain = this.x_domain; - this.set_domain(); - this.create_area(this.x, this.y); - this.create_svg(); - this.create_brush(); - this.draw_path(this.data); - this.draw_x_axis(); - this.draw_y_axis(); - return this.add_brush(); - }; - - ContributorsMasterGraph.prototype.redraw = function() { - this.process_dates(this.data); - ContributorsGraph.set_y_domain(this.data); - this.set_y_domain(); - this.svg.select("path").datum(this.data); - this.svg.select("path").attr("d", this.area); - return this.svg.select(".y.axis").call(this.y_axis); - }; - - return ContributorsMasterGraph; - })(ContributorsGraph); - - this.ContributorsAuthorGraph = (function(superClass) { - extend(ContributorsAuthorGraph, superClass); - - function ContributorsAuthorGraph(data1) { - this.data = data1; - // Don't split graph size in half for mobile devices. - if ($(window).width() < 768) { - this.width = $('.content').width() - 80; - } else { - this.width = ($('.content').width() / 2) - 100; - } - this.height = 200; - this.x = null; - this.y = null; - this.x_axis = null; - this.y_axis = null; - this.area = null; - this.svg = null; - this.list_item = null; - } - - ContributorsAuthorGraph.prototype.create_scale = function() { - return ContributorsAuthorGraph.__super__.create_scale.call(this, this.width, this.height); - }; - - ContributorsAuthorGraph.prototype.create_axes = function() { - this.x_axis = d3.svg.axis().scale(this.x).orient("bottom").ticks(8); - return this.y_axis = d3.svg.axis().scale(this.y).orient("left").ticks(5); - }; - - ContributorsAuthorGraph.prototype.create_area = function(x, y) { - return this.area = d3.svg.area().x(function(d) { - var parseDate; - parseDate = d3.time.format("%Y-%m-%d").parse; - return x(parseDate(d)); - }).y0(this.height).y1((function(_this) { - return function(d) { - if (_this.data[d] != null) { - return y(_this.data[d]); - } else { - return y(0); - } - }; - })(this)).interpolate("basis"); - }; - - ContributorsAuthorGraph.prototype.create_svg = function() { - this.list_item = d3.selectAll(".person")[0].pop(); - return this.svg = d3.select(this.list_item).append("svg").attr("width", this.width + this.MARGIN.left + this.MARGIN.right).attr("height", this.height + this.MARGIN.top + this.MARGIN.bottom).attr("class", "spark").append("g").attr("transform", "translate(" + this.MARGIN.left + "," + this.MARGIN.top + ")"); - }; - - ContributorsAuthorGraph.prototype.draw_path = function(data) { - return this.svg.append("path").datum(data).attr("class", "area-contributor").attr("d", this.area); - }; - - ContributorsAuthorGraph.prototype.draw = function() { - this.create_scale(); - this.create_axes(); - this.set_domain(); - this.create_area(this.x, this.y); - this.create_svg(); - this.draw_path(this.dates); - this.draw_x_axis(); - return this.draw_y_axis(); - }; - - ContributorsAuthorGraph.prototype.redraw = function() { - this.set_domain(); - this.svg.select("path").datum(this.dates); - this.svg.select("path").attr("d", this.area); - this.svg.select(".x.axis").call(this.x_axis); - return this.svg.select(".y.axis").call(this.y_axis); - }; - - return ContributorsAuthorGraph; - })(ContributorsGraph); -}).call(window); + return x(parseDate(d)); + }).y0(this.height).y1((function(_this) { + return function(d) { + if (_this.data[d] != null) { + return y(_this.data[d]); + } else { + return y(0); + } + }; + })(this)).interpolate("basis"); + }; + + ContributorsAuthorGraph.prototype.create_svg = function() { + this.list_item = d3.selectAll(".person")[0].pop(); + return this.svg = d3.select(this.list_item).append("svg").attr("width", this.width + this.MARGIN.left + this.MARGIN.right).attr("height", this.height + this.MARGIN.top + this.MARGIN.bottom).attr("class", "spark").append("g").attr("transform", "translate(" + this.MARGIN.left + "," + this.MARGIN.top + ")"); + }; + + ContributorsAuthorGraph.prototype.draw_path = function(data) { + return this.svg.append("path").datum(data).attr("class", "area-contributor").attr("d", this.area); + }; + + ContributorsAuthorGraph.prototype.draw = function() { + this.create_scale(); + this.create_axes(); + this.set_domain(); + this.create_area(this.x, this.y); + this.create_svg(); + this.draw_path(this.dates); + this.draw_x_axis(); + return this.draw_y_axis(); + }; + + ContributorsAuthorGraph.prototype.redraw = function() { + this.set_domain(); + this.svg.select("path").datum(this.dates); + this.svg.select("path").attr("d", this.area); + this.svg.select(".x.axis").call(this.x_axis); + return this.svg.select(".y.axis").call(this.y_axis); + }; + + return ContributorsAuthorGraph; +})(ContributorsGraph); diff --git a/app/assets/javascripts/graphs/stat_graph_contributors_util.js b/app/assets/javascripts/graphs/stat_graph_contributors_util.js index 7954c583598..c583757f3f2 100644 --- a/app/assets/javascripts/graphs/stat_graph_contributors_util.js +++ b/app/assets/javascripts/graphs/stat_graph_contributors_util.js @@ -1,138 +1,137 @@ /* eslint-disable func-names, space-before-function-paren, object-shorthand, no-var, one-var, camelcase, one-var-declaration-per-line, comma-dangle, no-param-reassign, no-return-assign, quotes, prefer-arrow-callback, wrap-iife, consistent-return, no-unused-vars, max-len, no-cond-assign, no-else-return, max-len */ -(function() { - window.ContributorsStatGraphUtil = { - parse_log: function(log) { - var by_author, by_email, data, entry, i, len, total, normalized_email; - total = {}; - by_author = {}; - by_email = {}; - for (i = 0, len = log.length; i < len; i += 1) { - entry = log[i]; - if (total[entry.date] == null) { - this.add_date(entry.date, total); - } - normalized_email = entry.author_email.toLowerCase(); - data = by_author[entry.author_name] || by_email[normalized_email]; - if (data == null) { - data = this.add_author(entry, by_author, by_email); - } - if (!data[entry.date]) { - this.add_date(entry.date, data); - } - this.store_data(entry, total[entry.date], data[entry.date]); - } - total = _.toArray(total); - by_author = _.toArray(by_author); - return { - total: total, - by_author: by_author - }; - }, - add_date: function(date, collection) { - collection[date] = {}; - return collection[date].date = date; - }, - add_author: function(author, by_author, by_email) { - var data, normalized_email; - data = {}; - data.author_name = author.author_name; - data.author_email = author.author_email; - normalized_email = author.author_email.toLowerCase(); - by_author[author.author_name] = data; - by_email[normalized_email] = data; - return data; - }, - store_data: function(entry, total, by_author) { - this.store_commits(total, by_author); - this.store_additions(entry, total, by_author); - return this.store_deletions(entry, total, by_author); - }, - store_commits: function(total, by_author) { - this.add(total, "commits", 1); - return this.add(by_author, "commits", 1); - }, - add: function(collection, field, value) { - if (collection[field] == null) { - collection[field] = 0; - } - return collection[field] += value; - }, - store_additions: function(entry, total, by_author) { - if (entry.additions == null) { - entry.additions = 0; + +export default { + parse_log: function(log) { + var by_author, by_email, data, entry, i, len, total, normalized_email; + total = {}; + by_author = {}; + by_email = {}; + for (i = 0, len = log.length; i < len; i += 1) { + entry = log[i]; + if (total[entry.date] == null) { + this.add_date(entry.date, total); } - this.add(total, "additions", entry.additions); - return this.add(by_author, "additions", entry.additions); - }, - store_deletions: function(entry, total, by_author) { - if (entry.deletions == null) { - entry.deletions = 0; + normalized_email = entry.author_email.toLowerCase(); + data = by_author[entry.author_name] || by_email[normalized_email]; + if (data == null) { + data = this.add_author(entry, by_author, by_email); } - this.add(total, "deletions", entry.deletions); - return this.add(by_author, "deletions", entry.deletions); - }, - get_total_data: function(parsed_log, field) { - var log, total_data; - log = parsed_log.total; - total_data = this.pick_field(log, field); - return _.sortBy(total_data, function(d) { - return d.date; - }); - }, - pick_field: function(log, field) { - var total_data; - total_data = []; - _.each(log, function(d) { - return total_data.push(_.pick(d, [field, 'date'])); - }); - return total_data; - }, - get_author_data: function(parsed_log, field, date_range) { - var author_data, log; - if (date_range == null) { - date_range = null; - } - log = parsed_log.by_author; - author_data = []; - _.each(log, (function(_this) { - return function(log_entry) { - var parsed_log_entry; - parsed_log_entry = _this.parse_log_entry(log_entry, field, date_range); - if (!_.isEmpty(parsed_log_entry.dates)) { - return author_data.push(parsed_log_entry); - } - }; - })(this)); - return _.sortBy(author_data, function(d) { - return d[field]; - }).reverse(); - }, - parse_log_entry: function(log_entry, field, date_range) { - var parsed_entry; - parsed_entry = {}; - parsed_entry.author_name = log_entry.author_name; - parsed_entry.author_email = log_entry.author_email; - parsed_entry.dates = {}; - parsed_entry.commits = parsed_entry.additions = parsed_entry.deletions = 0; - _.each(_.omit(log_entry, 'author_name', 'author_email'), (function(_this) { - return function(value, key) { - if (_this.in_range(value.date, date_range)) { - parsed_entry.dates[value.date] = value[field]; - parsed_entry.commits += value.commits; - parsed_entry.additions += value.additions; - return parsed_entry.deletions += value.deletions; - } - }; - })(this)); - return parsed_entry; - }, - in_range: function(date, date_range) { - var ref; - if (date_range === null || (date_range[0] <= (ref = new Date(date)) && ref <= date_range[1])) { - return true; - } else { - return false; + if (!data[entry.date]) { + this.add_date(entry.date, data); } + this.store_data(entry, total[entry.date], data[entry.date]); + } + total = _.toArray(total); + by_author = _.toArray(by_author); + return { + total: total, + by_author: by_author + }; + }, + add_date: function(date, collection) { + collection[date] = {}; + return collection[date].date = date; + }, + add_author: function(author, by_author, by_email) { + var data, normalized_email; + data = {}; + data.author_name = author.author_name; + data.author_email = author.author_email; + normalized_email = author.author_email.toLowerCase(); + by_author[author.author_name] = data; + by_email[normalized_email] = data; + return data; + }, + store_data: function(entry, total, by_author) { + this.store_commits(total, by_author); + this.store_additions(entry, total, by_author); + return this.store_deletions(entry, total, by_author); + }, + store_commits: function(total, by_author) { + this.add(total, "commits", 1); + return this.add(by_author, "commits", 1); + }, + add: function(collection, field, value) { + if (collection[field] == null) { + collection[field] = 0; + } + return collection[field] += value; + }, + store_additions: function(entry, total, by_author) { + if (entry.additions == null) { + entry.additions = 0; + } + this.add(total, "additions", entry.additions); + return this.add(by_author, "additions", entry.additions); + }, + store_deletions: function(entry, total, by_author) { + if (entry.deletions == null) { + entry.deletions = 0; + } + this.add(total, "deletions", entry.deletions); + return this.add(by_author, "deletions", entry.deletions); + }, + get_total_data: function(parsed_log, field) { + var log, total_data; + log = parsed_log.total; + total_data = this.pick_field(log, field); + return _.sortBy(total_data, function(d) { + return d.date; + }); + }, + pick_field: function(log, field) { + var total_data; + total_data = []; + _.each(log, function(d) { + return total_data.push(_.pick(d, [field, 'date'])); + }); + return total_data; + }, + get_author_data: function(parsed_log, field, date_range) { + var author_data, log; + if (date_range == null) { + date_range = null; + } + log = parsed_log.by_author; + author_data = []; + _.each(log, (function(_this) { + return function(log_entry) { + var parsed_log_entry; + parsed_log_entry = _this.parse_log_entry(log_entry, field, date_range); + if (!_.isEmpty(parsed_log_entry.dates)) { + return author_data.push(parsed_log_entry); + } + }; + })(this)); + return _.sortBy(author_data, function(d) { + return d[field]; + }).reverse(); + }, + parse_log_entry: function(log_entry, field, date_range) { + var parsed_entry; + parsed_entry = {}; + parsed_entry.author_name = log_entry.author_name; + parsed_entry.author_email = log_entry.author_email; + parsed_entry.dates = {}; + parsed_entry.commits = parsed_entry.additions = parsed_entry.deletions = 0; + _.each(_.omit(log_entry, 'author_name', 'author_email'), (function(_this) { + return function(value, key) { + if (_this.in_range(value.date, date_range)) { + parsed_entry.dates[value.date] = value[field]; + parsed_entry.commits += value.commits; + parsed_entry.additions += value.additions; + return parsed_entry.deletions += value.deletions; + } + }; + })(this)); + return parsed_entry; + }, + in_range: function(date, date_range) { + var ref; + if (date_range === null || (date_range[0] <= (ref = new Date(date)) && ref <= date_range[1])) { + return true; + } else { + return false; } - }; -}).call(window); + } +}; diff --git a/app/assets/javascripts/header.js b/app/assets/javascripts/header.js index fa85f9a6c86..a853c3aeb1f 100644 --- a/app/assets/javascripts/header.js +++ b/app/assets/javascripts/header.js @@ -2,7 +2,7 @@ (function() { $(document).on('todo:toggle', function(e, count) { var $todoPendingCount = $('.todos-pending-count'); - $todoPendingCount.text(gl.text.addDelimiter(count)); + $todoPendingCount.text(gl.text.highCountTrim(count)); $todoPendingCount.toggleClass('hidden', count === 0); }); })(); diff --git a/app/assets/javascripts/lib/utils/text_utility.js b/app/assets/javascripts/lib/utils/text_utility.js index f755d212b3c..579d322e3fb 100644 --- a/app/assets/javascripts/lib/utils/text_utility.js +++ b/app/assets/javascripts/lib/utils/text_utility.js @@ -14,6 +14,9 @@ require('vendor/latinise'); gl.text.addDelimiter = function(text) { return text ? text.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") : text; }; + gl.text.highCountTrim = function(count) { + return count > 99 ? '99+' : count; + }; gl.text.randomString = function() { return Math.random().toString(36).substring(7); }; diff --git a/app/assets/javascripts/milestone_select.js b/app/assets/javascripts/milestone_select.js index 8df1c8e7f94..51fa5c828b3 100644 --- a/app/assets/javascripts/milestone_select.js +++ b/app/assets/javascripts/milestone_select.js @@ -39,7 +39,7 @@ $value = $block.find('.value'); $loading = $block.find('.block-loading').fadeOut(); if (issueUpdateURL) { - milestoneLinkTemplate = _.template('<a href="/<%- namespace %>/<%- path %>/milestones/<%- iid %>" class="bold has-tooltip" data-container="body" title="<%- remaining %>"><%- title %></a>'); + milestoneLinkTemplate = _.template('<a href="/<%- full_path %>/milestones/<%- iid %>" class="bold has-tooltip" data-container="body" title="<%- remaining %>"><%- title %></a>'); milestoneLinkNoneTemplate = '<span class="no-value">None</span>'; collapsedSidebarLabelTemplate = _.template('<span class="has-tooltip" data-container="body" title="<%- remaining %>" data-placement="left"> <%- title %> </span>'); } @@ -181,8 +181,7 @@ $selectbox.hide(); $value.css('display', ''); if (data.milestone != null) { - data.milestone.namespace = _this.currentProject.namespace; - data.milestone.path = _this.currentProject.path; + data.milestone.full_path = _this.currentProject.full_path; data.milestone.remaining = gl.utils.timeFor(data.milestone.due_date); $value.html(milestoneLinkTemplate(data.milestone)); return $sidebarCollapsedValue.find('span').html(collapsedSidebarLabelTemplate(data.milestone)); diff --git a/app/assets/javascripts/network/network_bundle.js b/app/assets/javascripts/network/network_bundle.js index aae509caa79..e5947586583 100644 --- a/app/assets/javascripts/network/network_bundle.js +++ b/app/assets/javascripts/network/network_bundle.js @@ -2,9 +2,8 @@ /* global Network */ /* global ShortcutsNetwork */ -// require everything else in this directory -function requireAll(context) { return context.keys().map(context); } -requireAll(require.context('.', false, /^\.\/(?!network_bundle).*\.(js|es6)$/)); +require('./branch_graph'); +require('./network'); (function() { $(function() { diff --git a/app/assets/javascripts/search_autocomplete.js.es6 b/app/assets/javascripts/search_autocomplete.js.es6 index 6250e75d407..6fd5345a0a6 100644 --- a/app/assets/javascripts/search_autocomplete.js.es6 +++ b/app/assets/javascripts/search_autocomplete.js.es6 @@ -169,10 +169,10 @@ url: issuesPath + "/?author_username=" + userName }, 'separator', { text: 'Merge requests assigned to me', - url: mrPath + "/?assignee_id=" + userId + url: mrPath + "/?assignee_username=" + userName }, { text: "Merge requests I've created", - url: mrPath + "/?author_id=" + userId + url: mrPath + "/?author_username=" + userName } ]; if (!name) { diff --git a/app/assets/javascripts/version_check_image.js.es6 b/app/assets/javascripts/version_check_image.js.es6 index 1fa2b5ac399..d4f716acb72 100644 --- a/app/assets/javascripts/version_check_image.js.es6 +++ b/app/assets/javascripts/version_check_image.js.es6 @@ -1,10 +1,10 @@ -(() => { - class VersionCheckImage { - static bindErrorEvent(imageElement) { - imageElement.off('error').on('error', () => imageElement.hide()); - } +class VersionCheckImage { + static bindErrorEvent(imageElement) { + imageElement.off('error').on('error', () => imageElement.hide()); } +} - window.gl = window.gl || {}; - gl.VersionCheckImage = VersionCheckImage; -})(); +window.gl = window.gl || {}; +gl.VersionCheckImage = VersionCheckImage; + +module.exports = VersionCheckImage; diff --git a/app/assets/javascripts/vue_pipelines_index/pipelines.js.es6 b/app/assets/javascripts/vue_pipelines_index/pipelines.js.es6 index 0265c00a414..9d66d28cc62 100644 --- a/app/assets/javascripts/vue_pipelines_index/pipelines.js.es6 +++ b/app/assets/javascripts/vue_pipelines_index/pipelines.js.es6 @@ -23,7 +23,7 @@ const CommitPipelinesStoreWithTimeAgo = require('../commit/pipelines/pipelines_s apiScope: 'all', pageInfo: {}, pagenum: 1, - count: { all: 0, running_or_pending: 0 }, + count: {}, pageRequest: false, }; }, diff --git a/app/assets/javascripts/vue_pipelines_index/stage.js.es6 b/app/assets/javascripts/vue_pipelines_index/stage.js.es6 index 8cc417a9966..67fdd729e41 100644 --- a/app/assets/javascripts/vue_pipelines_index/stage.js.es6 +++ b/app/assets/javascripts/vue_pipelines_index/stage.js.es6 @@ -23,6 +23,13 @@ required: true, }, }, + + updated() { + if (this.builds) { + this.stopDropdownClickPropagation(); + } + }, + methods: { fetchBuilds(e) { const areaExpanded = e.currentTarget.attributes['aria-expanded']; @@ -37,17 +44,19 @@ return flash; }); }, - keepGraph(e) { - const { target } = e; - - if (target.className.indexOf('js-ci-action-icon') >= 0) return null; - - if ( - target.parentElement && - (target.parentElement.className.indexOf('js-ci-action-icon') >= 0) - ) return null; - return e.stopPropagation(); + /** + * When the user right clicks or cmd/ctrl + click in the job name + * the dropdown should not be closed and the link should open in another tab, + * so we stop propagation of the click event inside the dropdown. + * + * Since this component is rendered multiple times per page we need to guarantee we only + * target the click event of this component. + */ + stopDropdownClickPropagation() { + $(this.$el.querySelectorAll('.js-builds-dropdown-list a.mini-pipeline-graph-dropdown-item')).on('click', (e) => { + e.stopPropagation(); + }); }, }, computed: { @@ -76,13 +85,13 @@ template: ` <div> <button - @click='fetchBuilds($event)' + @click="fetchBuilds($event)" :class="triggerButtonClass" - :title='stage.title' + :title="stage.title" data-placement="top" data-toggle="dropdown" type="button" - :aria-label='stage.title' + :aria-label="stage.title" > <span v-html="svg" aria-hidden="true"></span> <i class="fa fa-caret-down" aria-hidden="true"></i> @@ -90,7 +99,6 @@ <ul class="dropdown-menu mini-pipeline-graph-dropdown-menu js-builds-dropdown-container"> <div class="arrow-up" aria-hidden="true"></div> <div - @click='keepGraph($event)' :class="dropdownClass" class="js-builds-dropdown-list scrollable-menu" v-html="buildsOrSpinner" diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss index 2bfdb9f9601..55ed4b7b06c 100644 --- a/app/assets/stylesheets/framework/lists.scss +++ b/app/assets/stylesheets/framework/lists.scss @@ -96,16 +96,6 @@ ul.unstyled-list > li { border-bottom: none; } -ul.task-list { - li.task-list-item { - list-style-type: none; - } - - ul:not(.task-list) { - padding-left: 1.3em; - } -} - // Generic content list ul.content-list { @include basic-list; diff --git a/app/assets/stylesheets/framework/mixins.scss b/app/assets/stylesheets/framework/mixins.scss index 1acd06122a3..df78bbdea51 100644 --- a/app/assets/stylesheets/framework/mixins.scss +++ b/app/assets/stylesheets/framework/mixins.scss @@ -76,6 +76,13 @@ #{$property}: $value; } +/* http://phrappe.com/css/conditional-css-for-webkit-based-browsers/ */ +@mixin on-webkit-only { + @media screen and (-webkit-min-device-pixel-ratio:0) { + @content; + } +} + @mixin keyframes($animation-name) { @-webkit-keyframes #{$animation-name} { @content; diff --git a/app/assets/stylesheets/framework/sidebar.scss b/app/assets/stylesheets/framework/sidebar.scss index d09b1c9d7f5..8978e284f55 100644 --- a/app/assets/stylesheets/framework/sidebar.scss +++ b/app/assets/stylesheets/framework/sidebar.scss @@ -55,7 +55,7 @@ padding-right: 0; @media (min-width: $screen-sm-min) and (max-width: $screen-sm-max) { - &:not(.build-sidebar):not(.wiki-sidebar) { + .content-wrapper { padding-right: $gutter_collapsed_width; } } diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss index 54958973f15..db5e2c51fe7 100644 --- a/app/assets/stylesheets/framework/typography.scss +++ b/app/assets/stylesheets/framework/typography.scss @@ -134,7 +134,7 @@ ul, ol { padding: 0; - margin: 3px 0 3px 28px !important; + margin: 3px 0 !important; } ul:dir(rtl), @@ -144,6 +144,29 @@ li { line-height: 1.6em; + margin-left: 25px; + padding-left: 3px; + + /* Normalize the bullet position on webkit. */ + @include on-webkit-only { + margin-left: 28px; + padding-left: 0; + } + } + + ul.task-list { + li.task-list-item { + list-style-type: none; + position: relative; + padding-left: 28px; + margin-left: 0 !important; + + input.task-list-item-checkbox { + position: absolute; + left: 8px; + top: 5px; + } + } } a[href*="/uploads/"], diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss index 181dcb7721f..f789ae1ccd3 100644 --- a/app/assets/stylesheets/pages/environments.scss +++ b/app/assets/stylesheets/pages/environments.scss @@ -35,7 +35,6 @@ display: table-cell; } - .environments-name, .environments-commit, .environments-actions { width: 20%; @@ -45,6 +44,7 @@ width: 10%; } + .environments-name, .environments-deploy, .environments-build { width: 15%; @@ -62,6 +62,22 @@ } } + .btn-group { + + > a { + color: $gl-text-color-secondary; + } + + svg path { + fill: $gl-text-color-secondary; + } + + .dropdown { + outline: none; + } + } + + .commit-title { margin: 0; } diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss index 80b0c9493d8..b595480561b 100644 --- a/app/assets/stylesheets/pages/issues.scss +++ b/app/assets/stylesheets/pages/issues.scss @@ -10,6 +10,11 @@ .issue-labels { display: inline-block; } + + .icon-merge-request-unmerged { + height: 13px; + margin-bottom: 3px; + } } } diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss index 00eb5b30fd5..3fe1eef307e 100644 --- a/app/assets/stylesheets/pages/pipelines.scss +++ b/app/assets/stylesheets/pages/pipelines.scss @@ -222,6 +222,11 @@ } } + .dropdown-menu { + max-height: 250px; + overflow-y: auto; + } + .dropdown-toggle, .dropdown-menu { color: $gl-text-color-secondary; diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index 6b05e5bb4aa..67110813abb 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -268,6 +268,13 @@ } } +.project-repo-buttons { + .project-action-button .dropdown-menu { + max-height: 250px; + overflow-y: auto; + } +} + .split-one { display: inline-table; margin-right: 12px; diff --git a/app/assets/stylesheets/pages/todos.scss b/app/assets/stylesheets/pages/todos.scss index 551a66fbf3a..af9ddb9ff80 100644 --- a/app/assets/stylesheets/pages/todos.scss +++ b/app/assets/stylesheets/pages/todos.scss @@ -6,6 +6,8 @@ .navbar-nav { li { .badge.todos-pending-count { + position: inherit; + top: -6px; margin-top: -5px; font-weight: normal; background: $todo-alert-blue; @@ -43,6 +45,12 @@ } } + .todo-avatar, + .todo-actions { + -webkit-flex: 0 0 auto; + flex: 0 0 auto; + } + .todo-actions { display: -webkit-flex; display: flex; @@ -55,8 +63,9 @@ } .todo-item { - -webkit-flex: auto; - flex: auto; + -webkit-flex: 0 1 100%; + flex: 0 1 100%; + min-width: 0; } } @@ -74,8 +83,29 @@ .todo-item { .todo-title { - @include str-truncated(calc(100% - 174px)); - overflow: visible; + display: flex; + + & > .title-item { + -webkit-flex: 0 0 auto; + flex: 0 0 auto; + margin: 0 2px; + + &:first-child { + margin-left: 0; + } + + &:last-child { + margin-right: 0; + } + } + + .todo-label { + -webkit-flex: 0 1 auto; + flex: 0 1 auto; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } } .status-box { @@ -154,10 +184,12 @@ .todo-item { .todo-title { - white-space: normal; - overflow: visible; - max-width: 100%; + flex-flow: row wrap; margin-bottom: 10px; + + .todo-label { + white-space: normal; + } } .todo-body { |